Skip to content

Commit

Permalink
Implement slashing at only one arm
Browse files Browse the repository at this point in the history
  • Loading branch information
filiph committed Apr 6, 2019
1 parent 0850a37 commit cbdf748
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 11 deletions.
8 changes: 4 additions & 4 deletions edgehead/lib/edgehead_action_builders_gather.gathered.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

146 changes: 146 additions & 0 deletions edgehead/lib/src/fight/actions/start_slash_at_arm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
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/fractal_stories/pose.dart';
import 'package:edgehead/fractal_stories/simulation.dart';
import 'package:edgehead/fractal_stories/situation.dart';
import 'package:edgehead/fractal_stories/storyline/storyline.dart';
import 'package:edgehead/fractal_stories/world_state.dart';
import 'package:edgehead/src/fight/actions/start_slash_at_body_part.dart';
import 'package:edgehead/src/fight/common/defense_situation.dart';
import 'package:edgehead/src/fight/common/start_defensible_action.dart';
import 'package:edgehead/src/fight/common/weapon_as_object2.dart';
import 'package:edgehead/src/fight/slash/slash_defense/slash_defense_situation.dart';
import 'package:edgehead/src/fight/slash/slash_situation.dart';
import 'package:edgehead/src/predetermined_result.dart';

class StartSlashAtArm extends StartDefensibleActionBase {
static final StartSlashAtArm singleton = StartSlashAtArm();

static const String className = "StartSlashAtArm";

@override
List<String> get commandPathTemplate {
throw StateError('$className has its own getCommandPath');
}

@override
String get commandTemplate => "slash >> <object's> >> arm";

@override
String get helpMessage => "Arms tend to be important in fight, and they "
"are often exposed. A disabled arm cannot hold a sword that would later "
"slash your neck.";

@override
String get name => className;

@override
bool get rerollable => true;

@override
Resource get rerollResource => Resource.stamina;

@override
String get rollReasonTemplate => "will <subject> slash the arm?";

@override
bool get shouldShortCircuitWhenFailed => false;

@override
void applyShortCircuit(Actor actor, Simulation sim, WorldStateBuilder world,
Storyline storyline, Actor enemy, Situation mainSituation) {
throw StateError("This action doesn't short-circuit on failure.");
}

@override
void applyStart(Actor a, Simulation sim, WorldStateBuilder world, Storyline s,
Actor enemy, Situation mainSituation) {
a.report(
s,
"<subject> swing<s> {${weaponAsObject2(a)} |}at "
"<objectOwner's> <object>",
object: Entity(name: 'arm'),
objectOwner: enemy,
actionThread: mainSituation.id,
isSupportiveActionInThread: true);
}

@override
DefenseSituation defenseSituationBuilder(Actor a, Simulation sim,
WorldStateBuilder w, Actor enemy, Predetermination predetermination) {
return createSlashDefenseSituation(
w.randomInt(), a, enemy, predetermination);
}

@override
List<String> getCommandPath(Actor target) {
final livingArms = _getAllArms(target).length;
assert(livingArms > 0,
"Trying to apply $className when there is no leg left.");
final isLast = livingArms == 1;

final commandPathTemplate = [
"attack <object>",
"maim",
"slash at <objectPronoun's> ${isLast ? 'remaining ' : ''}arm",
];

// Realize the "<object>" parts of the template.
return (Storyline()..add(commandPathTemplate.join('>>'), object: target))
.realizeAsString()
// Then split again into a list.
.split('>>');
}

@override
bool isApplicable(Actor a, Simulation sim, WorldState w, Actor enemy) =>
!a.isOnGround &&
// This is here because we currently don't have a way to dodge
// a thrust while on ground. TODO: fix and remove
!enemy.isOnGround &&
!a.anatomy.isBlind &&
a.currentWeapon.damageCapability.isSlashing &&
// Only allow arm attacks when enemy is at least extended.
enemy.pose <= Pose.extended &&
enemy.anatomy.anyWeaponAppendageAvailable;

@override
Situation mainSituationBuilder(
Actor a, Simulation sim, WorldStateBuilder w, Actor enemy) {
final arm = _getTargetArm(enemy);

return createSlashSituation(w.randomInt(), a, enemy,
designation: arm.designation);
}

@override
ReasonedSuccessChance successChanceGetter(
Actor a, Simulation sim, WorldState w, Actor enemy) {
final leg = _getTargetArm(enemy);
return computeStartSlashAtBodyPartGenerator(leg, a, sim, w, enemy);
}

static Iterable<BodyPart> _getAllArms(Actor target) {
assert(
target.anatomy.isHumanoid,
"This function currently assumes that legs are the only "
"body parts providing mobility.");

return target.anatomy.allParts
.where((part) => part.function == BodyPartFunction.wielding);
}

static BodyPart _getTargetArm(Actor enemy) {
assert(enemy.anatomy.isHumanoid, "Assuming just two arms.");
if (enemy.anatomy.primaryWeaponAppendageAvailable) {
// The "appendage" is a hand. We are targeting the arm.
return enemy.anatomy.findByDesignation(BodyPartDesignation.primaryArm);
}
if (enemy.anatomy.secondaryWeaponAppendageAvailable) {
// The "appendage" is a hand. We are targeting the arm.
return enemy.anatomy.findByDesignation(BodyPartDesignation.secondaryArm);
}
throw StateError('_getTargetArm was called when no arm is available');
}
}
6 changes: 2 additions & 4 deletions edgehead/lib/src/fight/actions/start_slash_at_body_part.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,12 @@ PartialApplyFunction startSlashReportStart(BodyPartDesignation designation) =>

bool _resolveIsApplicable(Actor a, Simulation sim, WorldState w, Actor enemy,
BodyPartDesignation designation) {
assert(!designation.isLeg, "Use SlashAtLeg instead.");
assert(!designation.isArm, "Use SlashAtArm instead.");
if (a.isOnGround) return false;
if (enemy.isOnGround) return false;
if (a.anatomy.isBlind) return false;
if (!a.currentWeapon.damageCapability.isSlashing) return false;
// Only allow leg attacks when enemy has worse than combat stance.
if (designation.isLeg && enemy.pose >= Pose.combat) return false;
// Only allow arm attacks when enemy is at least extended.
if (designation.isArm && enemy.pose > Pose.extended) return false;
// Only allow torso slashes when enemy is (at least) extended.
if (designation == BodyPartDesignation.torso && enemy.pose > Pose.extended) {
return false;
Expand Down
5 changes: 4 additions & 1 deletion edgehead/lib/src/fight/common/start_defensible_action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,10 @@ abstract class StartDefensibleActionBase extends EnemyTargetAction
/// This function should use [storyline] to report that the defensible action
/// couldn't even start. It can modify [world].
///
/// For example, "Orc tries to swing at you but completely misses."
/// For example, "Orc tries to swing at you but completely misses." In this
/// scenario, there is no need to create the defensible situation, since
/// there is no action to defend from. It failed too hard. Therefore,
/// the action short-circuits.
///
/// When this function is non-null, and the action fails, [applyStart] won't
/// be called. Nor will the action generate any situations (using
Expand Down
4 changes: 2 additions & 2 deletions edgehead/lib/src/fight/fight_situation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import 'package:edgehead/src/fight/actions/stand_up.dart';
import 'package:edgehead/src/fight/actions/start_break_neck_on_ground.dart';
import 'package:edgehead/src/fight/actions/start_leap.dart';
import 'package:edgehead/src/fight/actions/start_punch.dart';
import 'package:edgehead/src/fight/actions/start_slash_at_arm.dart';
import 'package:edgehead/src/fight/actions/start_slash_at_body_part.dart';
import 'package:edgehead/src/fight/actions/start_slash_at_leg.dart';
import 'package:edgehead/src/fight/actions/start_strike_down.dart';
Expand Down Expand Up @@ -93,8 +94,7 @@ abstract class FightSituation extends Object
startBreakNeckOnGroundBuilder(),
startLeapBuilder(),
startPunchBuilder(),
startSlashAtBodyPartGenerator(BodyPartDesignation.primaryArm),
startSlashAtBodyPartGenerator(BodyPartDesignation.secondaryArm),
StartSlashAtArm.singleton,
startSlashAtBodyPartGenerator(BodyPartDesignation.neck),
StartSlashAtLeg.singleton,
startStrikeDownBuilder(),
Expand Down

0 comments on commit cbdf748

Please sign in to comment.