|
|
|
@ -1,9 +1,10 @@
|
|
|
|
|
import React, { useState } from 'react';
|
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
|
import { ethers, BigNumber } from 'ethers';
|
|
|
|
|
import { useAccount, useContractReads, useContractRead, usePrepareContractWrite, useContractWrite, useWaitForTransaction } from 'wagmi';
|
|
|
|
|
import { Parallax } from 'react-parallax';
|
|
|
|
|
import { NotificationContainer, NotificationManager } from 'react-notifications';
|
|
|
|
|
import { AwesomeButton } from 'react-awesome-button';
|
|
|
|
|
import useWebSocket, { ReadyState } from 'react-use-websocket';
|
|
|
|
|
import Typewriter from 'react-ts-typewriter';
|
|
|
|
|
import Slider from 'rc-slider';
|
|
|
|
|
|
|
|
|
@ -112,6 +113,7 @@ class GenerateBombOverlay extends React.Component {
|
|
|
|
|
class GameMap extends React.Component {
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
this.state = {showStats: false}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shorten(s) {
|
|
|
|
@ -123,21 +125,9 @@ class GameMap extends React.Component {
|
|
|
|
|
<>
|
|
|
|
|
<h1 id="gameMapTitle">Metaverse Map</h1>
|
|
|
|
|
<p id="gameMapText">
|
|
|
|
|
{this.props.unaboomersRadicalized} / {this.props.unaboomerMaxSupply} Unaboomers radicalized and ready to terrorize the metaverse. <br />
|
|
|
|
|
{this.props.unaboomerMaxSupply - this.props.unaboomerMaxSurvivorCount - this.props.unaboomersRadicalized} potential Unaboomers remain.<br />
|
|
|
|
|
{this.props.unaboomersRadicalized} / {this.props.unaboomerMaxSupply} Unaboomers radicalized and ready to terrorize the metaverse. {this.props.unaboomersKilled} killed.<br />
|
|
|
|
|
This round will end and the project will fully start when {this.props.unaboomerMaxSurvivorCount} or less Unaboomers remain standing.<br />
|
|
|
|
|
</p>
|
|
|
|
|
{this.props.unaboomersRadicalized > 0 && (
|
|
|
|
|
<div id="gameStats">
|
|
|
|
|
<ul>
|
|
|
|
|
<li>Active Unaboomers: {this.props.unaboomersRadicalized - this.props.unaboomersKilled}</li>
|
|
|
|
|
<li>Dead Unaboomers: {this.props.unaboomersKilled}</li>
|
|
|
|
|
<li><p className="dots" style={{backgroundColor: '#E3B505'}}></p> _ Active Bombs: {this.props.bombsAssembled - this.props.bombsExploded}</li>
|
|
|
|
|
<li><p className="dots" style={{backgroundColor: '#D01500'}}></p> _ Exploded Bombs: {this.props.bombsExploded}</li>
|
|
|
|
|
<li><p className="dots" style={{backgroundColor: '#0095FF'}}></p> _ Dud Bombs: {this.props.bombsExploded - this.props.unaboomersKilled}</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{this.props.leaderKillCount > 0 && (
|
|
|
|
|
<div id="killLeader">
|
|
|
|
|
<img src={Boomer} width="50px" />
|
|
|
|
@ -158,6 +148,35 @@ class GameMap extends React.Component {
|
|
|
|
|
<GenerateBombOverlay amount={this.props.bombsExploded} color={'#D01500'} type={'dots'} />
|
|
|
|
|
<GenerateBombOverlay amount={this.props.bombsExploded - this.props.unaboomersKilled} color={'#0095FF'} type={'dots'} />
|
|
|
|
|
</div>
|
|
|
|
|
<div id="statsbox">
|
|
|
|
|
{this.state.showStats && (
|
|
|
|
|
<div className="m2">
|
|
|
|
|
<img src={Boomer} width="50px" />
|
|
|
|
|
<p className="nopad">
|
|
|
|
|
Kill Leader:<br />
|
|
|
|
|
<a href={"https://etherscan.io/address/" + this.props.leaderAddress} target="_blank">
|
|
|
|
|
{this.shorten(this.props.leaderAddress)}
|
|
|
|
|
</a>
|
|
|
|
|
</p>
|
|
|
|
|
<p className="nopad">
|
|
|
|
|
{this.props.leaderKillCount} kills
|
|
|
|
|
</p>
|
|
|
|
|
<hr />
|
|
|
|
|
<p className="nopad">
|
|
|
|
|
Active Unaboomers: {this.props.unaboomersRadicalized - this.props.unaboomersKilled} <br />
|
|
|
|
|
Dead Unaboomers: {this.props.unaboomersKilled} <br />
|
|
|
|
|
<i className="dots" style={{backgroundColor: '#E3B505', offset: '-20px'}}></i>: Active Bombs: {this.props.bombsAssembled - this.props.bombsExploded} <br />
|
|
|
|
|
<i className="dots" style={{backgroundColor: '#D01500'}}></i>: Exploded Bombs: {this.props.bombsExploded} <br />
|
|
|
|
|
<i className="dots" style={{backgroundColor: '#0095FF'}}></i>: Dud Bombs: {this.props.bombsExploded - this.props.unaboomersKilled} <br />
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<button className="button" onClick={() => {
|
|
|
|
|
this.setState({showStats: !this.state.showStats})
|
|
|
|
|
}}>
|
|
|
|
|
{this.state.showStats && (<>hide stats</>) || <>show stats</>}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
@ -516,6 +535,7 @@ function Section3(props) {
|
|
|
|
|
<NotificationContainer/>
|
|
|
|
|
</>}
|
|
|
|
|
{isConnected && options.unaboomerMaxSupply > 0 && (
|
|
|
|
|
<>
|
|
|
|
|
<GameMap
|
|
|
|
|
bombsAssembled={options.bombsAssembled}
|
|
|
|
|
bombBalance={options.bombBalance}
|
|
|
|
@ -527,6 +547,8 @@ function Section3(props) {
|
|
|
|
|
unaboomerMaxSupply={options.unaboomerMaxSupply}
|
|
|
|
|
unaboomerMaxSurvivorCount={options.unaboomerMaxSurvivorCount}
|
|
|
|
|
/>
|
|
|
|
|
<Trollbox ws={props.ws} address={address} />
|
|
|
|
|
</>
|
|
|
|
|
) || isConnected && (
|
|
|
|
|
<div id="heroText">
|
|
|
|
|
<h1>loading...</h1>
|
|
|
|
@ -537,12 +559,108 @@ function Section3(props) {
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Trollbox(props) {
|
|
|
|
|
const [showChat, setShowChat] = useState(false);
|
|
|
|
|
const [history, setHistory] = useState(() => {
|
|
|
|
|
const saved = localStorage.getItem('trollboxHistory');
|
|
|
|
|
return saved || JSON.stringify([])
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { sendJsonMessage, readyState } = useWebSocket(props.ws, {
|
|
|
|
|
onOpen: () => {
|
|
|
|
|
console.log('WebSocket connection established.');
|
|
|
|
|
},
|
|
|
|
|
onMessage: (msg) => {
|
|
|
|
|
let h = JSON.parse(history);
|
|
|
|
|
if (h.length > 500) {
|
|
|
|
|
h = h.splice(-500);
|
|
|
|
|
}
|
|
|
|
|
h.push(JSON.parse(msg.data));
|
|
|
|
|
setHistory(JSON.stringify(h));
|
|
|
|
|
},
|
|
|
|
|
shouldReconnect: () => true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
localStorage.setItem('trollboxHistory', history);
|
|
|
|
|
}, [history])
|
|
|
|
|
|
|
|
|
|
const connectionStatus = {
|
|
|
|
|
[ReadyState.CONNECTING]: 'Connecting',
|
|
|
|
|
[ReadyState.OPEN]: 'Open',
|
|
|
|
|
[ReadyState.CLOSING]: 'Closing',
|
|
|
|
|
[ReadyState.CLOSED]: 'Closed',
|
|
|
|
|
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
|
|
|
|
|
}[readyState];
|
|
|
|
|
|
|
|
|
|
function send(event) {
|
|
|
|
|
const message = (new FormData(event.target)).get("message");
|
|
|
|
|
if (message) {
|
|
|
|
|
sendJsonMessage({
|
|
|
|
|
from: props.address,
|
|
|
|
|
message
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
event.target.reset();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function shorten(s) {
|
|
|
|
|
return s.slice(-6)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div id="trollbox">
|
|
|
|
|
{readyState == ReadyState.OPEN && showChat && (
|
|
|
|
|
<>
|
|
|
|
|
<button className="button" onClick={() => {
|
|
|
|
|
setShowChat(false);
|
|
|
|
|
}}>hide chat</button>
|
|
|
|
|
<form id="sendForm" onSubmit={(ev) => {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
send(ev);
|
|
|
|
|
}}>
|
|
|
|
|
<input type="text" name="message" minLength="1" />
|
|
|
|
|
<button type="submit">Send</button>
|
|
|
|
|
</form>
|
|
|
|
|
<ul className="nopad">
|
|
|
|
|
{JSON.parse(history).length > 0 && JSON.parse(history).map((message, idx) => (
|
|
|
|
|
<li key={idx} className="messageLine">
|
|
|
|
|
<span className="fromAddress nopad">
|
|
|
|
|
<a href={"https://etherscan.io/address/" + message.from} target="_blank">
|
|
|
|
|
{shorten(message.from)}
|
|
|
|
|
</a>
|
|
|
|
|
:</span>
|
|
|
|
|
<span className="messageText">{message.message}</span>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{readyState == ReadyState.OPEN && !showChat && (
|
|
|
|
|
<button className="button" onClick={() => {
|
|
|
|
|
setShowChat(true);
|
|
|
|
|
}}>show chat</button>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{readyState == ReadyState.CONNECTING && (
|
|
|
|
|
<p>connecting to trollbox...</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function AllSections(props) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Section1 />
|
|
|
|
|
<Section2 />
|
|
|
|
|
<Section3 contractAddress={props.contractAddress} />
|
|
|
|
|
<Section3 contractAddress={props.contractAddress} ws={props.ws} />
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|