This commit is contained in:
ntr
2019-03-28 15:23:03 +11:00
parent 2494b2dd5f
commit 4e1b1dd2cb
38 changed files with 4551 additions and 1 deletions
+72
View File
@@ -0,0 +1,72 @@
// eslint-disable-next-line
const preact = require('preact');
const { connect } = require('preact-redux');
const actions = require('../actions');
const InstanceListContainer = require('./instance.list.container');
const CrypSpawnContainer = require('./cryp.spawn.container');
const CrypListContainer = require('./cryp.list.container');
const GameContainer = require('./game.container');
const InstanceContainer = require('./instance.container');
const addState = connect(
(state) => {
const { game, instance, ws } = state;
if (!game) {
console.log('clear gs interval');
// ws.clearGameStateInterval();
}
return { game, instance };
},
(dispatch) => {
function setGame(game) {
dispatch(actions.setGame(game));
}
return { setGame };
},
);
function renderBody(props) {
const { game, instance, setGame } = props;
if (game) {
return (
<div>
<GameContainer />
<button
className="button is-dark is-fullwidth"
type="submit"
onClick={() => setGame(null)}
>
Return to Main Menu
</button>
</div>
);
}
if (instance) {
return (
<div>
<InstanceContainer />
</div>
);
}
return (
<div>
<div className="background"/>
<CrypSpawnContainer />
<section className="row" >
<div className="six columns">
<CrypListContainer />
</div>
<div className="six columns">
<InstanceListContainer />
</div>
</section>
</div>
);
}
module.exports = addState(renderBody);
@@ -0,0 +1,27 @@
const { connect } = require('preact-redux');
const CrypList = require('./cryp.list');
const addState = connect(
function receiveState(state) {
const { ws, cryps, activeItem } = state;
function sendGamePve(crypId) {
return ws.sendGamePve(crypId);
}
function sendGamePvp(crypIds) {
return ws.sendGamePvp(crypIds);
}
function sendItemUse(targetId) {
if (activeItem) {
return ws.sendItemUse(activeItem, targetId);
}
return false;
}
return { cryps, sendGamePve, sendGamePvp, activeItem, sendItemUse };
}
);
module.exports = addState(CrypList);
+29
View File
@@ -0,0 +1,29 @@
const preact = require('preact');
const { stringSort } = require('./../utils');
const idSort = stringSort('id');
function CrypList({ cryps, activeCryp, avatar }) {
if (!cryps) return <div>not ready</div>;
const crypPanels = cryps.sort(idSort).map(cryp => (
<div key={cryp.id} className="home-cryp">
<h2>{cryp.name}</h2>
<div>{cryp.hp.value} HP</div>
<button
type="submit"
disabled={cryp.hp.value === 0}
onClick={() => activeCryp(cryp.id)}>
activate
</button>
</div>
));
return (
<div>
{crypPanels}
</div>
);
}
module.exports = CrypList;
@@ -0,0 +1,32 @@
const preact = require('preact');
function renderSpawnButton({ account, sendCrypSpawn }) {
let name = '';
if (!account) return <div>...</div>;
return false;
return (
<div className="row">
<div className="two columns">
<input
className="input"
type="text"
placeholder="cryp name"
onChange={e => (name = e.target.value)}
/>
</div>
<div className="two columns">
<button
className="button"
type="submit"
onClick={() => sendCrypSpawn(name)}>
Spawn 👾
</button>
</div>
</div>
);
}
module.exports = renderSpawnButton;
@@ -0,0 +1,16 @@
const { connect } = require('preact-redux');
const CrypSpawnButton = require('./cryp.spawn.button');
const addState = connect(
function receiveState(state) {
const { ws } = state;
function sendCrypSpawn(name) {
return ws.sendCrypSpawn(name);
}
return { account: state.account, sendCrypSpawn };
}
);
module.exports = addState(CrypSpawnButton);
@@ -0,0 +1,48 @@
const { connect } = require('preact-redux');
const actions = require('../actions');
const Game = require('./game');
const addState = connect(
function receiveState(state) {
const { ws, game, account, activeSkill, activeIncoming } = state;
function selectSkillTarget(targetTeamId) {
if (activeSkill) {
return ws.sendGameSkill(game.id, activeSkill.crypId, targetTeamId, activeSkill.skill.skill);
}
return false;
}
// intercept self casting skills
if (activeSkill && activeSkill.skill.self_targeting) {
ws.sendGameSkill(game.id, activeSkill.crypId, null, activeSkill.skill.skill);
}
function selectIncomingTarget(crypId) {
if (activeIncoming) {
return ws.sendGameTarget(game.id, crypId, activeIncoming);
}
return false;
}
return { game, account, activeSkill, activeIncoming, selectSkillTarget, selectIncomingTarget };
},
function receiveDispatch(dispatch) {
function setActiveSkill(crypId, skill) {
dispatch(actions.setActiveSkill(crypId, skill));
}
function setActiveIncoming(skillId) {
dispatch(actions.setActiveIncoming(skillId));
}
return { setActiveSkill, setActiveIncoming };
}
);
module.exports = addState(Game);
@@ -0,0 +1,42 @@
const preact = require('preact');
const { connect } = require('preact-redux');
const addState = connect(
(state) => {
const { ws, cryps } = state;
function sendGameJoin(gameId) {
return ws.sendGameJoin(gameId, [cryps[0].id]);
}
return { account: state.account, sendGameJoin };
},
);
function GameJoinButton({ account, sendGameJoin }) {
let gameId = '';
if (!account) return <div>...</div>;
return (
<div className="columns">
<div className="column">
<input
className="input"
type="text"
placeholder="gameId"
onChange={e => (gameId = e.target.value)}
/>
</div>
<div className="column is-4">
<button
className="button is-dark is-fullwidth"
type="submit"
onClick={() => sendGameJoin(gameId)}>
Join Game
</button>
</div>
</div>
);
}
module.exports = addState(GameJoinButton);
+184
View File
@@ -0,0 +1,184 @@
const preact = require('preact');
const key = require('keymaster');
const SKILL_HOT_KEYS = ['Q', 'W', 'E', 'R'];
function GamePanel(props) {
const {
game,
activeSkill,
activeIncoming,
setActiveSkill,
setActiveIncoming,
selectSkillTarget,
selectIncomingTarget,
account,
} = props;
if (!game) return <div>...</div>;
const otherTeams = game.teams.filter(t => t.id !== account.id);
const playerTeam = game.teams.find(t => t.id === account.id);
const incoming = game.stack.filter(s => s.target_team_id === playerTeam.id).map((inc) => {
key.unbind('1');
key('1', () => setActiveIncoming(inc.id));
return (
<div className="tile is-child" key={inc.id}>
<div>{JSON.stringify(inc)}</div>
<button
className="button is-dark is-fullwidth"
type="submit"
onClick={() => setActiveIncoming(inc.id)}>
(1) Block skill: {inc.skill}
</button>
</div>
);
});
function PlayerCrypCard(cryp) {
const skills = cryp.skills.map((skill, i) => {
const hotkey = SKILL_HOT_KEYS[i];
key.unbind(hotkey);
key(hotkey, () => setActiveSkill(cryp.id, skill));
return (
<button
key={i}
className="button is-dark"
type="submit"
onClick={() => setActiveSkill(cryp.id, skill)}
>
({hotkey}) {skill.skill} {skill.cd && `(${skill.cd}T)`}
</button>
);
});
const effects = cryp.effects.map((effect, i) => (
<div key={i}>{effect} for {effect.turns}T</div>
));
return (
<div
key={cryp.id}
style={ activeIncoming ? { cursor: 'pointer' } : {}}
onClick={() => selectIncomingTarget(cryp.id)}
className="tile is-vertical">
<div className="tile is-child">
<div className="columns" >
<div className="column is-10">
<p className="title">{cryp.name}</p>
<p className="subtitle">Level {cryp.lvl}</p>
</div>
<div className="column">
<figure className="image">
<svg width="40" height="40" data-jdenticon-value={cryp.name} />
</figure>
</div>
</div>
<div className="has-text-centered">{cryp.hp.value} / {cryp.stam.value} HP </div>
<progress className="progress is-dark" value={cryp.hp.value} max={cryp.stam.value}></progress>
<div className="has-text-centered">{cryp.xp} / {Math.pow(2, cryp.lvl + 1)} XP </div>
<progress className="progress is-dark" value={cryp.xp} max={Math.pow(2, cryp.lvl + 1)}></progress>
</div>
{effects}
{skills}
</div>
);
}
function PlayerTeam(team) {
const cryps = team.cryps.map(c => PlayerCrypCard(c, setActiveSkill));
return (
<div className="tile">
{cryps}
</div>
);
}
function OpponentCrypCard(cryp) {
const effects = cryp.effects.map((effect, i) => (
<div key={i}>{effect.effect} for {effect.turns}T</div>
));
return (
<div key={cryp.id} className="tile is-vertical">
<div className="tile is-child">
<div className="columns" >
<div className="column is-10">
<p className="title">{cryp.name}</p>
<p className="subtitle">Level {cryp.lvl}</p>
</div>
<div className="column">
<figure className="image">
<svg width="40" height="40" data-jdenticon-value={cryp.name} />
</figure>
</div>
</div>
<div className="has-text-centered">{cryp.hp.value} / {cryp.stam.value} HP </div>
<progress className="progress is-dark" value={cryp.hp.value} max={cryp.stam.value}></progress>
<div className="has-text-centered">{cryp.xp} / {Math.pow(2, cryp.lvl + 1)} XP </div>
<progress className="progress is-dark" value={cryp.xp} max={Math.pow(2, cryp.lvl + 1)}></progress>
</div>
{effects}
</div>
);
}
function OpponentTeam(team) {
const cryps = team.cryps.map(OpponentCrypCard);
return (
<div
className="tile"
style={activeSkill ? { cursor: 'pointer' } : {}}
onClick={() => selectSkillTarget(team.id)} >
{cryps}
</div>
);
}
// style={{ "min-height": "100%" }}
function phaseText(phase) {
switch (phase) {
case 'Skill':
return 'Choose abilities';
case 'Target':
return 'Block abilities';
case 'Finish':
return 'Game over';
}
}
const logs = game.log.reverse().map((l, i) => (<div key={i}>{l}</div>));
return (
<section className="columns">
<div className="column is-2 title is-1">
{phaseText(game.phase)}
</div>
<div className="column is-4">
{PlayerTeam(playerTeam, setActiveSkill)}
</div>
<div className="column is-4">
<div>
{otherTeams.map(OpponentTeam)}
</div>
<div>
{incoming}
</div>
</div>
<div className="column is-2">
<div className="title is-4">{logs}</div>
</div>
</section>
);
}
module.exports = GamePanel;
@@ -0,0 +1,17 @@
// eslint-disable-next-line
const preact = require('preact');
const LoginContainer = require('./login.container');
function renderHeader() {
return (
<header className="row header">
<h1 className="cryps-title six columns">
cryps.gg
</h1>
<LoginContainer />
</header>
);
}
module.exports = renderHeader;
@@ -0,0 +1,78 @@
const preact = require('preact');
const key = require('keymaster');
function convertVar(v) {
return v || '';
}
function Vbox(vbox) {
if (!vbox) return false;
const free = [];
for (let i = 0 ; i < vbox.free[0].length; i++) {
free.push([vbox.free[0][i], vbox.free[1][i], vbox.free[2][i]]);
}
const rows = free.map((row, i) => (
<tr key={i}>
<td>{convertVar(row[0])}</td>
<td>{convertVar(row[1])}</td>
<td>{convertVar(row[2])}</td>
</tr>
));
return (
<div className="four columns">
<span>vBox</span>
<table className="vbox-table">
<tbody>
{rows}
</tbody>
</table>
{JSON.stringify(vbox)}
</div>
);
}
function InstanceComponent(props) {
const {
instance,
account,
sendInstanceReady,
quit,
} = props;
if (!instance) return <div>...</div>;
return (
<section>
<div className="row">
<div className="six columns">
<button
className="instance-btn instance-ui-btn glow-btn"
onClick={quit}>
Menu
</button>
</div>
<div className="six columns">
<button
className="instance-btn instance-ui-btn green-btn u-pull-right"
onClick={() => sendInstanceReady()}>
Ready
</button>
</div>
</div>
<div className="row">
{Vbox(instance.vbox)}
<div className="four columns">
{JSON.stringify(instance.cryps)}
</div>
<div className="four columns">
ready btn
</div>
</div>
</section>
);
}
module.exports = InstanceComponent;
@@ -0,0 +1,27 @@
const { connect } = require('preact-redux');
const actions = require('../actions');
const Instance = require('./instance.component');
const addState = connect(
function receiveState(state) {
const { ws, instance, account } = state;
function sendInstanceReady() {
return ws.sendInstanceReady(instance.id);
}
return { instance, account, sendInstanceReady };
},
function receiveDispatch(dispatch, { instance }) {
function quit() {
dispatch(actions.setInstance(null));
}
return { quit };
}
);
module.exports = addState(Instance);
@@ -0,0 +1,27 @@
const { connect } = require('preact-redux');
const actions = require('../actions');
const InstanceList = require('./instance.list');
const addState = connect(
function receiveState(state) {
const { ws, events, instances } = state;
function setCrypsSet() {
console.log('set crypos');
// return ws.sendGamePvp(crypIds);
}
return { instances, setCrypsSet };
},
function receiveDispatch(dispatch) {
function setActiveInstance(instance) {
dispatch(actions.setInstance(instance));
}
return { setActiveInstance };
}
);
module.exports = addState(InstanceList);
@@ -0,0 +1,31 @@
// eslint-disable-next-line
const preact = require('preact');
const { NULL_UUID } = require('./../utils');
function instanceList({ instances, setActiveInstance, sendCrypsSet }) {
if (!instances) return <div>...</div>;
const instancePanels = instances.map((instance) => {
const name = instance.instance === NULL_UUID
? 'Normal Mode'
: `${instance.instance.substring(0, 5)}`;
return (
<button
className="instance-btn glow-btn"
key={instance.id}
onClick={() => setActiveInstance(instance)}>
{name}
</button>
);
});
return (
<section>
<h2>Instances</h2>
{instancePanels}
</section>
);
}
module.exports = instanceList;
@@ -0,0 +1,20 @@
const { connect } = require('preact-redux');
const actions = require('../actions');
const ItemList = require('./item.list');
const addState = connect(
function receiveState(state) {
const { items } = state;
return { items };
},
function receiveDispatch(dispatch) {
function setActiveItem(id) {
dispatch(actions.setActiveItem(id))
}
return { setActiveItem };
}
);
module.exports = addState(ItemList);
+37
View File
@@ -0,0 +1,37 @@
// eslint-disable-next-line
const preact = require('preact');
function ItemList({ items, setActiveItem }) {
if (!items) return <div>...</div>;
const itemPanels = items.map(item => (
<div key={item.id} className="tile is-parent is-vertical">
<div className="tile is-vertical is-child">
<div className="columns" >
<div className="column is-8">
<p className="title">{item.action}</p>
<p className="subtitle"></p>
</div>
<div className="column">
<figure className="image">
<svg width="40" height="40" data-jdenticon-value={item.action} />
</figure>
</div>
</div>
</div>
<button
className="button is-dark"
type="submit"
onClick={() => setActiveItem(item.id)}>
Use
</button>
</div>
));
return (
<div>
{itemPanels}
</div>
);
}
module.exports = ItemList;
+77
View File
@@ -0,0 +1,77 @@
// eslint-disable-next-line
const preact = require('preact');
function renderLogin({ account, submitLogin, submitRegister }) {
if (account) return (
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" className="ping-svg">
<path d="M0,50l50,-50v100l50,-50" className="ping-path"/>
<path d="M0,50l50,-50v100l50,-50" className="ping-path"/>
</svg>
<h3 className="header-username">{account.name}</h3>
</div>
);
const details = {
name: '',
password: '',
};
return (
<div className="login" >
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
className="input"
type="email"
placeholder="Email"
onChange={e => (details.name = e.target.value)}
/>
<span className="icon is-small is-left">
<i className="fas fa-user" />
</span>
<span className="icon is-small is-right">
<i className="fas fa-check" />
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left">
<input
className="input"
type="password"
placeholder="Password"
onChange={e => (details.password = e.target.value)}
/>
<span className="icon is-small is-left">
<i className="fas fa-lock" />
</span>
</p>
</div>
<div className="field">
<p className="control">
<button
className="button inverted"
type="submit"
onClick={() => submitLogin('ntr', 'grepgrepgrep')}>
Default
</button>
<button
className="button inverted"
type="submit"
onClick={() => submitLogin(details.name, details.password)}>
Login
</button>
<button
className="button inverted"
type="submit"
onClick={() => submitRegister(details.name, details.password)}>
Register
</button>
</p>
</div>
</div>
);
}
module.exports = renderLogin;
+18
View File
@@ -0,0 +1,18 @@
const { connect } = require('preact-redux');
const Login = require('./login.component');
const addState = connect(
(state) => {
const { ws } = state;
function submitLogin(name, password) {
return ws.sendAccountLogin(name, password);
}
function submitRegister(name, password) {
return ws.sendAccountRegister(name, password);
}
return { account: state.account, submitLogin, submitRegister };
},
);
module.exports = addState(Login);
+47
View File
@@ -0,0 +1,47 @@
const preact = require('preact');
// components all the way down
const Icon = name => (
<span>
{name}
<svg width="80" height="80" data-jdenticon-value={name} />
</span>
);
// the css attribute name `class` is reserved in js
// so in react you have to call it `className`
function Navbar() {
const NAMES = ['Mashy', 'ntr'];
return (
<div>
<nav className="navbar">
<div className="navbar-end">
<a href="/somewhere" className="navbar-item is-active">
Home
</a>
<a href="/somewhere" className="navbar-item">
Store
</a>
<a href="/somewhere" className="navbar-item">
FAQ
</a>
<span className="navbar-item">
<a href="/somewhere" className="button is-info is-inverted">
<span className="icon">
<svg width="80" height="80" data-jdenticon-value="Blog" />
</span>
<span>Blog</span>
</a>
</span>
</div>
</nav>
{NAMES.map(Icon)}
</div>
);
// map is a function that is called on every element of an array
// so in this ^^ case it calls Icon('Mashy') which returns some jsx
// that gets put into the dom
}
module.exports = Navbar;