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 hull points to drones and make them take area damage
* 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 untargettable effect (can only be targetted with area effects)
* 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 => {
let ship = new Ship();
check.equals(imaterialize(ship.ieffects()), []);
check.equals(ship.getEffects(), []);
let effect1 = new AttributeEffect("evasion", 4);
check.patch(ship.model, "getEffects", () => [effect1]);
check.equals(imaterialize(ship.ieffects()), [effect1]);
check.equals(ship.getEffects(), [effect1]);
let effect2 = new AttributeLimitEffect("evasion", 2);
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 => {

View File

@ -331,7 +331,7 @@ module TK.SpaceTac {
keys(this.attributes).forEach(attr => this.attributes[attr].reset());
// Apply attribute effects
iforeach(this.ieffects(), effect => {
this.getEffects().forEach(effect => {
if (effect instanceof AttributeEffect) {
this.attributes[effect.attrcode].addModifier(effect.value);
} 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.
*/
ieffects(): Iterator<BaseEffect> {
return ichain(
iarray(this.getModelEffects()),
imap(this.active_effects.iterator(), effect => (effect instanceof StickyEffect) ? effect.base : effect)
getEffects(): BaseEffect[] {
return this.getModelEffects().concat(
this.active_effects.list().map(effect => (effect instanceof StickyEffect) ? effect.base : effect)
);
}

View File

@ -48,7 +48,9 @@ module TK.SpaceTac {
// Action is overheated
OVERHEATED = "Overheated",
// 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;
}
// Check pinned status
if (any(ship.getEffects(), effect => effect instanceof PinnedEffect)) {
return ActionUnavailability.PINNED;
}
return null;
}

View File

@ -30,7 +30,7 @@ module TK.SpaceTac {
})
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(2, 2).getDescription(), "2 cooling (2 equipments)");
})

View File

@ -34,7 +34,7 @@ module TK.SpaceTac {
}
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[] {
if (ship != source) {
if (ship != source && !any(ship.getEffects(), effect => effect instanceof PinnedEffect && effect.hard)) {
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 exclusions = ExclusionAreas.fromShip(ship);

View File

@ -12,7 +12,7 @@ module TK.SpaceTac {
getLevelUpgrades(level: number): ShipUpgrade[] {
if (level == 1) {
let engine = new MoveAction("Engine", {
let engine = new MoveAction("Main Engine", {
distance_per_power: 420,
});
@ -23,12 +23,19 @@ module TK.SpaceTac {
}, "powerdepleter");
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)],
power: 3,
range: 300,
}, "submunitionmissile");
gatling.configureCooldown(2, 1);
}, "shieldbash");
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 [
{
@ -42,16 +49,20 @@ module TK.SpaceTac {
]
},
{
code: "Main Engine",
code: engine.name,
actions: [engine]
},
{
code: "Power Depleter",
code: depleter.name,
actions: [depleter]
},
{
code: "Gatling Gun",
actions: [gatling]
code: shield_basher.name,
actions: [shield_basher]
},
{
code: engine_hijack.name,
actions: [engine_hijack]
},
];
} else {