Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/__tests__/utility/ability-facing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect, describe, test } from '@jest/globals';
import { shouldFaceTargetDuringCast } from '../../utility/ability-facing';

describe('shouldFaceTargetDuringCast', () => {
test('faces the target when the ability says nothing', () => {
// Every existing ability is in this shape, so none of them change.
expect(shouldFaceTargetDuringCast({})).toBe(true);
});

test('faces the target when the ability opts in explicitly', () => {
expect(shouldFaceTargetDuringCast({ _facesTarget: true })).toBe(true);
});

test('leaves the caster alone only on an explicit opt out', () => {
expect(shouldFaceTargetDuringCast({ _facesTarget: false })).toBe(false);
});

test('treats an undefined flag as opting in', () => {
expect(shouldFaceTargetDuringCast({ _facesTarget: undefined })).toBe(true);
});
});
6 changes: 6 additions & 0 deletions src/abilities/Golden-Wyrm.ts
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,12 @@ export default (G: Game) => {

_targetTeam: Team.Ally,

/* Reaching out to heal an ally standing next to the Golden Wyrm should
not spin it around. Its own hexes span three columns, so an ally on a
frontal diagonal hex can compare as being behind it and make it turn its
back on the unit it is healing. */
_facesTarget: false,

_maxTransferAmount: 50,

require: function () {
Expand Down
7 changes: 5 additions & 2 deletions src/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Game from './game';
import { Player, ScoreEvent } from './player';
import { Point } from './utility/pointfacade';
import { getVisibilityAwareDelay } from './utility/time';
import { shouldFaceTargetDuringCast } from './utility/ability-facing';

/**
* Ability Class
Expand Down Expand Up @@ -142,6 +143,7 @@ export class Ability {
_targets: Hex[];
_addOffenseBuff: () => void;
_maxTransferAmount: number;
_facesTarget?: boolean;
_confirmTarget: (c: Creature) => boolean;
_damaged: boolean;
_executeHealthThreshold: number;
Expand Down Expand Up @@ -562,8 +564,9 @@ export class Ability {

this.creature.facePlayerDefault();

// Force creatures to face towards their target
if (args[0]) {
// Force creatures to face towards their target, unless the ability opts
// out because turning the caster around would be wrong for it.
if (args[0] && shouldFaceTargetDuringCast(this)) {
if (args[0] instanceof Creature) {
this.creature.faceHex(args[0]);
} else if (args[0] instanceof Array) {
Expand Down
22 changes: 22 additions & 0 deletions src/utility/ability-facing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* `Ability.animation2()` turns the caster to face its target before playing the
* cast animation. That is right for an attack, but wrong for abilities that
* reach out to a unit already beside the caster: the caster spins on the spot,
* and for a multi-hex creature a target on a frontal diagonal hex can even read
* as being behind it, so it turns its back on the ally it is helping.
*
* An ability opts out by declaring `_facesTarget: false`.
*/
export type FacingAwareAbility = {
_facesTarget?: boolean;
};

/**
* Whether an ability should re-orient its caster towards the target.
*
* Facing is the default; only an explicit `false` opts out, so abilities that
* say nothing keep the behaviour they have always had.
*/
export function shouldFaceTargetDuringCast(ability: FacingAwareAbility): boolean {
return ability._facesTarget !== false;
}