feat: added parry and homerun
This commit is contained in:
parent
71169690b7
commit
67131c7985
9 changed files with 440 additions and 181 deletions
|
|
@ -10,15 +10,16 @@
|
|||
"strategy": {
|
||||
"type": "in_order",
|
||||
"order": [
|
||||
"secondary"
|
||||
"temporary",
|
||||
"melee"
|
||||
],
|
||||
"reload": false
|
||||
"reload": true
|
||||
},
|
||||
"education": {
|
||||
"bio2350": true,
|
||||
"bio2380": true,
|
||||
"bio2410": true,
|
||||
"cbt2790": false,
|
||||
"cbt2790": true,
|
||||
"cbt2820": true,
|
||||
"cbt2830": true,
|
||||
"cbt2840": true,
|
||||
|
|
@ -27,33 +28,33 @@
|
|||
"cbt2125": true,
|
||||
"gen2116": true,
|
||||
"gen2119": true,
|
||||
"haf2104": false,
|
||||
"haf2105": false,
|
||||
"haf2106": false,
|
||||
"haf2107": false,
|
||||
"haf2108": false,
|
||||
"haf2109": false,
|
||||
"haf2104": true,
|
||||
"haf2105": true,
|
||||
"haf2106": true,
|
||||
"haf2107": true,
|
||||
"haf2108": true,
|
||||
"haf2109": true,
|
||||
"his2160": true,
|
||||
"his2170": true,
|
||||
"mth2240": false,
|
||||
"mth2250": false,
|
||||
"mth2260": false,
|
||||
"mth2320": false,
|
||||
"mth2240": true,
|
||||
"mth2250": true,
|
||||
"mth2260": true,
|
||||
"mth2320": true,
|
||||
"mth2310": true,
|
||||
"mth3330": true,
|
||||
"psy2640": false,
|
||||
"psy2650": false,
|
||||
"psy2660": false,
|
||||
"psy2670": false,
|
||||
"def2710": false,
|
||||
"def2730": false,
|
||||
"def2740": false,
|
||||
"def2750": false,
|
||||
"def2760": false,
|
||||
"psy2640": true,
|
||||
"psy2650": true,
|
||||
"psy2660": true,
|
||||
"psy2670": true,
|
||||
"def2710": true,
|
||||
"def2730": true,
|
||||
"def2740": true,
|
||||
"def2750": true,
|
||||
"def2760": true,
|
||||
"def3770": true,
|
||||
"spt2480": true,
|
||||
"spt2490": false,
|
||||
"spt2500": false
|
||||
"spt2490": true,
|
||||
"spt2500": true
|
||||
},
|
||||
"merits": {
|
||||
"life": 10,
|
||||
|
|
@ -86,148 +87,142 @@
|
|||
},
|
||||
"weapons": {
|
||||
"primary": null,
|
||||
"secondary": {
|
||||
"id": 490,
|
||||
"name": "Blunderbuss",
|
||||
"kind": "secondary",
|
||||
"cat": "shotgun",
|
||||
"base_dmg": 46,
|
||||
"base_acc": 24,
|
||||
"dmg": 46,
|
||||
"acc": 24,
|
||||
"ammo": {
|
||||
"clip_size": 1,
|
||||
"rate_of_fire": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
"secondary": null,
|
||||
"melee": {
|
||||
"id": 247,
|
||||
"name": "Katana",
|
||||
"kind": "melee",
|
||||
"cat": "slashing",
|
||||
"base_dmg": 52,
|
||||
"base_acc": 55,
|
||||
"dmg": 52,
|
||||
"acc": 55,
|
||||
"ammo": null,
|
||||
"mods": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"bonuses": [
|
||||
{
|
||||
"bonus": "bleed",
|
||||
"value": 100
|
||||
},
|
||||
null,
|
||||
null
|
||||
],
|
||||
"compatible_mods": [
|
||||
"laser1mw",
|
||||
"laser5mw",
|
||||
"laser30mw",
|
||||
"laser100mw",
|
||||
"extra_clip",
|
||||
"extra_clip2",
|
||||
"adjustable_trigger",
|
||||
"hair_trigger",
|
||||
"custom_grip",
|
||||
"skeet_choke",
|
||||
"improved_choke",
|
||||
"full_choke",
|
||||
"small_light",
|
||||
"precision_light",
|
||||
"tactical_illuminator"
|
||||
"compatible_mods": [],
|
||||
"experience": 0,
|
||||
"japanese": true
|
||||
},
|
||||
"temporary": {
|
||||
"id": 463,
|
||||
"name": "Epinephrine",
|
||||
"kind": "temporary",
|
||||
"cat": "temporary",
|
||||
"base_dmg": 0,
|
||||
"base_acc": 0,
|
||||
"dmg": 0,
|
||||
"acc": 0,
|
||||
"ammo": null,
|
||||
"mods": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"bonuses": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"compatible_mods": [],
|
||||
"experience": 0,
|
||||
"japanese": false
|
||||
},
|
||||
"melee": null,
|
||||
"temporary": null
|
||||
}
|
||||
},
|
||||
"armour": {
|
||||
"helmet": {
|
||||
"slot": "head",
|
||||
"id": 1355,
|
||||
"name": "Vanguard Respirator",
|
||||
"base_armour": 48,
|
||||
"armour": 48,
|
||||
"id": 675,
|
||||
"name": "Marauder Face Mask",
|
||||
"base_armour": 40,
|
||||
"armour": 40,
|
||||
"coverage": {
|
||||
"body": 2.819999933242798,
|
||||
"body": 11.489999771118164,
|
||||
"heart": 0,
|
||||
"stomach": 0,
|
||||
"chest": 0,
|
||||
"arm": 0,
|
||||
"groin": 0,
|
||||
"leg": 0,
|
||||
"throat": 0,
|
||||
"throat": 60.56999969482422,
|
||||
"hand": 0,
|
||||
"foot": 0,
|
||||
"head": 39.599998474121094
|
||||
"head": 100
|
||||
},
|
||||
"immunities": [
|
||||
"pepper_spray",
|
||||
"nerve_gas",
|
||||
"tear_gas"
|
||||
"pepper_spray"
|
||||
],
|
||||
"bonus": {
|
||||
"kind": "irrepressible",
|
||||
"value": null
|
||||
"kind": "invulnerable",
|
||||
"value": 4
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"slot": "body",
|
||||
"id": 1356,
|
||||
"name": "Vanguard Body",
|
||||
"base_armour": 48,
|
||||
"armour": 48,
|
||||
"id": 676,
|
||||
"name": "Marauder Body",
|
||||
"base_armour": 52,
|
||||
"armour": 52,
|
||||
"coverage": {
|
||||
"body": 44.279998779296875,
|
||||
"body": 42.470001220703125,
|
||||
"heart": 100,
|
||||
"stomach": 100,
|
||||
"chest": 100,
|
||||
"arm": 100,
|
||||
"groin": 35.38999938964844,
|
||||
"leg": 0.2800000011920929,
|
||||
"throat": 83.52999877929688,
|
||||
"hand": 0.12999999523162842,
|
||||
"groin": 0,
|
||||
"leg": 0,
|
||||
"throat": 84.72000122070312,
|
||||
"hand": 5.050000190734863,
|
||||
"foot": 0,
|
||||
"head": 0
|
||||
},
|
||||
"immunities": [],
|
||||
"bonus": {
|
||||
"kind": "irrepressible",
|
||||
"value": null
|
||||
"kind": "imperviable",
|
||||
"value": 4
|
||||
}
|
||||
},
|
||||
"pants": {
|
||||
"slot": "legs",
|
||||
"id": 1357,
|
||||
"name": "Vanguard Pants",
|
||||
"base_armour": 48,
|
||||
"armour": 48,
|
||||
"id": 677,
|
||||
"name": "Marauder Pants",
|
||||
"base_armour": 52,
|
||||
"armour": 52,
|
||||
"coverage": {
|
||||
"body": 24.959999084472656,
|
||||
"body": 20.989999771118164,
|
||||
"heart": 0,
|
||||
"stomach": 0,
|
||||
"stomach": 0.5199999809265137,
|
||||
"chest": 0,
|
||||
"arm": 0,
|
||||
"groin": 99.06999969482422,
|
||||
"leg": 100,
|
||||
"groin": 100,
|
||||
"leg": 96.69000244140625,
|
||||
"throat": 0,
|
||||
"hand": 0,
|
||||
"foot": 25.200000762939453,
|
||||
"foot": 0,
|
||||
"head": 0
|
||||
},
|
||||
"immunities": [],
|
||||
"bonus": {
|
||||
"kind": "irrepressible",
|
||||
"value": null
|
||||
"kind": "imperviable",
|
||||
"value": 4
|
||||
}
|
||||
},
|
||||
"gloves": {
|
||||
"slot": "hands",
|
||||
"id": 1359,
|
||||
"name": "Vanguard Gloves",
|
||||
"base_armour": 48,
|
||||
"armour": 48,
|
||||
"id": 679,
|
||||
"name": "Marauder Gloves",
|
||||
"base_armour": 52,
|
||||
"armour": 52,
|
||||
"coverage": {
|
||||
"body": 14.399999618530273,
|
||||
"body": 14.369999885559082,
|
||||
"heart": 0,
|
||||
"stomach": 0,
|
||||
"chest": 0,
|
||||
"arm": 0.7300000190734863,
|
||||
"arm": 0.5,
|
||||
"groin": 0,
|
||||
"leg": 0,
|
||||
"throat": 0,
|
||||
|
|
@ -237,24 +232,24 @@
|
|||
},
|
||||
"immunities": [],
|
||||
"bonus": {
|
||||
"kind": "irrepressible",
|
||||
"value": null
|
||||
"kind": "invulnerable",
|
||||
"value": 4
|
||||
}
|
||||
},
|
||||
"boots": {
|
||||
"slot": "feet",
|
||||
"id": 1358,
|
||||
"name": "Vanguard Boots",
|
||||
"base_armour": 48,
|
||||
"armour": 48,
|
||||
"id": 678,
|
||||
"name": "Marauder Boots",
|
||||
"base_armour": 52,
|
||||
"armour": 52,
|
||||
"coverage": {
|
||||
"body": 15.130000114440918,
|
||||
"body": 15.649999618530273,
|
||||
"heart": 0,
|
||||
"stomach": 0,
|
||||
"chest": 0,
|
||||
"arm": 0,
|
||||
"groin": 0,
|
||||
"leg": 5.829999923706055,
|
||||
"leg": 9.529999732971191,
|
||||
"throat": 0,
|
||||
"hand": 0,
|
||||
"foot": 100,
|
||||
|
|
@ -262,9 +257,12 @@
|
|||
},
|
||||
"immunities": [],
|
||||
"bonus": {
|
||||
"kind": "irrepressible",
|
||||
"value": null
|
||||
"kind": "invulnerable",
|
||||
"value": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
"property": {
|
||||
"damage": true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"strategy": {
|
||||
"type": "in_order",
|
||||
"order": [
|
||||
"primary"
|
||||
"primary",
|
||||
"melee"
|
||||
],
|
||||
"reload": false
|
||||
},
|
||||
|
|
@ -85,9 +86,92 @@
|
|||
"side_effects": 10
|
||||
},
|
||||
"weapons": {
|
||||
"primary": null,
|
||||
"primary": {
|
||||
"id": 399,
|
||||
"name": "ArmaLite M-15A4",
|
||||
"kind": "primary",
|
||||
"cat": "rifle",
|
||||
"base_dmg": 68,
|
||||
"base_acc": 57,
|
||||
"dmg": 68,
|
||||
"acc": 57,
|
||||
"ammo": {
|
||||
"ammo_kind": "standard",
|
||||
"clip_size": 15,
|
||||
"rate_of_fire": [
|
||||
3,
|
||||
5
|
||||
]
|
||||
},
|
||||
"mods": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"bonuses": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"compatible_mods": [
|
||||
"reflex_sight",
|
||||
"holographic_sight",
|
||||
"acog_sight",
|
||||
"thermal_sight",
|
||||
"laser1mw",
|
||||
"laser5mw",
|
||||
"laser30mw",
|
||||
"laser100mw",
|
||||
"small_suppressor",
|
||||
"standard_suppressor",
|
||||
"large_suppressor",
|
||||
"extended_mags",
|
||||
"high_capacity_mags",
|
||||
"extra_clip",
|
||||
"extra_clip2",
|
||||
"bipod",
|
||||
"tripod",
|
||||
"adjustable_trigger",
|
||||
"hair_trigger",
|
||||
"custom_grip",
|
||||
"recoil_pad",
|
||||
"standard_brake",
|
||||
"heavy_duty_brake",
|
||||
"tactical_brake",
|
||||
"small_light",
|
||||
"precision_light",
|
||||
"tactical_illuminator"
|
||||
],
|
||||
"experience": 0,
|
||||
"japanese": false
|
||||
},
|
||||
"secondary": null,
|
||||
"melee": null,
|
||||
"melee": {
|
||||
"id": 237,
|
||||
"name": "Kodachi",
|
||||
"kind": "melee",
|
||||
"cat": "slashing",
|
||||
"base_dmg": 62,
|
||||
"base_acc": 56,
|
||||
"dmg": 62,
|
||||
"acc": 56,
|
||||
"ammo": null,
|
||||
"mods": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"bonuses": [
|
||||
{
|
||||
"bonus": "parry",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"bonus": "homerun",
|
||||
"value": 100
|
||||
}
|
||||
],
|
||||
"compatible_mods": [],
|
||||
"experience": 0,
|
||||
"japanese": true
|
||||
},
|
||||
"temporary": null
|
||||
},
|
||||
"armour": {
|
||||
|
|
@ -121,27 +205,27 @@
|
|||
},
|
||||
"body": {
|
||||
"slot": "body",
|
||||
"id": 681,
|
||||
"name": "EOD Apron",
|
||||
"base_armour": 55,
|
||||
"armour": 55,
|
||||
"id": 676,
|
||||
"name": "Marauder Body",
|
||||
"base_armour": 52,
|
||||
"armour": 52,
|
||||
"coverage": {
|
||||
"body": 55.2400016784668,
|
||||
"body": 42.470001220703125,
|
||||
"heart": 100,
|
||||
"stomach": 100,
|
||||
"chest": 100,
|
||||
"arm": 100,
|
||||
"groin": 100,
|
||||
"leg": 17.579999923706055,
|
||||
"throat": 100,
|
||||
"hand": 16.8799991607666,
|
||||
"groin": 0,
|
||||
"leg": 0,
|
||||
"throat": 84.72000122070312,
|
||||
"hand": 5.050000190734863,
|
||||
"foot": 0,
|
||||
"head": 4.679999828338623
|
||||
"head": 0
|
||||
},
|
||||
"immunities": [],
|
||||
"bonus": {
|
||||
"kind": "impassable",
|
||||
"value": 0
|
||||
"kind": "imperviable",
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"pants": {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ use proxisim_models::bundle::{
|
|||
armour::{ArmourBodyPart, ArmourBodyParts, BodyPartCoverage},
|
||||
bonus::{ArmourBypassBonus, DamageMitigationBonus, MiscBonus},
|
||||
player::{
|
||||
Attacker, BodyPart, ChooseWeapon, CombatTurns, Current, CurrentTarget, Defeated, Defender,
|
||||
FightEndType, Health, HealthChange, PartDamageBonus, Player, PlayerStrategy, Weapons,
|
||||
ActionNullification, Attacker, BodyPart, ChooseWeapon, CombatTurns, Current, CurrentTarget,
|
||||
Defeated, Defender, FightEndType, Health, HealthChange, PartDamageBonus, PickedAction,
|
||||
Player, PlayerStrategy, Weapons,
|
||||
},
|
||||
stat::{
|
||||
AmmoControl, Clips, CritRate, DamageBonus, Defence, Dexterity, EffectiveStat, MaxHealth,
|
||||
|
|
@ -33,12 +34,12 @@ use crate::{
|
|||
pub mod stats;
|
||||
pub mod status_effect;
|
||||
|
||||
fn select_weapon<'a>(
|
||||
fn select_weapon(
|
||||
weapons: &Weapons,
|
||||
slot: WeaponSlot,
|
||||
reload: bool,
|
||||
usable_q: &'a Query<(Has<NeedsReload>, Option<&Children>), With<Usable>>,
|
||||
) -> Option<(Entity, Option<&'a Children>)> {
|
||||
usable_q: &Query<Has<NeedsReload>, With<Usable>>,
|
||||
) -> Option<WeaponSlot> {
|
||||
let id = match slot {
|
||||
WeaponSlot::Primary => weapons.primary?,
|
||||
WeaponSlot::Secondary => weapons.secondary?,
|
||||
|
|
@ -48,12 +49,12 @@ fn select_weapon<'a>(
|
|||
WeaponSlot::Kick => weapons.kick,
|
||||
};
|
||||
|
||||
let (needs_reload, children) = usable_q.get(id).ok()?;
|
||||
let needs_reload = usable_q.get(id).ok()?;
|
||||
|
||||
if !reload && needs_reload {
|
||||
None
|
||||
} else {
|
||||
Some((id, children))
|
||||
Some(slot)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,37 +100,61 @@ fn check_term_condition(
|
|||
}
|
||||
|
||||
pub fn pick_action(
|
||||
p_query: Query<(Entity, &Weapons, &PlayerStrategy), (With<Player>, Without<PickedAction>)>,
|
||||
usable_q: Query<Has<NeedsReload>, With<Usable>>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for (player, weapons, strat) in p_query {
|
||||
let slot = match strat {
|
||||
PlayerStrategy::AlwaysFists => WeaponSlot::Fists,
|
||||
PlayerStrategy::AlwaysKicks => {
|
||||
select_weapon(weapons, WeaponSlot::Kick, true, &usable_q)
|
||||
.unwrap_or(WeaponSlot::Fists)
|
||||
}
|
||||
PlayerStrategy::PrimaryMelee { reload } => {
|
||||
select_weapon(weapons, WeaponSlot::Primary, *reload, &usable_q)
|
||||
.or_else(|| select_weapon(weapons, WeaponSlot::Melee, true, &usable_q))
|
||||
.unwrap_or(WeaponSlot::Fists)
|
||||
}
|
||||
PlayerStrategy::InOrder { order, reload } => order
|
||||
.iter()
|
||||
.find_map(|slot| select_weapon(weapons, *slot, *reload, &usable_q))
|
||||
.unwrap_or(WeaponSlot::Fists),
|
||||
};
|
||||
|
||||
commands.entity(player).insert(PickedAction(slot));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_weapon(
|
||||
mut p_query: Query<
|
||||
(Entity, &Weapons, &PlayerStrategy, &mut CombatTurns),
|
||||
(Entity, &Weapons, &PickedAction, &mut CombatTurns),
|
||||
(With<Current>, With<Player>),
|
||||
>,
|
||||
target_q: Query<Entity, With<CurrentTarget>>,
|
||||
usable_q: Query<(Has<NeedsReload>, Option<&Children>), With<Usable>>,
|
||||
child_q: Query<Option<&Children>>,
|
||||
weapon_trigger_q: Query<&TurnTriggeredEffect>,
|
||||
mut commands: Commands,
|
||||
mut effects: Effects,
|
||||
metrics: Res<Metrics>,
|
||||
) {
|
||||
let (current, weapons, strat, mut turns) = p_query.single_mut().unwrap();
|
||||
let (weapon, children) = match strat {
|
||||
PlayerStrategy::AlwaysFists => (weapons.fists, None),
|
||||
PlayerStrategy::AlwaysKicks => select_weapon(weapons, WeaponSlot::Kick, true, &usable_q)
|
||||
.unwrap_or_else(|| (weapons.fists, Default::default())),
|
||||
PlayerStrategy::PrimaryMelee { reload } => {
|
||||
select_weapon(weapons, WeaponSlot::Primary, *reload, &usable_q)
|
||||
.or_else(|| select_weapon(weapons, WeaponSlot::Melee, true, &usable_q))
|
||||
.unwrap_or_else(|| (weapons.fists, Default::default()))
|
||||
}
|
||||
PlayerStrategy::InOrder { order, reload } => order
|
||||
.iter()
|
||||
.find_map(|slot| select_weapon(weapons, *slot, *reload, &usable_q))
|
||||
.unwrap_or_else(|| (weapons.fists, Default::default())),
|
||||
let (current, weapons, picked_action, mut turns) = p_query.single_mut().unwrap();
|
||||
let weapon = match picked_action.0 {
|
||||
WeaponSlot::Primary => weapons.primary.unwrap_or(weapons.fists),
|
||||
WeaponSlot::Secondary => weapons.secondary.unwrap_or(weapons.fists),
|
||||
WeaponSlot::Melee => weapons.melee.unwrap_or(weapons.fists),
|
||||
WeaponSlot::Temporary => weapons.temporary.unwrap_or(weapons.fists),
|
||||
WeaponSlot::Fists => weapons.fists,
|
||||
WeaponSlot::Kick => weapons.kick,
|
||||
};
|
||||
|
||||
metrics.increment_counter(Some(current), "turn", 1);
|
||||
metrics.increment_counter(Some(weapon), "turn", 1);
|
||||
|
||||
commands.entity(weapon).insert(Current);
|
||||
|
||||
let children = child_q.get(weapon).unwrap();
|
||||
|
||||
let target = target_q.single().unwrap();
|
||||
|
||||
if let Some(children) = children {
|
||||
|
|
@ -297,6 +322,46 @@ fn check_damage_bonuses(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(SystemParam)]
|
||||
struct NullificationParams<'w, 's> {
|
||||
nullification_q: Query<'w, 's, &'static ActionNullification>,
|
||||
}
|
||||
|
||||
fn check_action_nullification(
|
||||
params: &NullificationParams,
|
||||
shared: &mut SharedParams,
|
||||
target_children: &Children,
|
||||
target_action: &PickedAction,
|
||||
player_action: &PickedAction,
|
||||
) -> Option<&'static str> {
|
||||
for bonus in params.nullification_q.iter_many(target_children) {
|
||||
match bonus {
|
||||
ActionNullification::Parry { chance }
|
||||
if player_action.0 == WeaponSlot::Melee
|
||||
&& target_action.0 == WeaponSlot::Melee
|
||||
&& (*chance >= 1.0 || shared.rng.random_bool(*chance)) =>
|
||||
{
|
||||
return Some("parry");
|
||||
}
|
||||
ActionNullification::Homerun { chance }
|
||||
if player_action.0 == WeaponSlot::Temporary
|
||||
&& target_action.0 == WeaponSlot::Melee
|
||||
&& (*chance >= 1.0 || shared.rng.random_bool(*chance)) =>
|
||||
{
|
||||
return Some("homerun");
|
||||
}
|
||||
ActionNullification::GentsStripClub
|
||||
if player_action.0 == WeaponSlot::Melee && shared.rng.random_bool(0.25) =>
|
||||
{
|
||||
return Some("dodged");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(SystemParam)]
|
||||
struct DeferredDamageParams<'w, 's> {
|
||||
damage_q: Query<'w, 's, (Entity, &'static DeferredDamage)>,
|
||||
|
|
@ -379,6 +444,7 @@ struct EntityParams<'w, 's> {
|
|||
&'static SimpleStatEffective<DamageBonus>,
|
||||
&'static SimpleStatEffective<MaxHealth>,
|
||||
&'static Children,
|
||||
&'static PickedAction,
|
||||
&'static mut Health,
|
||||
Has<Attacker>,
|
||||
),
|
||||
|
|
@ -395,6 +461,8 @@ struct EntityParams<'w, 's> {
|
|||
&'static EffectiveStat<Defence>,
|
||||
&'static SimpleStatEffective<MaxHealth>,
|
||||
&'static ArmourBodyParts,
|
||||
&'static Children,
|
||||
&'static PickedAction,
|
||||
&'static mut Health,
|
||||
),
|
||||
(With<CurrentTarget>, Without<Current>),
|
||||
|
|
@ -405,11 +473,12 @@ struct EntityParams<'w, 's> {
|
|||
// of multi turn bonuses
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn use_damaging_weapon(
|
||||
(mut shared, mut bonus_mitigation, deferred, misc_bonus): (
|
||||
(mut shared, mut bonus_mitigation, deferred, misc_bonus, nullification): (
|
||||
SharedParams,
|
||||
BonusMitigationParams,
|
||||
DeferredDamageParams,
|
||||
DamageBonusParams,
|
||||
NullificationParams,
|
||||
),
|
||||
mut entities: EntityParams,
|
||||
armour_q: Query<&ArmourBodyPart>,
|
||||
|
|
@ -440,11 +509,20 @@ fn use_damaging_weapon(
|
|||
p_dmg_bonus,
|
||||
p_max_health,
|
||||
p_children,
|
||||
p_action,
|
||||
mut p_health,
|
||||
attacker,
|
||||
) = entities.player_q.single_mut().unwrap();
|
||||
let (target, target_dex, target_def, target_max_health, armour_parts, mut health) =
|
||||
entities.target_q.single_mut().unwrap();
|
||||
let (
|
||||
target,
|
||||
target_dex,
|
||||
target_def,
|
||||
target_max_health,
|
||||
armour_parts,
|
||||
t_children,
|
||||
t_action,
|
||||
mut health,
|
||||
) = entities.target_q.single_mut().unwrap();
|
||||
|
||||
if check_deferred_damage(
|
||||
&deferred,
|
||||
|
|
@ -549,6 +627,26 @@ fn use_damaging_weapon(
|
|||
return;
|
||||
};
|
||||
} else {
|
||||
if multi_attack_proc.is_none()
|
||||
&& let Some(kind) = check_action_nullification(
|
||||
&nullification,
|
||||
&mut shared,
|
||||
t_children,
|
||||
t_action,
|
||||
p_action,
|
||||
)
|
||||
{
|
||||
log!(shared.logger, "nullified", {
|
||||
actor: player,
|
||||
recipient: player,
|
||||
weapon: weapon,
|
||||
rounds,
|
||||
kind,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let body_part = if !non_targeted {
|
||||
shared.rng.sample(crit)
|
||||
} else {
|
||||
|
|
@ -641,7 +739,7 @@ fn use_damaging_weapon(
|
|||
shared.metrics.record_histogram(Some(player), "dmg", dmg_i);
|
||||
shared.metrics.record_histogram(Some(weapon), "dmg", dmg_i);
|
||||
|
||||
if dmg_i > 0 {
|
||||
if multi_attack_proc.is_none() && dmg_i > 0 {
|
||||
for effect in damage_proc_q.iter_many(children) {
|
||||
match *effect {
|
||||
DamageProcEffect::MultiTurn { value, bonus } => {
|
||||
|
|
@ -930,6 +1028,24 @@ fn process_health_changes(
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_action_end_of_turn(
|
||||
attacker_turn: Query<Has<Attacker>, (With<Current>, With<Player>)>,
|
||||
picked_q: Query<Entity, With<PickedAction>>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
if !attacker_turn.single().unwrap() {
|
||||
for player in picked_q {
|
||||
commands.entity(player).remove::<PickedAction>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_picked_actions(picked_q: Query<Entity, With<PickedAction>>, mut commands: Commands) {
|
||||
for player in picked_q {
|
||||
commands.entity(player).remove::<PickedAction>();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn configure(stages: &mut Stages) {
|
||||
stats::configure(stages);
|
||||
status_effect::configure(stages);
|
||||
|
|
@ -937,19 +1053,28 @@ pub(crate) fn configure(stages: &mut Stages) {
|
|||
stages.add_event::<ChooseWeapon>();
|
||||
stages.add_event::<HealthChange>();
|
||||
stages.equip.add_systems(designate_first);
|
||||
stages.pre_fight.add_systems(restore_health);
|
||||
stages.pre_turn.add_systems(pick_action);
|
||||
stages.turn.add_systems(use_damaging_weapon);
|
||||
stages.pre_fight.add_systems((restore_health, pick_action));
|
||||
stages.pre_turn.add_systems(prepare_weapon);
|
||||
stages
|
||||
.turn
|
||||
.add_systems((use_damaging_weapon, remove_action_end_of_turn));
|
||||
stages
|
||||
.post_turn
|
||||
.add_systems((check_term_condition, change_roles, process_health_changes))
|
||||
.add_systems((
|
||||
check_term_condition,
|
||||
change_roles,
|
||||
process_health_changes,
|
||||
pick_action,
|
||||
))
|
||||
.add_systems(
|
||||
check_stalemate
|
||||
.after(check_term_condition)
|
||||
.before(change_roles),
|
||||
);
|
||||
stages.post_fight.add_systems(record_post_fight_stats);
|
||||
stages
|
||||
.post_fight
|
||||
.add_systems((record_post_fight_stats, remove_picked_actions));
|
||||
stages
|
||||
.restore
|
||||
.add_systems((restore_initial_state, restore_health));
|
||||
.add_systems((restore_initial_state, restore_health, pick_action));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use proxisim_models::bundle::{
|
||||
bonus::{ArmourBypassBonus, BonusPartDamageBonus, BonusValue, MiscBonus, WeaponBonusType},
|
||||
player::PartDamageBonus,
|
||||
player::{ActionNullification, PartDamageBonus},
|
||||
stat::{
|
||||
AdditiveBonus, AmmoControl, Clips, CritRate, DamageBonus, SimpleStatBonus,
|
||||
SimpleStatEffective, Speed, Strength, WeaponAccuracy,
|
||||
},
|
||||
weapon::Weapon,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -197,10 +198,11 @@ impl BonusPartDamageBonus {
|
|||
pub(crate) fn prepare_bonuses(
|
||||
bonus_q: Query<(&ChildOf, &WeaponBonusType, &BonusValue)>,
|
||||
clips_q: Query<&SimpleStatEffective<Clips>>,
|
||||
weapon_q: Query<&ChildOf, With<Weapon>>,
|
||||
mut effects: Effects,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for (weapon, bonus, value) in bonus_q.iter() {
|
||||
for (weapon, bonus, value) in bonus_q {
|
||||
match bonus {
|
||||
WeaponBonusType::Berserk => {
|
||||
effects.spawn(
|
||||
|
|
@ -495,6 +497,23 @@ pub(crate) fn prepare_bonuses(
|
|||
chance: value.0 as f64 / 100.0,
|
||||
});
|
||||
}
|
||||
|
||||
WeaponBonusType::Parry => {
|
||||
let player = weapon_q.get(weapon.parent()).unwrap();
|
||||
commands
|
||||
.entity(player.parent())
|
||||
.with_child(ActionNullification::Parry {
|
||||
chance: value.0 as f64 / 100.0,
|
||||
});
|
||||
}
|
||||
WeaponBonusType::Homerun => {
|
||||
let player = weapon_q.get(weapon.parent()).unwrap();
|
||||
commands
|
||||
.entity(player.parent())
|
||||
.with_child(ActionNullification::Homerun {
|
||||
chance: value.0 as f64 / 100.0,
|
||||
});
|
||||
}
|
||||
val => unimplemented!("{val:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -540,12 +540,15 @@ pub(crate) fn configure(stages: &mut Stages) {
|
|||
// running this in the snapshot layer ensures that the stat increases aren't restored at the
|
||||
// end of the run
|
||||
stages.snapshot.add_systems(apply_first_turn_effects);
|
||||
stages.equip.add_systems(apply_passives);
|
||||
stages
|
||||
.equip
|
||||
.add_systems((apply_passives, restore_usability));
|
||||
stages.turn.add_systems(reload_weapon);
|
||||
stages.post_turn.add_systems(unset_current);
|
||||
stages
|
||||
.restore
|
||||
.add_systems((restore_ammo, restore_usability, apply_first_turn_effects));
|
||||
.post_fight
|
||||
.add_systems((restore_usability, restore_ammo));
|
||||
stages.restore.add_systems(apply_first_turn_effects);
|
||||
|
||||
temp::configure(stages);
|
||||
bonus::configure(stages);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use proxisim_models::bundle::{
|
||||
player::{Current, CurrentTarget, HealthChange, Player},
|
||||
weapon::{BuffingTemp, DebuffingTemp, Usable, Uses},
|
||||
player::{ActionNullification, Current, CurrentTarget, HealthChange, PickedAction, Player},
|
||||
weapon::{BuffingTemp, DebuffingTemp, Usable, Uses, WeaponSlot},
|
||||
};
|
||||
use rand::Rng as _;
|
||||
|
||||
use crate::{
|
||||
Stages,
|
||||
Rng, Stages,
|
||||
effect::Effects,
|
||||
log,
|
||||
log::Logger,
|
||||
|
|
@ -19,15 +20,39 @@ use crate::{
|
|||
pub struct AssociatedWeapon(pub Entity);
|
||||
|
||||
fn use_debuffing_temp(
|
||||
mut temp_q: Query<(Entity, &DebuffingTemp, &mut Uses), With<Current>>,
|
||||
target_q: Query<Entity, With<CurrentTarget>>,
|
||||
mut temp_q: Query<(Entity, &DebuffingTemp, &mut Uses, &ChildOf), With<Current>>,
|
||||
target_q: Query<(Entity, &Children, &PickedAction), With<CurrentTarget>>,
|
||||
nullification_q: Query<&ActionNullification>,
|
||||
mut effects: Effects,
|
||||
mut commands: Commands,
|
||||
mut rng: ResMut<Rng>,
|
||||
mut logger: Logger,
|
||||
) {
|
||||
let Ok((weapon, temp, mut uses)) = temp_q.single_mut() else {
|
||||
let Ok((weapon, temp, mut uses, player)) = temp_q.single_mut() else {
|
||||
return;
|
||||
};
|
||||
let target = target_q.single().unwrap();
|
||||
let (target, children, picked_action) = target_q.single().unwrap();
|
||||
|
||||
uses.0 -= 1;
|
||||
if uses.0 == 0 {
|
||||
commands.entity(weapon).remove::<Usable>();
|
||||
}
|
||||
|
||||
for bonus in nullification_q.iter_many(children) {
|
||||
if let ActionNullification::Homerun { chance } = bonus
|
||||
&& picked_action.0 == WeaponSlot::Melee
|
||||
&& (*chance >= 1.0 || rng.random_bool(*chance))
|
||||
{
|
||||
log!(logger, "nullified", {
|
||||
actor: player.parent(),
|
||||
recipient: target,
|
||||
kind: "homerun",
|
||||
weapon,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
match temp {
|
||||
DebuffingTemp::TearGas => effects.spawn_and_insert(
|
||||
|
|
@ -56,11 +81,6 @@ fn use_debuffing_temp(
|
|||
AssociatedWeapon(weapon),
|
||||
),
|
||||
};
|
||||
|
||||
uses.0 -= 1;
|
||||
if uses.0 == 0 {
|
||||
commands.entity(weapon).remove::<Usable>();
|
||||
}
|
||||
}
|
||||
|
||||
fn use_buffing_temp(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue