1
0
Fork 0

Forbid move and trigger actions while in vigilance

This commit is contained in:
Michaël Lemaire 2018-04-04 18:17:10 +02:00
parent 7bc6378754
commit c3268ebdea
12 changed files with 99 additions and 49 deletions

View File

@ -56,7 +56,6 @@ Battle
Ships models and actions
------------------------
* Fix vigilance action triggering when the ship moves with one active (moving should disable vigilance actions)
* Fix vigilance action not disabling when reaching the maximum number of triggerings
* Highlight the effects area that will contain the new position when move-targetting
* Add movement attribute (for main engine action, km/power)

View File

@ -295,7 +295,7 @@ module TK.SpaceTac {
});
// Deactivate toggle actions
iforeach(this.iToggleActions(true), action => {
this.getToggleActions(true).forEach(action => {
result = result.concat(action.getSpecificDiffs(this, battle, Target.newFromShip(this)));
});
@ -381,17 +381,19 @@ module TK.SpaceTac {
/**
* Iterator over toggle actions
*/
iToggleActions(only_active = false): Iterator<ToggleAction> {
return <Iterator<ToggleAction>>ifilter(iarray(this.actions.listAll()), action => {
return (action instanceof ToggleAction && (!only_active || this.actions.isToggled(action)));
});
getToggleActions(only_active = false): ToggleAction[] {
let result = cfilter(this.actions.listAll(), ToggleAction);
if (only_active) {
result = result.filter(action => this.actions.isToggled(action));
}
return result;
}
/**
* Get the effects that this ship has on another ship (which may be herself)
*/
getAreaEffects(ship: Ship): BaseEffect[] {
let toggled = imaterialize(this.iToggleActions(true));
let toggled = this.getToggleActions(true);
let effects = toggled.map(action => {
if (bool(action.filterImpactedShips(this, this.location, Target.newFromShip(ship), [ship]))) {
return action.effects;

View File

@ -44,22 +44,22 @@ module TK.SpaceTac.Specs {
check.patch(action, "getPowerUsage", () => 3);
let ship = new Ship();
check.equals(action.checkCannotBeApplied(ship), "action not available");
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.NO_SUCH_ACTION);
ship.actions.addCustom(action);
check.equals(action.checkCannotBeApplied(ship), "not enough power");
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.POWER);
ship.setValue("power", 5);
check.equals(action.checkCannotBeApplied(ship), null);
check.equals(action.checkCannotBeApplied(ship, 4), null);
check.equals(action.checkCannotBeApplied(ship, 3), null);
check.equals(action.checkCannotBeApplied(ship, 2), "not enough power");
check.equals(action.checkCannotBeApplied(ship, 2), ActionUnavailability.POWER);
ship.setValue("power", 3);
check.equals(action.checkCannotBeApplied(ship), null);
ship.setValue("power", 2);
check.equals(action.checkCannotBeApplied(ship), "not enough power");
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.POWER);
})
test.case("checks against overheat", check => {
@ -80,13 +80,13 @@ module TK.SpaceTac.Specs {
check.equals(action.checkCannotBeApplied(ship), null);
cooldown.use();
check.equals(action.checkCannotBeApplied(ship), "overheated");
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.OVERHEATED);
cooldown.cool();
check.equals(action.checkCannotBeApplied(ship), "overheated");
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.OVERHEATED);
cooldown.cool();
check.equals(action.checkCannotBeApplied(ship), "overheated");
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.OVERHEATED);
cooldown.cool();
check.equals(action.checkCannotBeApplied(ship), null);

View File

@ -35,6 +35,22 @@ module TK.SpaceTac {
ENEMIES
}
/**
* Reasons for action unavailibility
*/
export enum ActionUnavailability {
// Ship is not playing
NOT_PLAYING = "Not this ship turn",
// Action is not available
NO_SUCH_ACTION = "Action not available",
// Not enough power remaining
POWER = "Not enough power",
// Action is overheated
OVERHEATED = "Overheated",
// Vigilance is activated
VIGILANCE = "In vigilance"
}
/**
* Base class for a battle action.
*
@ -106,17 +122,17 @@ module TK.SpaceTac {
*
* Method to extend to set conditions
*
* Returns an informative message indicating why the action cannot be used, null otherwise
* Returns an unavalability reason, null otherwise
*/
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): string | null {
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): ActionUnavailability | null {
let battle = ship.getBattle();
if (battle && battle.playing_ship !== ship) {
// Ship is not playing
return "ship not playing";
return ActionUnavailability.NOT_PLAYING;
}
if (!ship.actions.getById(this.id)) {
return "action not available";
return ActionUnavailability.NO_SUCH_ACTION;
}
// Check AP usage
@ -125,12 +141,12 @@ module TK.SpaceTac {
}
var ap_usage = this.getPowerUsage(ship, null);
if (remaining_ap < ap_usage) {
return "not enough power";
return ActionUnavailability.POWER;
}
// Check cooldown
if (!ship.actions.isUsable(this)) {
return "overheated";
return ActionUnavailability.OVERHEATED;
}
return null;

View File

@ -8,11 +8,11 @@ module TK.SpaceTac.Specs {
battle.setPlayingShip(battle.play_order[0]);
let action = new EndTurnAction();
check.equals(action.checkCannotBeApplied(battle.play_order[0]), "action not available");
check.equals(action.checkCannotBeApplied(battle.play_order[0]), ActionUnavailability.NO_SUCH_ACTION);
action = EndTurnAction.SINGLETON;
check.equals(action.checkCannotBeApplied(battle.play_order[0]), null);
check.equals(action.checkCannotBeApplied(battle.play_order[1]), "ship not playing");
check.equals(action.checkCannotBeApplied(battle.play_order[1]), ActionUnavailability.NOT_PLAYING);
});
test.case("changes active ship", check => {

View File

@ -23,7 +23,7 @@ module TK.SpaceTac {
}
getPowerUsage(ship: Ship, target: Target | null): number {
let toggled_cost = isum(imap(ship.iToggleActions(true), action => action.power));
let toggled_cost = sum(ship.getToggleActions(true).map(action => action.power));
return ship.getValue("power") + toggled_cost - ship.getAttribute("power_capacity");
}

View File

@ -125,5 +125,16 @@ module TK.SpaceTac.Specs {
action = new MoveAction("Engine", { distance_per_power: 58, safety_distance: 12 });
check.equals(action.getEffectsDescription(), "Move: 58km per power point (safety: 12km)");
});
test.case("can't be used while in vigilance", check => {
let ship = new Ship();
TestTools.setShipModel(ship, 10, 10, 10);
let vigilance = ship.actions.addCustom(new VigilanceAction("Vigilance"));
let action = ship.actions.addCustom(new MoveAction("Engine"));
check.equals(action.checkCannotBeApplied(ship), null);
ship.actions.toggle(vigilance, true);
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.VIGILANCE);
});
});
}

View File

@ -48,7 +48,7 @@ module TK.SpaceTac {
return Target.newFromLocation(ship.arena_x + Math.cos(ship.arena_angle) * 100, ship.arena_y + Math.sin(ship.arena_angle) * 100);
}
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): string | null {
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): ActionUnavailability | null {
let base = super.checkCannotBeApplied(ship, Infinity);
if (base) {
return base;
@ -58,11 +58,16 @@ module TK.SpaceTac {
if (remaining_ap === null) {
remaining_ap = ship.getValue("power");
}
if (remaining_ap > 0.0001) {
return null;
} else {
return "not enough power";
if (remaining_ap < 0.0001) {
return ActionUnavailability.POWER;
}
// Check vigilance actions
if (any(ship.getToggleActions(true), action => action instanceof VigilanceAction)) {
return ActionUnavailability.VIGILANCE;
}
return null;
}
getPowerUsage(ship: Ship, target: Target | null): number {

View File

@ -136,5 +136,16 @@ module TK.SpaceTac.Specs {
action.configureTrigger({ effects: effects, power: 2, range: 120, blast: 100, angle: 80 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• evasion +20% in 100km radius");
})
test.case("can't be used while in vigilance", check => {
let ship = new Ship();
TestTools.setShipModel(ship, 10, 10, 10);
let vigilance = ship.actions.addCustom(new VigilanceAction("Vigilance"));
let action = ship.actions.addCustom(new TriggerAction("Weapon"));
check.equals(action.checkCannotBeApplied(ship), null);
ship.actions.toggle(vigilance, true);
check.equals(action.checkCannotBeApplied(ship), ActionUnavailability.VIGILANCE);
})
});
}

View File

@ -90,6 +90,21 @@ module TK.SpaceTac {
return this.range;
}
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): ActionUnavailability | null {
let base = super.checkCannotBeApplied(ship, remaining_ap);
if (base) {
return base;
}
// Check vigilance actions
if (any(ship.getToggleActions(true), action => action instanceof VigilanceAction)) {
// TODO Could allow trigger actions that does not involve a move effect
return ActionUnavailability.VIGILANCE;
}
return null;
}
filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
if (this.blast) {
return ships.filter(ship => arenaDistance(ship.location, target) <= this.blast);

View File

@ -9,9 +9,9 @@ module TK.SpaceTac.UI.Specs {
let ship = new Ship();
TestTools.setShipModel(ship, 100, 0, 10);
let action1 = new MoveAction("Thruster");
let action2 = new TriggerAction("Superweapon", { effects: [new DamageEffect(12)], power: 2, range: 50 });
let action3 = new EndTurnAction();
let action1 = ship.actions.addCustom(new MoveAction("Thruster"));
let action2 = ship.actions.addCustom(new TriggerAction("Superweapon", { effects: [new DamageEffect(12)], power: 2, range: 50 }));
let action3 = ship.actions.addCustom(new EndTurnAction());
ActionTooltip.fill(tooltip.getBuilder(), ship, action1, 0);
checkText(check, (<any>tooltip).container.content.children[1], "Use Thruster");

View File

@ -14,34 +14,25 @@ module TK.SpaceTac.UI {
builder.text(action.getTitle(ship), 150, 0, { size: 24 });
let cost = "";
if (action instanceof MoveAction) {
if (ship.getValue("power") == 0) {
cost = "Not enough power";
} else {
cost = `Cost: 1 power per ${action.distance_per_power}km`;
}
let unavailable = action.checkCannotBeApplied(ship);
if (unavailable != null) {
builder.text(unavailable, 150, 40, { color: "#e54d2b" });
} else if (action instanceof MoveAction) {
let cost = `Cost: 1 power per ${action.distance_per_power}km`;
builder.text(cost, 150, 40, { color: "#ffdd4b" });
} else {
let power_usage = action.getPowerUsage(ship, null);
if (power_usage) {
if (ship.getValue("power") < power_usage) {
cost = "Not enough power";
} else if (power_usage > 0) {
cost = `Cost: ${power_usage} power`;
} else {
cost = `Recover: ${-power_usage} power`;
}
let cost = (power_usage > 0) ? `Cost: ${power_usage} power` : `Recover: ${-power_usage} power`;
builder.text(cost, 150, 40, { color: "#ffdd4b" });
}
}
if (cost) {
builder.text(cost, 150, 40, { color: "#ffdd4b" });
}
let cooldown = ship.actions.getCooldown(action);
if (cooldown.overheat) {
if (cooldown.heat > 0) {
builder.text("Cooling down ...", 150, 80, { color: "#d8894d" });
} else if (cooldown.willOverheat() && cost != "Not enough power") {
} else if (!unavailable && cooldown.willOverheat()) {
if (cooldown.cooling > 1) {
let turns = cooldown.cooling - 1;
builder.text(`Unavailable for ${turns} turn${turns > 1 ? "s" : ""} if used`, 150, 80, { color: "#d8894d" });