1
0
Fork 0

New attribute system for action points

This commit is contained in:
Michaël Lemaire 2015-01-19 01:00:00 +01:00 committed by Michaël Lemaire
parent fc5c8a7c55
commit be434b4eb4
10 changed files with 270 additions and 24 deletions

View 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;
}
}
}
}

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -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 {

View file

@ -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 {

View 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);
}
}
}

View 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);
}
}
}

View 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);
});
});
}

View file

@ -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");

View file

@ -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);
});