master
lza_menace 2 years ago
parent f15ec5a252
commit ae420cbea3

17
package-lock.json generated

@ -12,7 +12,6 @@
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"ethers": "^5.7.2",
"lodash": "^4.17.21",
"rc-slider": "^10.1.0",
"react": "^18.2.0",
"react-awesome-button": "^7.0.4",
@ -23,6 +22,7 @@
"react-scroll": "^1.8.9",
"react-scroll-parallax": "^3.3.2",
"react-ts-typewriter": "^0.1.8-b",
"react-use-websocket": "^4.2.0",
"typescript": "^4.9.4",
"wagmi": "^0.9.2"
}
@ -21998,6 +21998,15 @@
"react-dom": "^18.2.0"
}
},
"node_modules/react-use-websocket": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.2.0.tgz",
"integrity": "sha512-ZovaTlc/tWX6a590fi3kMWImhyoWj46BWJWvO5oucZJzRnVVhYtes2D9g+5MKXjSdR7Es3456hB89v4/1pcBKg==",
"peerDependencies": {
"react": ">= 18.0.0",
"react-dom": ">= 18.0.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@ -41890,6 +41899,12 @@
"react-dom": "^18.2.0"
}
},
"react-use-websocket": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.2.0.tgz",
"integrity": "sha512-ZovaTlc/tWX6a590fi3kMWImhyoWj46BWJWvO5oucZJzRnVVhYtes2D9g+5MKXjSdR7Es3456hB89v4/1pcBKg==",
"requires": {}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

@ -19,6 +19,7 @@
"react-scroll": "^1.8.9",
"react-scroll-parallax": "^3.3.2",
"react-ts-typewriter": "^0.1.8-b",
"react-use-websocket": "^4.2.0",
"typescript": "^4.9.4",
"wagmi": "^0.9.2"
},

@ -57,7 +57,10 @@ ReactDOM.createRoot(document.getElementById("root")).render(
<RainbowKitProvider chains={chains} initialChain={5}>
<Wallet />
<div className="scrollContainer">
<AllSections contractAddress={'0x5a61b50dcd3d394e91794847c55b05f92d5a8e7c'} />
<AllSections
contractAddress={'0x5a61b50dcd3d394e91794847c55b05f92d5a8e7c'}
ws={'ws://localhost:5000/ws'}
/>
</div>
</RainbowKitProvider>
</WagmiConfig>

@ -36,4 +36,5 @@
--button-danger-color-hover: #6d2d7e;
--button-danger-color-active: #632973;
--button-danger-border: none;
z-index: 0;
}

@ -70,7 +70,7 @@ nav {
-moz-backdrop-filter: blur(3px);
font-size: 14px;
line-height: 14px;
z-index: 999;
z-index: 10;
}
nav::before {

@ -30,6 +30,10 @@
#heroText {
font-size: 2.5em;
}
#gameStats {
display: none;
}
}
#heroImage {
@ -190,4 +194,80 @@
.nopad a {
color: #ff00ea;
}
}
.m2 {
margin: 10px;
}
#statsbox {
position: fixed;
bottom: 0;
left: 0;
background-color: black;
text-align: left;
width: 49%;
margin: 0;
max-height: 400px;
overflow-y: auto;
word-wrap: break-word;
display: flex;
flex-direction: column;
min-width: 300px;
box-shadow: -1px -1px 20px teal;
}
#trollbox {
position: fixed;
bottom: 0;
right: 0;
background-color: black;
text-align: left;
width: 49%;
margin: 0;
max-height: 400px;
overflow-y: auto;
word-wrap: break-word;
display: flex;
flex-direction: column-reverse;
box-shadow: -1px -1px 20px #ff00ea;
min-width: 300px;
}
@media (max-width: 600px) {
#statsbox {
min-width: 200px;
}
#trollbox {
min-width: 200px;
}
}
#trollbox ul li, #trollbox span, #trollbox a {
list-style-type: none;
font-family: monospace;
}
#trollbox form {
margin: .8em 0;
}
#trollbox form input[type="text"] {
width: 60%;
}
.fromAddress {
margin: 4px 4px 0 0;
}
.messageLine {
width: 100%;
flex-direction: column-reverse;
}
.messageDate {
font-size: 8px;
float: right;
line-height: 1em;
}

@ -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,17 +535,20 @@ function Section3(props) {
<NotificationContainer/>
</>}
{isConnected && options.unaboomerMaxSupply > 0 && (
<GameMap
bombsAssembled={options.bombsAssembled}
bombBalance={options.bombBalance}
bombsExploded={options.bombsExploded}
unaboomersRadicalized={options.unaboomersRadicalized}
unaboomersKilled={options.unaboomersKilled}
leaderAddress={options.leaderAddress}
leaderKillCount={options.leaderKillCount}
unaboomerMaxSupply={options.unaboomerMaxSupply}
unaboomerMaxSurvivorCount={options.unaboomerMaxSurvivorCount}
/>
<>
<GameMap
bombsAssembled={options.bombsAssembled}
bombBalance={options.bombBalance}
bombsExploded={options.bombsExploded}
unaboomersRadicalized={options.unaboomersRadicalized}
unaboomersKilled={options.unaboomersKilled}
leaderAddress={options.leaderAddress}
leaderKillCount={options.leaderKillCount}
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} />
</>
)
}
Loading…
Cancel
Save