Added drone display
This commit is contained in:
parent
fbf3181920
commit
eb75658a10
44
README.md
44
README.md
|
@ -21,15 +21,40 @@ After making changes to sources, you need to recompile:
|
|||
|
||||
npm run build
|
||||
|
||||
## Attributes
|
||||
## Ships
|
||||
|
||||
### In-combat values (HSP)
|
||||
|
||||
In combat, a ship's vitals are represented by the HSP system (Hull-Shield-Power):
|
||||
|
||||
* **Initiative** - Ability to play before other ships in the play order
|
||||
* **Hull** - Amout of damage that a ship can receive before having to shut down all its systems
|
||||
* **Shield** - Amount of damage that the shield equipments may absorb to protect the Hull
|
||||
* **Power** - Available action points (some actions require more power than others)
|
||||
|
||||
These values will be changed by various effects (usage of equipments, sustained damage...).
|
||||
|
||||
### Attributes
|
||||
|
||||
Attributes represent a ship's ability to use its HSP system:
|
||||
|
||||
* **Initiative** - Ability to play before other ships in the play order
|
||||
* **Hull capacity** - Maximal Hull value (when the battle starts)
|
||||
* **Shield capacity** - Maximal Shield value (when the battle starts)
|
||||
* **Power capacity** - Maximal Power value
|
||||
* **Initial power** - Power immediately available at the start of battle
|
||||
* **Power recovery** - Power generated at the end of a ship's turn
|
||||
|
||||
## Skills
|
||||
These attributes are the sum of all currently applied effects (being permanent by an equipped item,
|
||||
or a temporary effect caused by a weapon or a drone).
|
||||
|
||||
For example, a ship that equips a power generator with "power recovery +3", but has a sticky effect
|
||||
of "power recovery -1" from a previous weapon hit, will have an effective power recovery of 2.
|
||||
|
||||
Attributes may also be upgraded permanently during level up.
|
||||
|
||||
### Skills
|
||||
|
||||
Skills represent a ship's ability to use equipments:
|
||||
|
||||
* **Materials** - Usage of physical materials such as bullets, shells...
|
||||
* **Electronics** - Components of computers and communication
|
||||
|
@ -38,6 +63,16 @@ After making changes to sources, you need to recompile:
|
|||
* **Gravity** - Interaction with gravitational forces
|
||||
* **Time** - Manipulation of time
|
||||
|
||||
Each equipment has minimal skill requirements to be used. For example, a weapon may require "materials >= 2"
|
||||
and "energy >= 3" to be equipped. A ship that does not meet these requirements will not be able to use
|
||||
the equipment.
|
||||
|
||||
As for attributes, skill values are controlled by equipments, effects and level up.
|
||||
|
||||
If an equipped item has a requirement of "time >= 2", that the ship has time skill of exactly 2, and that a
|
||||
temporary effect of "time -1" is active, the requirement is no longer fulfilled and the equipped item
|
||||
is then temporarily disabled (no more effects and cannot be used), until the "time -1" effect is lifted.
|
||||
|
||||
## Drones
|
||||
|
||||
Drones are static objects, deployed by ships, that apply effects in a circular zone around themselves.
|
||||
|
@ -50,6 +85,9 @@ Drone effects are applied :
|
|||
|
||||
Drones are fully autonomous, and once deployed, are not controlled by their owner ship.
|
||||
|
||||
They are small and cannot be the direct target of weapons. They are not affected by area effects,
|
||||
except for area damage and area effects specifically designed for drones.
|
||||
|
||||
A drone lasts for a given number of turns, counting down each time its owner's turn starts.
|
||||
When reaching the number of turns, the drone is destroyed (before the owner's turn is started).
|
||||
For example, a drone with 1-turn duration will destroy just before the next turn of its owner.
|
||||
|
|
8
TODO
8
TODO
|
@ -1,6 +1,10 @@
|
|||
* Restore serialization
|
||||
* Drones: add sprite, radius and tooltip
|
||||
* Drones: add tooltip
|
||||
* Drones: add hull points and take area damage
|
||||
* Organize arena objects and information in layers
|
||||
* Allow to cancel last moves
|
||||
* Add more visual effects to weapons, hits and explosions
|
||||
* Add keyboard shortcuts for actions
|
||||
* Effect should be random in a range (eg. "damage target 50-75")
|
||||
* Add an overload/cooling system
|
||||
* Add auto-move to attack
|
||||
|
@ -19,4 +23,4 @@
|
|||
* Add a victory screen, with loot display
|
||||
* Add retreat from battle
|
||||
* Map : restore ability to jump to other systems
|
||||
* Map : add stores
|
||||
* Map : add stores and shipyards
|
||||
|
|
|
@ -110,14 +110,18 @@ module TS.SpaceTac.Game {
|
|||
let [drone, effect] = newTestDrone(0, 0, 5, owner);
|
||||
drone.duration = 2;
|
||||
|
||||
let result = drone.onTurnStart(other);
|
||||
expect(result).toBe(true);
|
||||
result = drone.onTurnStart(owner);
|
||||
expect(result).toBe(true);
|
||||
result = drone.onTurnStart(other);
|
||||
expect(result).toBe(true);
|
||||
result = drone.onTurnStart(owner);
|
||||
expect(result).toBe(false);
|
||||
let battle = new Battle();
|
||||
spyOn(owner, "getBattle").and.returnValue(battle);
|
||||
let removeDrone = spyOn(battle, "removeDrone").and.callThrough();
|
||||
|
||||
drone.onTurnStart(other);
|
||||
expect(removeDrone).not.toHaveBeenCalled();
|
||||
drone.onTurnStart(owner);
|
||||
expect(removeDrone).not.toHaveBeenCalled();
|
||||
drone.onTurnStart(other);
|
||||
expect(removeDrone).not.toHaveBeenCalled();
|
||||
drone.onTurnStart(owner);
|
||||
expect(removeDrone).toHaveBeenCalledWith(drone);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ module TS.SpaceTac.Game {
|
|||
* Drones are static objects that apply effects in a circular zone around themselves.
|
||||
*/
|
||||
export class Drone {
|
||||
// Code of the drone
|
||||
code: string;
|
||||
|
||||
// Ship that deployed the drone
|
||||
owner: Ship;
|
||||
|
||||
|
@ -23,8 +26,9 @@ module TS.SpaceTac.Game {
|
|||
// Ships starting their turn the radius
|
||||
inside_at_start: Ship[] = [];
|
||||
|
||||
constructor(owner: Ship) {
|
||||
constructor(owner: Ship, code = "drone") {
|
||||
this.owner = owner;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,16 +60,20 @@ module TS.SpaceTac.Game {
|
|||
|
||||
/**
|
||||
* Called when a ship turn starts
|
||||
*
|
||||
* Returns false if the drone should be destroyed
|
||||
*/
|
||||
onTurnStart(ship: Ship): boolean {
|
||||
onTurnStart(ship: Ship) {
|
||||
if (ship == this.owner) {
|
||||
if (this.duration <= 1) {
|
||||
return false;
|
||||
} else {
|
||||
this.duration--;
|
||||
this.duration--;
|
||||
}
|
||||
|
||||
if (this.duration <= 0) {
|
||||
if (this.owner) {
|
||||
let battle = this.owner.getBattle();
|
||||
if (battle) {
|
||||
battle.removeDrone(this);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ship.isInCircle(this.x, this.y, this.radius)) {
|
||||
|
@ -74,14 +82,13 @@ module TS.SpaceTac.Game {
|
|||
} else {
|
||||
remove(this.inside_at_start, ship);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a ship turn ends
|
||||
*/
|
||||
onTurnEnd(ship: Ship) {
|
||||
if (ship.isInCircle(this.x, this.y, this.radius) && contains(this.inside_at_start, ship)) {
|
||||
if (this.duration > 0 && ship.isInCircle(this.x, this.y, this.radius) && contains(this.inside_at_start, ship)) {
|
||||
this.singleApply(ship);
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +97,7 @@ module TS.SpaceTac.Game {
|
|||
* Called after a ship moved
|
||||
*/
|
||||
onShipMove(ship: Ship) {
|
||||
if (ship.isInCircle(this.x, this.y, this.radius)) {
|
||||
if (this.duration > 0 && ship.isInCircle(this.x, this.y, this.radius)) {
|
||||
if (add(this.inside, ship)) {
|
||||
this.singleApply(ship);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ module TS.SpaceTac.Game {
|
|||
battle.playing_ship = ship;
|
||||
TestTools.setShipAP(ship, 3);
|
||||
let equipment = new Equipment();
|
||||
equipment.code = "testdrone";
|
||||
equipment.distance = 8;
|
||||
equipment.ap_usage = 2;
|
||||
equipment.duration = 2;
|
||||
|
@ -48,6 +49,7 @@ module TS.SpaceTac.Game {
|
|||
expect(battle.drones.length).toBe(1);
|
||||
|
||||
let drone = battle.drones[0];
|
||||
expect(drone.code).toEqual("testdrone");
|
||||
expect(drone.duration).toEqual(2);
|
||||
expect(drone.owner).toBe(ship);
|
||||
expect(drone.x).toEqual(5);
|
||||
|
|
|
@ -16,7 +16,7 @@ module TS.SpaceTac.Game {
|
|||
}
|
||||
|
||||
protected customApply(battle: Battle, ship: Ship, target: Target): boolean {
|
||||
let drone = new Drone(ship);
|
||||
let drone = new Drone(ship, this.equipment.code);
|
||||
drone.x = target.x;
|
||||
drone.y = target.y;
|
||||
drone.radius = this.equipment.blast;
|
||||
|
|
|
@ -15,6 +15,7 @@ module TS.SpaceTac.Game.Equipments {
|
|||
|
||||
expect(battle.drones.length).toBe(1);
|
||||
let drone = battle.drones[0];
|
||||
expect(drone.duration).toBe(1);
|
||||
ship.setAttribute("hull_capacity", 100);
|
||||
ship.setValue("hull", 85);
|
||||
drone.singleApply(ship);
|
||||
|
|
|
@ -10,6 +10,7 @@ module TS.SpaceTac.Game.Equipments {
|
|||
|
||||
this.min_level = new IntegerRange(1, 4);
|
||||
|
||||
this.setLifetime(1, 1);
|
||||
this.setDeployDistance(50, 100);
|
||||
this.setEffectRadius(40, 80);
|
||||
this.setPowerConsumption(4, 5);
|
||||
|
|
|
@ -15,7 +15,10 @@ module TS.SpaceTac.View {
|
|||
private battleview: BattleView;
|
||||
|
||||
// List of ship sprites
|
||||
private ship_sprites: ArenaShip[];
|
||||
private ship_sprites: ArenaShip[] = [];
|
||||
|
||||
// List of drone sprites
|
||||
private drone_sprites: ArenaDrone[] = [];
|
||||
|
||||
// Currently hovered ship
|
||||
private hovered: ArenaShip;
|
||||
|
@ -27,7 +30,6 @@ module TS.SpaceTac.View {
|
|||
super(battleview.game);
|
||||
|
||||
this.battleview = battleview;
|
||||
this.ship_sprites = [];
|
||||
this.playing = null;
|
||||
this.hovered = null;
|
||||
this.range_hint = null;
|
||||
|
@ -129,5 +131,30 @@ module TS.SpaceTac.View {
|
|||
|
||||
this.battleview.gameui.audio.playOnce("battle-ship-change");
|
||||
}
|
||||
|
||||
// Spawn a new drone
|
||||
addDrone(drone: Game.Drone): void {
|
||||
if (!any(this.drone_sprites, sprite => sprite.drone == drone)) {
|
||||
let sprite = new ArenaDrone(this.battleview, drone);
|
||||
this.addChild(sprite);
|
||||
this.drone_sprites.push(sprite);
|
||||
|
||||
sprite.position.set(drone.owner.arena_x, drone.owner.arena_y);
|
||||
this.game.tweens.create(sprite.position).to({ x: drone.x, y: drone.y }, 1800, Phaser.Easing.Sinusoidal.InOut, true, 200);
|
||||
} else {
|
||||
console.error("Drone added twice to arena", drone);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a destroyed drone
|
||||
removeDrone(drone: Game.Drone): void {
|
||||
let sprite = first(this.drone_sprites, sprite => sprite.drone == drone);
|
||||
if (sprite) {
|
||||
remove(this.drone_sprites, sprite);
|
||||
sprite.destroy();
|
||||
} else {
|
||||
console.error("Drone not found in arena for removal", drone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
33
src/view/battle/ArenaDrone.ts
Normal file
33
src/view/battle/ArenaDrone.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
module TS.SpaceTac.View {
|
||||
/**
|
||||
* Drone sprite in the arena
|
||||
*/
|
||||
export class ArenaDrone extends Phaser.Group {
|
||||
// Link to displayed drone
|
||||
drone: Game.Drone;
|
||||
|
||||
// Sprite
|
||||
sprite: Phaser.Button;
|
||||
|
||||
// Radius
|
||||
radius: Phaser.Graphics;
|
||||
|
||||
constructor(battleview: BattleView, drone: Game.Drone) {
|
||||
super(battleview.game);
|
||||
|
||||
this.drone = drone;
|
||||
|
||||
this.radius = new Phaser.Graphics(this.game, 0, 0);
|
||||
this.radius.lineStyle(3, 0xe9f2f9, 0.5);
|
||||
this.radius.beginFill(0xe9f2f9, 0.0);
|
||||
this.radius.drawCircle(0, 0, drone.radius * 2);
|
||||
this.radius.endFill();
|
||||
this.addChild(this.radius);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,33 +30,26 @@ module TS.SpaceTac.View {
|
|||
processBattleEvent(event: Game.BaseLogEvent) {
|
||||
console.log("Battle event", event);
|
||||
|
||||
switch (event.code) {
|
||||
case "ship_change":
|
||||
this.processShipChangeEvent(<Game.ShipChangeEvent>event);
|
||||
break;
|
||||
case "damage":
|
||||
this.processDamageEvent(<Game.DamageEvent>event);
|
||||
break;
|
||||
case "move":
|
||||
this.processMoveEvent(<Game.MoveEvent>event);
|
||||
break;
|
||||
case "value":
|
||||
this.processValueChangedEvent(<Game.ValueChangeEvent>event);
|
||||
break;
|
||||
case "death":
|
||||
this.processDeathEvent(<Game.DeathEvent>event);
|
||||
break;
|
||||
case "fire":
|
||||
this.processFireEvent(<Game.FireEvent>event);
|
||||
break;
|
||||
case "endbattle":
|
||||
this.processEndBattleEvent(<Game.EndBattleEvent>event);
|
||||
break;
|
||||
case "effectadd":
|
||||
case "effectduration":
|
||||
case "effectdel":
|
||||
this.processEffectEvent(event);
|
||||
break;
|
||||
if (event instanceof Game.ShipChangeEvent) {
|
||||
this.processShipChangeEvent(event);
|
||||
} else if (event instanceof Game.MoveEvent) {
|
||||
this.processMoveEvent(event);
|
||||
} else if (event instanceof Game.ValueChangeEvent) {
|
||||
this.processValueChangedEvent(event);
|
||||
} else if (event instanceof Game.DeathEvent) {
|
||||
this.processDeathEvent(event);
|
||||
} else if (event instanceof Game.FireEvent) {
|
||||
this.processFireEvent(event);
|
||||
} else if (event instanceof Game.DamageEvent) {
|
||||
this.processDamageEvent(event);
|
||||
} else if (event instanceof Game.EndBattleEvent) {
|
||||
this.processEndBattleEvent(event);
|
||||
} else if (event instanceof Game.DroneDeployedEvent) {
|
||||
this.processDroneDeployedEvent(event);
|
||||
} else if (event instanceof Game.DroneDestroyedEvent) {
|
||||
this.processDroneDestroyedEvent(event);
|
||||
} else if (event.code == "effectadd" || event.code == "effectduration" || event.code == "effectdel") {
|
||||
this.processEffectEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,5 +143,15 @@ module TS.SpaceTac.View {
|
|||
item.updateEffects();
|
||||
}
|
||||
}
|
||||
|
||||
// New drone deployed
|
||||
private processDroneDeployedEvent(event: Game.DroneDeployedEvent): void {
|
||||
this.view.arena.addDrone(event.drone);
|
||||
}
|
||||
|
||||
// Drone destroyed
|
||||
private processDroneDestroyedEvent(event: Game.DroneDestroyedEvent): void {
|
||||
this.view.arena.removeDrone(event.drone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue