New attribute system for action points
This commit is contained in:
parent
fc5c8a7c55
commit
be434b4eb4
81
src/scripts/game/Attribute.ts
Normal file
81
src/scripts/game/Attribute.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Code to identify
|
||||
export enum AttributeCode {
|
||||
// Initiative level
|
||||
Initiative,
|
||||
|
||||
// Hull points (similar to health points in other games)
|
||||
Hull,
|
||||
|
||||
// Damage the shield can take
|
||||
Shield,
|
||||
|
||||
// Current level of action points
|
||||
AP,
|
||||
|
||||
// Action points recovered by turn
|
||||
AP_Recovery,
|
||||
|
||||
// Starting action points in a battle
|
||||
AP_Initial,
|
||||
|
||||
// Miscellaneous attribute
|
||||
Misc
|
||||
}
|
||||
|
||||
// Value computed from equipment
|
||||
// This value can be altered by effects
|
||||
// Example attributes are health points, action points recovery...
|
||||
export class Attribute {
|
||||
// Identifying code of this attribute
|
||||
code: AttributeCode;
|
||||
|
||||
// Maximal attribute value
|
||||
maximal: number;
|
||||
|
||||
// Current attribute value
|
||||
current: number;
|
||||
|
||||
// Create an attribute
|
||||
constructor(code: AttributeCode, maximal: number = 1, current: number = 0) {
|
||||
this.code = code;
|
||||
this.maximal = maximal;
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
// Set the maximal value
|
||||
setMaximal(value: number): void {
|
||||
this.maximal = value;
|
||||
}
|
||||
|
||||
// Set an absolute value
|
||||
// Returns true if the value changed
|
||||
set(value: number): boolean {
|
||||
var old_value = this.current;
|
||||
this.current = value;
|
||||
this.fix();
|
||||
return this.current !== old_value;
|
||||
}
|
||||
|
||||
// Add an offset to current value
|
||||
// Returns true if the value changed
|
||||
add(value: number): boolean {
|
||||
var old_value = this.current;
|
||||
this.current += value;
|
||||
this.fix();
|
||||
return this.current !== old_value;
|
||||
}
|
||||
|
||||
// Fix the value to remain lower than maximal, and positive
|
||||
private fix(): void {
|
||||
if (this.current > this.maximal) {
|
||||
this.current = this.maximal;
|
||||
}
|
||||
if (this.current < 0.0001) {
|
||||
this.current = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,6 +90,9 @@ module SpaceTac.Game {
|
|||
// This will call all necessary initialization steps (initiative, placement...)
|
||||
// This will not add any event to the battle log
|
||||
start(): void {
|
||||
this.fleets.forEach((fleet: Fleet) => {
|
||||
fleet.setBattle(this);
|
||||
});
|
||||
this.placeShips();
|
||||
this.throwInitiative();
|
||||
this.advanceToNextShip(false);
|
||||
|
|
|
@ -9,10 +9,14 @@ module SpaceTac.Game {
|
|||
// List of ships
|
||||
ships: Ship[];
|
||||
|
||||
// Current battle in which the fleet is engaged (null if not fighting)
|
||||
battle: Battle;
|
||||
|
||||
// Create a fleet, bound to a player
|
||||
constructor(player: Player) {
|
||||
this.player = player;
|
||||
this.ships = [];
|
||||
this.battle = null;
|
||||
}
|
||||
|
||||
// Add a ship in this fleet
|
||||
|
@ -20,5 +24,10 @@ module SpaceTac.Game {
|
|||
ship.fleet = this;
|
||||
this.ships.push(ship);
|
||||
}
|
||||
|
||||
// Set the current battle
|
||||
setBattle(battle: Battle): void {
|
||||
this.battle = battle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,13 +32,13 @@ module SpaceTac.Game {
|
|||
initative_throw: number;
|
||||
|
||||
// Current number of action points
|
||||
ap_current: number;
|
||||
ap_current: Attribute;
|
||||
|
||||
// Maximal number of action points
|
||||
ap_maximal: number;
|
||||
// Initial number of action points, at the start of a battle
|
||||
ap_initial: Attribute;
|
||||
|
||||
// Number of action points recovered by turn
|
||||
ap_recover: number;
|
||||
ap_recover: Attribute;
|
||||
|
||||
// Number of action points used to make a 1.0 move
|
||||
movement_cost: number;
|
||||
|
@ -51,9 +51,9 @@ module SpaceTac.Game {
|
|||
this.fleet = fleet;
|
||||
this.name = name;
|
||||
this.initiative_level = 1;
|
||||
this.ap_current = 10;
|
||||
this.ap_maximal = 20;
|
||||
this.ap_recover = 5;
|
||||
this.ap_current = new Attribute(AttributeCode.AP);
|
||||
this.ap_initial = new Attribute(AttributeCode.AP_Initial);
|
||||
this.ap_recover = new Attribute(AttributeCode.AP_Recovery);
|
||||
this.movement_cost = 0.1;
|
||||
this.slots = [];
|
||||
|
||||
|
@ -86,7 +86,20 @@ module SpaceTac.Game {
|
|||
|
||||
// Return the player owning this ship
|
||||
getPlayer(): Player {
|
||||
return this.fleet.player;
|
||||
if (this.fleet) {
|
||||
return this.fleet.player;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// get the current battle this ship is engaged in
|
||||
getBattle(): Battle {
|
||||
if (this.fleet) {
|
||||
return this.fleet.battle;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of actions available
|
||||
|
@ -105,13 +118,61 @@ module SpaceTac.Game {
|
|||
return actions;
|
||||
}
|
||||
|
||||
// Consumes action points
|
||||
useActionPoints(ap: number): void {
|
||||
this.ap_current -= ap;
|
||||
// Set an attribute value
|
||||
// If offset is true, the value will be added to current value
|
||||
// If log is true, an attribute event will be added to the battle log
|
||||
setAttribute(attr: Attribute, value: number, offset: boolean = false, log: boolean = true) {
|
||||
var changed: boolean;
|
||||
|
||||
if (this.ap_current <= 0.001) {
|
||||
this.ap_current = 0;
|
||||
if (offset) {
|
||||
changed = attr.add(value);
|
||||
} else {
|
||||
changed = attr.set(value);
|
||||
}
|
||||
|
||||
if (changed && log) {
|
||||
var battle = this.getBattle();
|
||||
if (battle) {
|
||||
battle.log.add(new AttributeChangeEvent(this, attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the action points counter
|
||||
// This should be called once at the start of a battle
|
||||
// If no value is provided, the attribute ap_initial will be used
|
||||
initializeActionPoints(value: number = null): void {
|
||||
if (value === null) {
|
||||
value = this.ap_initial.current;
|
||||
}
|
||||
this.setAttribute(this.ap_current, value);
|
||||
}
|
||||
|
||||
// Recover action points
|
||||
// This should be called once at the start of a turn
|
||||
// If no value is provided, the current attribute ap_recovery will be used
|
||||
recoverActionPoints(value: number = null): void {
|
||||
if (value === null) {
|
||||
value = this.ap_recover.current;
|
||||
}
|
||||
this.setAttribute(this.ap_current, value, true);
|
||||
}
|
||||
|
||||
// Consumes action points
|
||||
useActionPoints(value: number): void {
|
||||
this.setAttribute(this.ap_current, -value, true);
|
||||
}
|
||||
|
||||
// Method called at the start of this ship turn
|
||||
startTurn(first: boolean): void {
|
||||
// Manage action points
|
||||
if (first) {
|
||||
this.initializeActionPoints();
|
||||
} else {
|
||||
this.recoverActionPoints();
|
||||
}
|
||||
|
||||
// TODO Apply active effects
|
||||
}
|
||||
|
||||
// Get the maximal position reachable in the arena with current action points
|
||||
|
@ -119,7 +180,7 @@ module SpaceTac.Game {
|
|||
var dx = x - this.arena_x;
|
||||
var dy = y - this.arena_y;
|
||||
var length = Math.sqrt(dx * dx + dy * dy);
|
||||
var max_length = this.ap_current / this.movement_cost;
|
||||
var max_length = this.ap_current.current / this.movement_cost;
|
||||
if (max_length >= length) {
|
||||
return [x, y];
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ module SpaceTac.Game {
|
|||
}
|
||||
|
||||
canBeUsed(battle: Battle, ship: Ship): boolean {
|
||||
return ship.ap_current > 0;
|
||||
return ship.ap_current.current > 0;
|
||||
}
|
||||
|
||||
checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target {
|
||||
|
|
13
src/scripts/game/equipments/BasicPowerCore.ts
Normal file
13
src/scripts/game/equipments/BasicPowerCore.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module SpaceTac.Game.Equipments {
|
||||
"use strict";
|
||||
|
||||
export class BasicPowerCore extends LootTemplate {
|
||||
constructor() {
|
||||
super(SlotType.Power, "Basic Power Core");
|
||||
|
||||
this.min_level = new IntegerRange(1, 1);
|
||||
}
|
||||
}
|
||||
}
|
12
src/scripts/game/events/AttributeChangeEvent.ts
Normal file
12
src/scripts/game/events/AttributeChangeEvent.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Event logged when a ship moves
|
||||
export class AttributeChangeEvent extends BaseLogEvent {
|
||||
constructor(ship: Ship, attribute: Attribute) {
|
||||
super("attr", ship);
|
||||
}
|
||||
}
|
||||
}
|
63
src/scripts/game/specs/Attribute.spec.ts
Normal file
63
src/scripts/game/specs/Attribute.spec.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
/// <reference path="../../definitions/jasmine.d.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
describe("Attribute", function () {
|
||||
it("applies minimal and maximal value", function () {
|
||||
var attr = new Attribute(AttributeCode.Misc, 100, 50);
|
||||
expect(attr.current).toBe(50);
|
||||
|
||||
attr.add(8);
|
||||
expect(attr.current).toBe(58);
|
||||
|
||||
attr.add(60);
|
||||
expect(attr.current).toBe(100);
|
||||
|
||||
attr.add(-72);
|
||||
expect(attr.current).toBe(28);
|
||||
|
||||
attr.add(-60);
|
||||
expect(attr.current).toBe(0);
|
||||
|
||||
attr.set(8);
|
||||
expect(attr.current).toBe(8);
|
||||
|
||||
attr.set(-4);
|
||||
expect(attr.current).toBe(0);
|
||||
|
||||
attr.set(105);
|
||||
expect(attr.current).toBe(100);
|
||||
});
|
||||
|
||||
it("tells if value changed", function () {
|
||||
var result: boolean;
|
||||
var attr = new Attribute(AttributeCode.Misc, 100, 50);
|
||||
expect(attr.current).toBe(50);
|
||||
|
||||
result = attr.set(51);
|
||||
expect(result).toBe(true);
|
||||
|
||||
result = attr.set(51);
|
||||
expect(result).toBe(false);
|
||||
|
||||
result = attr.add(1);
|
||||
expect(result).toBe(true);
|
||||
|
||||
result = attr.add(0);
|
||||
expect(result).toBe(false);
|
||||
|
||||
result = attr.add(1000);
|
||||
expect(result).toBe(true);
|
||||
|
||||
result = attr.add(2000);
|
||||
expect(result).toBe(false);
|
||||
|
||||
result = attr.set(-500);
|
||||
expect(result).toBe(true);
|
||||
|
||||
result = attr.add(-600);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -6,7 +6,8 @@ module SpaceTac.Game {
|
|||
describe("MoveAction", function () {
|
||||
it("checks movement against remaining AP", function () {
|
||||
var ship = new Ship(null, "Test");
|
||||
ship.ap_current = 6;
|
||||
ship.ap_current.setMaximal(20);
|
||||
ship.ap_current.set(6);
|
||||
ship.movement_cost = 2;
|
||||
ship.arena_x = 0;
|
||||
ship.arena_y = 0;
|
||||
|
@ -18,7 +19,7 @@ module SpaceTac.Game {
|
|||
result = action.checkTarget(null, ship, Target.newFromLocation(0, 8));
|
||||
expect(result).toEqual(Target.newFromLocation(0, 3));
|
||||
|
||||
ship.ap_current = 0;
|
||||
ship.ap_current.set(0);
|
||||
result = action.checkTarget(null, ship, Target.newFromLocation(0, 8));
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
@ -38,7 +39,8 @@ module SpaceTac.Game {
|
|||
it("applies to ship location, battle log and AP", function () {
|
||||
var battle = new Battle(null, null);
|
||||
var ship = new Ship(null, "Test");
|
||||
ship.ap_current = 5;
|
||||
ship.ap_current.setMaximal(20);
|
||||
ship.ap_current.set(5);
|
||||
ship.movement_cost = 1;
|
||||
ship.arena_x = 0;
|
||||
ship.arena_y = 0;
|
||||
|
@ -48,13 +50,13 @@ module SpaceTac.Game {
|
|||
expect(result).toBe(true);
|
||||
expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001);
|
||||
expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001);
|
||||
expect(ship.ap_current).toEqual(0);
|
||||
expect(ship.ap_current.current).toEqual(0);
|
||||
|
||||
result = action.apply(battle, ship, Target.newFromLocation(10, 10));
|
||||
expect(result).toBe(false);
|
||||
expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001);
|
||||
expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001);
|
||||
expect(ship.ap_current).toEqual(0);
|
||||
expect(ship.ap_current.current).toEqual(0);
|
||||
|
||||
expect(battle.log.events.length).toBe(1);
|
||||
expect(battle.log.events[0].code).toEqual("move");
|
||||
|
|
|
@ -6,7 +6,8 @@ module SpaceTac.Game {
|
|||
describe("Ship", function () {
|
||||
it("limits movement range by action points", function () {
|
||||
var ship = new Ship(null, "Test");
|
||||
ship.ap_current = 8;
|
||||
ship.ap_current.setMaximal(20);
|
||||
ship.ap_current.set(8);
|
||||
ship.movement_cost = 3;
|
||||
ship.setArenaPosition(50, 50);
|
||||
|
||||
|
@ -20,17 +21,18 @@ module SpaceTac.Game {
|
|||
|
||||
it("moves and consumes action points", function () {
|
||||
var ship = new Ship(null, "Test");
|
||||
ship.ap_current = 8;
|
||||
ship.ap_current.setMaximal(20);
|
||||
ship.ap_current.set(8);
|
||||
ship.movement_cost = 3;
|
||||
ship.setArenaPosition(50, 50);
|
||||
|
||||
ship.moveTo(51, 50);
|
||||
expect(ship.ap_current).toEqual(5);
|
||||
expect(ship.ap_current.current).toEqual(5);
|
||||
expect(ship.arena_x).toEqual(51);
|
||||
expect(ship.arena_y).toEqual(50);
|
||||
|
||||
ship.moveTo(53, 50);
|
||||
expect(ship.ap_current).toBe(0);
|
||||
expect(ship.ap_current.current).toBe(0);
|
||||
expect(ship.arena_x).toBeCloseTo(52.333333, 0.00001);
|
||||
expect(ship.arena_y).toEqual(50);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue