This commit is contained in:
ntr 2019-05-06 00:10:13 +10:00
parent f04a7101ee
commit 3fb35288d8
15 changed files with 203 additions and 175 deletions

View File

@ -1,3 +1,8 @@
# vbox_info ->
combos [strike, [R R Attack]]
specs [spec [bonus amount, [r g b]]
# Playthrough
cryps join game

View File

@ -116,6 +116,21 @@ button.left:hover, button.left:focus {
box-shadow: inset 0.5em 0 0 0 whitesmoke;
}
button.action {
animation: action 1s infinite ease-in-out alternate;
}
@keyframes action {
0% {
box-shadow: inset 0 0 0 0 whitesmoke;
}
100% {
box-shadow: inset 0.5em 0 0 0 whitesmoke;
}
}
svg {
flex: 1;
fill: none;
@ -427,6 +442,12 @@ header {
margin: 0;
}
table .highlight {
background: whitesmoke;
color: black;
font-weight: bold;
}
button[disabled] {
color: #333;
border-color: #333;
@ -489,7 +510,6 @@ table td {
padding: 0.2em;
text-align: center;
height: 40px;
cursor: pointer;
text-transform: uppercase;
}
@ -498,6 +518,7 @@ table td {
transition-duration: 0.5s;
transition-delay: 0;
transition-timing-function: ease;
cursor: pointer;
}
.vbox-table table td:active {

View File

@ -28,7 +28,8 @@
"phaser": "^3.15.1",
"preact": "^8.3.1",
"preact-redux": "^2.0.3",
"redux": "^4.0.0"
"redux": "^4.0.0",
"redux-diff-logger": "0.0.9"
},
"devDependencies": {
"babel-core": "^6.26.3",

View File

@ -4,6 +4,9 @@ export const setAccount = value => ({ type: SET_ACCOUNT, value });
export const SET_CRYPS = 'SET_CRYPS';
export const setCryps = value => ({ type: SET_CRYPS, value });
export const SET_VBOX_INFO = 'SET_VBOX_INFO';
export const setVboxInfo = value => ({ type: SET_VBOX_INFO, value });
export const SET_INSTANCES = 'SET_INSTANCES';
export const setInstances = value => ({ type: SET_INSTANCES, value });

View File

@ -2,7 +2,7 @@ const preact = require('preact');
const range = require('lodash/range');
const { ITEMS: { SKILLS, COLOURS, SPECS: SPEC_CONSTANT } } = require('./../constants');
const { COLOUR_ICONS, STATS, SPECS } = require('../utils');
const { COLOUR_ICONS, STATS, SPECS, convertVar, crypAvatar } = require('../utils');
function Info(args) {
const {
@ -12,10 +12,16 @@ function Info(args) {
instance,
player,
setInfo,
vboxInfo,
} = args;
function infoVar([type, value]) {
let red = 0; let blue = 0; let green = 0;
function CrypVar() {
const [type, value] = info;
if (!type) return false;
let red = 0;
let blue = 0;
let green = 0;
player.cryps.forEach(cryp => {
red += cryp.colours.red;
blue += cryp.colours.blue;
@ -100,7 +106,12 @@ function Info(args) {
}
}
function infoCrypElement(cryp) {
function CrypInfo() {
if (!activeCryp) return false;
const cryp = player.cryps.find(c => c.id === activeCryp.id);
if (!cryp) return false;
// onClick={() => setInfo('skill', { skill: s, cryp })}
const skills = range(0, 3).map(i => {
const skill = cryp.skills[i];
@ -139,7 +150,6 @@ function Info(args) {
return (
<div className="info-cryp">
<h2>{cryp.name}</h2>
<div className="stats">
{stats}
</div>
@ -158,10 +168,10 @@ function Info(args) {
return instance.rounds[instance.rounds.length - 1].find(r => r.player_ids.includes(id));
}
function playerText(player) {
const round = playerRound(player.id);
function playerText(p) {
const round = playerRound(p.id);
if (!round) {
return player.ready
return p.ready
? 'ready'
: '';
}
@ -169,12 +179,14 @@ function Info(args) {
if (round.finished) return 'finished';
if (round.game_id) return 'in game';
return player.ready
return p.ready
? 'ready'
: '';
}
function scoreBoard() {
function ScoreBoard() {
if (activeCryp || info[0]) return null;
const players = instance.players.map((p, i) => {
const pText = playerText(p);
return (
@ -196,29 +208,33 @@ function Info(args) {
);
}
const scoreBoardEl = activeCryp || info[0]
? null
: scoreBoard();
const infoCryp = activeCryp
? infoCrypElement(player.cryps.find(c => c.id === activeCryp.id))
: null;
const otherInfo = info[0]
? infoVar(info)
: null;
function Combos() {
if (!info[0]) return false;
if (activeCryp) return false;
return (
<table>
<tbody>
{vboxInfo.combos.filter(c => c.units.includes(info[1])).map((c, i) =>
<tr key={i} >
<td className="highlight" >{convertVar(c.var)}</td>
{c.units.map(u => <td>{convertVar(u)}</td>)}
</tr>
)}
</tbody>
</table>
);
}
// const beginningHdr = instance.phase === 'Lobby'
// ? <h2>game beginning...</h2>
// : null;
const instanceInfoClass = `instance-info ${!info[0] ? '' : 'hidden'}`;
return (
<div className={instanceInfoClass} >
{scoreBoardEl}
{infoCryp}
{otherInfo}
<div className="instance-info" >
<ScoreBoard />
<CrypInfo />
<Combos />
<CrypVar />
</div>
);
}

View File

@ -10,6 +10,7 @@ const addState = connect(
info,
ws,
instance,
vboxInfo,
player,
} = state;
@ -23,6 +24,7 @@ const addState = connect(
sendUnequip,
instance,
player,
vboxInfo,
};
},

View File

@ -69,7 +69,8 @@ function Cryp(props) {
return setActiveCryp(cryp);
}
return <button key={i} className="right" onClick={skillClick} >{s}</button>;
const classes = `right ${skill ? '' : 'action'}`;
return <button key={i} className={classes} onClick={skillClick} >{s}</button>;
});
// needed for ondrop to fire

View File

@ -3,19 +3,7 @@ const range = require('lodash/range');
const shapes = require('./shapes');
function convertVar(v) {
if (['Red', 'Green', 'Blue'].includes(v)) {
return (
shapes.vboxColour(v.toLowerCase())
);
}
return v || <span>&nbsp;</span>;
// uncomment for double borders in vbox;
// if (v) {
// return <div>{v}</div>;
// }
// return;
}
const { convertVar } = require('./../utils');
function Vbox(args) {
const {
@ -131,10 +119,7 @@ function Vbox(args) {
function boundClick(e, i) {
if (reclaiming && vbox.bound[i]) sendVboxReclaim(i);
else if (vbox.bound[i]) {
const insert = ['Red', 'Green', 'Blue'].includes(vbox.bound[i])
? combiner.findIndex(j => j === null)
: 2;
const insert = combiner.findIndex(j => j === null);
if (insert === -1) return setCombiner([i, null, null]);
combiner[insert] = i;
boundTimer = null;

View File

@ -18,24 +18,24 @@ function registerEvents(store) {
});
// cryp animations
function crypAnimations() {
const cryps = document.querySelectorAll('img');
if (!cryps.length) return window.requestAnimationFrame(crypAnimations);
return anime({
targets: 'img',
translateX: () => anime.random(-20, 20),
translateY: () => anime.random(0, -40),
rotate: () => anime.random(-15, 15),
duration: () => anime.random(5000, 6000),
delay: () => anime.random(0, 1000),
direction: 'alternate',
easing: 'linear',
loop: true,
});
}
setInterval(crypAnimations, 5000);
crypAnimations();
// // cryp animations
// function crypAnimations() {
// const cryps = document.querySelectorAll('img');
// if (!cryps.length) return window.requestAnimationFrame(crypAnimations);
// return anime({
// targets: 'img',
// translateX: () => anime.random(-20, 20),
// translateY: () => anime.random(0, -40),
// rotate: () => anime.random(-15, 15),
// duration: () => anime.random(5000, 6000),
// delay: () => anime.random(0, 1000),
// direction: 'alternate',
// easing: 'linear',
// loop: true,
// });
// }
// setInterval(crypAnimations, 5000);
// crypAnimations();
function setPing(ping) {
store.dispatch(actions.setPing(ping));
@ -134,7 +134,6 @@ function registerEvents(store) {
const player = v.players.find(p => p.id === account.id);
if (player) store.dispatch(actions.setPlayer(player));
if (v) ws.startInstanceStateTimeout(v.id);
return store.dispatch(actions.setInstance(v));
}
@ -150,6 +149,10 @@ function registerEvents(store) {
console.log('EVENT ->', 'crypStatusUpdate', { id, skill, target });
}
function setVboxInfo(v) {
return store.dispatch(actions.setVboxInfo(v));
}
// events.on('SET_PLAYER', setInstance);
// events.on('SEND_SKILL', function skillActive(gameId, crypId, targetCrypId, skill) {
@ -189,94 +192,8 @@ function registerEvents(store) {
});
}
// function loginPrompt() {
// const USER_INPUT = '<input className="input" type="email" placeholder="username" />';
// const PASSWORD_INPUT = '<input className="input" type="password" placeholder="password" />';
// const LOGIN_BUTTON = '<button type="submit">Login</button>';
// const REGISTER_BUTTON = '<button type="submit">Register</button>';
// const DEMO_BUTTON = '<button type="submit">Demo</button>';
// const ws = registry.get('ws');
// function submitLogin(instance, thisToast, button, e, inputs) {
// const USERNAME = inputs[0].value;
// const PASSWORD = inputs[1].value;
// ws.sendAccountLogin(USERNAME, PASSWORD);
// }
// function submitRegister(instance, thisToast, button, e, inputs) {
// const USERNAME = inputs[0].value;
// const PASSWORD = inputs[1].value;
// ws.sendAccountCreate(USERNAME, PASSWORD);
// }
// function submitDemo() {
// ws.sendAccountDemo();
// }
// const existing = document.querySelector('#login'); // Selector of your toast
// if (existing) toast.hide({}, existing, 'reconnect');
// toast.question({
// id: 'login',
// theme: 'dark',
// color: 'black',
// timeout: false,
// // overlay: true,
// drag: false,
// close: false,
// title: 'LOGIN',
// position: 'center',
// inputs: [
// [USER_INPUT, 'change', () => true, true], // true to focus
// [PASSWORD_INPUT, 'change', () => true],
// ],
// buttons: [
// [LOGIN_BUTTON, submitLogin], // true to focus
// [REGISTER_BUTTON, submitRegister], // true to focus
// [DEMO_BUTTON, submitDemo], // true to focus
// ],
// });
// console.log('ACCOUNT', function closeLoginCb() {
// const prompt = document.querySelector('#login'); // Selector of your toast
// if (prompt) toast.hide({ transitionOut: 'fadeOut' }, prompt, 'EVENT ->');
// });
// }
// events.on('CRYP_SPAWN', function spawnPrompt() {
// const NAME_INPUT = '<input className="input" type="email" placeholder="name" />';
// const SPAWN_BUTTON = '<button type="submit">SPAWN</button>';
// const ws = registry.get('ws');
// function submitSpawn(instance, thisToast, button, e, inputs) {
// const NAME = inputs[0].value;
// ws.sendCrypSpawn(NAME);
// instance.hide({ transitionOut: 'fadeOut' }, thisToast, 'button');
// }
// toast.question({
// theme: 'dark',
// color: 'black',
// timeout: false,
// // overlay: true,
// drag: false,
// close: true,
// title: 'SPAWN CRYP',
// position: 'center',
// inputs: [
// [NAME_INPUT, 'change', null, true], // true to focus
// ],
// buttons: [
// [SPAWN_BUTTON, submitSpawn], // true to focus
// ],
// });
// });
return {
errorPrompt,
// loginPrompt,
clearCombiner,
setAccount,
setActiveSkill,
@ -294,6 +211,7 @@ function registerEvents(store) {
setZone,
setPing,
setScores,
setVboxInfo,
};
}

View File

@ -1,8 +1,9 @@
const preact = require('preact');
const jdenticon = require('jdenticon');
const logger = require('redux-diff-logger');
const { Provider } = require('preact-redux');
const { createStore, combineReducers } = require('redux');
const { createStore, combineReducers, applyMiddleware } = require('redux');
const reducers = require('./reducers');
const actions = require('./actions');
@ -15,7 +16,8 @@ const Header = require('./components/header.container');
const Body = require('./components/body.component');
// Redux Store
const store = createStore(
const createStoreWithMiddleware = applyMiddleware(logger)(createStore);
const store = createStoreWithMiddleware(
combineReducers({
account: reducers.accountReducer,
activeSkill: reducers.activeSkillReducer,
@ -27,6 +29,7 @@ const store = createStore(
resolution: reducers.resolutionReducer,
showLog: reducers.showLogReducer,
info: reducers.infoReducer,
vboxInfo: reducers.vboxInfoReducer,
instance: reducers.instanceReducer,
player: reducers.playerReducer,
ping: reducers.pingReducer,
@ -37,9 +40,10 @@ const store = createStore(
})
);
document.fonts.load('16pt "Jura"').then(() => {
const events = registerEvents(store);
store.subscribe(() => console.log(store.getState()));
// store.subscribe(() => console.log(store.getState()));
setupKeys(store);
const ws = createSocket(events);

View File

@ -20,6 +20,16 @@ function pingReducer(state = defaultPing, action) {
}
}
const defaultVboxInfo = { combos: [], vars: [] };
function vboxInfoReducer(state = defaultVboxInfo, action) {
switch (action.type) {
case actions.SET_VBOX_INFO:
return action.value;
default:
return state;
}
}
const defaultActiveSkill = null;
function activeSkillReducer(state = defaultActiveSkill, action) {
switch (action.type) {
@ -188,4 +198,5 @@ module.exports = {
wsReducer,
infoReducer,
pingReducer,
vboxInfoReducer,
};

View File

@ -64,14 +64,6 @@ function createSocket(events) {
send({ method: 'cryp_spawn', params: { name } });
}
function sendCrypLearn(id, skill) {
send({ method: 'cryp_learn', params: { id, skill } });
}
function sendCrypForget(id, skill) {
send({ method: 'cryp_forget', params: { id, skill } });
}
function sendGameState(id) {
send({ method: 'game_state', params: { id } });
}
@ -119,6 +111,10 @@ function createSocket(events) {
send({ method: 'player_vbox_reclaim', params: { instance_id: instanceId, index } });
}
function sendVboxInfo() {
send({ method: 'vbox_info', params: {} });
}
function sendGameSkill(gameId, crypId, targetCrypId, skill) {
send({
method: 'game_skill',
@ -178,6 +174,7 @@ function createSocket(events) {
function accountInstanceList(res) {
const [struct, playerList] = res;
sendVboxInfo();
events.setInstanceList(playerList);
}
@ -228,9 +225,9 @@ function createSocket(events) {
clearTimeout(instanceStateTimeout);
}
function instanceScores(response) {
const [structName, scores] = response;
events.setScores(scores);
function vboxInfo(response) {
const [structName, info] = response;
events.setVboxInfo(info);
}
// -------------
@ -241,18 +238,16 @@ function createSocket(events) {
// this object wraps the reply types to a function
const handlers = {
cryp_spawn: crypSpawn,
cryp_forget: () => true,
cryp_learn: () => true,
game_state: gameState,
account_login: accountLogin,
account_create: accountLogin,
account_cryps: accountCryps,
account_instances: accountInstanceList,
instance_scores: instanceScores,
zone_create: res => console.log(res),
zone_state: zoneState,
zone_close: res => console.log(res),
instance_state: instanceState,
vbox_info: vboxInfo,
};
function logout() {
@ -346,8 +341,6 @@ function createSocket(events) {
sendGameSkill,
sendGameTarget,
sendCrypSpawn,
sendCrypLearn,
sendCrypForget,
sendSpecForget,
sendZoneCreate,
sendZoneJoin,
@ -364,6 +357,7 @@ function createSocket(events) {
sendVboxCombine,
sendVboxDiscard,
sendVboxUnequip,
sendVboxInfo,
startInstanceStateTimeout,
startGameStateTimeout,
connect,

View File

@ -344,8 +344,23 @@ function getCombatText(cryp, resolution) {
return '';
}
function convertVar(v) {
if (['Red', 'Green', 'Blue'].includes(v)) {
return (
shapes.vboxColour(v.toLowerCase())
);
}
return v || <span>&nbsp;</span>;
// uncomment for double borders in vbox;
// if (v) {
// return <div>{v}</div>;
// }
// return;
}
module.exports = {
stringSort,
convertVar,
numSort,
genAvatar,
crypAvatar,

View File

@ -21,9 +21,9 @@ use account::{Account, account_create, account_login, account_from_token, accoun
use skill::{Skill};
// use zone::{Zone, zone_create, zone_join, zone_close};
use spec::{Spec};
use player::{Score, player_mm_cryps_set, Player};
use player::{Score, player_mm_cryps_set};
use instance::{Instance, instance_state, instance_new, instance_ready, instance_join};
use vbox::{Var, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip};
use vbox::{Var, VboxInfo, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip, vbox_info};
pub struct Rpc;
@ -86,6 +86,8 @@ impl Rpc {
"player_vbox_reclaim" => Rpc::player_vbox_reclaim(data, &mut tx, account.unwrap(), client),
"player_vbox_unequip" => Rpc::player_vbox_unequip(data, &mut tx, account.unwrap(), client),
"vbox_info" => Ok(RpcResponse { method: "vbox_info".to_string(), params: RpcResult::VboxInfo(vbox_info()) }),
_ => Err(format_err!("unknown method - {:?}", v.method)),
};
@ -392,6 +394,7 @@ pub enum RpcResult {
Account(Account),
CrypList(Vec<Cryp>),
GameState(Game),
VboxInfo(VboxInfo),
InstanceScores(Vec<(String, Score)>),
// ZoneState(Zone),
// ZoneClose(()),

View File

@ -344,7 +344,8 @@ impl From<Spec> for Var {
}
struct Combo {
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Combo {
var: Var,
units: Vec<Var>,
}
@ -417,6 +418,50 @@ fn get_combos() -> Vec<Combo> {
return combinations;
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VarInfo {
pub v: Var,
pub spec: bool,
pub skill: bool,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxInfo {
pub combos: Vec<Combo>,
pub vars: Vec<VarInfo>,
}
pub fn vbox_info() -> VboxInfo {
let combos = get_combos();
let mut vars = combos
.into_iter()
.flat_map(|mut c| {
c.units.push(c.var);
c.units
})
.collect::<Vec<Var>>();
vars.sort_unstable();
vars.dedup();
let vars = vars
.into_iter()
.map(|v| VarInfo {
v,
spec: v.into_spec().is_some(),
skill: v.into_skill().is_some(),
})
.collect::<Vec<VarInfo>>();
let combos = get_combos();
return VboxInfo {
combos,
vars,
};
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Vbox {
pub bits: u16,
@ -632,4 +677,8 @@ mod tests {
assert_eq!(count.red, 2);
}
#[test]
fn vbox_info_test() {
println!("{:#?}", vbox_info());
}
}