1
0
Fork 0

Added pinned effect, to prevent ships from moving

This commit is contained in:
Michaël Lemaire 2018-06-13 20:17:46 +02:00
parent f7d0d066c0
commit 7d586d5a2b
14 changed files with 515 additions and 242 deletions

View File

@ -75,7 +75,6 @@ Ships models and actions
* Add damage on collisions (when two ships are moved to the same place) * Add damage on collisions (when two ships are moved to the same place)
* Add hull points to drones and make them take area damage * Add hull points to drones and make them take area damage
* Allow to customize effects based on whether a target is enemy, allied or self * Allow to customize effects based on whether a target is enemy, allied or self
* Add anchored effect (cannot be moved)
* Add a reflect damage effect * Add a reflect damage effect
* Add untargettable effect (can only be targetted with area effects) * Add untargettable effect (can only be targetted with area effects)
* Add damage modifier (to change the options of incoming damage or outgoing damage) * Add damage modifier (to change the options of incoming damage or outgoing damage)

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 165 KiB

View File

@ -136,15 +136,15 @@ module TK.SpaceTac.Specs {
test.case("lists active effects", check => { test.case("lists active effects", check => {
let ship = new Ship(); let ship = new Ship();
check.equals(imaterialize(ship.ieffects()), []); check.equals(ship.getEffects(), []);
let effect1 = new AttributeEffect("evasion", 4); let effect1 = new AttributeEffect("evasion", 4);
check.patch(ship.model, "getEffects", () => [effect1]); check.patch(ship.model, "getEffects", () => [effect1]);
check.equals(imaterialize(ship.ieffects()), [effect1]); check.equals(ship.getEffects(), [effect1]);
let effect2 = new AttributeLimitEffect("evasion", 2); let effect2 = new AttributeLimitEffect("evasion", 2);
ship.active_effects.add(new StickyEffect(effect2, 4)); ship.active_effects.add(new StickyEffect(effect2, 4));
check.equals(imaterialize(ship.ieffects()), [effect1, effect2]); check.equals(ship.getEffects(), [effect1, effect2]);
}); });
test.case("gets a textual description of an attribute", check => { test.case("gets a textual description of an attribute", check => {

View File

@ -331,7 +331,7 @@ module TK.SpaceTac {
keys(this.attributes).forEach(attr => this.attributes[attr].reset()); keys(this.attributes).forEach(attr => this.attributes[attr].reset());
// Apply attribute effects // Apply attribute effects
iforeach(this.ieffects(), effect => { this.getEffects().forEach(effect => {
if (effect instanceof AttributeEffect) { if (effect instanceof AttributeEffect) {
this.attributes[effect.attrcode].addModifier(effect.value); this.attributes[effect.attrcode].addModifier(effect.value);
} else if (effect instanceof AttributeMultiplyEffect) { } else if (effect instanceof AttributeMultiplyEffect) {
@ -371,10 +371,9 @@ module TK.SpaceTac {
* *
* This combines the permanent effects from ship model, with sticky and area effects. * This combines the permanent effects from ship model, with sticky and area effects.
*/ */
ieffects(): Iterator<BaseEffect> { getEffects(): BaseEffect[] {
return ichain( return this.getModelEffects().concat(
iarray(this.getModelEffects()), this.active_effects.list().map(effect => (effect instanceof StickyEffect) ? effect.base : effect)
imap(this.active_effects.iterator(), effect => (effect instanceof StickyEffect) ? effect.base : effect)
); );
} }

View File

@ -48,7 +48,9 @@ module TK.SpaceTac {
// Action is overheated // Action is overheated
OVERHEATED = "Overheated", OVERHEATED = "Overheated",
// Vigilance is activated // Vigilance is activated
VIGILANCE = "In vigilance" VIGILANCE = "In vigilance",
// Ship is pinned
PINNED = "Pinned",
} }
/** /**

View File

@ -67,6 +67,11 @@ module TK.SpaceTac {
return ActionUnavailability.VIGILANCE; return ActionUnavailability.VIGILANCE;
} }
// Check pinned status
if (any(ship.getEffects(), effect => effect instanceof PinnedEffect)) {
return ActionUnavailability.PINNED;
}
return null; return null;
} }

View File

@ -30,7 +30,7 @@ module TK.SpaceTac {
}) })
test.case("builds a textual description", check => { test.case("builds a textual description", check => {
check.equals(new CooldownEffect(0, 0).getDescription(), "Full cooling (all equipments)"); check.equals(new CooldownEffect(0, 0).getDescription(), "full cooling (all equipments)");
check.equals(new CooldownEffect(1, 1).getDescription(), "1 cooling (1 equipment)"); check.equals(new CooldownEffect(1, 1).getDescription(), "1 cooling (1 equipment)");
check.equals(new CooldownEffect(2, 2).getDescription(), "2 cooling (2 equipments)"); check.equals(new CooldownEffect(2, 2).getDescription(), "2 cooling (2 equipments)");
}) })

View File

@ -34,7 +34,7 @@ module TK.SpaceTac {
} }
getDescription(): string { getDescription(): string {
return `${this.cooling ? this.cooling : "Full"} cooling (${this.maxcount ? this.maxcount : "all"} equipment${this.maxcount != 1 ? "s" : ""})`; return `${this.cooling ? this.cooling : "full"} cooling (${this.maxcount ? this.maxcount : "all"} equipment${this.maxcount != 1 ? "s" : ""})`;
} }
} }
} }

View File

@ -0,0 +1,62 @@
module TK.SpaceTac.Specs {
testing("PinnedEffect", test => {
test.case("shows a textual description", check => {
check.equals(new PinnedEffect().getDescription(), "pinned");
check.equals(new PinnedEffect(true).getDescription(), "anchored");
});
test.case("prevents a ship from using its engine", check => {
let ship = new Ship();
TestTools.setShipModel(ship, 1, 1, 1);
let engine = TestTools.addEngine(ship, 100);
check.equals(engine.checkCannotBeApplied(ship), null, "engine can initially be used");
let cases: [string, BaseEffect][] = [
["soft pin", new PinnedEffect()],
["hard pin", new PinnedEffect(true)],
["sticky soft pin", new StickyEffect(new PinnedEffect())],
["sticky hard pin", new StickyEffect(new PinnedEffect(true))],
];
cases.forEach(([title, effect]) => {
check.in(title, check => {
ship.active_effects.add(effect);
check.equals(engine.checkCannotBeApplied(ship), ActionUnavailability.PINNED, "engine cannot be used when pinned");
ship.active_effects.remove(effect);
check.equals(engine.checkCannotBeApplied(ship), null, "engine can be used again");
});
});
});
test.case("prevents a ship from being moved by another effect, in hard mode", check => {
let battle = TestTools.createBattle();
let ship = battle.fleets[0].ships[0];
let enemy = battle.fleets[1].ships[0];
enemy.setArenaPosition(0, 500);
let effect = new RepelEffect(100);
check.equals(effect.getOnDiffs(enemy, ship).length, 1, "ship can initially be moved");
check.in("soft pin", check => {
let pin = enemy.active_effects.add(new PinnedEffect());
check.equals(effect.getOnDiffs(enemy, ship).length, 1, "ship can still be moved");
enemy.active_effects.remove(pin);
check.equals(effect.getOnDiffs(enemy, ship).length, 1, "ship can still be moved");
});
check.in("hard pin", check => {
let pin = enemy.active_effects.add(new PinnedEffect(true));
check.equals(effect.getOnDiffs(enemy, ship).length, 0, "ship cannot be moved");
enemy.active_effects.remove(pin);
check.equals(effect.getOnDiffs(enemy, ship).length, 1, "ship can be moved again");
});
check.in("sticky hard pin", check => {
let pin = enemy.active_effects.add(new StickyEffect(new PinnedEffect(true)));
check.equals(effect.getOnDiffs(enemy, ship).length, 0, "ship cannot be moved");
enemy.active_effects.remove(pin);
check.equals(effect.getOnDiffs(enemy, ship).length, 1, "ship can be moved again");
});
});
});
}

View File

@ -0,0 +1,22 @@
/// <reference path="BaseEffect.ts"/>
module TK.SpaceTac {
/**
* Pin a ship in space, preventing him from moving using its engine
*
* If hard pinned, the ship also may not be moved by another MoveEffect
*/
export class PinnedEffect extends BaseEffect {
constructor(readonly hard = false) {
super("pinned");
}
isBeneficial(): boolean {
return false;
}
getDescription(): string {
return this.hard ? "anchored" : "pinned";
}
}
}

View File

@ -14,7 +14,7 @@ module TK.SpaceTac {
} }
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] { getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
if (ship != source) { if (ship != source && !any(ship.getEffects(), effect => effect instanceof PinnedEffect && effect.hard)) {
let angle = arenaAngle(source.location, ship.location); let angle = arenaAngle(source.location, ship.location);
let destination = new ArenaLocation(ship.arena_x + Math.cos(angle) * this.value, ship.arena_y + Math.sin(angle) * this.value); let destination = new ArenaLocation(ship.arena_x + Math.cos(angle) * this.value, ship.arena_y + Math.sin(angle) * this.value);
let exclusions = ExclusionAreas.fromShip(ship); let exclusions = ExclusionAreas.fromShip(ship);

View File

@ -12,7 +12,7 @@ module TK.SpaceTac {
getLevelUpgrades(level: number): ShipUpgrade[] { getLevelUpgrades(level: number): ShipUpgrade[] {
if (level == 1) { if (level == 1) {
let engine = new MoveAction("Engine", { let engine = new MoveAction("Main Engine", {
distance_per_power: 420, distance_per_power: 420,
}); });
@ -23,12 +23,19 @@ module TK.SpaceTac {
}, "powerdepleter"); }, "powerdepleter");
depleter.configureCooldown(1, 1); depleter.configureCooldown(1, 1);
let gatling = new TriggerAction("Shield Basher", { let shield_basher = new TriggerAction("Shield Basher", {
effects: [new DamageEffect(2, DamageEffectMode.SHIELD_ONLY, false)], effects: [new DamageEffect(2, DamageEffectMode.SHIELD_ONLY, false)],
power: 3, power: 3,
range: 300, range: 300,
}, "submunitionmissile"); }, "shieldbash");
gatling.configureCooldown(2, 1); shield_basher.configureCooldown(2, 1);
let engine_hijack = new TriggerAction("Engine Hijacking", {
effects: [new StickyEffect(new PinnedEffect(), 2)],
power: 2,
range: 400,
}, "pin");
engine_hijack.configureCooldown(1, 2);
return [ return [
{ {
@ -42,16 +49,20 @@ module TK.SpaceTac {
] ]
}, },
{ {
code: "Main Engine", code: engine.name,
actions: [engine] actions: [engine]
}, },
{ {
code: "Power Depleter", code: depleter.name,
actions: [depleter] actions: [depleter]
}, },
{ {
code: "Gatling Gun", code: shield_basher.name,
actions: [gatling] actions: [shield_basher]
},
{
code: engine_hijack.name,
actions: [engine_hijack]
}, },
]; ];
} else { } else {