This commit is contained in:
ntr 2019-12-07 12:42:57 +10:00
parent be0bf33753
commit cc64d21859
3 changed files with 209 additions and 215 deletions

View File

@ -4,8 +4,8 @@ use rand::prelude::*;
use failure::Error;
use failure::err_msg;
use skill::{Skill, Cast, Disable, EventVariant, EventConstruct};
use game::{Colour};
use skill::{Skill, Cast};
use game::{Colour, Disable, EventVariant, EventConstruct};
use effect::{Cooldown, Effect};
use spec::{Spec};
use item::{Item};
@ -423,11 +423,11 @@ impl Construct {
match skill.cd {
Some(cd) => {
skill.cd = Some(cd.saturating_add(turns));
events.push(EventVariant::CooldownIncrease { target: self.id, turns })
events.push(EventVariant::CooldownIncrease { construct: self.id, turns })
},
None => {
skill.cd = Some(turns);
events.push(EventVariant::CooldownIncrease { target: self.id, turns })
events.push(EventVariant::CooldownIncrease { construct: self.id, turns })
},
}
}
@ -548,7 +548,6 @@ impl Construct {
pub fn recharge(&mut self, red_amount: usize, blue_amount: usize) -> Vec<EventVariant> {
let mut events = vec![];
let target = self.id;
if self.is_ko() { return events; }
match self.affected(Effect::Invert) {
@ -565,7 +564,7 @@ impl Construct {
let blue = new_blue_life - current_blue_life;
if red != 0 || blue != 0 {
events.push(EventVariant::Recharge { target, red, blue });
events.push(EventVariant::Recharge { construct: self.id, red, blue });
}
},
true => {
@ -592,7 +591,7 @@ impl Construct {
let red_damage_amount = red_current_green_life - self.green_life();
events.push(EventVariant::Damage {
target,
construct: self.id,
amount: red_damage_amount,
mitigation: red_mitigation,
colour: Colour::Red,
@ -622,7 +621,7 @@ impl Construct {
let blue_damage_amount = blue_current_green_life - self.green_life();
events.push(EventVariant::Damage {
target,
construct: self.id,
amount: blue_damage_amount,
mitigation: blue_mitigation,
colour: Colour::Blue,
@ -637,7 +636,7 @@ impl Construct {
pub fn deal_green_damage(&mut self, amount: usize) -> Vec<EventVariant> {
let mut events = vec![];
if self.is_ko() { return events; }
let target = self.id;
let construct = self.id;
let mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::GreenDamageTaken))
@ -657,7 +656,7 @@ impl Construct {
let overhealing = modified_power - healing;
events.push(EventVariant::Healing {
target,
construct,
amount: healing,
overhealing,
});
@ -671,7 +670,7 @@ impl Construct {
let delta = current_green_life - self.green_life();
events.push(EventVariant::Damage {
target,
construct,
amount: delta,
mitigation: 0,
colour: Colour::Green,
@ -687,7 +686,7 @@ impl Construct {
let mut events = vec![];
if self.is_ko() { return events; }
let target = self.id;
let construct = self.id;
let mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::RedDamageTaken))
@ -716,7 +715,7 @@ impl Construct {
events.push(
EventVariant::Damage {
target,
construct,
amount: delta,
mitigation,
colour: Colour::Red,
@ -724,7 +723,7 @@ impl Construct {
}
);
if self.is_ko() {
events.push(EventVariant::Ko { target });
events.push(EventVariant::Ko { construct });
}
},
true => {
@ -743,7 +742,7 @@ impl Construct {
if healing > 0 {
events.push(
EventVariant::Healing {
target,
construct,
amount: healing,
overhealing: overhealing - recharge,
}
@ -751,7 +750,7 @@ impl Construct {
}
if recharge > 0 {
events.push(EventVariant::Recharge { target, red: recharge, blue: 0 });
events.push(EventVariant::Recharge { construct, red: recharge, blue: 0 });
}
}
};
@ -763,7 +762,7 @@ impl Construct {
let mut events = vec![];
if self.is_ko() { return events; }
let target = self.id;
let construct = self.id;
let mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::BlueDamageTaken))
@ -787,7 +786,7 @@ impl Construct {
let delta = current_green_life - self.green_life();
events.push(EventVariant::Damage {
target,
construct,
amount: delta,
mitigation,
colour: Colour::Blue,
@ -808,11 +807,11 @@ impl Construct {
let recharge = self.blue_life.value - current_life;
if healing > 0 {
events.push(EventVariant::Healing { target, amount: healing, overhealing });
events.push(EventVariant::Healing { construct, amount: healing, overhealing });
}
if recharge > 0 {
events.push(EventVariant::Recharge { target, red: 0, blue: recharge });
events.push(EventVariant::Recharge { construct, red: 0, blue: recharge });
}
}
};
@ -838,7 +837,7 @@ impl Construct {
// todo modified durations cause of buffs
let result = EventVariant::Effect {
target: self.id,
construct: self.id,
effect: effect.effect,
duration: effect.duration,
display: EventConstruct::new(self)

View File

@ -10,7 +10,8 @@ use failure::Error;
use failure::err_msg;
use construct::{Construct, ConstructEffect, Stat};
use skill::{Skill, Cast, Event, EventVariant, resolve};
use skill::{Skill, Cast};
use effect::{Effect};
use player::{Player};
use instance::{TimeControl};
@ -23,6 +24,13 @@ pub enum Phase {
Finished,
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Colour {
Red,
Blue,
Green,
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Value {
Stat { construct: Uuid, stat: Stat, mult: usize },
@ -33,22 +41,140 @@ pub enum Value {
// Skills { construct: Uuid, colour: Colour },
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Colour {
Red,
Blue,
Green,
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
pub enum Action {
Hit { construct: Uuid },
Cast { construct: Uuid },
Healing { construct: Uuid, values: Vec<Value>, colour: Colour },
Damage { construct: Uuid, values: Vec<Value>, colour: Colour },
Effect { construct: Uuid, effect: ConstructEffect },
IncreaseCooldowns { construct: Uuid, turns: usize },
// Recharge { skill: Skill, red: usize, blue: usize },
}
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
pub enum Action {
Hit { skill: Skill },
Cast { skill: Skill },
Damage { skill: Skill, construct: Uuid, values: Vec<Value>, colour: Colour },
Effect { skill: Skill, construct: Uuid, effect: ConstructEffect },
IncreaseCooldowns { skill: Skill, construct: Uuid, turns: usize },
Healing { skill: Skill, construct: Uuid, values: Vec<Value>, colour: Colour },
// Recharge { skill: Skill, red: usize, blue: usize },
pub struct Event {
pub cast: Cast,
pub focus: Vec<Uuid>,
pub variant: EventVariant,
pub delay: i64,
}
impl Event {
pub fn new(cast: Cast, variant: EventVariant) -> Event {
let focus = match variant {
EventVariant::HitAoe { construct: _ } => vec![cast.source, cast.target], // fixme
_ => vec![cast.source, cast.target],
};
let delay = variant.delay();
Event {
cast,
delay,
focus,
variant,
}
}
}
pub type Disable = Vec<Effect>;
pub type Direction = (i8, i8);
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum EventVariant {
Cast { construct: Uuid, player: Uuid, direction: Direction },
Hit { construct: Uuid, player: Uuid, direction: Direction },
HitAoe { construct: Uuid },
Damage { construct: Uuid, amount: usize, mitigation: usize, colour: Colour, display: EventConstruct },
Effect { construct: Uuid, effect: Effect, duration: u8, display: EventConstruct },
Removal { construct: Uuid, effect: Option<Effect>, display: EventConstruct },
Healing { construct: Uuid, amount: usize, overhealing: usize },
Recharge { construct: Uuid, red: usize, blue: usize },
Inversion { construct: Uuid },
Reflection { construct: Uuid },
Ko { construct: Uuid },
CooldownIncrease { construct: Uuid, turns: usize },
CooldownDecrease { construct: Uuid, turns: usize },
Forfeit (),
}
impl EventVariant {
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 {
EventVariant::Cast { construct: _, direction: _, player: _ } => target_delay,
EventVariant::Hit { construct: _, direction: _, player: _ } |
EventVariant::HitAoe { construct: _ } => target_duration - combat_text_overlap,
_ => combat_text_delay,
}
}
}
// used to show the progress of a construct
// while the resolutions are animating
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub struct EventConstruct {
pub id: Uuid,
pub red: usize,
pub green: usize,
pub blue: usize,
}
impl EventConstruct {
pub fn new(construct: &Construct) -> EventConstruct {
EventConstruct {
id: construct.id,
red: construct.red_life(),
green: construct.green_life(),
blue: construct.blue_life(),
}
}
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum EventStages {
#[serde(rename = "START_SKILL END_SKILL POST_SKILL")]
AllStages, // Anim Anim Anim
#[serde(rename = "START_SKILL END_SKILL")]
StartEnd, // Anim Anim Skip
#[serde(rename = "START_SKILL POST_SKILL")]
StartPost, // Anim Skip Anim
#[serde(rename = "START_SKILL")]
StartOnly, // Anim Skip Skip
#[serde(rename = "END_SKILL POST_SKILL")]
EndPost, // Skip Anim Anim
#[serde(rename = "END_SKILL")]
EndOnly, // Skip Anim Skip
#[serde(rename = "POST_SKILL")]
PostOnly, // Skip Skip Anim
}
impl EventStages {
fn delay(self) -> i64 {
let source_duration = 1000; // Time for SOURCE ONLY
let target_delay = 500; // Used for Source + Target
let target_duration = 1500; // Time for TARGET ONLY
let post_skill = 1000; // Time for all POST
let source_and_target_total = target_delay + target_duration; // SOURCE + TARGET time
match self {
EventStages::AllStages => source_and_target_total + post_skill, // Anim Anim Anim
EventStages::StartEnd => source_and_target_total, // Anim Anim Skip
EventStages::StartPost => source_duration + post_skill, // Anim Skip Anim
EventStages::StartOnly => source_duration, // Anim Skip Skip
EventStages::EndPost => target_duration + post_skill, // Skip Anim Anim
EventStages::EndOnly => target_duration, // Skip Anim Skip
EventStages::PostOnly => post_skill, // Skip Skip Anim
}
}
}
#[derive(Debug,Clone,Serialize,Deserialize)]
@ -445,6 +571,37 @@ impl Game {
self
}
fn finalise_cast(&self, cast: Cast) -> Vec<Cast> {
let target_player = self.players.iter()
.find(|t| t.constructs.iter().any(|c| c.id == cast.target))
.unwrap();
if let Some(t) = target_player.intercepting() {
return vec![Cast { target: t.id, ..cast }];
}
// if self.construct[source].multistrike() {
// return vec![
// Cast { target: t.id, ..cast },
// Cast { target: t.id, ..cast },
// ];
// }
let targets = match cast.skill.aoe() {
true => self.players.iter()
.find(|t| t.constructs.iter().any(|c| c.id == cast.target))
.unwrap()
.constructs
.iter()
.map(|c| Cast { target: c.id, ..cast })
.collect(),
false => vec![cast],
};
return targets;
}
fn resolve_stack(mut self) -> Game {
if self.phase != Phase::Resolve {
panic!("game not in Resolve phase");
@ -472,7 +629,12 @@ impl Game {
while let Some(cast) = self.stack.pop() {
// info!("{:} casts ", cast);
resolve(&mut self, cast);
let casts = self.finalise_cast(cast);
for cast in casts {
self.resolve(cast);
}
// r_animation_ms = events.iter().fold(r_animation_ms, |acc, r| acc + r.clone().get_delay());
// if theres no resolution events, the skill didn't trigger (disable etc)
@ -496,16 +658,18 @@ impl Game {
self.skill_phase_start(r_animation_ms)
}
pub fn actions(&mut self, cast: Cast) -> &mut Game {
pub fn resolve(&mut self, cast: Cast) -> &mut Game {
let mut events_group = vec![];
let skill = cast.skill;
// calculate values first?
// for result damage value need to pass &events and .find()
for action in cast.actions() {
let mut events = match action {
Action::Cast { construct, skill, direction } => self.cast(construct, skill),
Action::Hit { construct, skill } => self.hit(construct, skill),
Action::Cast { construct } => self.cast(cast),
Action::Hit { construct } => self.hit(construct, skill),
Action::Damage { construct, values, colour } => self.damage(construct, values, colour),
Action::Healing { construct, values, colour } => unimplemented!(),
Action::Effect { construct, effect } => self.effect(construct, effect),
@ -519,8 +683,8 @@ impl Game {
self
}
fn cast(&mut self, construct: Uuid, skill: Skill) -> Vec<Event> {
vec![Event::new(EventVariant::Cast { skill: skill }, construct)]
fn cast(&mut self, cast: Cast) -> Vec<Event> {
vec![Event::new(cast, EventVariant::Cast { construct: cast.source, player: cast.player, direction: self.direction(cast) })]
}
fn hit(&mut self, construct: Uuid, skill: Skill) -> Vec<Event> {
@ -1388,7 +1552,7 @@ mod tests {
let source = game.players[0].constructs[0].id;
let target = game.players[1].constructs[0].id;
game.actions(Cast::new(source, player_id, target, Skill::Bash).actions());
game.resolve(Cast::new(source, player_id, target, Skill::Bash));
println!("{:?}", game.events);
}

View File

@ -720,175 +720,6 @@ fn end() {}
// return cast_actions(skill, &mut a, &mut b, resolutions);
// }
fn modify_cast(game: &Game, cast: Cast) -> Vec<Cast> {
let target_player = game.players.iter()
.find(|t| t.constructs.iter().any(|c| c.id == cast.target))
.unwrap();
if let Some(t) = target_player.intercepting() {
return vec![Cast { target: t.id, ..cast }];
}
// if game.construct[source].multistrike() {
// return vec![
// Cast { target: t.id, ..cast },
// Cast { target: t.id, ..cast },
// ];
// }
let targets = match cast.skill.aoe() {
true => game.players.iter()
.find(|t| t.constructs.iter().any(|c| c.id == cast.target))
.unwrap()
.constructs
.iter()
.map(|c| Cast { target: c.id, ..cast })
.collect(),
false => vec![cast],
};
return targets;
}
pub fn resolve(game: &mut Game, cast: Cast) {
let casts = modify_cast(game, cast);
// let source = game.construct_by_id(cast.source).unwrap().clone();
// if skill.aoe() { // Send an aoe skill event for anims
// game.event(Event::new(&source,
// &game.construct_by_id(cast.target).unwrap().clone()).event(Event::AoeSkill { skill }).stages(EventStages::StartEnd));
// }
for cast in casts {
game.actions(cast.actions());
}
}
pub type Disable = Vec<Effect>;
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum EventVariant {
Cast { target: Uuid, player: Uuid, x: i8, y: i8 },
Hit { target: Uuid, player: Uuid, x: i8, y: i8 },
HitAoe { target: Uuid },
Damage { target: Uuid, amount: usize, mitigation: usize, colour: Colour, display: EventConstruct },
Effect { target: Uuid, effect: Effect, duration: u8, display: EventConstruct },
Removal { target: Uuid, effect: Option<Effect>, display: EventConstruct },
Healing { target: Uuid, amount: usize, overhealing: usize },
Recharge { target: Uuid, red: usize, blue: usize },
Inversion { target: Uuid },
Reflection { target: Uuid },
Ko { target: Uuid },
CooldownIncrease { target: Uuid, turns: usize },
CooldownDecrease { target: Uuid, turns: usize },
Forfeit (),
}
impl EventVariant {
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 {
EventVariant::Cast { target: _, x: _, y: _, player: _ } => target_delay,
EventVariant::Hit { target: _, x: _, y: _, player: _ } |
EventVariant::HitAoe { target: _ } => target_duration - combat_text_overlap,
_ => combat_text_delay,
}
}
pub fn to_event(&self, cast: Cast) -> Event {
let delay = self.delay();
let focus = match self {
EventVariant::HitAoe { target: _ } => vec![cast.source, cast.target], // some tricky multi target here l8r
_ => vec![cast.source, cast.target],
};
Event {
cast,
focus,
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
// while the resolutions are animating
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub struct EventConstruct {
pub id: Uuid,
pub red: usize,
pub green: usize,
pub blue: usize,
}
impl EventConstruct {
pub fn new(construct: &Construct) -> EventConstruct {
EventConstruct {
id: construct.id,
red: construct.red_life(),
green: construct.green_life(),
blue: construct.blue_life(),
}
}
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum EventStages {
#[serde(rename = "START_SKILL END_SKILL POST_SKILL")]
AllStages, // Anim Anim Anim
#[serde(rename = "START_SKILL END_SKILL")]
StartEnd, // Anim Anim Skip
#[serde(rename = "START_SKILL POST_SKILL")]
StartPost, // Anim Skip Anim
#[serde(rename = "START_SKILL")]
StartOnly, // Anim Skip Skip
#[serde(rename = "END_SKILL POST_SKILL")]
EndPost, // Skip Anim Anim
#[serde(rename = "END_SKILL")]
EndOnly, // Skip Anim Skip
#[serde(rename = "POST_SKILL")]
PostOnly, // Skip Skip Anim
}
impl EventStages {
fn delay(self) -> i64 {
let source_duration = 1000; // Time for SOURCE ONLY
let target_delay = 500; // Used for Source + Target
let target_duration = 1500; // Time for TARGET ONLY
let post_skill = 1000; // Time for all POST
let source_and_target_total = target_delay + target_duration; // SOURCE + TARGET time
match self {
EventStages::AllStages => source_and_target_total + post_skill, // Anim Anim Anim
EventStages::StartEnd => source_and_target_total, // Anim Anim Skip
EventStages::StartPost => source_duration + post_skill, // Anim Skip Anim
EventStages::StartOnly => source_duration, // Anim Skip Skip
EventStages::EndPost => target_duration + post_skill, // Skip Anim Anim
EventStages::EndOnly => target_duration, // Skip Anim Skip
EventStages::PostOnly => post_skill, // Skip Skip Anim
}
}
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Skill {