diff --git a/edgehead/lib/director/situational/leroy_quits.dart b/edgehead/lib/director/situational/leroy_quits.dart index e2c558bc0..a3b1347e5 100644 --- a/edgehead/lib/director/situational/leroy_quits.dart +++ b/edgehead/lib/director/situational/leroy_quits.dart @@ -28,3 +28,5 @@ final _leroyQuits = Rule(_id++, 2, true, (ApplicabilityContext c) { b.currentRoomName = 'bleeds_trader_hut'; }); }); + +// TODO: leroy simply quits when being too long with Aren diff --git a/edgehead/lib/src/fight/actions/disarm_kick.dart b/edgehead/lib/src/fight/actions/disarm_kick.dart index 0b4225f15..04cc4c1fc 100644 --- a/edgehead/lib/src/fight/actions/disarm_kick.dart +++ b/edgehead/lib/src/fight/actions/disarm_kick.dart @@ -87,7 +87,7 @@ class DisarmKick extends EnemyTargetAction with CombatCommandPath { @override ReasonedSuccessChance getSuccessChance( Actor a, Simulation sim, WorldState world, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, world.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/actions/smack_with_harmless_item.dart b/edgehead/lib/src/fight/actions/smack_with_harmless_item.dart index 583aa0ffe..c490d5b50 100644 --- a/edgehead/lib/src/fight/actions/smack_with_harmless_item.dart +++ b/edgehead/lib/src/fight/actions/smack_with_harmless_item.dart @@ -80,7 +80,7 @@ class SmackWithHarmlessItem extends EnemyTargetAction with CombatCommandPath { @override ReasonedSuccessChance getSuccessChance( Actor a, Simulation sim, WorldState world, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.3, [ + return getCombatMoveChance(a, enemy, 0.3, world.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Bonus(40, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/actions/start_bite.dart b/edgehead/lib/src/fight/actions/start_bite.dart index b1efc2fd1..46a7ea070 100644 --- a/edgehead/lib/src/fight/actions/start_bite.dart +++ b/edgehead/lib/src/fight/actions/start_bite.dart @@ -31,7 +31,7 @@ ReasonedSuccessChance computeStartBiteAtBodyPartGenerator( math.max(bodyPart.swingSurfaceLeft, bodyPart.swingSurfaceRight) / 10, 1); final base = minBase + maxBase * relativeBiteSurface; - return getCombatMoveChance(a, enemy, base, [ + return getCombatMoveChance(a, enemy, base, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), const Modifier(30, CombatReason.balance), diff --git a/edgehead/lib/src/fight/actions/start_blunt_swing_at_head.dart b/edgehead/lib/src/fight/actions/start_blunt_swing_at_head.dart index e95fb8746..8f5f20f2c 100644 --- a/edgehead/lib/src/fight/actions/start_blunt_swing_at_head.dart +++ b/edgehead/lib/src/fight/actions/start_blunt_swing_at_head.dart @@ -20,7 +20,7 @@ const String startBluntSwingAtHeadHelpMessage = ReasonedSuccessChance computeBluntSwingAtHeadPlayer( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.2, [ + return getCombatMoveChance(a, enemy, 0.2, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), const Modifier(20, CombatReason.balance), diff --git a/edgehead/lib/src/fight/actions/start_break_neck_on_ground.dart b/edgehead/lib/src/fight/actions/start_break_neck_on_ground.dart index 64b8a4523..b1ac90cc4 100644 --- a/edgehead/lib/src/fight/actions/start_break_neck_on_ground.dart +++ b/edgehead/lib/src/fight/actions/start_break_neck_on_ground.dart @@ -17,7 +17,7 @@ const String startBreakNeckOnGroundHelpMessage = ReasonedSuccessChance computeBreakNeckOnGroundChance( Actor a, Simulation sim, WorldState w, Actor enemy) => - getCombatMoveChance(a, enemy, 0.6, [ + getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), ...disabledModifiers, ]); diff --git a/edgehead/lib/src/fight/actions/start_clash.dart b/edgehead/lib/src/fight/actions/start_clash.dart index a3355496d..bf2459d96 100644 --- a/edgehead/lib/src/fight/actions/start_clash.dart +++ b/edgehead/lib/src/fight/actions/start_clash.dart @@ -16,7 +16,7 @@ import 'package:edgehead/src/predetermined_result.dart'; ReasonedSuccessChance computeStartClash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.8, [ + return getCombatMoveChance(a, enemy, 0.8, w.statefulRandomState, [ const Modifier(95, CombatReason.dexterity), const Modifier(30, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/actions/start_crack_skull_on_ground.dart b/edgehead/lib/src/fight/actions/start_crack_skull_on_ground.dart index 76cba6ec7..07d0f7b12 100644 --- a/edgehead/lib/src/fight/actions/start_crack_skull_on_ground.dart +++ b/edgehead/lib/src/fight/actions/start_crack_skull_on_ground.dart @@ -17,7 +17,7 @@ const String startCrackSkullOnGroundHelpMessage = ReasonedSuccessChance computeCrackSkullOnGroundChance( Actor a, Simulation sim, WorldState w, Actor enemy) => - getCombatMoveChance(a, enemy, 0.6, [ + getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), Penalty(a.currentDamageCapability.length >= 2 ? 40 : 90, CombatReason.targetHasWeapon), diff --git a/edgehead/lib/src/fight/actions/start_feint_slash.dart b/edgehead/lib/src/fight/actions/start_feint_slash.dart index f8fef1f06..71571bbe6 100644 --- a/edgehead/lib/src/fight/actions/start_feint_slash.dart +++ b/edgehead/lib/src/fight/actions/start_feint_slash.dart @@ -17,7 +17,7 @@ import 'package:meta/meta.dart'; ReasonedSuccessChance computeStartFeint( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.8, const [ + return getCombatMoveChance(a, enemy, 0.8, w.statefulRandomState, const [ Modifier(95, CombatReason.dexterity), Modifier(50, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/actions/start_leap.dart b/edgehead/lib/src/fight/actions/start_leap.dart index 371219351..1f2c50be3 100644 --- a/edgehead/lib/src/fight/actions/start_leap.dart +++ b/edgehead/lib/src/fight/actions/start_leap.dart @@ -17,7 +17,7 @@ const String startLeapHelpMessage = ReasonedSuccessChance computeStartLeap( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.2, [ + return getCombatMoveChance(a, enemy, 0.2, w.statefulRandomState, [ const Modifier(70, CombatReason.balance), const Modifier(50, CombatReason.height), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/actions/start_pull_down.dart b/edgehead/lib/src/fight/actions/start_pull_down.dart index 79c7e3c08..582365322 100644 --- a/edgehead/lib/src/fight/actions/start_pull_down.dart +++ b/edgehead/lib/src/fight/actions/start_pull_down.dart @@ -16,7 +16,7 @@ import 'package:edgehead/src/predetermined_result.dart'; ReasonedSuccessChance computeStartPullDown( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.05, [ + return getCombatMoveChance(a, enemy, 0.05, w.statefulRandomState, [ const Modifier(20, CombatReason.dexterity), const Modifier(10, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/actions/start_punch.dart b/edgehead/lib/src/fight/actions/start_punch.dart index 9c52193ba..04fda532a 100644 --- a/edgehead/lib/src/fight/actions/start_punch.dart +++ b/edgehead/lib/src/fight/actions/start_punch.dart @@ -17,7 +17,7 @@ const String startPunchHelpMessage = ReasonedSuccessChance computeStartPunch( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(75, CombatReason.dexterity), const Modifier(30, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/actions/start_punch_on_ground.dart b/edgehead/lib/src/fight/actions/start_punch_on_ground.dart index 2b8df442c..b586778c3 100644 --- a/edgehead/lib/src/fight/actions/start_punch_on_ground.dart +++ b/edgehead/lib/src/fight/actions/start_punch_on_ground.dart @@ -17,7 +17,7 @@ const String startPunchOnGroundHelpMessage = ReasonedSuccessChance computeStartPunchOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(75, CombatReason.dexterity), ...disabledModifiers, ]); diff --git a/edgehead/lib/src/fight/actions/start_slash_at_body_part.dart b/edgehead/lib/src/fight/actions/start_slash_at_body_part.dart index 611820a16..65c39c786 100644 --- a/edgehead/lib/src/fight/actions/start_slash_at_body_part.dart +++ b/edgehead/lib/src/fight/actions/start_slash_at_body_part.dart @@ -35,7 +35,7 @@ ReasonedSuccessChance computeStartSlashAtBodyPartGenerator( math.max(bodyPart.swingSurfaceLeft, bodyPart.swingSurfaceRight) / 10, 1); final base = minBase + maxBase * relativeSlashSurface; - return getCombatMoveChance(a, enemy, base, const [ + return getCombatMoveChance(a, enemy, base, w.statefulRandomState, const [ Modifier(30, CombatReason.dexterity), Modifier(30, CombatReason.balance), Modifier(30, CombatReason.weaponReach), diff --git a/edgehead/lib/src/fight/actions/start_strike_down.dart b/edgehead/lib/src/fight/actions/start_strike_down.dart index 029d2ca43..e4ca23f57 100644 --- a/edgehead/lib/src/fight/actions/start_strike_down.dart +++ b/edgehead/lib/src/fight/actions/start_strike_down.dart @@ -33,7 +33,7 @@ ReasonedSuccessChance computeStartStrikeDownPlayer( WeaponType.dagger.defaultLength; final base = (didRecentlyRoll ? 0.8 : 0.4) - (hasShortBlade ? 0.1 : 0); - return getCombatMoveChance(a, enemy, base, [ + return getCombatMoveChance(a, enemy, base, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), const Modifier(30, CombatReason.balance), diff --git a/edgehead/lib/src/fight/actions/start_sweep_feet.dart b/edgehead/lib/src/fight/actions/start_sweep_feet.dart index 6d60c3aab..9c7c25ede 100644 --- a/edgehead/lib/src/fight/actions/start_sweep_feet.dart +++ b/edgehead/lib/src/fight/actions/start_sweep_feet.dart @@ -17,7 +17,7 @@ import 'package:edgehead/src/predetermined_result.dart'; ReasonedSuccessChance computeStartSweepFeet( Actor a, Simulation sim, WorldState w, Actor enemy) { assert(a.isPlayer); - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(70, CombatReason.dexterity), const Modifier(70, CombatReason.balance), const Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/actions/start_throw_harmless.dart b/edgehead/lib/src/fight/actions/start_throw_harmless.dart index e7774faa7..3183ec2de 100644 --- a/edgehead/lib/src/fight/actions/start_throw_harmless.dart +++ b/edgehead/lib/src/fight/actions/start_throw_harmless.dart @@ -17,7 +17,7 @@ const String startThrowHarmlessHelpMessage = ReasonedSuccessChance computeThrowHarmlessPlayer( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.2, [ + return getCombatMoveChance(a, enemy, 0.2, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), const Modifier(10, CombatReason.balance), diff --git a/edgehead/lib/src/fight/actions/start_throw_rock.dart b/edgehead/lib/src/fight/actions/start_throw_rock.dart index 327d9c1e6..2f613ac2b 100644 --- a/edgehead/lib/src/fight/actions/start_throw_rock.dart +++ b/edgehead/lib/src/fight/actions/start_throw_rock.dart @@ -20,7 +20,7 @@ const String startThrowRockHelpMessage = ReasonedSuccessChance computeThrowRockPlayer( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.3, [ + return getCombatMoveChance(a, enemy, 0.3, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), const Modifier(20, CombatReason.balance), diff --git a/edgehead/lib/src/fight/actions/start_throw_thrusting_weapon.dart b/edgehead/lib/src/fight/actions/start_throw_thrusting_weapon.dart index ca728d1fc..dffaedb10 100644 --- a/edgehead/lib/src/fight/actions/start_throw_thrusting_weapon.dart +++ b/edgehead/lib/src/fight/actions/start_throw_thrusting_weapon.dart @@ -25,7 +25,8 @@ ReasonedSuccessChance computeThrowThrustingWeaponPlayer( final hasDagger = a.currentWeapon?.damageCapability?.type == WeaponType.dagger ?? false; final hasThrowingWeapon = hasSpear || hasDagger; - return getCombatMoveChance(a, enemy, hasThrowingWeapon ? 0.3 : 0.01, [ + return getCombatMoveChance( + a, enemy, hasThrowingWeapon ? 0.3 : 0.01, w.statefulRandomState, [ Modifier(hasThrowingWeapon ? 20 : 10, CombatReason.dexterity), const Penalty(20, CombatReason.targetHasShield), Modifier(hasThrowingWeapon ? 20 : 10, CombatReason.balance), diff --git a/edgehead/lib/src/fight/actions/start_thrust.dart b/edgehead/lib/src/fight/actions/start_thrust.dart index 918ae4049..4b1a96cb4 100644 --- a/edgehead/lib/src/fight/actions/start_thrust.dart +++ b/edgehead/lib/src/fight/actions/start_thrust.dart @@ -29,7 +29,7 @@ ReasonedSuccessChance computeThrustAtBodyPartChance( const maxBase = 0.6; final base = lerpDouble(bodyPart.thrustSurface, 0, 8, minBase, maxBase); - return getCombatMoveChance(a, enemy, base, [ + return getCombatMoveChance(a, enemy, base, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Modifier(30, CombatReason.weaponReach), const Penalty(30, CombatReason.targetHasShield), diff --git a/edgehead/lib/src/fight/actions/start_thrust_on_ground.dart b/edgehead/lib/src/fight/actions/start_thrust_on_ground.dart index 58f2369b6..067ac4ed3 100644 --- a/edgehead/lib/src/fight/actions/start_thrust_on_ground.dart +++ b/edgehead/lib/src/fight/actions/start_thrust_on_ground.dart @@ -24,7 +24,7 @@ const String startThrustOnGroundHelpMessage = ReasonedSuccessChance computeStartThrustOnGroundPlayer( Actor a, Simulation sim, WorldState w, Actor enemy) { assert(a.isPlayer); - return getCombatMoveChance(a, enemy, 0.5, [ + return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ const Modifier(20, CombatReason.dexterity), const Penalty(60, CombatReason.targetHasShield), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/actions/wrestle_weapon_on_ground.dart b/edgehead/lib/src/fight/actions/wrestle_weapon_on_ground.dart index 6e1e6c809..05edab1ab 100644 --- a/edgehead/lib/src/fight/actions/wrestle_weapon_on_ground.dart +++ b/edgehead/lib/src/fight/actions/wrestle_weapon_on_ground.dart @@ -113,7 +113,8 @@ class WrestleWeaponOnGround extends EnemyTargetAction with CombatCommandPath { @override ReasonedSuccessChance getSuccessChance( Actor a, Simulation sim, WorldState world, Actor enemy) { - return getCombatMoveChance(a, enemy, a.holdsSomeWeapon ? 0.2 : 0.4, [ + return getCombatMoveChance( + a, enemy, a.holdsSomeWeapon ? 0.2 : 0.4, world.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Bonus(90, CombatReason.targetHasAllEyesDisabled), ]); diff --git a/edgehead/lib/src/fight/bite/bite_defense/actions/dodge_bite.dart b/edgehead/lib/src/fight/bite/bite_defense/actions/dodge_bite.dart index 34bf75dd2..40be5d64c 100644 --- a/edgehead/lib/src/fight/bite/bite_defense/actions/dodge_bite.dart +++ b/edgehead/lib/src/fight/bite/bite_defense/actions/dodge_bite.dart @@ -15,7 +15,7 @@ import 'package:edgehead/src/fight/fight_situation.dart'; ReasonedSuccessChance computeDodgeBite( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.5, [ + return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ const Modifier(60, CombatReason.dexterity), const Modifier(50, CombatReason.balance), const Bonus(50, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/bite/bite_defense/actions/impale_biter.dart b/edgehead/lib/src/fight/bite/bite_defense/actions/impale_biter.dart index bdc717972..1457db514 100644 --- a/edgehead/lib/src/fight/bite/bite_defense/actions/impale_biter.dart +++ b/edgehead/lib/src/fight/bite/bite_defense/actions/impale_biter.dart @@ -213,7 +213,7 @@ class ImpaleBiter extends OtherActorAction { @override ReasonedSuccessChance getSuccessChance( Actor a, Simulation sim, WorldState w, Actor enemy) { - final chance = getCombatMoveChance(a, enemy, 0.3, [ + final chance = getCombatMoveChance(a, enemy, 0.3, w.statefulRandomState, [ const Modifier(40, CombatReason.dexterity), const Modifier(30, CombatReason.height), const Modifier(20, CombatReason.balance), diff --git a/edgehead/lib/src/fight/bite/bite_defense/actions/jump_back_from_bite.dart b/edgehead/lib/src/fight/bite/bite_defense/actions/jump_back_from_bite.dart index 313927ded..c489e6c75 100644 --- a/edgehead/lib/src/fight/bite/bite_defense/actions/jump_back_from_bite.dart +++ b/edgehead/lib/src/fight/bite/bite_defense/actions/jump_back_from_bite.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeJumpBackBite( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(10, CombatReason.balance), const Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/bite/bite_defense/actions/shield_block_bite.dart b/edgehead/lib/src/fight/bite/bite_defense/actions/shield_block_bite.dart index b40bb5b0e..dfeb4dd78 100644 --- a/edgehead/lib/src/fight/bite/bite_defense/actions/shield_block_bite.dart +++ b/edgehead/lib/src/fight/bite/bite_defense/actions/shield_block_bite.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeShieldBlockBite( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Bonus(50, CombatReason.targetHasSecondaryArmDisabled), diff --git a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/defensive_parry_blunt_swing.dart b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/defensive_parry_blunt_swing.dart index eb5e809b8..4daf0d80d 100644 --- a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/defensive_parry_blunt_swing.dart +++ b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/defensive_parry_blunt_swing.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeDefensiveParryBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(95, CombatReason.dexterity), const Modifier(30, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/dodge_blunt_swing.dart b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/dodge_blunt_swing.dart index da92d65d7..1088e5179 100644 --- a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/dodge_blunt_swing.dart +++ b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/dodge_blunt_swing.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeDodgeBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(60, CombatReason.dexterity), const Modifier(50, CombatReason.balance), const Bonus(50, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/jump_back_from_blunt_swing.dart b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/jump_back_from_blunt_swing.dart index c6b1318c8..119891aa7 100644 --- a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/jump_back_from_blunt_swing.dart +++ b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/jump_back_from_blunt_swing.dart @@ -9,7 +9,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeJumpBackBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(10, CombatReason.balance), const Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/parry_blunt_swing.dart b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/parry_blunt_swing.dart index 57ed90871..cb126d6a8 100644 --- a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/parry_blunt_swing.dart +++ b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/parry_blunt_swing.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeParryBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(70, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/roll_away_from_blunt_swing.dart b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/roll_away_from_blunt_swing.dart index 597276d5d..86fbafb91 100644 --- a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/roll_away_from_blunt_swing.dart +++ b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/roll_away_from_blunt_swing.dart @@ -10,7 +10,7 @@ import 'package:edgehead/src/fight/fight_situation.dart'; ReasonedSuccessChance computeRollAwayFromBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.5, [ + return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(10, CombatReason.balance), const Bonus(20, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/shield_block_blunt_swing.dart b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/shield_block_blunt_swing.dart index 3b86a1b02..d3ddc5366 100644 --- a/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/shield_block_blunt_swing.dart +++ b/edgehead/lib/src/fight/blunt_swing/blunt_swing_defense/actions/shield_block_blunt_swing.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeShieldBlockBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Bonus(50, CombatReason.targetHasSecondaryArmDisabled), diff --git a/edgehead/lib/src/fight/clash/clash_defense/actions/counter_clash.dart b/edgehead/lib/src/fight/clash/clash_defense/actions/counter_clash.dart index 921dddaf3..dcae65462 100644 --- a/edgehead/lib/src/fight/clash/clash_defense/actions/counter_clash.dart +++ b/edgehead/lib/src/fight/clash/clash_defense/actions/counter_clash.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeCounterClash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.2, const [ + return getCombatMoveChance(a, enemy, 0.2, w.statefulRandomState, const [ Modifier(20, CombatReason.dexterity), Modifier(20, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/common/conflict_chance.dart b/edgehead/lib/src/fight/common/conflict_chance.dart index 325518930..0c56482b6 100644 --- a/edgehead/lib/src/fight/common/conflict_chance.dart +++ b/edgehead/lib/src/fight/common/conflict_chance.dart @@ -1,6 +1,9 @@ +import 'dart:math'; + import 'package:edgehead/fractal_stories/action.dart'; import 'package:edgehead/fractal_stories/actor.dart'; import 'package:edgehead/fractal_stories/anatomy/body_part.dart'; +import 'package:edgehead/stateful_random/stateful_random.dart'; import 'package:meta/meta.dart'; /// Modifiers applicable to most combat situations. These will make it easier @@ -48,6 +51,9 @@ const List reasonsRequiringPenalties = [ CombatReason.targetHasShield, ]; +/// Used in [varyChance]. +final StatefulRandom _statefulRandom = StatefulRandom(42); + /// This is a convenience method for constructing [ReasonedSuccessChance] /// for the combat in Edgehead. /// @@ -63,7 +69,7 @@ const List reasonsRequiringPenalties = [ /// /// Example: /// -/// return getCombatMoveChance(a, enemy, 0.5, [ +/// return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ /// const Bonus(90, CombatReason.dexterity), /// const Bonus(30, CombatReason.balance), /// ]); @@ -73,8 +79,16 @@ const List reasonsRequiringPenalties = [ /// stance. The difference in dexterity of the two actors can nudge /// the success chance almost all the way (`90`) up to 100%, or down to 0%. The /// combat stance can change the final success chance, too, but only by 30%. -ReasonedSuccessChance getCombatMoveChance(Actor performer, - Actor target, double base, List> modifiers) { +/// +/// If [randomSeed] isn't `null`, then the combat chance will be varied +/// according to [varyChance]. +ReasonedSuccessChance getCombatMoveChance( + Actor performer, + Actor target, + double base, + int randomSeed, + List> modifiers, +) { assert(base > 0.0, "For sureFailures, use ReasonedSuccessChance.sureFailure"); assert( base < 1.0, "For sureSuccesses, use ReasonedSuccessChance.sureSuccess"); @@ -121,10 +135,56 @@ ReasonedSuccessChance getCombatMoveChance(Actor performer, } } + if (randomSeed != null) { + value = varyChance(value, randomSeed); + } + return ReasonedSuccessChance(value, successReasons: successReasons, failureReasons: failureReasons); } +/// Takes a chance [value] (from 0.0 to 1.0) and a [randomSeed], and varies +/// the chance. +@visibleForTesting +double varyChance(double value, int randomSeed) { + assert(value >= 0.0); + assert(value <= 1.0); + + /// The minimum distance between the resulting value and any of + /// the extremities (0 and 1). + const padding = 0.02; + + if (value < padding || value > 1.0 - padding) return value; + + // Set random according to the current state of the world. + _statefulRandom.loadState(randomSeed); + + /// The max value change. For example, if initial value is 0.5, then + /// the resulting value must be 0.5 ± maxVariance. + const maxVariance = 0.3; + + /// The max value change represented as a ratio of the distance between + /// the initial value and one of the extremities (0 or 1). + const scale = 0.7; + + final distanceToClosestExtremity = min( + (value - 0.0).abs(), + (1.0 - value).abs(), + ); + + final scaledDistance = distanceToClosestExtremity * scale; + final clampedDistance = min(scaledDistance, maxVariance); + + /// A random position on the scale from 0 to 2 times clamped distance + /// (from the value minus the distance to the value plus the distance, + /// so 2 distance in total). + final randomPosition = _statefulRandom.nextDouble() * clampedDistance * 2; + + // The final number is the minimum (value minus distance) plus the random + // position. + return (value - clampedDistance) + randomPosition; +} + /// Returns the portion of body parts with given [function] that are disabled /// ([BodyPart.isAnimated] is `false`). /// diff --git a/edgehead/lib/src/fight/counter_attack/actions/counter_blunt_swing.dart b/edgehead/lib/src/fight/counter_attack/actions/counter_blunt_swing.dart index 1c99f7d15..a4d621c4d 100644 --- a/edgehead/lib/src/fight/counter_attack/actions/counter_blunt_swing.dart +++ b/edgehead/lib/src/fight/counter_attack/actions/counter_blunt_swing.dart @@ -20,7 +20,7 @@ const String counterBluntSwingHelpMessage = /// Will the actor be able to even execute the counter? ReasonedSuccessChance computeCounterBluntSwing( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Penalty(50, CombatReason.targetHasShield), const Modifier(50, CombatReason.balance), diff --git a/edgehead/lib/src/fight/counter_attack/actions/counter_slash.dart b/edgehead/lib/src/fight/counter_attack/actions/counter_slash.dart index ca08fced4..9e25c6035 100644 --- a/edgehead/lib/src/fight/counter_attack/actions/counter_slash.dart +++ b/edgehead/lib/src/fight/counter_attack/actions/counter_slash.dart @@ -24,7 +24,7 @@ const String counterSlashHelpMessage = /// it lets the enemy defend (otherwise). ReasonedSuccessChance computeCounterSlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), // No weaponReach modifier. Counter slash can be effective even with // a short weapon. diff --git a/edgehead/lib/src/fight/counter_attack/actions/counter_tackle.dart b/edgehead/lib/src/fight/counter_attack/actions/counter_tackle.dart index 161582985..dbadc348b 100644 --- a/edgehead/lib/src/fight/counter_attack/actions/counter_tackle.dart +++ b/edgehead/lib/src/fight/counter_attack/actions/counter_tackle.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/fight_situation.dart'; ReasonedSuccessChance computeCounterTackle( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.5, [ + return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(50, CombatReason.balance), const Bonus(50, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/counter_attack/actions/counter_thrust.dart b/edgehead/lib/src/fight/counter_attack/actions/counter_thrust.dart index 5012ec275..7ddc5e2c0 100644 --- a/edgehead/lib/src/fight/counter_attack/actions/counter_thrust.dart +++ b/edgehead/lib/src/fight/counter_attack/actions/counter_thrust.dart @@ -18,7 +18,7 @@ const String counterThrustHelpMessage = ReasonedSuccessChance computeCounterThrust( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), const Modifier(30, CombatReason.balance), diff --git a/edgehead/lib/src/fight/counter_attack/actions/counter_thrust_on_ground.dart b/edgehead/lib/src/fight/counter_attack/actions/counter_thrust_on_ground.dart index 0be16fd21..fe45d1d61 100644 --- a/edgehead/lib/src/fight/counter_attack/actions/counter_thrust_on_ground.dart +++ b/edgehead/lib/src/fight/counter_attack/actions/counter_thrust_on_ground.dart @@ -15,7 +15,7 @@ const String counterThrustOnGroundHelpMessage = ReasonedSuccessChance computeCounterThrustOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Penalty(30, CombatReason.targetHasShield), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/evade_on_ground.dart b/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/evade_on_ground.dart index 8ca0aa7b0..36edad966 100644 --- a/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/evade_on_ground.dart +++ b/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/evade_on_ground.dart @@ -10,7 +10,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeEvadeOnGroundChance( Actor a, Simulation sim, WorldState w, Actor enemy) => - getCombatMoveChance(a, enemy, 0.6, [ + getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Penalty(50, CombatReason.performerHasLimitedVision), ]); diff --git a/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/on_ground_parry_blunt.dart b/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/on_ground_parry_blunt.dart index 706250f3c..844fca018 100644 --- a/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/on_ground_parry_blunt.dart +++ b/edgehead/lib/src/fight/fatality_on_ground/wrestle_defense/actions/on_ground_parry_blunt.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeOnGroundParryBlunt( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.5, [ + return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ const Modifier(70, CombatReason.dexterity), const Bonus(50, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/feint/feint_defense/actions/counter_feint.dart b/edgehead/lib/src/fight/feint/feint_defense/actions/counter_feint.dart index d4ca77558..fb309eb29 100644 --- a/edgehead/lib/src/fight/feint/feint_defense/actions/counter_feint.dart +++ b/edgehead/lib/src/fight/feint/feint_defense/actions/counter_feint.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/feint/feint_situation.dart'; ReasonedSuccessChance computeCounterFeint( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.3, const [ + return getCombatMoveChance(a, enemy, 0.3, w.statefulRandomState, const [ Modifier(20, CombatReason.dexterity), Modifier(20, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/leap/leap_defense/actions/impale_leaper.dart b/edgehead/lib/src/fight/leap/leap_defense/actions/impale_leaper.dart index 86efcb5fb..c43427fcf 100644 --- a/edgehead/lib/src/fight/leap/leap_defense/actions/impale_leaper.dart +++ b/edgehead/lib/src/fight/leap/leap_defense/actions/impale_leaper.dart @@ -125,7 +125,7 @@ class ImpaleLeaper extends EnemyTargetAction { @override ReasonedSuccessChance getSuccessChance( Actor a, Simulation sim, WorldState w, Actor enemy) { - final chance = getCombatMoveChance(a, enemy, 0.4, [ + final chance = getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.height), const Modifier(20, CombatReason.balance), diff --git a/edgehead/lib/src/fight/leap/leap_defense/actions/swing_blunt_at_leaper.dart b/edgehead/lib/src/fight/leap/leap_defense/actions/swing_blunt_at_leaper.dart index b47add065..792206ae2 100644 --- a/edgehead/lib/src/fight/leap/leap_defense/actions/swing_blunt_at_leaper.dart +++ b/edgehead/lib/src/fight/leap/leap_defense/actions/swing_blunt_at_leaper.dart @@ -153,7 +153,7 @@ class SwingBluntAtLeaper extends EnemyTargetAction { @override ReasonedSuccessChance getSuccessChance( Actor a, Simulation sim, WorldState w, Actor enemy) { - final chance = getCombatMoveChance(a, enemy, 0.2, [ + final chance = getCombatMoveChance(a, enemy, 0.2, w.statefulRandomState, [ const Modifier(40, CombatReason.dexterity), const Modifier(30, CombatReason.height), const Modifier(20, CombatReason.balance), diff --git a/edgehead/lib/src/fight/off_balance_opportunity/actions/off_balance_opportunity_thrust.dart b/edgehead/lib/src/fight/off_balance_opportunity/actions/off_balance_opportunity_thrust.dart index 7c1c04669..53678bcbe 100644 --- a/edgehead/lib/src/fight/off_balance_opportunity/actions/off_balance_opportunity_thrust.dart +++ b/edgehead/lib/src/fight/off_balance_opportunity/actions/off_balance_opportunity_thrust.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/common/humanoid_pain_or_death.dart'; ReasonedSuccessChance computeOpportunityThrust( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(20, CombatReason.dexterity), const Penalty(20, CombatReason.targetHasShield), const Modifier(20, CombatReason.balance), diff --git a/edgehead/lib/src/fight/slash/slash_defense/actions/defensive_parry_slash.dart b/edgehead/lib/src/fight/slash/slash_defense/actions/defensive_parry_slash.dart index a48e70362..e71b637e8 100644 --- a/edgehead/lib/src/fight/slash/slash_defense/actions/defensive_parry_slash.dart +++ b/edgehead/lib/src/fight/slash/slash_defense/actions/defensive_parry_slash.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeDefensiveParrySlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(95, CombatReason.dexterity), const Modifier(30, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/slash/slash_defense/actions/dodge_slash.dart b/edgehead/lib/src/fight/slash/slash_defense/actions/dodge_slash.dart index 5273754e6..18ab87a67 100644 --- a/edgehead/lib/src/fight/slash/slash_defense/actions/dodge_slash.dart +++ b/edgehead/lib/src/fight/slash/slash_defense/actions/dodge_slash.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeDodgeSlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(60, CombatReason.dexterity), const Modifier(50, CombatReason.balance), const Bonus(50, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/slash/slash_defense/actions/jump_back.dart b/edgehead/lib/src/fight/slash/slash_defense/actions/jump_back.dart index 5f837a776..fa8fd54cc 100644 --- a/edgehead/lib/src/fight/slash/slash_defense/actions/jump_back.dart +++ b/edgehead/lib/src/fight/slash/slash_defense/actions/jump_back.dart @@ -9,7 +9,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeJumpBackSlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(10, CombatReason.balance), const Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/slash/slash_defense/actions/parry_slash.dart b/edgehead/lib/src/fight/slash/slash_defense/actions/parry_slash.dart index f7834131f..99fe678d6 100644 --- a/edgehead/lib/src/fight/slash/slash_defense/actions/parry_slash.dart +++ b/edgehead/lib/src/fight/slash/slash_defense/actions/parry_slash.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeParrySlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(70, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/slash/slash_defense/actions/roll_back.dart b/edgehead/lib/src/fight/slash/slash_defense/actions/roll_back.dart index f281795b3..057dc81f2 100644 --- a/edgehead/lib/src/fight/slash/slash_defense/actions/roll_back.dart +++ b/edgehead/lib/src/fight/slash/slash_defense/actions/roll_back.dart @@ -10,7 +10,7 @@ import 'package:edgehead/src/fight/fight_situation.dart'; ReasonedSuccessChance computeRollBackSlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(10, CombatReason.balance), const Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/slash/slash_defense/actions/shield_block_slash.dart b/edgehead/lib/src/fight/slash/slash_defense/actions/shield_block_slash.dart index 919ea5f39..767800d7c 100644 --- a/edgehead/lib/src/fight/slash/slash_defense/actions/shield_block_slash.dart +++ b/edgehead/lib/src/fight/slash/slash_defense/actions/shield_block_slash.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeShieldBlockSlash( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Bonus(50, CombatReason.targetHasSecondaryArmDisabled), diff --git a/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/dodge_slash_on_ground.dart b/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/dodge_slash_on_ground.dart index 4e5690b67..f92e103c0 100644 --- a/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/dodge_slash_on_ground.dart +++ b/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/dodge_slash_on_ground.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeDodgeSlashOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.8, [ + return getCombatMoveChance(a, enemy, 0.8, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Bonus(50, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/shield_block_slash_on_ground.dart b/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/shield_block_slash_on_ground.dart index 2fd3569e5..15fe66772 100644 --- a/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/shield_block_slash_on_ground.dart +++ b/edgehead/lib/src/fight/slash_on_ground/slash_on_ground_defense/actions/shield_block_slash_on_ground.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeShieldBlockSlashOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(20, CombatReason.dexterity), const Bonus(70, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_parry.dart b/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_parry.dart index 510a58a07..ddf67b0a4 100644 --- a/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_parry.dart +++ b/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_parry.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeOnGroundParry( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.5, [ + return getCombatMoveChance(a, enemy, 0.5, w.statefulRandomState, [ const Modifier(70, CombatReason.dexterity), const Bonus(50, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_shield_block.dart b/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_shield_block.dart index 5f0fc30b0..7a022f9f6 100644 --- a/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_shield_block.dart +++ b/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/on_ground_shield_block.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeOnGroundShieldBlock( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(70, CombatReason.dexterity), ]); } diff --git a/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/roll_out_of_way.dart b/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/roll_out_of_way.dart index 20a569728..173def281 100644 --- a/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/roll_out_of_way.dart +++ b/edgehead/lib/src/fight/strike_down/strike_down_defense/actions/roll_out_of_way.dart @@ -14,7 +14,7 @@ ReasonedSuccessChance computeRollOutOfWay( final didRecentlyRoll = recentlyRolledOutOfWay(w, a); final base = didRecentlyRoll ? 0.3 : 0.9; - return getCombatMoveChance(a, enemy, base, [ + return getCombatMoveChance(a, enemy, base, w.statefulRandomState, [ const Modifier(70, CombatReason.dexterity), const Bonus(30, CombatReason.targetHasOneLegDisabled), const Bonus(90, CombatReason.targetHasAllLegsDisabled), diff --git a/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/jump_to_side_and_counter.dart b/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/jump_to_side_and_counter.dart index 386f8eefc..baa4d4821 100644 --- a/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/jump_to_side_and_counter.dart +++ b/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/jump_to_side_and_counter.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/strike_from_ground/strike_from_ground_situati ReasonedSuccessChance computeJumpToSide( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.4, [ + return getCombatMoveChance(a, enemy, 0.4, w.statefulRandomState, [ const Modifier(60, CombatReason.dexterity), const Bonus(30, CombatReason.targetHasOneLegDisabled), const Bonus(50, CombatReason.targetHasAllLegsDisabled), diff --git a/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/step_back.dart b/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/step_back.dart index 56c3b3c1e..dc4f462e6 100644 --- a/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/step_back.dart +++ b/edgehead/lib/src/fight/strike_from_ground/strike_from_ground_defense/actions/step_back.dart @@ -10,7 +10,7 @@ import 'package:edgehead/src/fight/strike_from_ground/strike_from_ground_situati ReasonedSuccessChance computeStepBack( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(95, CombatReason.dexterity), const Bonus(30, CombatReason.targetHasOneLegDisabled), const Bonus(90, CombatReason.targetHasAllLegsDisabled), diff --git a/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/avoid_sweep_feet.dart b/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/avoid_sweep_feet.dart index cd9482fad..e03bf8aa8 100644 --- a/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/avoid_sweep_feet.dart +++ b/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/avoid_sweep_feet.dart @@ -10,7 +10,7 @@ import 'package:edgehead/src/fight/sweep_feet/sweep_feet_situation.dart'; ReasonedSuccessChance computeAvoidSweep( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, const [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, const [ Modifier(30, CombatReason.dexterity), Modifier(20, CombatReason.balance), Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/counter_sweep_feet.dart b/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/counter_sweep_feet.dart index 6c9b85670..8c7735584 100644 --- a/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/counter_sweep_feet.dart +++ b/edgehead/lib/src/fight/sweep_feet/sweep_feet_defense/actions/counter_sweep_feet.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/sweep_feet/sweep_feet_situation.dart'; ReasonedSuccessChance computeCounterSweepFeet( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.3, const [ + return getCombatMoveChance(a, enemy, 0.3, w.statefulRandomState, const [ Modifier(30, CombatReason.dexterity), Modifier(20, CombatReason.balance), ...disabledModifiers, diff --git a/edgehead/lib/src/fight/throw/throw_defense/actions/catch_projectile.dart b/edgehead/lib/src/fight/throw/throw_defense/actions/catch_projectile.dart index 7285e10a9..cf5e8d998 100644 --- a/edgehead/lib/src/fight/throw/throw_defense/actions/catch_projectile.dart +++ b/edgehead/lib/src/fight/throw/throw_defense/actions/catch_projectile.dart @@ -10,7 +10,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeCatchProjectile( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.05, [ + return getCombatMoveChance(a, enemy, 0.05, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Penalty(30, CombatReason.performerHasLimitedVision), ]); diff --git a/edgehead/lib/src/fight/throw/throw_defense/actions/dodge_throw.dart b/edgehead/lib/src/fight/throw/throw_defense/actions/dodge_throw.dart index cea13ccef..43bd2495c 100644 --- a/edgehead/lib/src/fight/throw/throw_defense/actions/dodge_throw.dart +++ b/edgehead/lib/src/fight/throw/throw_defense/actions/dodge_throw.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/throw/move_projectile_to_ground.dart'; ReasonedSuccessChance computeDodgeThrow( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(60, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Penalty(100, CombatReason.performerHasLimitedVision), diff --git a/edgehead/lib/src/fight/throw/throw_defense/actions/shield_block_throw.dart b/edgehead/lib/src/fight/throw/throw_defense/actions/shield_block_throw.dart index afbf49a3b..932c1ec58 100644 --- a/edgehead/lib/src/fight/throw/throw_defense/actions/shield_block_throw.dart +++ b/edgehead/lib/src/fight/throw/throw_defense/actions/shield_block_throw.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/throw/move_projectile_to_ground.dart'; ReasonedSuccessChance computeShieldBlockThrow( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Penalty(100, CombatReason.performerHasLimitedVision), diff --git a/edgehead/lib/src/fight/thrust/thrust_defense/actions/dodge_thrust.dart b/edgehead/lib/src/fight/thrust/thrust_defense/actions/dodge_thrust.dart index db286c9c5..0a152c89a 100644 --- a/edgehead/lib/src/fight/thrust/thrust_defense/actions/dodge_thrust.dart +++ b/edgehead/lib/src/fight/thrust/thrust_defense/actions/dodge_thrust.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeDodgeThrust( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.6, [ + return getCombatMoveChance(a, enemy, 0.6, w.statefulRandomState, [ const Modifier(60, CombatReason.dexterity), const Modifier(50, CombatReason.balance), const Bonus(50, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/thrust/thrust_defense/actions/jump_back.dart b/edgehead/lib/src/fight/thrust/thrust_defense/actions/jump_back.dart index 94908bc4a..9feab6dcc 100644 --- a/edgehead/lib/src/fight/thrust/thrust_defense/actions/jump_back.dart +++ b/edgehead/lib/src/fight/thrust/thrust_defense/actions/jump_back.dart @@ -9,7 +9,7 @@ import 'package:edgehead/src/fight/common/defense_situation.dart'; ReasonedSuccessChance computeJumpBackThrust( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(90, CombatReason.dexterity), const Modifier(10, CombatReason.balance), const Bonus(30, CombatReason.targetHasOneLegDisabled), diff --git a/edgehead/lib/src/fight/thrust/thrust_defense/actions/shield_block_thrust.dart b/edgehead/lib/src/fight/thrust/thrust_defense/actions/shield_block_thrust.dart index 07dbb7f49..94ee49896 100644 --- a/edgehead/lib/src/fight/thrust/thrust_defense/actions/shield_block_thrust.dart +++ b/edgehead/lib/src/fight/thrust/thrust_defense/actions/shield_block_thrust.dart @@ -13,7 +13,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeShieldBlockThrust( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.7, [ + return getCombatMoveChance(a, enemy, 0.7, w.statefulRandomState, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), const Bonus(50, CombatReason.targetHasSecondaryArmDisabled), diff --git a/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/dodge_thrust_on_ground.dart b/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/dodge_thrust_on_ground.dart index d15e3ed43..c8fc38942 100644 --- a/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/dodge_thrust_on_ground.dart +++ b/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/dodge_thrust_on_ground.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeDodgeThrustOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.8, [ + return getCombatMoveChance(a, enemy, 0.8, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Bonus(50, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/jump_over_thrust_on_ground.dart b/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/jump_over_thrust_on_ground.dart index 5b9c68c71..6e4168d3f 100644 --- a/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/jump_over_thrust_on_ground.dart +++ b/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/jump_over_thrust_on_ground.dart @@ -12,7 +12,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeJumpOverThrustOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(30, CombatReason.dexterity), const Bonus(50, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/shield_block_thrust_on_ground.dart b/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/shield_block_thrust_on_ground.dart index 52443d664..4368b20b7 100644 --- a/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/shield_block_thrust_on_ground.dart +++ b/edgehead/lib/src/fight/thrust_on_ground/thrust_on_ground_defense/actions/shield_block_thrust_on_ground.dart @@ -11,7 +11,7 @@ import 'package:edgehead/src/fight/counter_attack/counter_attack_situation.dart' ReasonedSuccessChance computeShieldBlockThrustOnGround( Actor a, Simulation sim, WorldState w, Actor enemy) { - return getCombatMoveChance(a, enemy, 0.9, [ + return getCombatMoveChance(a, enemy, 0.9, w.statefulRandomState, [ const Modifier(20, CombatReason.dexterity), const Bonus(70, CombatReason.targetHasOneEyeDisabled), const Bonus(90, CombatReason.targetHasAllEyesDisabled), diff --git a/edgehead/test/conflict_chance_test.dart b/edgehead/test/conflict_chance_test.dart index 51805181e..478bb4119 100644 --- a/edgehead/test/conflict_chance_test.dart +++ b/edgehead/test/conflict_chance_test.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:edgehead/fractal_stories/actor.dart'; import 'package:edgehead/fractal_stories/pose.dart'; import 'package:edgehead/src/fight/common/conflict_chance.dart'; @@ -11,7 +13,7 @@ void main() { Actor.initialized(1000, testRandomIdGetter, "goblin", dexterity: 100); test('player gets ~70% chance over goblin with a max50 dexterity roll', () { - final chance = getCombatMoveChance(aren, goblin, 0.6, [ + final chance = getCombatMoveChance(aren, goblin, 0.6, null, [ const Modifier(50, CombatReason.dexterity), ]); @@ -19,7 +21,7 @@ void main() { }); test('goblin gets ~45% chance over player with a max50 dexterity roll', () { - final chance = getCombatMoveChance(goblin, aren, 0.6, [ + final chance = getCombatMoveChance(goblin, aren, 0.6, null, [ const Modifier(50, CombatReason.dexterity), ]); @@ -29,7 +31,7 @@ void main() { test('player gets ~50% chance over goblin when out of balance', () { final outOfBalanceAren = aren.rebuild((b) => b..pose = Pose.offBalance); - final chance = getCombatMoveChance(outOfBalanceAren, goblin, 0.6, [ + final chance = getCombatMoveChance(outOfBalanceAren, goblin, 0.6, null, [ const Modifier(50, CombatReason.dexterity), const Modifier(30, CombatReason.balance), ]); @@ -39,7 +41,7 @@ void main() { }); test('player gets ~90% chance over goblin with a max95 dex roll', () { - final chance = getCombatMoveChance(aren, goblin, 0.8, [ + final chance = getCombatMoveChance(aren, goblin, 0.8, null, [ const Modifier(95, CombatReason.dexterity), ]); @@ -47,7 +49,7 @@ void main() { }); test('goblin gets ~40% chance over player with a max95 dex roll', () { - final chance = getCombatMoveChance(goblin, aren, 0.8, [ + final chance = getCombatMoveChance(goblin, aren, 0.8, null, [ const Modifier(95, CombatReason.dexterity), ]); @@ -58,7 +60,7 @@ void main() { final superman = Actor.initialized(111, testRandomIdGetter, "superman", dexterity: 999); - final chance = getCombatMoveChance(superman, goblin, 0.5, [ + final chance = getCombatMoveChance(superman, goblin, 0.5, null, [ const Modifier(50, CombatReason.dexterity), ]); @@ -67,7 +69,7 @@ void main() { group('.inverted()', () { test('simple inversion with modifier', () { - final chance = getCombatMoveChance(aren, goblin, 0.8, [ + final chance = getCombatMoveChance(aren, goblin, 0.8, null, [ const Modifier(95, CombatReason.dexterity), ]); @@ -78,7 +80,7 @@ void main() { test('inversion with two modifiers', () { var offBalanceGoblin = goblin.rebuild((b) => b..pose = Pose.offBalance); - final chance = getCombatMoveChance(aren, offBalanceGoblin, 0.8, [ + final chance = getCombatMoveChance(aren, offBalanceGoblin, 0.8, null, [ const Modifier(50, CombatReason.dexterity), const Modifier(50, CombatReason.balance), ]); @@ -88,7 +90,7 @@ void main() { }); test('inversion with modifier and bonus', () { - final chance = getCombatMoveChance(aren, goblin, 0.8, [ + final chance = getCombatMoveChance(aren, goblin, 0.8, null, [ const Modifier(50, CombatReason.dexterity), const Bonus(50, CombatReason.performerIsPlayer), ]); @@ -113,4 +115,21 @@ void main() { expect(categorized, orderedEquals(all)); }); + + group('varyChance', () { + final random = Random(); + + test('returns close to a high number', () { + expect(varyChance(0.85, random.nextInt(0xFFFFFF)), greaterThan(0.5)); + }); + + test('returns close to a high number', () { + expect(varyChance(0.10, random.nextInt(0xFFFFFF)), lessThan(0.5)); + }); + + test('does not go from middle completely to extremity', () { + expect(varyChance(0.50, random.nextInt(0xFFFFFF)), lessThan(0.9)); + expect(varyChance(0.50, random.nextInt(0xFFFFFF)), greaterThan(0.1)); + }); + }); }