From ef1f0914b8a410a71bd15f88b1395f566ce4d1fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Wed, 28 Jan 2015 01:00:00 +0100 Subject: [PATCH] Added hull and shield attributes, and weapon damage on them --- src/scripts/game/Ship.ts | 25 +++-- src/scripts/game/Tools.ts | 2 +- src/scripts/game/actions/FireWeaponAction.ts | 6 ++ src/scripts/game/effects/DamageEffect.ts | 19 +++- .../game/equipments/BasicForceField.ts | 15 +++ src/scripts/game/equipments/IronHull.ts | 15 +++ src/scripts/game/specs/AbstractWeapon.spec.ts | 101 ++++++++++++++++++ src/scripts/game/specs/Ship.spec.ts | 15 +++ 8 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 src/scripts/game/equipments/BasicForceField.ts create mode 100644 src/scripts/game/equipments/IronHull.ts diff --git a/src/scripts/game/Ship.ts b/src/scripts/game/Ship.ts index eec18fc..d516588 100644 --- a/src/scripts/game/Ship.ts +++ b/src/scripts/game/Ship.ts @@ -12,12 +12,6 @@ module SpaceTac.Game { // Current level level: number; - // Number of shield points - shield: number; - - // Number of hull points - hull: number; - // Position in the arena arena_x: number; arena_y: number; @@ -37,6 +31,12 @@ module SpaceTac.Game { // Number of action points recovered by turn ap_recover: Attribute; + // Number of hull points (once it reaches 0, the ship is dead) + hull: Attribute; + + // Number of shield points (a shield wan absorb some damage to protect the hull) + shield: Attribute; + // Number of action points used to make a 1.0 move movement_cost: number; @@ -56,9 +56,14 @@ module SpaceTac.Game { this.ap_current = this.newAttribute(AttributeCode.AP); this.ap_initial = this.newAttribute(AttributeCode.AP_Initial); this.ap_recover = this.newAttribute(AttributeCode.AP_Recovery); + this.hull = this.newAttribute(AttributeCode.Hull); + this.shield = this.newAttribute(AttributeCode.Shield); this.movement_cost = 0.1; this.slots = []; + this.arena_x = 0; + this.arena_y = 0; + if (fleet) { fleet.addShip(this); } @@ -229,6 +234,8 @@ module SpaceTac.Game { }); this.initiative.setMaximal(new_attrs.getValue(AttributeCode.Initiative)); this.ap_current.setMaximal(new_attrs.getValue(AttributeCode.AP)); + this.hull.setMaximal(new_attrs.getValue(AttributeCode.Hull)); + this.shield.setMaximal(new_attrs.getValue(AttributeCode.Shield)); // Compute new current values for attributes new_attrs = new AttributeCollection(); @@ -239,6 +246,12 @@ module SpaceTac.Game { this.ap_recover.set(new_attrs.getValue(AttributeCode.AP_Recovery)); } + // Fully restore hull and shield + restoreHealth(): void { + this.hull.set(this.hull.maximal); + this.shield.set(this.shield.maximal); + } + // Collect all effects to apply for updateAttributes private collectEffects(code: string = null): BaseEffect[] { var result: BaseEffect[] = []; diff --git a/src/scripts/game/Tools.ts b/src/scripts/game/Tools.ts index 539bee5..2581bff 100644 --- a/src/scripts/game/Tools.ts +++ b/src/scripts/game/Tools.ts @@ -6,7 +6,7 @@ module SpaceTac.Game { // Copy an object (only a shallow copy of immediate properties) static copyObject (object: T): T { - var objectCopy = {}; + var objectCopy = Object.create(object.constructor.prototype); for (var key in object) { if (object.hasOwnProperty(key)) { diff --git a/src/scripts/game/actions/FireWeaponAction.ts b/src/scripts/game/actions/FireWeaponAction.ts index ec3cab1..ffaeff0 100644 --- a/src/scripts/game/actions/FireWeaponAction.ts +++ b/src/scripts/game/actions/FireWeaponAction.ts @@ -49,6 +49,12 @@ module SpaceTac.Game { var eff_result = effect.applyOnShip(target.ship); result = result || eff_result; }); + + // Consume AP + if (result) { + ship.useActionPoints(this.equipment.ap_usage); + } + return result; } else { // TODO target in space (=> apply blast radius) diff --git a/src/scripts/game/effects/DamageEffect.ts b/src/scripts/game/effects/DamageEffect.ts index c4e5444..33264e0 100644 --- a/src/scripts/game/effects/DamageEffect.ts +++ b/src/scripts/game/effects/DamageEffect.ts @@ -15,7 +15,24 @@ module SpaceTac.Game { } applyOnShip(ship: Ship): boolean { - // TODO + var damage = this.value; + + // Apply on shields + var absorbed = ship.shield.current; + if (damage >= ship.shield.current) { + ship.setAttribute(ship.shield, 0); + } else { + ship.setAttribute(ship.shield, -damage, true); + } + damage -= absorbed; + + // Apply on hull + if (damage >= ship.hull.current) { + ship.setAttribute(ship.hull, 0); + } else { + ship.setAttribute(ship.hull, -damage, true); + } + return true; } } diff --git a/src/scripts/game/equipments/BasicForceField.ts b/src/scripts/game/equipments/BasicForceField.ts new file mode 100644 index 0000000..b57ce17 --- /dev/null +++ b/src/scripts/game/equipments/BasicForceField.ts @@ -0,0 +1,15 @@ +/// + +module SpaceTac.Game.Equipments { + "use strict"; + + export class BasicForceField extends LootTemplate { + constructor() { + super(SlotType.Shield, "BasicForceField"); + + this.min_level = new IntegerRange(1, 3); + + this.addPermanentAttributeMaxEffect(AttributeCode.Shield, 100, 200); + } + } +} diff --git a/src/scripts/game/equipments/IronHull.ts b/src/scripts/game/equipments/IronHull.ts new file mode 100644 index 0000000..54aecf3 --- /dev/null +++ b/src/scripts/game/equipments/IronHull.ts @@ -0,0 +1,15 @@ +/// + +module SpaceTac.Game.Equipments { + "use strict"; + + export class IronHull extends LootTemplate { + constructor() { + super(SlotType.Armor, "IronHull"); + + this.min_level = new IntegerRange(1, 3); + + this.addPermanentAttributeMaxEffect(AttributeCode.Hull, 100, 200); + } + } +} diff --git a/src/scripts/game/specs/AbstractWeapon.spec.ts b/src/scripts/game/specs/AbstractWeapon.spec.ts index e454beb..886255d 100644 --- a/src/scripts/game/specs/AbstractWeapon.spec.ts +++ b/src/scripts/game/specs/AbstractWeapon.spec.ts @@ -18,5 +18,106 @@ module SpaceTac.Game.Specs { expect(action.code).toEqual("fire"); expect(action.needs_target).toBe(true); }); + + it("controls ability to target emptiness", function () { + var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50, 60); + weapon.setRange(10, 20, true); + + var equipment = weapon.generateFixed(20); + var action = equipment.action; + expect(action.can_target_space).toBe(true); + + weapon.setRange(10, 20, false); + + equipment = weapon.generateFixed(20); + action = equipment.action; + expect(action.can_target_space).toBe(false); + }); + + it("can't friendly fire", function () { + var fleet1 = new Fleet(new Player()); + var fleet2 = new Fleet(new Player()); + var ship1a = new Ship(fleet1); + var ship1b = new Ship(fleet1); + var ship2a = new Ship(fleet2); + + var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50, 60); + weapon.setRange(10, 10); + var equipment = weapon.generateFixed(0); + + expect(equipment.action.checkShipTarget(null, ship1a, Target.newFromShip(ship2a))).toEqual( + Target.newFromShip(ship2a)); + expect(equipment.action.checkShipTarget(null, ship1a, Target.newFromShip(ship1b))).toBeNull(); + }); + + it("can't fire farther than its range", function () { + var fleet1 = new Fleet(new Player()); + var fleet2 = new Fleet(new Player()); + + var ship = new Ship(fleet1); + ship.setArenaPosition(10, 10); + + var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50); + weapon.setRange(10, 10, true); + + var equipment = weapon.generateFixed(0); + expect(equipment.distance).toEqual(10); + + expect(equipment.action.checkLocationTarget(null, ship, Target.newFromLocation(15, 10))).toEqual( + Target.newFromLocation(15, 10)); + expect(equipment.action.checkLocationTarget(null, ship, Target.newFromLocation(30, 10))).toEqual( + Target.newFromLocation(20, 10)); + + // Ship targetting + var ship2 = new Ship(fleet2); + + ship2.setArenaPosition(10, 15); + expect(equipment.action.checkShipTarget(null, ship, Target.newFromShip(ship2))).toEqual( + Target.newFromShip(ship2)); + + ship2.setArenaPosition(10, 25); + expect(equipment.action.checkShipTarget(null, ship, Target.newFromShip(ship2))).toBeNull(); + + // Forbid targetting in space + weapon.setRange(10, 10, false); + equipment = weapon.generateFixed(0); + expect(equipment.action.checkLocationTarget(null, ship, Target.newFromLocation(15, 10))).toBeNull(); + }); + + it("can target an enemy ship and damage it", function () { + var fleet1 = new Fleet(new Player()); + var fleet2 = new Fleet(new Player()); + + var ship1 = new Ship(fleet1); + ship1.ap_current.set(50); + + var ship2 = new Ship(fleet2); + ship2.hull.setMaximal(100); + ship2.shield.setMaximal(30); + ship2.restoreHealth(); + + expect(ship2.hull.current).toEqual(100); + expect(ship2.shield.current).toEqual(30); + + var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 20); + weapon.ap_usage = new IntegerRange(1, 1); + + var equipment = weapon.generateFixed(0); + + equipment.action.apply(null, ship1, Target.newFromShip(ship2)); + expect(ship2.hull.current).toEqual(100); + expect(ship2.shield.current).toEqual(10); + expect(ship1.ap_current.current).toEqual(49); + + equipment.action.apply(null, ship1, Target.newFromShip(ship2)); + expect(ship2.hull.current).toEqual(90); + expect(ship2.shield.current).toEqual(0); + expect(ship1.ap_current.current).toEqual(48); + + equipment.action.apply(null, ship1, Target.newFromShip(ship2)); + expect(ship2.hull.current).toEqual(70); + expect(ship2.shield.current).toEqual(0); + expect(ship1.ap_current.current).toEqual(47); + }); }); } diff --git a/src/scripts/game/specs/Ship.spec.ts b/src/scripts/game/specs/Ship.spec.ts index 1eb0ef4..180638b 100644 --- a/src/scripts/game/specs/Ship.spec.ts +++ b/src/scripts/game/specs/Ship.spec.ts @@ -103,5 +103,20 @@ module SpaceTac.Game { ship.updateAttributes(); expect(ship.ap_current.maximal).toBe(9); }); + + it("repairs hull and recharges shield", function () { + var ship = new Ship(null, "Test"); + + ship.hull.setMaximal(120); + ship.shield.setMaximal(150); + + expect(ship.hull.current).toEqual(0); + expect(ship.shield.current).toEqual(0); + + ship.restoreHealth(); + + expect(ship.hull.current).toEqual(120); + expect(ship.shield.current).toEqual(150); + }); }); }