half merged

This commit is contained in:
ntr 2019-12-07 11:47:45 +10:00
commit be0bf33753
9 changed files with 222 additions and 261 deletions

View File

@ -1,71 +1,58 @@
function getObjects(resolution, game, account) { const actions = require('./actions');
const [type, event] = resolution.variant; const { TIMES } = require('./constants');
const playerTeam = game.players.find(t => t.id === account.id); function setAnimations(r, store, account) {
const playerTeamIds = playerTeam.constructs.map(c => c.id); store.dispatch(actions.setAnimFocus(r.focus));
const otherTeam = game.players.find(t => t.id !== account.id);
const otherTeamIds = otherTeam.constructs.map(c => c.id);
const sourceIsPlayer = playerTeamIds.includes(event.source);
const targetIsPlayer = playerTeamIds.includes(resolution.target);
const targetting = () => { if (r.variant[0] === 'Cast') {
if (type === 'AoeSkill') { store.dispatch(actions.setAnimText(null));
if (targetIsPlayer) return playerTeamIds;
return otherTeamIds;
}
return [resolution.target];
};
const sameTeam = (sourceIsPlayer && targetIsPlayer) || (!sourceIsPlayer && !targetIsPlayer);
let y = 0;
if (!sameTeam) y = targetIsPlayer ? 1 : -1;
const i = sourceIsPlayer
? playerTeamIds.findIndex(c => c === event.source)
: otherTeamIds.findIndex(c => c === event.source);
const j = targetIsPlayer
? playerTeamIds.findIndex(c => c === resolution.target)
: otherTeamIds.findIndex(c => c === resolution.target);
const x = j - i;
const direction = { x, y };
// const targetTeam = targetIsPlayer ? playerTeamIds : otherTeamIds;
const getFocusTargets = () => {
if (type === 'HitCast') {
const { source } = event;
const { target } = resolution;
if (source !== target) return [source, target];
return [target];
}
if (type === 'AoeSkill') {
if (targetIsPlayer) return playerTeamIds;
return otherTeamIds;
}
return [resolution.target];
};
const { player } = r.cast;
const { x, y, target } = r.variant[1];
const animY = y && player === account.id ? -1 : y;
const animSource = { const animSource = {
animation: 'sourceCast', animation: 'sourceCast',
constructId: event.source, constructId: target,
direction, direction: { x, y: animY },
}; };
store.dispatch(actions.setAnimSource(animSource));
return setTimeout(() => store.dispatch(actions.setAnimSource(null)), TIMES.SOURCE_DURATION_MS);
}
if (r.variant[0].includes('Hit')) {
store.dispatch(actions.setAnimText(null));
const { player, skill } = r.cast;
const { x, y, target } = r.variant[1];
const animY = y && player === account.id ? -1 : y;
const isPlayer = player === account.id;
const animTarget = { const animTarget = {
skill: event.skill, constructId: target,
constructId: targetting(), player: isPlayer,
player: playerTeamIds.includes(resolution.target), skill,
direction, direction: { x, y: animY },
}; };
store.dispatch(actions.setAnimTarget(animTarget));
return { return setTimeout(() => store.dispatch(actions.setAnimTarget(null)), TIMES.TARGET_DURATION_MS);
animSource, }
animTarget,
focusTargets: getFocusTargets(), return store.dispatch(actions.setAnimText(r));
skill: event.skill,
};
} }
function clearAnimations(store) {
store.dispatch(actions.setAnimSkill(null));
store.dispatch(actions.setAnimSource(null));
store.dispatch(actions.setAnimTarget(null));
store.dispatch(actions.setAnimText(null));
store.dispatch(actions.setAnimating(false));
store.dispatch(actions.setGameEffectInfo(null));
store.dispatch(actions.setAnimFocus(null));
}
module.exports = { module.exports = {
getObjects, setAnimations,
clearAnimations,
}; };

View File

@ -46,8 +46,8 @@ class Attack extends Component {
y: [400, 200], y: [400, 200],
height: [100, 10, 0], height: [100, 10, 0],
width: [12, 5, 0], width: [12, 5, 0],
delay: () => anime.random(TIMES.TARGET_DELAY_MS, TIMES.TARGET_DELAY_MS + TIMES.TARGET_DURATION_MS / 2), delay: () => anime.random(0, TIMES.TARGET_DURATION_MS / 4),
duration: TIMES.TARGET_DURATION_MS, duration: TIMES.TARGET_DURATION_MS * 5 / 4,
})); }));
} }
@ -59,9 +59,7 @@ class Attack extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb && this.props.animCb();
} }
} }
module.exports = addState(Attack); module.exports = addState(Attack);

View File

@ -7,7 +7,7 @@ const shapes = require('./shapes');
const { removeTier } = require('../utils'); const { removeTier } = require('../utils');
const { TIMES } = require('./../constants'); const { TIMES } = require('./../constants');
const addState = connect(({ animText, animSkill, itemInfo }) => ({ animText, animSkill, itemInfo })); const addState = connect(({ animText, itemInfo }) => ({ animText, itemInfo }));
class AnimText extends preact.Component { class AnimText extends preact.Component {
shouldComponentUpdate(newProps) { shouldComponentUpdate(newProps) {
@ -17,7 +17,7 @@ class AnimText extends preact.Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { animText, construct } = this.props; const { animText, construct } = this.props;
if (animText && animText !== prevProps.animText && animText.target === construct.id) { if (animText && animText !== prevProps.animText && animText.variant[1].target === construct.id) {
anime({ anime({
targets: '.combat-text', targets: '.combat-text',
top: '40%', top: '40%',
@ -28,10 +28,10 @@ class AnimText extends preact.Component {
} }
render() { render() {
const { construct, animText, animSkill, itemInfo } = this.props; const { construct, animText, itemInfo } = this.props;
if (animText && animText.target === construct.id) { if (animText && animText.variant[1].target === construct.id) {
const itemSourceDescription = () => { const itemSourceDescription = () => {
const itemSource = itemInfo.combos.filter(c => c.item === removeTier(animSkill)); const itemSource = itemInfo.combos.filter(c => c.item === removeTier(animText.cast.skill));
const itemSourceInfo = itemSource.length const itemSourceInfo = itemSource.length
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}` ? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
: false; : false;
@ -82,7 +82,7 @@ class AnimText extends preact.Component {
return ( return (
<div class="combat-text"> <div class="combat-text">
<h2><span>{animSkill}</span></h2> <h2><span>{animText.cast.skill}</span></h2>
<span>{itemSourceDescription()}</span> <span>{itemSourceDescription()}</span>
{generateAnimText()} {generateAnimText()}
</div> </div>

View File

@ -21,11 +21,10 @@ const addState = connect(
class GameConstructEffects extends preact.Component { class GameConstructEffects extends preact.Component {
shouldComponentUpdate(newProps) { shouldComponentUpdate(newProps) {
if (newProps.animText !== this.props.animText) { if (newProps.animText && newProps.animText !== this.props.animText) {
if (newProps.animText && newProps.animText.constructId === this.props.construct.id) { const [type, info] = newProps.animText.variant;
const [type] = newProps.animText.variant; if (info.target === this.props.construct.id
if (type === 'Effect' || type === 'Removal') return true; && (type === 'Effect' || type === 'Removal')) return true;
}
} }
if (newProps.construct !== this.props.construct) return true; if (newProps.construct !== this.props.construct) return true;
return false; return false;

View File

@ -7,11 +7,10 @@ const addState = connect(({ animText }) => ({ animText }));
class GameConstructLife extends preact.Component { class GameConstructLife extends preact.Component {
shouldComponentUpdate(newProps) { shouldComponentUpdate(newProps) {
if (newProps.animText !== this.props.animText) { if (newProps.animText && newProps.animText !== this.props.animText) {
if (newProps.animText && newProps.animText.target === this.props.construct.id) { const [type, info] = newProps.animText.variant;
const [type] = newProps.animText.variant; if (info.target === this.props.construct.id
if (type === 'Damage' || type === 'Healing' || type === 'Recharge') return true; && (type === 'Damage' || type === 'Healing' || type === 'Recharge')) return true;
}
} }
if (newProps.construct !== this.props.construct) return true; if (newProps.construct !== this.props.construct) return true;
return false; return false;

View File

@ -5,10 +5,9 @@ const eachSeries = require('async/eachSeries');
const sample = require('lodash/sample'); const sample = require('lodash/sample');
const actions = require('./actions'); const actions = require('./actions');
const animations = require('./animations.utils'); const { setAnimations, clearAnimations } = require('./animations.utils');
const { infoToast, errorToast } = require('./utils'); const { infoToast, errorToast } = require('./utils');
const { tutorialVbox } = require('./tutorial.utils'); const { tutorialVbox } = require('./tutorial.utils');
const { TIMES } = require('./constants');
function registerEvents(store) { function registerEvents(store) {
function notify(msg) { function notify(msg) {
@ -87,41 +86,14 @@ function registerEvents(store) {
store.dispatch(actions.setAnimating(true)); store.dispatch(actions.setAnimating(true));
store.dispatch(actions.setGameSkillInfo(null)); store.dispatch(actions.setGameSkillInfo(null));
// stop fetching the game state til animations are done // stop fetching the game state til animations are done
const newRes = game.events[currentGame.events.length]; const newRes = game.events[game.events.length - 1];
return eachSeries(newRes, (r, cb) => { return eachSeries(newRes, (r, cb) => {
const timeout = r.delay; const timeout = r.delay;
setAnimations(r, store, account);
if (r.variant[0].includes('Hit')) {
let animTimeOut = TIMES.TARGET_DURATION_MS;
const anims = animations.getObjects(r, game, account);
if (r.variant[0] === 'HitCast') {
animTimeOut += TIMES.TARGET_DELAY_MS;
store.dispatch(actions.setAnimSource(anims.animSource));
}
store.dispatch(actions.setAnimFocus(anims.focusTargets));
store.dispatch(actions.setAnimSkill(anims.skill));
store.dispatch(actions.setAnimTarget(anims.animTarget));
store.dispatch(actions.setAnimText(null));
setTimeout(() => {
store.dispatch(actions.setAnimSource(null));
store.dispatch(actions.setAnimTarget(null));
}, animTimeOut);
} else {
store.dispatch(actions.setAnimText(r));
}
return setTimeout(cb, timeout); return setTimeout(cb, timeout);
}, err => { }, err => {
if (err) return console.error(err); if (err) return console.error(err);
// clear animation state clearAnimations(store);
store.dispatch(actions.setAnimSkill(null));
store.dispatch(actions.setAnimSource(null));
store.dispatch(actions.setAnimTarget(null));
store.dispatch(actions.setAnimText(null));
store.dispatch(actions.setAnimating(false));
store.dispatch(actions.setGameEffectInfo(null));
store.dispatch(actions.setAnimFocus(null));
// set the game state so resolutions don't fire twice // set the game state so resolutions don't fire twice
store.dispatch(actions.setGame(game)); store.dispatch(actions.setGame(game));
ws.sendGameState(game.id); ws.sendGameState(game.id);

View File

@ -4,7 +4,7 @@ use rand::prelude::*;
use failure::Error; use failure::Error;
use failure::err_msg; use failure::err_msg;
use skill::{Skill, Cast, Disable, Event, EventVariant, EventConstruct}; use skill::{Skill, Cast, Disable, EventVariant, EventConstruct};
use game::{Colour}; use game::{Colour};
use effect::{Cooldown, Effect}; use effect::{Cooldown, Effect};
use spec::{Spec}; use spec::{Spec};
@ -415,7 +415,7 @@ impl Construct {
self self
} }
pub fn increase_cooldowns(&mut self, turns: usize) -> Vec<Event> { pub fn increase_cooldowns(&mut self, turns: usize) -> Vec<EventVariant> {
let mut events = vec![]; let mut events = vec![];
for skill in self.skills.iter_mut() { for skill in self.skills.iter_mut() {
@ -423,11 +423,11 @@ impl Construct {
match skill.cd { match skill.cd {
Some(cd) => { Some(cd) => {
skill.cd = Some(cd.saturating_add(turns)); skill.cd = Some(cd.saturating_add(turns));
events.push(Event::new(EventVariant::CooldownIncrease { turns, skill: skill.skill }, self.id)) events.push(EventVariant::CooldownIncrease { target: self.id, turns })
}, },
None => { None => {
skill.cd = Some(turns); skill.cd = Some(turns);
events.push(Event::new(EventVariant::CooldownIncrease { turns, skill: skill.skill }, self.id)) events.push(EventVariant::CooldownIncrease { target: self.id, turns })
}, },
} }
} }
@ -546,9 +546,9 @@ impl Construct {
} }
} }
pub fn recharge(&mut self, red_amount: usize, blue_amount: usize) -> Vec<Event> { pub fn recharge(&mut self, red_amount: usize, blue_amount: usize) -> Vec<EventVariant> {
let mut events = vec![]; let mut events = vec![];
let target = self.id;
if self.is_ko() { return events; } if self.is_ko() { return events; }
match self.affected(Effect::Invert) { match self.affected(Effect::Invert) {
@ -565,7 +565,7 @@ impl Construct {
let blue = new_blue_life - current_blue_life; let blue = new_blue_life - current_blue_life;
if red != 0 || blue != 0 { if red != 0 || blue != 0 {
events.push(Event::new(EventVariant::Recharge { red, blue }, self.id)); events.push(EventVariant::Recharge { target, red, blue });
} }
}, },
true => { true => {
@ -591,12 +591,13 @@ impl Construct {
self.reduce_green_life(red_remainder); self.reduce_green_life(red_remainder);
let red_damage_amount = red_current_green_life - self.green_life(); let red_damage_amount = red_current_green_life - self.green_life();
events.push(Event::new(EventVariant::Damage { events.push(EventVariant::Damage {
target,
amount: red_damage_amount, amount: red_damage_amount,
mitigation: red_mitigation, mitigation: red_mitigation,
colour: Colour::Red, colour: Colour::Red,
display: EventConstruct::new(self), display: EventConstruct::new(self),
}, self.id)); });
} }
if blue_amount != 0 { if blue_amount != 0 {
@ -620,21 +621,23 @@ impl Construct {
self.reduce_green_life(blue_remainder); self.reduce_green_life(blue_remainder);
let blue_damage_amount = blue_current_green_life - self.green_life(); let blue_damage_amount = blue_current_green_life - self.green_life();
events.push(Event::new(EventVariant::Damage { events.push(EventVariant::Damage {
target,
amount: blue_damage_amount, amount: blue_damage_amount,
mitigation: blue_mitigation, mitigation: blue_mitigation,
colour: Colour::Blue, colour: Colour::Blue,
display: EventConstruct::new(self), display: EventConstruct::new(self),
}, self.id)); });
} }
} }
} }
return events; return events;
} }
pub fn deal_green_damage(&mut self, amount: usize) -> Vec<Event> { pub fn deal_green_damage(&mut self, amount: usize) -> Vec<EventVariant> {
let mut events = vec![]; let mut events = vec![];
if self.is_ko() { return events; } if self.is_ko() { return events; }
let target = self.id;
let mods = self.effects.iter() let mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::GreenDamageTaken)) .filter(|e| e.effect.modifications().contains(&Stat::GreenDamageTaken))
@ -653,10 +656,11 @@ impl Construct {
let healing = new_green_life - current_green_life; let healing = new_green_life - current_green_life;
let overhealing = modified_power - healing; let overhealing = modified_power - healing;
events.push(Event::new(EventVariant::Healing { events.push(EventVariant::Healing {
target,
amount: healing, amount: healing,
overhealing, overhealing,
}, self.id)); });
}, },
true => { true => {
// events.push(Event::new(EventVariant::Inversion { skill })); // events.push(Event::new(EventVariant::Inversion { skill }));
@ -666,22 +670,24 @@ impl Construct {
self.reduce_green_life(modified_power); self.reduce_green_life(modified_power);
let delta = current_green_life - self.green_life(); let delta = current_green_life - self.green_life();
events.push(Event::new(EventVariant::Damage { events.push(EventVariant::Damage {
target,
amount: delta, amount: delta,
mitigation: 0, mitigation: 0,
colour: Colour::Green, colour: Colour::Green,
display: EventConstruct::new(self), display: EventConstruct::new(self),
}, self.id)); });
} }
} }
return events; return events;
} }
pub fn deal_red_damage(&mut self, amount: usize) -> Vec<Event> { pub fn deal_red_damage(&mut self, amount: usize) -> Vec<EventVariant> {
let mut events = vec![]; let mut events = vec![];
if self.is_ko() { return events; } if self.is_ko() { return events; }
let target = self.id;
let mods = self.effects.iter() let mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::RedDamageTaken)) .filter(|e| e.effect.modifications().contains(&Stat::RedDamageTaken))
@ -708,17 +714,17 @@ impl Construct {
self.reduce_green_life(remainder); self.reduce_green_life(remainder);
let delta = current_green_life - self.green_life(); let delta = current_green_life - self.green_life();
events.push(Event::new( events.push(
EventVariant::Damage { EventVariant::Damage {
target,
amount: delta, amount: delta,
mitigation, mitigation,
colour: Colour::Red, colour: Colour::Red,
display: EventConstruct::new(self), display: EventConstruct::new(self),
}, }
self.id );
));
if self.is_ko() { if self.is_ko() {
events.push(Event::new(EventVariant::Ko {}, self.id)); events.push(EventVariant::Ko { target });
} }
}, },
true => { true => {
@ -735,16 +741,17 @@ impl Construct {
let recharge = self.red_life.value - current_life; let recharge = self.red_life.value - current_life;
if healing > 0 { if healing > 0 {
events.push(Event::new( events.push(
EventVariant::Healing{ EventVariant::Healing {
target,
amount: healing, amount: healing,
overhealing: overhealing - recharge, overhealing: overhealing - recharge,
}, self.id }
)); );
} }
if recharge > 0 { if recharge > 0 {
events.push(Event::new(EventVariant::Recharge { red: recharge, blue: 0 }, self.id)); events.push(EventVariant::Recharge { target, red: recharge, blue: 0 });
} }
} }
}; };
@ -752,10 +759,11 @@ impl Construct {
return events; return events;
} }
pub fn deal_blue_damage(&mut self, amount: usize) -> Vec<Event> { pub fn deal_blue_damage(&mut self, amount: usize) -> Vec<EventVariant> {
let mut events = vec![]; let mut events = vec![];
if self.is_ko() { return events; } if self.is_ko() { return events; }
let target = self.id;
let mods = self.effects.iter() let mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::BlueDamageTaken)) .filter(|e| e.effect.modifications().contains(&Stat::BlueDamageTaken))
@ -778,12 +786,13 @@ impl Construct {
self.reduce_green_life(remainder); self.reduce_green_life(remainder);
let delta = current_green_life - self.green_life(); let delta = current_green_life - self.green_life();
events.push(Event::new(EventVariant::Damage { events.push(EventVariant::Damage {
target,
amount: delta, amount: delta,
mitigation, mitigation,
colour: Colour::Blue, colour: Colour::Blue,
display: EventConstruct::new(self), display: EventConstruct::new(self),
}, self.id)); });
}, },
true => { true => {
// events.push(Event::new(EventVariant::Inversion { skill })); // events.push(Event::new(EventVariant::Inversion { skill }));
@ -799,17 +808,11 @@ impl Construct {
let recharge = self.blue_life.value - current_life; let recharge = self.blue_life.value - current_life;
if healing > 0 { if healing > 0 {
events.push( events.push(EventVariant::Healing { target, amount: healing, overhealing });
Event::new(EventVariant::Healing {
amount: healing,
overhealing,
},
self.id
));
} }
if recharge > 0 { if recharge > 0 {
events.push(Event::new(EventVariant::Recharge { red: 0, blue: recharge }, self.id)); events.push(EventVariant::Recharge { target, red: 0, blue: recharge });
} }
} }
}; };
@ -817,7 +820,7 @@ impl Construct {
return events; return events;
} }
pub fn add_effect(&mut self, effect: ConstructEffect) -> Vec<Event> { pub fn add_effect(&mut self, effect: ConstructEffect) -> Vec<EventVariant> {
if self.is_ko() { return vec![] } if self.is_ko() { return vec![] }
if self.affected(Effect::Banish) { panic!("banish immunity not fixt yet") } if self.affected(Effect::Banish) { panic!("banish immunity not fixt yet") }
@ -834,13 +837,12 @@ impl Construct {
} }
// todo modified durations cause of buffs // todo modified durations cause of buffs
let result = Event::new( let result = EventVariant::Effect {
EventVariant::Effect { target: self.id,
effect: effect.effect, effect: effect.effect,
duration: effect.duration, duration: effect.duration,
display: EventConstruct::new(self), display: EventConstruct::new(self)
}, self.id };
);
return vec![result]; return vec![result];
} }

View File

@ -42,12 +42,13 @@ pub enum Colour {
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
pub enum Action { pub enum Action {
Cast { construct: Uuid, skill: Skill }, Hit { skill: Skill },
Hit { construct: Uuid, skill: Skill }, Cast { skill: Skill },
Damage { construct: Uuid, values: Vec<Value>, colour: Colour }, Damage { skill: Skill, construct: Uuid, values: Vec<Value>, colour: Colour },
Healing { construct: Uuid, values: Vec<Value>, colour: Colour }, Effect { skill: Skill, construct: Uuid, effect: ConstructEffect },
Effect { construct: Uuid, effect: ConstructEffect }, IncreaseCooldowns { skill: Skill, construct: Uuid, turns: usize },
IncreaseCooldowns { construct: Uuid, turns: usize }, Healing { skill: Skill, construct: Uuid, values: Vec<Value>, colour: Colour },
// Recharge { skill: Skill, red: usize, blue: usize },
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
@ -495,15 +496,15 @@ impl Game {
self.skill_phase_start(r_animation_ms) self.skill_phase_start(r_animation_ms)
} }
pub fn actions(&mut self, actions: Vec<Action>) -> &mut Game { pub fn actions(&mut self, cast: Cast) -> &mut Game {
let mut events_group = vec![]; let mut events_group = vec![];
// calculate values first? // calculate values first?
// for result damage value need to pass &events and .find() // for result damage value need to pass &events and .find()
for action in actions { for action in cast.actions() {
let mut events = match action { let mut events = match action {
Action::Cast { construct, skill } => self.cast(construct, skill), Action::Cast { construct, skill, direction } => self.cast(construct, skill),
Action::Hit { construct, skill } => self.hit(construct, skill), Action::Hit { construct, skill } => self.hit(construct, skill),
Action::Damage { construct, values, colour } => self.damage(construct, values, colour), Action::Damage { construct, values, colour } => self.damage(construct, values, colour),
Action::Healing { construct, values, colour } => unimplemented!(), Action::Healing { construct, values, colour } => unimplemented!(),
@ -540,6 +541,31 @@ impl Game {
self.construct_by_id(construct).unwrap().increase_cooldowns(turns) self.construct_by_id(construct).unwrap().increase_cooldowns(turns)
} }
fn direction(&mut self, cast: Cast) -> (i8, i8) {
let i = self.players.iter()
.find(|t| t.constructs.iter().any(|c| c.id == cast.source))
.unwrap().constructs
.iter()
.position(|c| c.id == cast.source)
.unwrap() as i8;
let j = self.players.iter()
.find(|t| t.constructs.iter().any(|c| c.id == cast.target))
.unwrap().constructs
.iter()
.position(|c| c.id == cast.target)
.unwrap() as i8;
let x = j - i;
let target = self.construct_by_id(cast.target).unwrap();
// is the caster player account same as target player account side of screen
let y = match cast.player == target.account {
true => 0,
false => 1
};
(x, y)
}
fn progress_durations(&mut self, events: &Vec<Cast>) -> &mut Game { fn progress_durations(&mut self, events: &Vec<Cast>) -> &mut Game {
for mut construct in self.all_constructs() { for mut construct in self.all_constructs() {
// info!("progressing durations for {:}", construct.name); // info!("progressing durations for {:}", construct.name);

View File

@ -32,6 +32,10 @@ impl Cast {
}; };
} }
pub fn target(self) -> Uuid {
self.target
}
pub fn new_tick(source: &mut Construct, target: &mut Construct, skill: Skill) -> Cast { pub fn new_tick(source: &mut Construct, target: &mut Construct, skill: Skill) -> Cast {
Cast { Cast {
id: Uuid::new_v4(), id: Uuid::new_v4(),
@ -53,10 +57,10 @@ impl Cast {
let mut actions = vec![]; let mut actions = vec![];
if self.skill.cast_animation() { if self.skill.cast_animation() {
actions.push({ Action::Cast { construct: self.source, skill: self.skill }}); actions.push(Action::Cast { cast: *self });
} }
actions.push(Action::Hit { construct: self.target, skill: self.skill }); actions.push(Action::Hit { cast: *self });
let mut rest = match self.skill { let mut rest = match self.skill {
Skill::Attack => vec![ Skill::Attack => vec![
@ -85,18 +89,21 @@ impl Cast {
Skill::Amplify => vec![ Skill::Amplify => vec![
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect { effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }, effect: ConstructEffect { effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None },
}, },
], ],
Skill::AmplifyPlus => vec![ Skill::AmplifyPlus => vec![
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect { effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }, effect: ConstructEffect { effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None },
}, },
], ],
Skill::AmplifyPlusPlus => vec![ Skill::AmplifyPlusPlus => vec![
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect { effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None }, effect: ConstructEffect { effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None },
}, },
@ -115,6 +122,7 @@ impl Cast {
], ],
Skill::AbsorbPlus => vec![ Skill::AbsorbPlus => vec![
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlus)), tick: None }, effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlus)), tick: None },
}, },
@ -126,6 +134,7 @@ impl Cast {
], ],
Skill::AbsorbPlusPlus => vec![ Skill::AbsorbPlusPlus => vec![
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlusPlus)), tick: None }, effect: ConstructEffect { effect: Effect::Absorb, duration: 1, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlusPlus)), tick: None },
}, },
@ -150,6 +159,7 @@ impl Cast {
values: vec![Value::Stat { construct: self.target, stat: Stat::BlueLife, mult: self.skill.multiplier() }], values: vec![Value::Stat { construct: self.target, stat: Stat::BlueLife, mult: self.skill.multiplier() }],
}, },
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None } effect: ConstructEffect { effect: Effect::Banish, duration: 2, meta: None, tick: None }
} }
@ -159,6 +169,7 @@ impl Cast {
Skill::BashPlus | Skill::BashPlus |
Skill::BashPlusPlus => vec![ Skill::BashPlusPlus => vec![
Action::Damage { Action::Damage {
cast: *self,
construct: self.target, construct: self.target,
colour: Colour::Red, colour: Colour::Red,
values: vec![ values: vec![
@ -167,10 +178,12 @@ impl Cast {
], ],
}, },
Action::Effect { Action::Effect {
cast: *self,
construct: self.target, construct: self.target,
effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None } effect: ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None }
}, },
Action::IncreaseCooldowns { Action::IncreaseCooldowns {
cast: *self,
construct: self.target, construct: self.target,
turns: 1, turns: 1,
}, },
@ -180,6 +193,7 @@ impl Cast {
Skill::BlastPlus | Skill::BlastPlus |
Skill::BlastPlusPlus => vec![ Skill::BlastPlusPlus => vec![
Action::Damage { Action::Damage {
cast: *self,
construct: self.target, construct: self.target,
colour: Colour::Blue, colour: Colour::Blue,
values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }], values: vec![Value::Stat { construct: self.source, stat: Stat::BluePower, mult: self.skill.multiplier() }],
@ -260,6 +274,7 @@ impl Cast {
Skill::CounterAttackPlus | Skill::CounterAttackPlus |
Skill::CounterAttackPlusPlus => vec![ Skill::CounterAttackPlusPlus => vec![
Action::Damage { Action::Damage {
cast: *self,
construct: self.target, construct: self.target,
colour: Colour::Red, colour: Colour::Red,
values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }], values: vec![Value::Stat { construct: self.source, stat: Stat::RedPower, mult: self.skill.multiplier() }],
@ -295,7 +310,6 @@ impl Cast {
], ],
Skill::Slay | Skill::Slay |
Skill::SlayPlus | Skill::SlayPlus |
Skill::SlayPlusPlus => vec![ Skill::SlayPlusPlus => vec![
@ -387,7 +401,6 @@ impl Cast {
colour: Colour::Red, colour: Colour::Red,
}, },
], ],
_ => unimplemented!() _ => unimplemented!()
}; };
@ -398,7 +411,6 @@ impl Cast {
fn end() {} fn end() {}
// fn heal(source: &mut Construct, target: &mut Construct, skill: Skill) { // fn heal(source: &mut Construct, target: &mut Construct, skill: Skill) {
// let amount = source.green_power().pct(skill.multiplier()); // let amount = source.green_power().pct(skill.multiplier());
// target.deal_green_damage(skill, amount) // target.deal_green_damage(skill, amount)
@ -756,105 +768,72 @@ pub fn resolve(game: &mut Game, cast: Cast) {
pub type Disable = Vec<Effect>; pub type Disable = Vec<Effect>;
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub struct Event {
pub target: Uuid,
pub variant: EventVariant,
pub stages: EventStages,
pub delay: i64,
}
impl Event {
pub fn new(variant: EventVariant, target: Uuid) -> Event {
let stages = variant.stages();
Event {
target,
variant,
delay: stages.delay(),
stages: stages,
}
}
}
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
pub enum EventVariant { pub enum EventVariant {
Cast { skill: Skill }, Cast { target: Uuid, player: Uuid, x: i8, y: i8 },
Hit { skill: Skill }, Hit { target: Uuid, player: Uuid, x: i8, y: i8 },
HitAoe { target: Uuid },
Damage { amount: usize, mitigation: usize, colour: Colour, display: EventConstruct }, Damage { target: Uuid, amount: usize, mitigation: usize, colour: Colour, display: EventConstruct },
Effect { effect: Effect, duration: u8, display: EventConstruct }, Effect { target: Uuid, effect: Effect, duration: u8, display: EventConstruct },
Removal { effect: Option<Effect>, display: EventConstruct }, Removal { target: Uuid, effect: Option<Effect>, display: EventConstruct },
Disable { disable: Disable }, Healing { target: Uuid, amount: usize, overhealing: usize },
Healing { amount: usize, overhealing: usize }, Recharge { target: Uuid, red: usize, blue: usize },
Recharge { red: usize, blue: usize }, Inversion { target: Uuid },
Inversion { skill: Skill }, Reflection { target: Uuid },
Reflection { skill: Skill }, Ko { target: Uuid },
AoeSkill { skill: Skill },
Skill { skill: Skill }, CooldownIncrease { target: Uuid, turns: usize },
TargetKo { skill: Skill }, CooldownDecrease { target: Uuid, turns: usize },
// skill not necessary but makes it neater as all events are arrays in js
Ko (),
Forfeit (), Forfeit (),
Incomplete (),
// not used
Evasion { skill: Skill, evasion_rating: usize },
CooldownIncrease { turns: usize, skill: Skill },
CooldownDecrease { turns: usize, skill: Skill },
} }
impl EventVariant { impl EventVariant {
fn stages(&self) -> EventStages { fn delay(&self) -> i64 {
// let source_duration = 1000; // Time for SOURCE ONLY
let target_duration = 1500; // Time for target animation
let target_delay = 500; // Add delay if theres source animation
let combat_text_delay = 1300; // Time for all post skill
let combat_text_overlap = 600; // overlap between animation and combat text
match self { match self {
EventVariant::Disable { disable: _} EventVariant::Cast { target: _, x: _, y: _, player: _ } => target_delay,
=> EventStages::PostOnly, EventVariant::Hit { target: _, x: _, y: _, player: _ } |
EventVariant::Damage { amount: _, mitigation: _, colour: _, display: _ } EventVariant::HitAoe { target: _ } => target_duration - combat_text_overlap,
=> EventStages::PostOnly, _ => combat_text_delay,
EventVariant::Healing { amount: _, overhealing: _} }
=> EventStages::PostOnly, }
EventVariant::Recharge { red: _, blue: _}
=> EventStages::PostOnly,
EventVariant::Inversion { skill: _ }
=> EventStages::PostOnly,
EventVariant::Reflection { skill: _ }
=> EventStages::PostOnly,
EventVariant::AoeSkill { skill: _ }
=> EventStages::PostOnly,
EventVariant::Skill { skill: _ }
=> EventStages::PostOnly,
EventVariant::Effect { effect: _, duration: _, display: _ }
=> EventStages::PostOnly,
EventVariant::Removal { effect: _, display: _ }
=> EventStages::PostOnly,
EventVariant::TargetKo { skill: _ }
=> EventStages::PostOnly,
EventVariant::Ko ()
=> EventStages::PostOnly,
EventVariant::Forfeit ()
=> EventStages::PostOnly,
EventVariant::Incomplete ()
=> EventStages::PostOnly,
EventVariant::Evasion { skill: _, evasion_rating: _ }
=> EventStages::PostOnly,
EventVariant::CooldownDecrease { skill: _, turns: _ } pub fn to_event(&self, cast: Cast) -> Event {
=> EventStages::PostOnly, let delay = self.delay();
EventVariant::CooldownIncrease { skill: _, turns: _ } let focus = match self {
=> EventStages::PostOnly, EventVariant::HitAoe { target: _ } => vec![cast.source, cast.target], // some tricky multi target here l8r
_ => vec![cast.source, cast.target],
};
EventVariant::Hit { skill: _ } Event {
=> EventStages::PostOnly, cast,
EventVariant::Cast { skill: _ } focus,
=> EventStages::PostOnly, variant: *self,
delay,
} }
} }
} }
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
pub struct Event {
pub cast: Cast,
pub focus: Vec<Uuid>,
pub variant: EventVariant,
pub delay: i64,
}
// used to show the progress of a construct // used to show the progress of a construct
// while the resolutions are animating // while the resolutions are animating
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub struct EventConstruct { pub struct EventConstruct {
pub id: Uuid, pub id: Uuid,
pub red: usize, pub red: usize,
@ -1763,8 +1742,6 @@ impl Skill {
} }
// #[cfg(test)] // #[cfg(test)]
mod tests { mod tests {
use skill::*; use skill::*;
@ -1775,18 +1752,19 @@ mod tests {
let actions = cast.actions(); let actions = cast.actions();
match actions[0] { match actions[0] {
Action::Hit { construct: _, skill } => { Action::Hit { cast } => {
assert_eq!(skill, Skill::Attack); assert_eq!(cast.skill, Skill::Attack);
}, },
_ => panic!("{:?}", actions), _ => panic!("{:?}", actions),
}; };
match actions[1] { match actions[1] {
Action::Damage { construct: _, values: _, colour } => { Action::Damage { cast: _, construct: _, values: _, colour } => {
assert_eq!(colour, Colour::Red); assert_eq!(colour, Colour::Red);
}, },
_ => panic!("{:?}", actions), _ => panic!("{:?}", actions),
}; };
} }
// #[test] // #[test]