Simplified drone system
This commit is contained in:
parent
cbb860b1ec
commit
ee1cbc9c14
|
@ -125,11 +125,8 @@ the end of turn (it will only start cooling down after being overheated).
|
|||
|
||||
Drones are static objects, deployed by ships, that apply effects in a circular zone around themselves.
|
||||
|
||||
A drone lasts for a given number of battle cycles. For example, if there are 8 ships in play, a 2-cycles
|
||||
drone will try to activate 16 times, before being destroyed.
|
||||
|
||||
All drones activate between two ship turns. At each activation, the drone effects are applied to any ship
|
||||
in the surrounding zone, except if less than a battle cycle passed since last activation for this ship.
|
||||
Drones activate between two ship turns. At each activation, the drone effects are applied to any ship
|
||||
in the surrounding zone. A drone will live for a given number of activations, before being destroyed.
|
||||
|
||||
Drones are fully autonomous, and once deployed, are not controlled by their owner ship.
|
||||
|
||||
|
|
2
TODO
2
TODO
|
@ -27,7 +27,7 @@
|
|||
* Actions: fix targetting not resetting when using keyboard shortcuts
|
||||
* Suspend AI operation when the game is paused (window not focused)
|
||||
* Add actions with cost dependent of distance (like current move actions)
|
||||
* Keep move actions out of arena borders
|
||||
* Keep move and drone actions out of arena borders
|
||||
* Find incentives to move from starting position
|
||||
* Outcome: add battle statistics and/or honors
|
||||
* Outcome: disable the loot button if there is no loot
|
||||
|
|
|
@ -53,45 +53,6 @@ module TS.SpaceTac {
|
|||
expect(effect.getApplyCalls()).toEqual([ship1, ship2]);
|
||||
});
|
||||
|
||||
it("maintains ship application countdown", function () {
|
||||
let battle = new Battle();
|
||||
spyOn(battle, "getCycleLength").and.returnValue(7);
|
||||
let ship = new Ship(battle.fleets[0]);
|
||||
let drone = new Drone(ship, "test", 2);
|
||||
|
||||
expect(drone.getShipCountdown(ship)).toBe(0);
|
||||
drone.startShipCountdown(ship);
|
||||
expect(drone.getShipCountdown(ship)).toBe(7);
|
||||
});
|
||||
|
||||
it("applies at most once per battle cycle", function () {
|
||||
let battle = new Battle();
|
||||
let ship1 = new Ship(battle.fleets[0], "ship1");
|
||||
ship1.setArenaPosition(0, 0);
|
||||
let ship2 = new Ship(battle.fleets[1], "ship2");
|
||||
ship2.setArenaPosition(100, 100);
|
||||
battle.throwInitiative();
|
||||
expect(battle.getCycleLength()).toEqual(2);
|
||||
|
||||
let [drone, effect] = newTestDrone(2, 2, 8, ship1);
|
||||
expect(effect.getApplyCalls()).toEqual([]);
|
||||
|
||||
drone.activate();
|
||||
expect(effect.getApplyCalls()).toEqual([ship1]);
|
||||
|
||||
drone.activate();
|
||||
expect(effect.getApplyCalls()).toEqual([]);
|
||||
|
||||
drone.activate();
|
||||
expect(effect.getApplyCalls()).toEqual([ship1]);
|
||||
|
||||
drone.activate();
|
||||
expect(effect.getApplyCalls()).toEqual([]);
|
||||
|
||||
drone.activate();
|
||||
expect(effect.getApplyCalls()).toEqual([ship1]);
|
||||
});
|
||||
|
||||
it("signals the need for destruction after its lifetime", function () {
|
||||
let battle = new Battle();
|
||||
let owner = new Ship(battle.fleets[0]);
|
||||
|
|
|
@ -23,14 +23,11 @@ module TS.SpaceTac {
|
|||
// Effects to apply
|
||||
effects: BaseEffect[] = [];
|
||||
|
||||
// Cycle countdown for ships
|
||||
countdown: [Ship, number][] = [];
|
||||
|
||||
constructor(owner: Ship, code = "drone", base_duration = 1) {
|
||||
this.battle = owner.getBattle() || new Battle();
|
||||
this.owner = owner;
|
||||
this.code = code;
|
||||
this.duration = base_duration * this.battle.getCycleLength();
|
||||
this.duration = base_duration;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,42 +41,11 @@ module TS.SpaceTac {
|
|||
return `For ${this.duration} activation${this.duration > 1 ? "s" : ""}:\n${effects}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get countdown until next activation for a given ship
|
||||
*/
|
||||
getShipCountdown(ship: Ship): number {
|
||||
let countdown = 0;
|
||||
this.countdown.forEach(([iship, icountdown]) => {
|
||||
if (iship === ship) {
|
||||
countdown = icountdown;
|
||||
}
|
||||
});
|
||||
return countdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the countdown for a given ship
|
||||
*/
|
||||
startShipCountdown(ship: Ship): void {
|
||||
let found = false;
|
||||
this.countdown = this.countdown.map(([iship, countdown]): [Ship, number] => {
|
||||
if (iship === ship) {
|
||||
found = true;
|
||||
return [iship, this.battle.getCycleLength()];
|
||||
} else {
|
||||
return [iship, countdown];
|
||||
}
|
||||
});
|
||||
if (!found) {
|
||||
this.countdown.push([ship, this.battle.getCycleLength()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of affected ships.
|
||||
*/
|
||||
getAffectedShips(): Ship[] {
|
||||
let ships = ifilter(this.battle.iships(), ship => ship.alive && ship.isInCircle(this.x, this.y, this.radius) && this.getShipCountdown(ship) == 0);
|
||||
let ships = ifilter(this.battle.iships(), ship => ship.alive && ship.isInCircle(this.x, this.y, this.radius));
|
||||
return imaterialize(ships);
|
||||
}
|
||||
|
||||
|
@ -95,7 +61,6 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
ships.forEach(ship => {
|
||||
this.startShipCountdown(ship);
|
||||
this.effects.forEach(effect => effect.applyOnShip(ship));
|
||||
});
|
||||
}
|
||||
|
@ -107,8 +72,6 @@ module TS.SpaceTac {
|
|||
activate(log = true) {
|
||||
this.apply(this.getAffectedShips(), log);
|
||||
|
||||
this.countdown = this.countdown.map(([ship, countdown]): [Ship, number] => [ship, countdown - 1]).filter(([ship, countdown]) => countdown > 0);
|
||||
|
||||
this.duration--;
|
||||
if (this.duration == 0) {
|
||||
this.battle.removeDrone(this, log);
|
||||
|
|
|
@ -30,7 +30,6 @@ module TS.SpaceTac {
|
|||
let ship = battle.fleets[0].addShip();
|
||||
ship.setArenaPosition(0, 0);
|
||||
battle.playing_ship = ship;
|
||||
spyOn(battle, "getCycleLength").and.returnValue(4);
|
||||
TestTools.setShipAP(ship, 3);
|
||||
let equipment = new Equipment(SlotType.Weapon, "testdrone");
|
||||
let action = new DeployDroneAction(equipment, 2, 8, 2, 4, [new DamageEffect(50)]);
|
||||
|
@ -44,7 +43,7 @@ module TS.SpaceTac {
|
|||
|
||||
let drone = battle.drones[0];
|
||||
expect(drone.code).toEqual("testdrone");
|
||||
expect(drone.duration).toEqual(8);
|
||||
expect(drone.duration).toEqual(2);
|
||||
expect(drone.owner).toBe(ship);
|
||||
expect(drone.x).toEqual(5);
|
||||
expect(drone.y).toEqual(0);
|
||||
|
|
|
@ -65,7 +65,7 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
getEffectsDescription(): string {
|
||||
let desc = `Deploy drone for ${this.lifetime} cycle${this.lifetime > 1 ? "s" : ""} (power usage ${this.power}, max range ${this.deploy_distance}km)`;
|
||||
let desc = `Deploy drone for ${this.lifetime} activation${this.lifetime > 1 ? "s" : ""} (power usage ${this.power}, max range ${this.deploy_distance}km)`;
|
||||
let effects = this.effects.map(effect => {
|
||||
let suffix = `for ships in ${this.effect_radius}km radius`;
|
||||
return "• " + effect.getDescription() + " " + suffix;
|
||||
|
|
|
@ -5,26 +5,26 @@ module TS.SpaceTac.Equipments {
|
|||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 1 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 300, 1, 100, [new ValueEffect("hull", 30)]));
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 300, 10, 100, [new ValueEffect("hull", 10)]));
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 2 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 310, 1, 110, [new ValueEffect("hull", 33)]));
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 310, 11, 110, [new ValueEffect("hull", 12)]));
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 3 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 320, 1, 120, [new ValueEffect("hull", 36)]));
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 320, 12, 120, [new ValueEffect("hull", 14)]));
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 10 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 390, 2, 190, [new ValueEffect("hull", 57)]));
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 390, 19, 190, [new ValueEffect("hull", 28)]));
|
||||
});
|
||||
|
||||
it("generates a drone that may repair ships hull", function () {
|
||||
let template = new RepairDrone();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 300, 1, 100, [new ValueEffect("hull", 30)]));
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 300, 10, 100, [new ValueEffect("hull", 10)]));
|
||||
|
||||
let battle = new Battle();
|
||||
let ship = battle.fleets[0].addShip();
|
||||
|
@ -36,11 +36,11 @@ module TS.SpaceTac.Equipments {
|
|||
|
||||
expect(battle.drones.length).toBe(1);
|
||||
let drone = battle.drones[0];
|
||||
expect(drone.duration).toBe(1);
|
||||
expect(drone.duration).toBe(10);
|
||||
ship.setAttribute("hull_capacity", 100);
|
||||
ship.setValue("hull", 55);
|
||||
ship.setValue("hull", 85);
|
||||
drone.apply([ship]);
|
||||
expect(ship.getValue("hull")).toBe(85);
|
||||
expect(ship.getValue("hull")).toBe(95);
|
||||
drone.apply([ship]);
|
||||
expect(ship.getValue("hull")).toBe(100);
|
||||
});
|
||||
|
|
|
@ -10,8 +10,8 @@ module TS.SpaceTac.Equipments {
|
|||
|
||||
this.setSkillsRequirements({ "skill_human": 1 });
|
||||
this.setCooldown(irepeat(1), istep(3, irepeat(0.2)));
|
||||
this.addDroneAction(irepeat(4), istep(300, irepeat(10)), istep(1, irepeat(0.2)), istep(100, irepeat(10)), [
|
||||
new EffectTemplate(new ValueEffect("hull"), { "value": istep(30, irepeat(3)) })
|
||||
this.addDroneAction(irepeat(4), istep(300, irepeat(10)), istep(10, irepeat(1)), istep(100, irepeat(10)), [
|
||||
new EffectTemplate(new ValueEffect("hull"), { "value": istep(10, irepeat(2)) })
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,22 +4,25 @@ module TS.SpaceTac.UI {
|
|||
*/
|
||||
export class ArenaDrone extends Phaser.Group {
|
||||
// Link to view
|
||||
view: BattleView;
|
||||
view: BattleView
|
||||
|
||||
// Link to displayed drone
|
||||
drone: Drone;
|
||||
drone: Drone
|
||||
|
||||
// Sprite
|
||||
sprite: Phaser.Button;
|
||||
sprite: Phaser.Button
|
||||
|
||||
// Radius
|
||||
radius: Phaser.Graphics;
|
||||
radius: Phaser.Graphics
|
||||
|
||||
// Activation effect
|
||||
activation: Phaser.Graphics;
|
||||
activation: Phaser.Graphics
|
||||
|
||||
// Duration info
|
||||
duration: Phaser.Text
|
||||
|
||||
// Destroyed state
|
||||
destroyed = false;
|
||||
destroyed = false
|
||||
|
||||
constructor(battleview: BattleView, drone: Drone) {
|
||||
super(battleview.game);
|
||||
|
@ -32,7 +35,7 @@ module TS.SpaceTac.UI {
|
|||
this.radius.beginFill(0xe9f2f9, 0.0);
|
||||
this.radius.drawCircle(0, 0, drone.radius * 2);
|
||||
this.radius.endFill();
|
||||
this.addChild(this.radius);
|
||||
this.add(this.radius);
|
||||
|
||||
this.activation = new Phaser.Graphics(this.game, 0, 0);
|
||||
this.activation.lineStyle(2, 0xe9f2f9, 0.7);
|
||||
|
@ -40,12 +43,17 @@ module TS.SpaceTac.UI {
|
|||
this.activation.drawCircle(0, 0, drone.radius * 2);
|
||||
this.activation.endFill();
|
||||
this.activation.visible = false;
|
||||
this.addChild(this.activation);
|
||||
this.add(this.activation);
|
||||
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, `battle-actions-deploy-${drone.code}`);
|
||||
this.sprite.anchor.set(0.5, 0.5);
|
||||
this.sprite.scale.set(0.1, 0.1);
|
||||
this.addChild(this.sprite);
|
||||
this.add(this.sprite);
|
||||
|
||||
this.duration = new Phaser.Text(this.game, 0, 40, "", { font: "bold 16pt Arial", fill: "#ffdd4b" });
|
||||
this.duration.anchor.set(0.5, 0.5);
|
||||
this.duration.visible = false;
|
||||
this.add(this.duration);
|
||||
|
||||
this.view.tooltip.bindDynamicText(this.sprite, () => {
|
||||
return this.destroyed ? "" : this.drone.getDescription();
|
||||
|
@ -90,8 +98,12 @@ module TS.SpaceTac.UI {
|
|||
* Set the tactical mode display
|
||||
*/
|
||||
setTacticalMode(active: boolean) {
|
||||
if (active) {
|
||||
this.duration.text = `${this.drone.duration}`;
|
||||
}
|
||||
this.sprite.rotation = active ? -this.rotation : 0;
|
||||
this.sprite.scale.set(active ? 0.3 : 0.1);
|
||||
this.sprite.scale.set(active ? 0.2 : 0.1);
|
||||
this.view.animations.setVisible(this.duration, active, 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue