diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index d68c2068..ae997377 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -141,12 +141,25 @@ section { } } - .game { + .game-demo { grid-area: game; + + display: grid; + grid-template-columns: 1fr 2fr; + + .game { + display: flex; + flex-flow: column; + + .game-construct { + flex: 1; + } + } } .construct-list { grid-area: vcons; + height: 100%; svg { height: 100%; diff --git a/client/src/actions.jsx b/client/src/actions.jsx index d4242eb1..d4fe0dc8 100644 --- a/client/src/actions.jsx +++ b/client/src/actions.jsx @@ -8,6 +8,8 @@ export const setAnimSource = value => ({ type: 'SET_ANIM_SOURCE', value }); export const setAnimTarget = value => ({ type: 'SET_ANIM_TARGET', value }); export const setAnimText = value => ({ type: 'SET_ANIM_TEXT', value }); +export const setDemo = value => ({ type: 'SET_DEMO', value }); + export const setActiveItem = value => ({ type: 'SET_ACTIVE_VAR', value }); export const setActiveSkill = (constructId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: constructId ? { constructId, skill } : null }); export const setCombiner = value => ({ type: 'SET_COMBINER', value: Array.from(value) }); diff --git a/client/src/components/animations.jsx b/client/src/components/animations.jsx index ff1c9eaf..f72b356b 100644 --- a/client/src/components/animations.jsx +++ b/client/src/components/animations.jsx @@ -68,6 +68,7 @@ class ConstructAnimation extends Component { const animSkill = removeTier(skill); if (!constructId.includes(construct.id)) return false; + // find target animation const chooseAnim = (animSkill) => { switch (animSkill) { diff --git a/client/src/components/demo.jsx b/client/src/components/demo.jsx index 1315c593..b06b191e 100644 --- a/client/src/components/demo.jsx +++ b/client/src/components/demo.jsx @@ -1,8 +1,51 @@ +const { connect } = require('preact-redux'); const preact = require('preact'); +const sample = require('lodash/sample'); + +const actions = require('../actions'); const shapes = require('./shapes'); -const molecule = require('./molecule'); + +const { TIMES: { SOURCE_AND_TARGET_TOTAL_DURATION } } = require('./../constants'); + +const { ConstructAvatar } = require('./construct'); +const { ConstructAnimation } = require('./animations'); + +const addState = connect( + function receiveState(state) { + const { + account, + itemInfo, + demo, + } = state; + + return { + account, + itemInfo, + demo, + }; + }, + + function receiveDispatch(dispatch) { + function setAnimTarget(anim) { + dispatch(actions.setAnimTarget(anim)); + } + + return { setAnimTarget }; + } +); + function Demo(args) { + const { + demo, + itemInfo, + account, + + setAnimTarget, + } = args; + + if (!demo || !itemInfo.items.length || account) return false; + const vboxDemo = () => { const phase = this.state.phase || 'vbox'; const items = this.state.items || ['Red', 'Red', 'Attack']; @@ -13,8 +56,6 @@ function Demo(args) { equipped, } = this.state; - console.log(combiner, this.state); - function inventoryBtn(i, j) { if (!i) return ; const highlighted = combiner.indexOf(j) > -1; @@ -79,22 +120,22 @@ function Demo(args) { return this.setState({ combiner: [], items: ['Red', 'Red', 'Attack'], equipped: false, equipping: false }); } - if (items.length === 1 && combiner[0] === 0) { - return this.setState({ combiner: [], items: [''], equipped: true, equipping: false }); + if (items[0] === 'Strike' && combiner[0] === 0) { + return this.setState({ combiner: [], items: ['', '', ''], equipped: true, equipping: false }); } - if (items.length === 1) { - return this.setState({ combiner: [0], items: ['Strike'], equipping: true }); + if (items[0] === 'Strike') { + return this.setState({ combiner: [0], items: ['Strike', '', ''], equipping: true }); } if (combiner.length === 3) { - return this.setState({ combiner: [], items: ['Strike'] }); + return this.setState({ combiner: [], items: ['Strike', '', ''] }); } combiner.push(combiner.length); this.setState({ combiner }); return true; - }, 1500); + }, 2000); const skills = ['Strike']; @@ -106,10 +147,10 @@ function Demo(args) {
{inventoryElement()}
- {[0, 1, 2].map(i => ( + {demo[0].constructs.map((c, i) => (
- {molecule()} -

+

{c.name}

+
{i === 0 && this.state.equipped ? @@ -129,15 +170,42 @@ function Demo(args) { ); }; + setTimeout(() => { + setAnimTarget({ + skill: sample(itemInfo.items.filter(i => i.skill)).item, + constructId: [sample(demo[1].constructs).id], + player: Math.round(Math.random()), + direction: 0, + }); + + // setTimeout(setAnimTarget(null), 5000); + }, 2000); + + const gameDemo = () => { + return ( +
+

GAME PHASE

+
+
+ + +
+
+
+ + +
+
+
+ ); + }; return (
{vboxDemo()} -
-

GAME PHASE

-
+ {gameDemo()}
); } -module.exports = Demo; +module.exports = addState(Demo); diff --git a/client/src/components/game.jsx b/client/src/components/game.jsx index eddde654..95c34691 100644 --- a/client/src/components/game.jsx +++ b/client/src/components/game.jsx @@ -42,7 +42,6 @@ const addState = connect( function receiveDispatch(dispatch) { function setActiveSkill(constructId, skill) { dispatch(actions.setActiveSkill(constructId, skill)); - // particlesJS(`particles-${constructId}`, config); } function setActiveConstruct(construct) { diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx index 316fc767..f2018d30 100644 --- a/client/src/components/welcome.jsx +++ b/client/src/components/welcome.jsx @@ -54,9 +54,9 @@ function Welcome() {

mnml.gg

mnml is a turn-based 1v1 strategy game in an abstract setting.

-

build your team of 3 constructs from a shifting meta of skills, effects and specialisations in order to outplay your opponents.

+

outplay your opponents by building your team of 3 constructs from a shifting meta of skills, effects and specialisations.

simple rules, complex interactions, simultaneous turns to increase the pace, and a unique speed mechanic;

-

mnml is a tactical game in a genre of its own.

+

mnml is a tactical game unlike any other.

free to play

no email required

glhf

diff --git a/client/src/events.jsx b/client/src/events.jsx index f378ba24..e62117d6 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -18,6 +18,10 @@ function registerEvents(store) { store.dispatch(actions.setPing(ping)); } + function setDemo(d) { + store.dispatch(actions.setDemo(d)); + } + function setNav(v) { store.dispatch(actions.setNav(v)); } @@ -229,6 +233,7 @@ function registerEvents(store) { setAccountInstances, setActiveItem, setActiveSkill, + setDemo, setConstructList, setNewConstruct, setGame, diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx index 496a5acc..cfc6dad5 100644 --- a/client/src/reducers.jsx +++ b/client/src/reducers.jsx @@ -23,6 +23,8 @@ module.exports = { animTarget: createReducer(null, 'SET_ANIM_TARGET'), animText: createReducer(null, 'SET_ANIM_TEXT'), + demo: createReducer(null, 'SET_DEMO'), + combiner: createReducer([], 'SET_COMBINER'), constructs: createReducer([], 'SET_CONSTRUCTS'), constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'), diff --git a/client/src/socket.jsx b/client/src/socket.jsx index a2ab9217..1435713d 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -202,10 +202,14 @@ function createSocket(events) { events.setItemInfo(info); } + function onDemo(v) { + events.setDemo(v); + } + let pongTimeout; function onPong() { events.setPing(Date.now() - ping); - // pongTimeout = setTimeout(sendPing, 1000); + pongTimeout = setTimeout(sendPing, 10000); } // ------------- @@ -227,6 +231,7 @@ function createSocket(events) { InstanceState: onInstanceState, ItemInfo: onItemInfo, Pong: onPong, + Demo: onDemo, QueueRequested: () => events.notify('pvp queue request received'), QueueJoined: () => events.notify('you have joined the pvp queue'), diff --git a/server/src/instance.rs b/server/src/instance.rs index d6a76c7a..9ee46ea5 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -763,6 +763,25 @@ pub fn instance_game_finished(tx: &mut Transaction, game: &Game, instance_id: Uu Ok(()) } +pub fn demo() -> Result, Error> { + let bot = bot_player(); + + // generate bot imgs for the client to see + for c in bot.constructs.iter() { + img::molecular_write(c.img)?; + }; + + let bot2 = bot_player(); + + // generate bot imgs for the client to see + for c in bot2.constructs.iter() { + img::molecular_write(c.img)?; + }; + + + Ok(vec![bot, bot2]) +} + #[cfg(test)] mod tests { use super::*; diff --git a/server/src/mob.rs b/server/src/mob.rs index 6bb6aaf1..2cab954b 100644 --- a/server/src/mob.rs +++ b/server/src/mob.rs @@ -27,3 +27,4 @@ pub fn bot_player() -> Player { let constructs = instance_mobs(bot_id); Player::new(bot_id, &name(), constructs).set_bot(true) } + diff --git a/server/src/rpc.rs b/server/src/rpc.rs index d8ce6405..48919ac8 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -21,10 +21,12 @@ use account; use construct::{Construct}; use events::{Event}; use game::{Game, game_state, game_skill, game_skill_clear, game_ready}; -use instance::{Instance, instance_state, instance_practice, instance_ready}; +use instance::{Instance, instance_state, instance_practice, instance_ready, demo}; use item::{Item, ItemInfoCtr, item_info}; use mtx; use mail; + +use player::{Player}; use payments; use mail::Email; use pg::{Db}; @@ -41,6 +43,8 @@ pub enum RpcMessage { AccountInstances(Vec), AccountShop(mtx::Shop), + Demo(Vec), + ConstructSpawn(Construct), GameState(Game), ItemInfo(ItemInfoCtr), @@ -268,6 +272,8 @@ impl Handler for Connection { // tx should do nothing tx.commit().unwrap(); + } else { + self.ws.send(RpcMessage::Demo(demo().unwrap())).unwrap(); } Ok(())