Skip to content

Commit 2e3a0b8

Browse files
authored
Merge pull request #544 from Vrixyz/291-weight-component
Weight logic to Knockback
2 parents d1030e5 + 1eb6cb8 commit 2e3a0b8

File tree

12 files changed

+484
-30
lines changed

12 files changed

+484
-30
lines changed

src/core/battle.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::default::Default;
1+
use std::{default::Default, fmt};
22

33
use serde::{Deserialize, Serialize};
44

@@ -43,6 +43,38 @@ pub struct Id(i32);
4343
#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, PartialOrd)]
4444
pub struct Strength(pub i32);
4545

46+
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd)]
47+
pub enum Weight {
48+
Normal = 0,
49+
Heavy = 1,
50+
Immovable = 2,
51+
}
52+
53+
impl Default for Weight {
54+
fn default() -> Self {
55+
Weight::Normal
56+
}
57+
}
58+
59+
impl fmt::Display for Weight {
60+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61+
match *self {
62+
Weight::Normal => write!(f, "Normal"),
63+
Weight::Heavy => write!(f, "Heavy"),
64+
Weight::Immovable => write!(f, "Immovable"),
65+
}
66+
}
67+
}
68+
69+
#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, PartialOrd)]
70+
pub struct PushStrength(pub Weight);
71+
72+
impl PushStrength {
73+
pub fn can_push(self, weight: Weight) -> bool {
74+
weight != Weight::Immovable && self.0 >= weight
75+
}
76+
}
77+
4678
#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, PartialOrd)]
4779
pub struct Attacks(pub i32);
4880

src/core/battle/ability.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use std::fmt;
33
use serde::{Deserialize, Serialize};
44

55
use crate::core::{
6-
battle::{Attacks, Strength},
6+
battle::{Attacks, PushStrength, Strength},
77
map::Distance,
88
};
99

1010
/// Active ability.
1111
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, derive_more::From)]
1212
pub enum Ability {
13-
Knockback,
13+
Knockback(Knockback),
1414
Club,
1515
Jump(Jump),
1616
Poison,
@@ -31,6 +31,12 @@ pub enum Ability {
3131
Bloodlust,
3232
}
3333

34+
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
35+
pub struct Knockback {
36+
#[serde(default)]
37+
pub strength: PushStrength,
38+
}
39+
3440
// TODO: use named fields?
3541
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
3642
pub struct Jump(pub Distance);
@@ -92,7 +98,7 @@ pub struct RechargeableAbility {
9298
impl fmt::Display for Ability {
9399
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94100
match *self {
95-
Ability::Knockback => write!(f, "Knockback"),
101+
Ability::Knockback(a) => write!(f, "Knockback-{}", a.strength.0),
96102
Ability::Club => write!(f, "Club"),
97103
Ability::Jump(a) => write!(f, "Jump-{}", (a.0).0),
98104
Ability::Poison => write!(f, "Poison"),

src/core/battle/check.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn check_command_use_ability(state: &State, command: &command::UseAbility) -> Re
101101
check_agent_can_attack(state, command.id)?;
102102
check_agent_ability_ready(state, command.id, &command.ability)?;
103103
match command.ability {
104-
Ability::Knockback => check_ability_knockback(state, command.id, command.pos),
104+
Ability::Knockback(a) => check_ability_knockback(state, command.id, command.pos, a),
105105
Ability::Club => check_ability_club(state, command.id, command.pos),
106106
Ability::Jump(a) => check_ability_jump(state, command.id, command.pos, a),
107107
Ability::Poison => check_ability_poison(state, command.id, command.pos),
@@ -123,7 +123,12 @@ fn check_command_use_ability(state: &State, command: &command::UseAbility) -> Re
123123
}
124124
}
125125

126-
fn check_ability_knockback(state: &State, id: Id, pos: PosHex) -> Result<(), Error> {
126+
fn check_ability_knockback(
127+
state: &State,
128+
id: Id,
129+
pos: PosHex,
130+
_: ability::Knockback,
131+
) -> Result<(), Error> {
127132
let selected_pos = state.parts().pos.get(id).0;
128133
check_min_distance(selected_pos, pos, Distance(1))?;
129134
check_max_distance(selected_pos, pos, Distance(1))?;

src/core/battle/component.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ pub struct Pos(pub map::PosHex);
1717

1818
/// Blocks the whole tile. Two blocker objects can't coexist in one tile.
1919
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
20-
pub struct Blocker;
20+
pub struct Blocker {
21+
#[serde(default)]
22+
pub weight: battle::Weight,
23+
}
2124

2225
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
2326
pub struct Strength {

src/core/battle/effect.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
33
use crate::core::{
44
battle::{
55
component::{Component, ObjType},
6-
Phase, PosHex, Strength,
6+
Phase, PosHex, PushStrength, Strength,
77
},
88
map::Dir,
99
};
@@ -110,6 +110,7 @@ pub struct Create {
110110
pub struct FlyOff {
111111
pub from: PosHex,
112112
pub to: PosHex,
113+
pub strength: PushStrength,
113114
}
114115

115116
#[derive(Clone, Debug, Deserialize, PartialEq)]
@@ -127,4 +128,5 @@ pub struct Dodge {
127128
pub struct Knockback {
128129
pub from: PosHex,
129130
pub to: PosHex,
131+
pub strength: PushStrength,
130132
}

src/core/battle/execute.rs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::core::{
1414
event::{self, ActiveEvent, Event},
1515
movement::Path,
1616
state::{self, BattleResult, State},
17-
Id, Moves, Phase, PlayerId, Strength,
17+
Id, Moves, Phase, PlayerId, PushStrength, Strength, Weight,
1818
},
1919
map::{self, Dir, PosHex},
2020
utils,
@@ -369,9 +369,16 @@ fn try_execute_passive_abilities_on_attack(
369369
PassiveAbility::HeavyImpact => {
370370
let dir = Dir::get_dir_from_to(attacker_pos, target_pos);
371371
let from = target_pos;
372-
let to = Dir::get_neighbor_pos(target_pos, dir);
373-
if state.map().is_inboard(to) && !state::is_tile_blocked(state, to) {
374-
let effect = effect::FlyOff { from, to }.into();
372+
let strength = PushStrength(Weight::Normal);
373+
let blocker_weight = state.parts().blocker.get(target_id).weight;
374+
let to = if strength.can_push(blocker_weight) {
375+
Dir::get_neighbor_pos(target_pos, dir)
376+
} else {
377+
from
378+
};
379+
let is_inboard = state.map().is_inboard(to);
380+
if to == from || is_inboard && !state::is_tile_blocked(state, to) {
381+
let effect = effect::FlyOff { from, to, strength }.into();
375382
effects.instant.push(effect);
376383
}
377384
}
@@ -673,15 +680,22 @@ impl ExecuteContext {
673680
fn execute_use_ability_knockback(
674681
state: &mut State,
675682
command: &command::UseAbility,
683+
ability: ability::Knockback,
676684
) -> ExecuteContext {
677685
let mut context = ExecuteContext::default();
678686
let id = state::blocker_id_at(state, command.pos);
679687
let from = command.pos;
688+
let strength = ability.strength;
680689
let actor_pos = state.parts().pos.get(command.id).0;
681690
let dir = Dir::get_dir_from_to(actor_pos, command.pos);
682-
let to = Dir::get_neighbor_pos(command.pos, dir);
683-
if state.map().is_inboard(to) && !state::is_tile_blocked(state, to) {
684-
let effect = effect::Knockback { from, to }.into();
691+
let blocker_weight = state.parts().blocker.get(id).weight;
692+
let to = if strength.can_push(blocker_weight) {
693+
Dir::get_neighbor_pos(command.pos, dir)
694+
} else {
695+
from
696+
};
697+
if to == from || state.map().is_inboard(to) && !state::is_tile_blocked(state, to) {
698+
let effect = effect::Knockback { from, to, strength }.into();
685699
context.instant_effects.push((id, vec![effect]));
686700
context.moved_actor_ids.push(id);
687701
}
@@ -936,11 +950,21 @@ fn execute_use_ability_explode_push(
936950
if distance.0 > 1 || command.id == id {
937951
continue;
938952
}
953+
let blocker_weight = state.parts().blocker.get(id).weight;
939954
let dir = Dir::get_dir_from_to(from, pos);
940-
let to = Dir::get_neighbor_pos(pos, dir);
955+
let to = if PushStrength(Weight::Normal).can_push(blocker_weight) {
956+
Dir::get_neighbor_pos(pos, dir)
957+
} else {
958+
pos
959+
};
941960
let mut effects = Vec::new();
942-
if state.map().is_inboard(to) && !state::is_tile_blocked(state, to) {
943-
effects.push(effect::Knockback { from: pos, to }.into());
961+
if to == pos || (state.map().is_inboard(to) && !state::is_tile_blocked(state, to)) {
962+
let effect = effect::Knockback {
963+
from: pos,
964+
to,
965+
strength: PushStrength(Weight::Normal),
966+
};
967+
effects.push(effect.into());
944968
context.moved_actor_ids.push(id);
945969
}
946970
context.instant_effects.push((id, effects));
@@ -1126,7 +1150,7 @@ fn execute_use_ability_bloodlust(
11261150

11271151
fn execute_use_ability(state: &mut State, cb: Cb, command: &command::UseAbility) {
11281152
let mut context = match command.ability {
1129-
Ability::Knockback => execute_use_ability_knockback(state, command),
1153+
Ability::Knockback(a) => execute_use_ability_knockback(state, command, a),
11301154
Ability::Club => execute_use_ability_club(state, command),
11311155
Ability::Jump(_) => execute_use_ability_jump(state, command),
11321156
Ability::Dash => execute_use_ability_dash(state, command),

src/core/battle/state/apply.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,15 +338,20 @@ fn apply_effect_wound(state: &mut State, id: Id, effect: &effect::Wound) {
338338

339339
fn apply_effect_knockback(state: &mut State, id: Id, effect: &effect::Knockback) {
340340
assert!(state.map().is_inboard(effect.from));
341+
if effect.to == effect.from {
342+
return;
343+
}
341344
assert!(state.map().is_inboard(effect.to));
342345
assert!(!state::is_tile_blocked(state, effect.to));
343346
let parts = state.parts_mut();
344347
parts.pos.get_mut(id).0 = effect.to;
345-
// TODO: push anyone who's in the way aside
346348
}
347349

348350
fn apply_effect_fly_off(state: &mut State, id: Id, effect: &effect::FlyOff) {
349351
assert!(state.map().is_inboard(effect.from));
352+
if effect.to == effect.from {
353+
return;
354+
}
350355
assert!(state.map().is_inboard(effect.to));
351356
assert!(!state::is_tile_blocked(state, effect.to));
352357
let parts = state.parts_mut();

0 commit comments

Comments
 (0)