Merge branch 'master' of ssh://mnml.gg:40022/~/mnml

This commit is contained in:
ntr 2019-05-31 12:26:03 +10:00
commit 1571a39c24
5 changed files with 105 additions and 130 deletions

View File

@ -2,17 +2,14 @@ const preact = require('preact');
const { STATS, eventClasses, getCombatText, ConstructAvatar } = require('../utils'); const { STATS, eventClasses, getCombatText, ConstructAvatar } = require('../utils');
// const { animationDivs } = require('../animations'); // const { animationDivs } = require('../animations');
const GameConstruct = require('./game.construct'); const GameConstruct = require('./game.construct');
const shapes = require('./shapes');
function GamePanel(props) { function GamePanel(props) {
const { const {
game, game,
account, account,
resolution, resolution,
activeSkill,
setActiveSkill, setActiveSkill,
setActiveConstruct, setActiveConstruct,
selectSkillTarget,
sendInstanceState, sendInstanceState,
sendGameReady, sendGameReady,
showLog, showLog,
@ -109,8 +106,8 @@ function GamePanel(props) {
); );
function PlayerTeam(team) { function PlayerTeam(team) {
const constructs = team.constructs.map((c, i) => <GameConstruct key={c.id} construct={c} />); const constructs = team.constructs.map(c =>
<GameConstruct key={c.id} construct={c} player={true} />);
return ( return (
<div className="team player"> <div className="team player">
{constructs} {constructs}
@ -118,62 +115,9 @@ function GamePanel(props) {
); );
} }
function OpponentConstruct(construct, i) {
const ko = construct.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, construct);
const stats = ['RedLife', 'GreenLife', 'BlueLife'].map((s, j) => (
<div key={j} alt={STATS[s].stat}>
{shapes[s]()}
<div className="max" >{construct[STATS[s].stat].value} / {construct[STATS[s].stat].max}</div>
<div className="value" >{construct[STATS[s].stat].value}</div>
</div>
));
const [combatText, combatClass] = getCombatText(construct, resolution);
const combatTextClass = `combat-text ${combatClass}`;
const combatTextEl = combatText
? <div className={combatTextClass}>{combatText}</div>
: null;
const effects = construct.effects.length
? construct.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
: <div>&nbsp;</div>;
const playerTeamIds = playerTeam.constructs.map(c => c.id);
const targeting = game.stack
.filter(s => playerTeamIds.includes(s.source_construct_id) && s.target_construct_id === construct.id)
.map((s, i) => <h3 key={i}>{`< ${s.skill}`}</h3>);
// const anim = (
// <div className="anim-container">
// {animationDivs(combatClass)}
// </div>
// );
return (
<div
key={i}
className={`game-construct ${ko} ${classes}`}
style={ activeSkill ? { cursor: 'pointer' } : {}}
onClick={() => selectSkillTarget(construct.id)} >
<div className="stats">{stats}</div>
<h3 className="name" >{construct.name}</h3>
<div className="effects">{effects}</div>
<div className="targeting">{targeting}</div>
<figure
className="img"
onClick={() => selectSkillTarget(construct.id)} >
<ConstructAvatar name={construct.name} id={construct.id} />
{combatTextEl}
</figure>
</div>
);
}
function OpponentTeam(team) { function OpponentTeam(team) {
const constructs = team.constructs.map(OpponentConstruct); const constructs = team.constructs.map(c =>
<GameConstruct key={c.id} construct={c} player={false} />);
return ( return (
<div className="team opponent"> <div className="team opponent">
{constructs} {constructs}

View File

@ -3,7 +3,7 @@ const preact = require('preact');
const range = require('lodash/range'); const range = require('lodash/range');
const actions = require('../actions'); const actions = require('../actions');
const { STATS, eventClasses, getCombatText, ConstructAvatar } = require('../utils'); const { STATS, eventClasses, getCombatText, ConstructAvatar, constructHealth } = require('../utils');
const { animationDivs } = require('../animations'); const { animationDivs } = require('../animations');
const shapes = require('./shapes'); const shapes = require('./shapes');
@ -46,6 +46,7 @@ function GameConstruct(props) {
game, game,
account, account,
construct, construct,
player,
resolution, resolution,
activeSkill, activeSkill,
setActiveConstruct, setActiveConstruct,
@ -54,18 +55,23 @@ function GameConstruct(props) {
const ko = construct.green_life.value === 0 ? 'ko' : ''; const ko = construct.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, construct); const classes = eventClasses(resolution, construct);
const skills = range(0, 3) const life = constructHealth(resolution, construct);
.map(i => <SkillBtn key={i} construct={construct} i={i} />);
const stats = ['RedLife', 'GreenLife', 'BlueLife'].map((s, j) => ( const stats = ['RedLife', 'GreenLife', 'BlueLife'].map((s, j) => (
<div key={j} alt={STATS[s].stat}> <div key={j} alt={STATS[s].stat}>
{shapes[s]()} {shapes[s]()}
<div className="max" >{construct[STATS[s].stat].value} / {construct[STATS[s].stat].max}</div> <div className="max" >{life[s]} / {construct[STATS[s].stat].max}</div>
<div className="value" >{construct[STATS[s].stat].value}</div> <div className="value" >{life[s]}</div>
</div> </div>
)); ));
const skills = range(0, 3)
.map(i => <SkillBtn key={i} construct={construct} i={i} />);
let crypSkills = <div> &nbsp; </div>;
if (player) crypSkills = (<div className="skills"> {skills} </div>);
const [combatText, combatClass] = getCombatText(construct, resolution); const [combatText, combatClass] = getCombatText(construct, resolution);
const combatTextClass = `combat-text ${combatClass}`; const combatTextClass = `combat-text ${combatClass}`;
const combatTextEl = combatText const combatTextEl = combatText
@ -93,30 +99,19 @@ function GameConstruct(props) {
<div <div
style={ activeSkill ? { cursor: 'pointer' } : {}} style={ activeSkill ? { cursor: 'pointer' } : {}}
className={`game-construct ${ko} ${classes}`} > className={`game-construct ${ko} ${classes}`} >
<h3 className="name"> <h3 className="name"> {construct.name} </h3>
{construct.name} {crypSkills}
</h3> <div className="targeting"> {targeting} </div>
<div className="skills"> <div className="stats"> {stats} </div>
{skills}
</div>
<div className="targeting">
{targeting}
</div>
<figure <figure
className="img" className="img"
onClick={() => selectSkillTarget(construct.id)} > onClick={() => selectSkillTarget(construct.id)} >
<ConstructAvatar name={construct.name} id={construct.id} /> <ConstructAvatar name={construct.name} id={construct.id} />
{combatTextEl} {combatTextEl}
{anim}
</figure> </figure>
<div className="effects"> <div className="effects"> {effects} </div>
{effects}
</div>
<div className="stats">
{stats}
</div>
</div> </div>
); );
} }
module.exports = addState(GameConstruct); module.exports = addState(GameConstruct);

View File

@ -3,7 +3,7 @@ const eachSeries = require('async/eachSeries');
const actions = require('./actions'); const actions = require('./actions');
const { TIMES } = require('./constants'); const { TIMES } = require('./constants');
const { getCombatSequence, resoConstructHealth } = require('./utils'); const { getCombatSequence } = require('./utils');
function registerEvents(store) { function registerEvents(store) {
@ -49,9 +49,6 @@ function registerEvents(store) {
if (skip) return sCb(); if (skip) return sCb();
const stagedR = Object.create(r); const stagedR = Object.create(r);
stagedR.stage = stage; stagedR.stage = stage;
// Apply damage for each construct
if (stage === 'POST_SKILL') resoConstructHealth(stagedR, currentGame);
store.dispatch(actions.setResolution(stagedR)); store.dispatch(actions.setResolution(stagedR));
return setTimeout(sCb, TIMES[stage]); return setTimeout(sCb, TIMES[stage]);

View File

@ -158,38 +158,71 @@ const STATS = {
}; };
function resoConstructHealth(resolution, currentGame) { function constructHealth(resolution, construct) {
if (!resolution) return false; if (!resolution) {
return {
RedLife: construct.red_life.value,
GreenLife: construct.green_life.value,
BlueLife: construct.blue_life.value,
};
}
const [type, event] = resolution.event;
const modifyHealth = construct => {
if (construct.id !== resolution.target.id) return false; // not target if (construct.id !== resolution.target.id) {
const [type, event] = resolution.event; if (construct.id === resolution.source.id) {
if (type === 'Damage') { return {
const { amount, mitigation, colour } = event; RedLife: resolution.source.red,
construct.green_life.value -= amount; GreenLife: resolution.source.green,
if (colour === 'Red') { BlueLife: resolution.source.blue,
construct.red_life.value -= mitigation; };
}
if (colour === 'Blue') {
construct.blue_life.value -= mitigation;
}
} }
return {
RedLife: construct.red_life.value,
GreenLife: construct.green_life.value,
BlueLife: construct.blue_life.value,
};
}
if (type === 'Healing') { let RedLife = resolution.target.red;
const { amount } = event; let BlueLife = resolution.target.blue;
construct.green_life.value += amount; let GreenLife = resolution.target.green;
if (resolution.stage === 'POST_SKILL') {
return { RedLife, GreenLife, BlueLife };
}
if (type === 'Damage') {
const { amount, mitigation, colour } = event;
GreenLife = construct.green_life.max < GreenLife + amount
? construct.green_life.max
: GreenLife + amount;
if (colour === 'Red') {
RedLife = construct.red_life.max < RedLife + mitigation
? construct.red_life.max
: RedLife + mitigation;
} }
if (colour === 'Blue') {
if (type === 'Recharge') { BlueLife = construct.blue_life.max < BlueLife + mitigation
const { red, blue } = event; ? construct.blue_life.max
construct.red_life.value += red; : BlueLife + mitigation;
construct.blue_life.value += blue;
} }
return true; }
};
currentGame.players.forEach(player => player.constructs.forEach(modifyHealth));
return true;
if (type === 'Healing') {
const { amount } = event;
GreenLife = GreenLife - amount < 0 ? 0 : GreenLife - amount;
}
if (type === 'Recharge') {
const { red, blue } = event;
RedLife = RedLife - red < 0 ? 0 : RedLife - red;
BlueLife = BlueLife - red < 0 ? 0 : BlueLife - blue;
}
return { RedLife, GreenLife, BlueLife };
} }
function eventClasses(resolution, construct) { function eventClasses(resolution, construct) {
@ -297,8 +330,7 @@ function eventClasses(resolution, construct) {
function getCombatSequence(event) { function getCombatSequence(event) {
if (!event) return false; if (!event) return false;
// Skip combat animations depending on event type, expandable in future // Skip combat animations depending on event type, expandable in future
const dotTicks = ['DecayTick', 'CorruptionTick', 'TriageTick', 'SiphonTick', 'StrangleTick']; if (['Inversion'].includes(event[0])) return false;
if (['Skill', 'AoeSkill'].includes(event[0])) return ['START_SKILL', 'END_SKILL']; if (['Skill', 'AoeSkill'].includes(event[0])) return ['START_SKILL', 'END_SKILL'];
if (['Immunity'].includes(event[0])) return ['START_SKILL', 'POST_SKILL']; if (['Immunity'].includes(event[0])) return ['START_SKILL', 'POST_SKILL'];
if (['Removal'].includes(event[0])) return ['POST_SKILL']; if (['Removal'].includes(event[0])) return ['POST_SKILL'];
@ -325,7 +357,7 @@ function getCombatSequence(event) {
if (['Ko'].includes(event[0]) if (['Ko'].includes(event[0])
|| (event[1].skill.includes('Throw') && event[1].effect === 'Vulnerable')) return ['POST_SKILL']; || (event[1].skill.includes('Throw') && event[1].effect === 'Vulnerable')) return ['POST_SKILL'];
if (dotTicks.includes(event[1].skill)) return ['END_SKILL', 'POST_SKILL']; if (['Tick'].includes(event[1].skill)) return ['END_SKILL', 'POST_SKILL'];
return ['START_SKILL', 'END_SKILL', 'POST_SKILL']; return ['START_SKILL', 'END_SKILL', 'POST_SKILL'];
} }
@ -456,7 +488,7 @@ module.exports = {
eventClasses, eventClasses,
getCombatSequence, getCombatSequence,
getCombatText, getCombatText,
resoConstructHealth, constructHealth,
NULL_UUID, NULL_UUID,
STATS, STATS,
COLOURS, COLOURS,

View File

@ -388,6 +388,9 @@ pub type Immunity = Vec<Effect>;
pub struct LogConstruct { pub struct LogConstruct {
pub id: Uuid, pub id: Uuid,
pub name: String, pub name: String,
pub red: u64,
pub green: u64,
pub blue: u64,
} }
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
@ -400,8 +403,20 @@ pub struct Resolution {
impl Resolution { impl Resolution {
fn new(source: &Construct, target: &Construct) -> Resolution { fn new(source: &Construct, target: &Construct) -> Resolution {
Resolution { Resolution {
source: LogConstruct { id: source.id, name: source.name.clone() }, source: LogConstruct {
target: LogConstruct { id: target.id, name: target.name.clone() }, id: source.id,
name: source.name.clone(),
red: source.red_life(),
green: source.green_life(),
blue: source.blue_life(),
},
target: LogConstruct {
id: target.id,
name: target.name.clone(),
red: target.red_life(),
green: target.green_life(),
blue: target.blue_life(),
},
event: Event::Incomplete, event: Event::Incomplete,
} }
} }
@ -1427,14 +1442,6 @@ impl Skill {
} }
} }
fn touch(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
target.deal_red_damage(skill, 0)
.into_iter()
.for_each(|e| results.push(Resolution::new(source, target).event(e)));
return results;
}
fn attack(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { fn attack(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
let amount = source.red_power().pct(skill.multiplier()); let amount = source.red_power().pct(skill.multiplier());
target.deal_red_damage(skill, amount) target.deal_red_damage(skill, amount)
@ -1453,7 +1460,7 @@ fn strike(source: &mut Construct, target: &mut Construct, mut results: Resolutio
return results; return results;
} }
fn injure(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { /*fn injure(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
let amount = source.red_power().pct(skill.multiplier()); let amount = source.red_power().pct(skill.multiplier());
target.deal_red_damage(skill, amount) target.deal_red_damage(skill, amount)
.into_iter() .into_iter()
@ -1464,7 +1471,7 @@ fn injure(source: &mut Construct, target: &mut Construct, mut results: Resolutio
return results; return results;
} }
*/
fn stun(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { fn stun(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
skill.effect().into_iter() skill.effect().into_iter()
.for_each(|e| (results.push(Resolution::new(source, target).event(target.add_effect(skill, e))))); .for_each(|e| (results.push(Resolution::new(source, target).event(target.add_effect(skill, e)))));