diff --git a/client/src/actions.jsx b/client/src/actions.jsx
index 8b23cfa1..8eb1697f 100644
--- a/client/src/actions.jsx
+++ b/client/src/actions.jsx
@@ -1,8 +1,11 @@
export const setAccount = value => ({ type: 'SET_ACCOUNT', value });
export const setActiveConstruct = value => ({ type: 'SET_ACTIVE_CONSTRUCT', value });
+
export const setAnimating = value => ({ type: 'SET_ANIMATING', value });
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 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/animations.utils.jsx b/client/src/animations.utils.jsx
index 49fe19ee..6a773ab8 100644
--- a/client/src/animations.utils.jsx
+++ b/client/src/animations.utils.jsx
@@ -85,22 +85,98 @@ function getSequence(resolution) {
}
}
+const SOURCE_DURATION_MS = 1000;
+const TARGET_DELAY_MS = 500;
+const TARGET_DURATION_MS = 1500;
+const POST_SKILL_DELAY_MS = 2000;
+const POST_SKILL_DURATION_MS = 1000;
+const SOURCE_AND_TARGET_TOTAL_DURATION = TARGET_DELAY_MS + TARGET_DURATION_MS + POST_SKILL_DURATION_MS;
+
function getTime(stages) {
if (stages.includes('START_SKILL') && stages.includes('END_SKILL')) {
return TIMES.SOURCE_AND_TARGET_TOTAL_DURATION;
}
- if (stages.includes('START_SKILL')) return TIMES.SOURCE_DURATION_MS;
- if (stages.includes('END_SKILL')) return TIMES.TARGET_DURATION_MS;
- if (stages.includes('POST_SKILL')) return TIMES.POST_SKILL_DURATION_MS;
+ let time = 0;
- return 0;
+ if (stages.includes('START_SKILL')) time += TIMES.SOURCE_DURATION_MS;
+ if (stages.includes('END_SKILL')) time += TIMES.TARGET_DURATION_MS;
+ if (stages.includes('POST_SKILL')) time += TIMES.POST_SKILL_DURATION_MS;
+
+ return time;
+}
+
+function getText(resolution, sequence) {
+ if (!resolution) return { text: null, constructId: null };
+ if (!sequence.includes('POST_SKILL')) return { text: null, constructId: null };
+
+ function generateText() {
+ const [type, event] = resolution.event;
+ if (type === 'Ko') {
+ return 'KO!';
+ }
+
+ if (type === 'Disable') {
+ const { disable } = event;
+ return `${disable}`;
+ }
+
+ if (type === 'Immunity') {
+ return 'IMMUNE';
+ }
+
+ if (type === 'Damage') {
+ const { mitigation, colour } = event;
+ let { amount } = event;
+ if (colour === 'Green') amount *= -1;
+ const mitigationText = mitigation
+ ? `(${mitigation})`
+ : '';
+ return `${amount} ${mitigationText}`;
+ }
+
+ if (type === 'Healing') {
+ const { amount, overhealing } = event;
+ return `${amount} (${overhealing} OH)`;
+ }
+
+ if (type === 'Inversion') {
+ return 'INVERT';
+ }
+
+ if (type === 'Reflection') {
+ return 'REFLECT';
+ }
+
+ if (type === 'Effect') {
+ const { effect, duration } = event;
+ return `+ ${effect} ${duration}T`;
+ }
+
+ if (type === 'Recharge') {
+ const { red, blue } = event;
+ return [`+${red}R ${blue}B`, ''];
+ }
+
+ if (type === 'Removal') {
+ const { effect } = event;
+ return `-${effect}`;
+ }
+
+ return false;
+ }
+
+ return {
+ text: generateText(),
+ constructId: resolution.target.id,
+ };
}
module.exports = {
getObjects,
getTime,
getSequence,
+ getText,
};
diff --git a/client/src/components/construct.jsx b/client/src/components/construct.jsx
index 7cd8899d..6eb08e69 100644
--- a/client/src/components/construct.jsx
+++ b/client/src/components/construct.jsx
@@ -140,6 +140,26 @@ class ConstructAvatar extends Component {
}
}
+
+const addStateText = connect(
+ function receiveState(state) {
+ const { animText } = state;
+ return { animText };
+ }
+);
+
+function constructText(props) {
+ const { construct, animText } = props;
+ if (!construct || !animText) return false;
+
+ const text = animText.constructId === construct.id
+ ? animText.text
+ : null;
+
+ return
{text}
;
+}
+
module.exports = {
ConstructAvatar: addState(ConstructAvatar),
+ ConstructText: addStateText(constructText),
};
diff --git a/client/src/components/game.construct.jsx b/client/src/components/game.construct.jsx
index 5e284e07..4569b4a1 100644
--- a/client/src/components/game.construct.jsx
+++ b/client/src/components/game.construct.jsx
@@ -3,8 +3,8 @@ const { Component } = require('preact');
const preact = require('preact');
const range = require('lodash/range');
-const { STATS, eventClasses, getCombatText } = require('../utils');
-const { ConstructAvatar } = require('./construct');
+const { STATS, eventClasses } = require('../utils');
+const { ConstructAvatar, ConstructText } = require('./construct');
const { ConstructAnimation } = require('./animations');
const shapes = require('./shapes');
@@ -20,9 +20,10 @@ const addState = connect(
ws,
game,
account,
- resolution,
activeSkill,
- avatarAnimation,
+ resolution,
+
+ animText,
} = state;
function selectSkillTarget(targetConstructId) {
@@ -40,22 +41,11 @@ const addState = connect(
game,
account,
resolution,
+ animText,
activeSkill,
- avatarAnimation,
selectSkillTarget,
};
},
-
- function receiveDispatch(dispatch) {
- function setAvatarAnimation(source, target, id, animTargetId, type, params) {
- return dispatch(actions.setAvatarAnimation({ source, target, id, animTargetId, type, params }));
- }
-
- return {
- setAvatarAnimation,
- };
- }
-
);
@@ -72,9 +62,13 @@ class GameConstruct extends Component {
account,
construct,
player,
- resolution,
activeSkill,
selectSkillTarget,
+
+ // todo remove dep
+ resolution,
+
+ animText,
} = this.props;
const ko = construct.green_life.value === 0 ? 'ko' : '';
@@ -97,7 +91,7 @@ class GameConstruct extends Component {
const effects = construct.effects.length
? construct.effects.map(c => {c.effect} - {c.duration}T
)
:
;
- const combatText = getCombatText(resolution, construct);
+
return (
selectSkillTarget(construct.id)}
@@ -108,7 +102,7 @@ class GameConstruct extends Component {
{stats}
-
{combatText}
+
{effects}
);
diff --git a/client/src/events.jsx b/client/src/events.jsx
index 3843ea0c..074acd29 100644
--- a/client/src/events.jsx
+++ b/client/src/events.jsx
@@ -55,27 +55,36 @@ function registerEvents(store) {
return eachSeries(newRes, (r, cb) => {
if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();
+ store.dispatch(actions.setResolution(r));
+
// convert server enum into anims keywords
// todo make serersideonly
const sequence = animations.getSequence(r);
const timeout = animations.getTime(sequence);
const anims = animations.getObjects(r, sequence, game, account);
+ const text = animations.getText(r, sequence);
- store.dispatch(actions.setAnimSource(anims.animSource));
- store.dispatch(actions.setAnimTarget(anims.animTarget));
+ if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource));
+ if (sequence.includes('END_SKILL')) store.dispatch(actions.setAnimTarget(anims.animTarget));
+ if (sequence.includes('POST_SKILL')) store.dispatch(actions.setAnimText(text));
return setTimeout(() => {
store.dispatch(actions.setAnimSource(null));
store.dispatch(actions.setAnimTarget(null));
+ store.dispatch(actions.setAnimText(null));
return setTimeout(cb, 50);
- }, 3000);
+ }, timeout);
}, err => {
if (err) return console.error(err);
// clear animation state
store.dispatch(actions.setAnimSource(null));
store.dispatch(actions.setAnimTarget(null));
+ store.dispatch(actions.setAnimText(null));
store.dispatch(actions.setAnimating(false));
+ store.dispatch(actions.setSkip(false));
+ store.dispatch(actions.setResolution(null));
+
// set the game state so resolutions don't fire twice
store.dispatch(actions.setGame(game));
ws.sendGameState(game.id);
diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx
index 9a36cccf..398e3721 100644
--- a/client/src/reducers.jsx
+++ b/client/src/reducers.jsx
@@ -15,9 +15,12 @@ module.exports = {
activeConstruct: createReducer(null, 'SET_ACTIVE_CONSTRUCT'),
activeItem: createReducer(null, 'SET_ACTIVE_VAR'),
activeSkill: createReducer(null, 'SET_ACTIVE_SKILL'),
+
animating: createReducer(false, 'SET_ANIMATING'),
animSource: createReducer(null, 'SET_ANIM_SOURCE'),
animTarget: createReducer(null, 'SET_ANIM_TARGET'),
+ animText: createReducer(null, 'SET_ANIM_TEXT'),
+
combiner: createReducer([null, null, null], 'SET_COMBINER'),
constructs: createReducer([], 'SET_CONSTRUCTS'),
constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'),
diff --git a/client/src/utils.jsx b/client/src/utils.jsx
index f50dc7a3..58340adf 100644
--- a/client/src/utils.jsx
+++ b/client/src/utils.jsx
@@ -86,8 +86,7 @@ const STATS = {
};
function eventClasses(game, account, resolution, construct) {
- if (!resolution || resolution === 'clear') return '';
- const postSkill = resolution.stages.includes('POST_SKILL');
+ if (!resolution) return '';
const source = construct.id === resolution.source.id;
const target = construct.id === resolution.target.id;
// not involved at all. blur them
@@ -113,7 +112,7 @@ function eventClasses(game, account, resolution, construct) {
if (type === 'Damage') {
const { colour } = event;
- if (target && postSkill) {
+ if (target) {
construct.green_life.value = resolution.target.green;
if (colour === 'Red') {
construct.red_life.value = resolution.target.red;
@@ -131,7 +130,7 @@ function eventClasses(game, account, resolution, construct) {
}
if (type === 'Healing') {
- if (target && postSkill) {
+ if (target) {
construct.green_life.value = resolution.target.green;
return 'green-damage';
}
@@ -139,17 +138,17 @@ function eventClasses(game, account, resolution, construct) {
if (type === 'Effect') {
const { construct_effects: constructEffects } = event;
- if (target && postSkill) construct.effects = constructEffects;
+ if (target) construct.effects = constructEffects;
}
if (type === 'Removal') {
const { construct_effects: constructEffects } = event;
- if (target && postSkill) construct.effects = constructEffects;
+ if (target) construct.effects = constructEffects;
}
if (type === 'Recharge') {
const { red, blue } = event;
- if (target && postSkill) {
+ if (target) {
if (red > 0 && blue > 0) {
construct.red_life.value = resolution.target.red;
construct.blue_life.value = resolution.target.blue;
@@ -169,66 +168,6 @@ function eventClasses(game, account, resolution, construct) {
return '';
}
-function getCombatText(resolution, construct) {
- if (!resolution || resolution === 'clear') return false;
- if (!resolution.stages.includes('POST_SKILL')) return false;
- if (construct.id !== resolution.target.id) return false;
-
- const [type, event] = resolution.event;
- if (type === 'Ko') {
- return 'KO!';
- }
-
- if (type === 'Disable') {
- const { disable } = event;
- return `${disable}`;
- }
-
- if (type === 'Immunity') {
- return 'IMMUNE';
- }
-
- if (type === 'Damage') {
- const { mitigation, colour } = event;
- let { amount } = event;
- if (colour === 'Green') amount *= -1;
- const mitigationText = mitigation
- ? `(${mitigation})`
- : '';
- return `${amount} ${mitigationText}`;
- }
-
- if (type === 'Healing') {
- const { amount, overhealing } = event;
- return `${amount} (${overhealing} OH)`;
- }
-
- if (type === 'Inversion') {
- return 'INVERT';
- }
-
- if (type === 'Reflection') {
- return 'REFLECT';
- }
-
- if (type === 'Effect') {
- const { effect, duration } = event;
- return `+ ${effect} ${duration}T`;
- }
-
- if (type === 'Recharge') {
- const { red, blue } = event;
- return [`+${red}R ${blue}B`, ''];
- }
-
- if (type === 'Removal') {
- const { effect } = event;
- return `-${effect}`;
- }
-
- return false;
-}
-
function convertItem(v) {
if (['Red', 'Green', 'Blue'].includes(v)) {
return (
@@ -378,7 +317,6 @@ module.exports = {
convertItem,
numSort,
eventClasses,
- getCombatText,
postData,
errorToast,
NULL_UUID,