Refactoring of attributes/values system
This commit is contained in:
parent
fcb45346e4
commit
8e43116a1f
5
TODO
5
TODO
|
@ -1,8 +1,7 @@
|
||||||
* Restore serialization
|
* Restore serialization
|
||||||
* Refactor attribute effects (add/sub, value/max, temporary/permanent)
|
* Drones: add hooks on game events
|
||||||
* Drones: add hooks on events
|
|
||||||
* Drones: add sprite, radius and tooltip
|
* Drones: add sprite, radius and tooltip
|
||||||
* Repair drone: add graphics
|
* Repair drone: add graphics and proper description
|
||||||
* Allow to cancel last moves
|
* Allow to cancel last moves
|
||||||
* Effect should be random in a range (eg. "damage target 50-75")
|
* Effect should be random in a range (eg. "damage target 50-75")
|
||||||
* Add an overload/cooling system
|
* Add an overload/cooling system
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
describe("Attribute", function () {
|
|
||||||
it("is initially not limited", function () {
|
|
||||||
var attr = new Attribute();
|
|
||||||
|
|
||||||
attr.set(8888888);
|
|
||||||
expect(attr.current).toBe(8888888);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("enumerates codes", function () {
|
|
||||||
var result = [];
|
|
||||||
Attribute.forEachCode((code: AttributeCode) => {
|
|
||||||
result.push(code);
|
|
||||||
});
|
|
||||||
expect(result).toEqual([
|
|
||||||
AttributeCode.Initiative,
|
|
||||||
AttributeCode.Hull,
|
|
||||||
AttributeCode.Shield,
|
|
||||||
AttributeCode.Power,
|
|
||||||
AttributeCode.Power_Recovery,
|
|
||||||
AttributeCode.Power_Initial,
|
|
||||||
AttributeCode.Cap_Material,
|
|
||||||
AttributeCode.Cap_Energy,
|
|
||||||
AttributeCode.Cap_Electronics,
|
|
||||||
AttributeCode.Cap_Human,
|
|
||||||
AttributeCode.Cap_Time,
|
|
||||||
AttributeCode.Cap_Gravity,
|
|
||||||
AttributeCode.Misc
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("gets human readable name", function () {
|
|
||||||
expect(ATTRIBUTE_NAMES[AttributeCode.Initiative]).toEqual("initiative");
|
|
||||||
expect(ATTRIBUTE_NAMES[AttributeCode.Power]).toEqual("power");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("applies minimal and maximal value", function () {
|
|
||||||
var attr = new Attribute(AttributeCode.Misc, 50, 100);
|
|
||||||
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);
|
|
||||||
|
|
||||||
attr.setMaximal(50);
|
|
||||||
expect(attr.current).toBe(50);
|
|
||||||
|
|
||||||
attr.setMaximal(80);
|
|
||||||
expect(attr.current).toBe(50);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("tells if value changed", function () {
|
|
||||||
var result: boolean;
|
|
||||||
var attr = new Attribute(AttributeCode.Misc, 50, 100);
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
// Code to identify
|
|
||||||
export enum AttributeCode {
|
|
||||||
// Initiative level
|
|
||||||
Initiative,
|
|
||||||
|
|
||||||
// Hull points (similar to health points or HP in other games)
|
|
||||||
Hull,
|
|
||||||
|
|
||||||
// Damage the shield can take
|
|
||||||
Shield,
|
|
||||||
|
|
||||||
// Power available to make actions (similar to action points or AP in other games)
|
|
||||||
Power,
|
|
||||||
|
|
||||||
// Power recovered each turn
|
|
||||||
Power_Recovery,
|
|
||||||
|
|
||||||
// Starting power in a battle
|
|
||||||
Power_Initial,
|
|
||||||
|
|
||||||
// Capability level in materials
|
|
||||||
Cap_Material,
|
|
||||||
|
|
||||||
// Capability level in energy
|
|
||||||
Cap_Energy,
|
|
||||||
|
|
||||||
// Capability level in electronics
|
|
||||||
Cap_Electronics,
|
|
||||||
|
|
||||||
// Capability level in human things
|
|
||||||
Cap_Human,
|
|
||||||
|
|
||||||
// Capability level in time manipulation
|
|
||||||
Cap_Time,
|
|
||||||
|
|
||||||
// Capability level in gravity manipulation
|
|
||||||
Cap_Gravity,
|
|
||||||
|
|
||||||
// Miscellaneous attribute
|
|
||||||
Misc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name mapping for attributes
|
|
||||||
export const ATTRIBUTE_NAMES = [
|
|
||||||
"initiative",
|
|
||||||
"hull",
|
|
||||||
"shield",
|
|
||||||
"power",
|
|
||||||
"power recovery",
|
|
||||||
"initial power",
|
|
||||||
"materials",
|
|
||||||
"energy",
|
|
||||||
"electronics",
|
|
||||||
"human",
|
|
||||||
"time",
|
|
||||||
"gravity"
|
|
||||||
]
|
|
||||||
|
|
||||||
// Value computed from equipment
|
|
||||||
// This value can be altered by effects
|
|
||||||
// Example attributes are health points, power 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 = AttributeCode.Misc, current: number = 0, maximal: number = null) {
|
|
||||||
this.code = code;
|
|
||||||
this.maximal = maximal;
|
|
||||||
this.current = current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterator over each code
|
|
||||||
static forEachCode(callback: (code: AttributeCode) => void) {
|
|
||||||
for (var val in AttributeCode) {
|
|
||||||
var parsed = parseInt(val, 10);
|
|
||||||
if (!isNaN(parsed)) {
|
|
||||||
callback(<AttributeCode>parsed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the maximal value
|
|
||||||
setMaximal(value: number): void {
|
|
||||||
this.maximal = value;
|
|
||||||
this.fix();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 be integer, positive and lower than maximal
|
|
||||||
private fix(): void {
|
|
||||||
if (this.maximal !== null && this.current > this.maximal) {
|
|
||||||
this.current = this.maximal;
|
|
||||||
}
|
|
||||||
if (this.current < 0) {
|
|
||||||
this.current = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
describe("AttributeCollection", function () {
|
|
||||||
it("sets and gets an attribute value", function () {
|
|
||||||
var coll = new AttributeCollection();
|
|
||||||
|
|
||||||
coll.setValue(AttributeCode.Initiative, 5);
|
|
||||||
expect(coll.getValue(AttributeCode.Initiative)).toBe(5);
|
|
||||||
|
|
||||||
expect(coll.getValue(AttributeCode.Hull)).toBe(0);
|
|
||||||
coll.setValue(AttributeCode.Hull, 2);
|
|
||||||
expect(coll.getValue(AttributeCode.Hull)).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets and gets an attribute maximal", function () {
|
|
||||||
var coll = new AttributeCollection();
|
|
||||||
|
|
||||||
coll.setMaximum(AttributeCode.Initiative, 5);
|
|
||||||
expect(coll.getMaximum(AttributeCode.Initiative)).toBe(5);
|
|
||||||
|
|
||||||
expect(coll.getMaximum(AttributeCode.Hull)).toBe(null);
|
|
||||||
coll.setMaximum(AttributeCode.Hull, 2);
|
|
||||||
expect(coll.getMaximum(AttributeCode.Hull)).toBe(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
// Collection of several attributes
|
|
||||||
export class AttributeCollection {
|
|
||||||
// Attributes
|
|
||||||
private attributes: Attribute[];
|
|
||||||
|
|
||||||
// Base constructor
|
|
||||||
constructor() {
|
|
||||||
this.attributes = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get or create an attribute by its code
|
|
||||||
getRawAttr(code: AttributeCode): Attribute {
|
|
||||||
var attr = this.attributes[code];
|
|
||||||
if (!attr) {
|
|
||||||
attr = new Attribute(code);
|
|
||||||
this.attributes[code] = attr;
|
|
||||||
}
|
|
||||||
return attr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an attribute value
|
|
||||||
getValue(attrcode: AttributeCode): number {
|
|
||||||
var attr = this.getRawAttr(attrcode);
|
|
||||||
return attr.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set an attribute value
|
|
||||||
setValue(attrcode: AttributeCode, value: number): number {
|
|
||||||
var attr = this.getRawAttr(attrcode);
|
|
||||||
attr.set(value);
|
|
||||||
return attr.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an offset to an attribute value
|
|
||||||
addValue(attrcode: AttributeCode, offset: number): number {
|
|
||||||
var attr = this.getRawAttr(attrcode);
|
|
||||||
attr.add(offset);
|
|
||||||
return attr.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an attribute maximum
|
|
||||||
getMaximum(attrcode: AttributeCode): number {
|
|
||||||
var attr = this.getRawAttr(attrcode);
|
|
||||||
return attr.maximal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set an attribute maximum
|
|
||||||
setMaximum(attrcode: AttributeCode, value: number): number {
|
|
||||||
var attr = this.getRawAttr(attrcode);
|
|
||||||
attr.setMaximal(value);
|
|
||||||
return attr.maximal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,15 +5,15 @@ module TS.SpaceTac.Game {
|
||||||
var fleet2 = new Fleet(null);
|
var fleet2 = new Fleet(null);
|
||||||
|
|
||||||
var ship1 = new Ship(fleet1, "F1S1");
|
var ship1 = new Ship(fleet1, "F1S1");
|
||||||
ship1.initiative.setMaximal(2);
|
ship1.setAttribute("initiative", 2);
|
||||||
var ship2 = new Ship(fleet1, "F1S2");
|
var ship2 = new Ship(fleet1, "F1S2");
|
||||||
ship2.initiative.setMaximal(4);
|
ship2.setAttribute("initiative", 4);
|
||||||
var ship3 = new Ship(fleet1, "F1S3");
|
var ship3 = new Ship(fleet1, "F1S3");
|
||||||
ship3.initiative.setMaximal(1);
|
ship3.setAttribute("initiative", 1);
|
||||||
var ship4 = new Ship(fleet2, "F2S1");
|
var ship4 = new Ship(fleet2, "F2S1");
|
||||||
ship4.initiative.setMaximal(8);
|
ship4.setAttribute("initiative", 8);
|
||||||
var ship5 = new Ship(fleet2, "F2S2");
|
var ship5 = new Ship(fleet2, "F2S2");
|
||||||
ship5.initiative.setMaximal(2);
|
ship5.setAttribute("initiative", 2);
|
||||||
|
|
||||||
var battle = new Battle(fleet1, fleet2);
|
var battle = new Battle(fleet1, fleet2);
|
||||||
expect(battle.play_order.length).toBe(0);
|
expect(battle.play_order.length).toBe(0);
|
||||||
|
|
|
@ -84,7 +84,7 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
// Sort by throw result
|
// Sort by throw result
|
||||||
play_order.sort(function (ship1: Ship, ship2: Ship) {
|
play_order.sort(function (ship1: Ship, ship2: Ship) {
|
||||||
return (ship2.initiative.current - ship1.initiative.current);
|
return (ship2.play_priority - ship1.play_priority);
|
||||||
});
|
});
|
||||||
this.play_order = play_order;
|
this.play_order = play_order;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ module TS.SpaceTac.Game {
|
||||||
it("logs ship change events", function () {
|
it("logs ship change events", function () {
|
||||||
var battle = Battle.newQuickRandom();
|
var battle = Battle.newQuickRandom();
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
battle.log.addFilter("attr");
|
battle.log.addFilter("value");
|
||||||
expect(battle.log.events.length).toBe(0);
|
expect(battle.log.events.length).toBe(0);
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
@ -70,7 +70,7 @@ module TS.SpaceTac.Game {
|
||||||
it("can receive simulated initial state events", function () {
|
it("can receive simulated initial state events", function () {
|
||||||
var battle = Battle.newQuickRandom();
|
var battle = Battle.newQuickRandom();
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
battle.log.addFilter("attr");
|
battle.log.addFilter("value");
|
||||||
expect(battle.log.events.length).toBe(0);
|
expect(battle.log.events.length).toBe(0);
|
||||||
|
|
||||||
battle.injectInitialEvents();
|
battle.injectInitialEvents();
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
module TS.SpaceTac.Game.Specs {
|
module TS.SpaceTac.Game.Specs {
|
||||||
describe("EffectTemplate", () => {
|
describe("EffectTemplate", () => {
|
||||||
it("interpolates between weak and strong effects", () => {
|
it("interpolates between weak and strong effects", () => {
|
||||||
var base_effect = new AttributeMaxEffect(AttributeCode.Hull, 6);
|
var base_effect = new AttributeEffect("hull_capacity", 6);
|
||||||
var template = new EffectTemplate(base_effect);
|
var template = new EffectTemplate(base_effect);
|
||||||
|
|
||||||
template.addModifier("value", new Range(2, 8));
|
template.addModifier("value", new Range(2, 8));
|
||||||
|
|
||||||
var effect = <AttributeMaxEffect>template.generateFixed(0.0);
|
var effect = <AttributeEffect>template.generateFixed(0.0);
|
||||||
expect(effect.code).toEqual("attrmax");
|
expect(effect.code).toEqual("attr");
|
||||||
expect(effect.value).toEqual(2);
|
expect(effect.value).toEqual(2);
|
||||||
|
|
||||||
effect = <AttributeMaxEffect>template.generateFixed(1.0);
|
effect = <AttributeEffect>template.generateFixed(1.0);
|
||||||
expect(effect.code).toEqual("attrmax");
|
expect(effect.code).toEqual("attr");
|
||||||
expect(effect.value).toEqual(8);
|
expect(effect.value).toEqual(8);
|
||||||
|
|
||||||
effect = <AttributeMaxEffect>template.generateFixed(0.5);
|
effect = <AttributeEffect>template.generateFixed(0.5);
|
||||||
expect(effect.code).toEqual("attrmax");
|
expect(effect.code).toEqual("attr");
|
||||||
expect(effect.value).toEqual(5);
|
expect(effect.value).toEqual(5);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,28 +6,28 @@ module TS.SpaceTac.Game.Specs {
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||||
|
|
||||||
equipment.requirements.push(new Attribute(AttributeCode.Cap_Time, 2));
|
equipment.requirements["skill_time"] = 2;
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(false);
|
expect(equipment.canBeEquipped(ship)).toBe(false);
|
||||||
|
|
||||||
ship.cap_time.set(1);
|
ship.attributes.skill_time.set(1);
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(false);
|
expect(equipment.canBeEquipped(ship)).toBe(false);
|
||||||
|
|
||||||
ship.cap_time.set(2);
|
ship.attributes.skill_time.set(2);
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||||
|
|
||||||
ship.cap_time.set(3);
|
ship.attributes.skill_time.set(3);
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||||
|
|
||||||
// Second requirement
|
// Second requirement
|
||||||
equipment.requirements.push(new Attribute(AttributeCode.Cap_Material, 3));
|
equipment.requirements["skill_material"] = 3;
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(false);
|
expect(equipment.canBeEquipped(ship)).toBe(false);
|
||||||
|
|
||||||
ship.cap_material.set(4);
|
ship.attributes.skill_material.set(4);
|
||||||
|
|
||||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -44,8 +44,8 @@ module TS.SpaceTac.Game.Specs {
|
||||||
expect(equipment.getActionDescription()).toEqual("- 50 damage on all ships in 20km of impact");
|
expect(equipment.getActionDescription()).toEqual("- 50 damage on all ships in 20km of impact");
|
||||||
|
|
||||||
equipment.blast = 0;
|
equipment.blast = 0;
|
||||||
equipment.target_effects.push(new StickyEffect(new AttributeLimitEffect(AttributeCode.Shield, 200), 3));
|
equipment.target_effects.push(new StickyEffect(new AttributeLimitEffect("shield_capacity", 200), 3));
|
||||||
expect(equipment.getActionDescription()).toEqual("- 50 damage on target\n- limit shield to 200 for 3 turns on target");
|
expect(equipment.getActionDescription()).toEqual("- 50 damage on target\n- limit shield capacity to 200 for 3 turns on target");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ module TS.SpaceTac.Game {
|
||||||
min_level: number;
|
min_level: number;
|
||||||
|
|
||||||
// Minimal attribute to be able to equip this equipment
|
// Minimal attribute to be able to equip this equipment
|
||||||
requirements: Attribute[];
|
requirements: { [key: string]: number };
|
||||||
|
|
||||||
// Action associated with this equipment
|
// Action associated with this equipment
|
||||||
action: BaseAction;
|
action: BaseAction;
|
||||||
|
@ -45,7 +45,7 @@ module TS.SpaceTac.Game {
|
||||||
this.slot = slot;
|
this.slot = slot;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.name = code;
|
this.name = code;
|
||||||
this.requirements = [];
|
this.requirements = {};
|
||||||
this.permanent_effects = [];
|
this.permanent_effects = [];
|
||||||
this.target_effects = [];
|
this.target_effects = [];
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,8 @@ module TS.SpaceTac.Game {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
var able = true;
|
var able = true;
|
||||||
this.requirements.forEach((cap: Attribute) => {
|
iteritems(this.requirements, (attr, minvalue) => {
|
||||||
if (ship.attributes.getValue(cap.code) < cap.current) {
|
if (ship.getAttribute(<keyof ShipAttributes>attr) < minvalue) {
|
||||||
able = false;
|
able = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,8 +8,8 @@ module TS.SpaceTac.Game.Specs {
|
||||||
template.duration = new IntegerRange(1, 2);
|
template.duration = new IntegerRange(1, 2);
|
||||||
template.ap_usage = new Range(4, 12);
|
template.ap_usage = new Range(4, 12);
|
||||||
template.min_level = new IntegerRange(5, 9);
|
template.min_level = new IntegerRange(5, 9);
|
||||||
template.addRequirement(AttributeCode.Cap_Energy, 2, 8);
|
template.addRequirement("skill_energy", 2, 8);
|
||||||
template.addRequirement(AttributeCode.Cap_Human, 5);
|
template.addRequirement("skill_human", 5);
|
||||||
|
|
||||||
var equipment = template.generateFixed(0.0);
|
var equipment = template.generateFixed(0.0);
|
||||||
|
|
||||||
|
@ -21,9 +21,10 @@ module TS.SpaceTac.Game.Specs {
|
||||||
expect(equipment.duration).toEqual(1);
|
expect(equipment.duration).toEqual(1);
|
||||||
expect(equipment.ap_usage).toEqual(4);
|
expect(equipment.ap_usage).toEqual(4);
|
||||||
expect(equipment.min_level).toEqual(5);
|
expect(equipment.min_level).toEqual(5);
|
||||||
expect(equipment.requirements.length).toBe(2);
|
expect(equipment.requirements).toEqual({
|
||||||
expect(equipment.requirements[0]).toEqual(new Attribute(AttributeCode.Cap_Energy, 2));
|
"skill_energy": 2,
|
||||||
expect(equipment.requirements[1]).toEqual(new Attribute(AttributeCode.Cap_Human, 5));
|
"skill_human": 5
|
||||||
|
});
|
||||||
|
|
||||||
equipment = template.generateFixed(1.0);
|
equipment = template.generateFixed(1.0);
|
||||||
|
|
||||||
|
@ -35,9 +36,10 @@ module TS.SpaceTac.Game.Specs {
|
||||||
expect(equipment.duration).toEqual(2);
|
expect(equipment.duration).toEqual(2);
|
||||||
expect(equipment.ap_usage).toEqual(12);
|
expect(equipment.ap_usage).toEqual(12);
|
||||||
expect(equipment.min_level).toEqual(9);
|
expect(equipment.min_level).toEqual(9);
|
||||||
expect(equipment.requirements.length).toBe(2);
|
expect(equipment.requirements).toEqual({
|
||||||
expect(equipment.requirements[0]).toEqual(new Attribute(AttributeCode.Cap_Energy, 8));
|
"skill_energy": 8,
|
||||||
expect(equipment.requirements[1]).toEqual(new Attribute(AttributeCode.Cap_Human, 5));
|
"skill_human": 5
|
||||||
|
});
|
||||||
|
|
||||||
equipment = template.generateFixed(0.5);
|
equipment = template.generateFixed(0.5);
|
||||||
|
|
||||||
|
@ -49,9 +51,10 @@ module TS.SpaceTac.Game.Specs {
|
||||||
expect(equipment.duration).toEqual(2);
|
expect(equipment.duration).toEqual(2);
|
||||||
expect(equipment.ap_usage).toEqual(8);
|
expect(equipment.ap_usage).toEqual(8);
|
||||||
expect(equipment.min_level).toEqual(7);
|
expect(equipment.min_level).toEqual(7);
|
||||||
expect(equipment.requirements.length).toBe(2);
|
expect(equipment.requirements).toEqual({
|
||||||
expect(equipment.requirements[0]).toEqual(new Attribute(AttributeCode.Cap_Energy, 5));
|
"skill_energy": 5,
|
||||||
expect(equipment.requirements[1]).toEqual(new Attribute(AttributeCode.Cap_Human, 5));
|
"skill_human": 5
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("restricts power range to stay in a level range", () => {
|
it("restricts power range to stay in a level range", () => {
|
||||||
|
|
|
@ -7,8 +7,8 @@ module TS.SpaceTac.Game {
|
||||||
// Base name that will be given to generated equipment
|
// Base name that will be given to generated equipment
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
// Capability requirement ranges (indexed by AttributeCode)
|
// Capability requirement ranges (indexed by attributes)
|
||||||
requirements: IntegerRange[];
|
requirements: { [key: string]: IntegerRange };
|
||||||
|
|
||||||
// Distance to target
|
// Distance to target
|
||||||
distance: Range;
|
distance: Range;
|
||||||
|
@ -35,7 +35,7 @@ module TS.SpaceTac.Game {
|
||||||
constructor(slot: SlotType, name: string) {
|
constructor(slot: SlotType, name: string) {
|
||||||
this.slot = slot;
|
this.slot = slot;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.requirements = [];
|
this.requirements = {};
|
||||||
this.distance = new Range(0, 0);
|
this.distance = new Range(0, 0);
|
||||||
this.blast = new Range(0, 0);
|
this.blast = new Range(0, 0);
|
||||||
this.duration = new IntegerRange(0, 0);
|
this.duration = new IntegerRange(0, 0);
|
||||||
|
@ -46,7 +46,7 @@ module TS.SpaceTac.Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a capability requirement
|
// Set a capability requirement
|
||||||
addRequirement(capability: AttributeCode, min: number, max: number = null): void {
|
addRequirement(capability: keyof ShipAttributes, min: number, max: number = null): void {
|
||||||
this.requirements[capability] = new IntegerRange(min, max);
|
this.requirements[capability] = new IntegerRange(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +73,9 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
result.action = this.getActionForEquipment(result);
|
result.action = this.getActionForEquipment(result);
|
||||||
|
|
||||||
this.requirements.forEach((requirement: IntegerRange, index: AttributeCode) => {
|
iteritems(this.requirements, (key: string, requirement: IntegerRange) => {
|
||||||
if (requirement) {
|
if (requirement) {
|
||||||
result.requirements.push(new Attribute(index, requirement.getProportional(power)));
|
result.requirements[key] = requirement.getProportional(power);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,23 +124,23 @@ module TS.SpaceTac.Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience function to add a permanent attribute effect on equipment
|
// Convenience function to add an attribute effect on equipment
|
||||||
addPermanentAttributeValueEffect(code: AttributeCode, min: number, max: number = null): void {
|
addAttributeEffect(code: keyof ShipAttributes, min: number, max: number = null): void {
|
||||||
var template = new EffectTemplate(new AttributeValueEffect(code, 0));
|
var template = new EffectTemplate(new AttributeEffect(code, 0));
|
||||||
template.addModifier("value", new IntegerRange(min, max));
|
template.addModifier("value", new IntegerRange(min, max));
|
||||||
this.permanent_effects.push(template);
|
this.permanent_effects.push(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience function to add a permanent attribute max effect on equipment
|
// Convenience function to add a permanent attribute limit effect on equipment
|
||||||
addPermanentAttributeMaxEffect(code: AttributeCode, min: number, max: number = null): void {
|
addAttributeLimitEffect(code: keyof ShipAttributes, min: number, max: number = null): void {
|
||||||
var template = new EffectTemplate(new AttributeMaxEffect(code, 0));
|
var template = new EffectTemplate(new AttributeLimitEffect(code, 0));
|
||||||
template.addModifier("value", new IntegerRange(min, max));
|
template.addModifier("value", new IntegerRange(min, max));
|
||||||
this.permanent_effects.push(template);
|
this.permanent_effects.push(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience function to add an offset effect on attribute value
|
// Convenience function to add a value effect on equipment
|
||||||
addAttributeAddEffect(code: AttributeCode, min: number, max: number | null = null): void {
|
addValueEffectOnTarget(code: keyof ShipValues, min: number, max: number = null): void {
|
||||||
let template = new EffectTemplate(new AttributeAddEffect(code, 0));
|
var template = new EffectTemplate(new ValueEffect(code, 0));
|
||||||
template.addModifier("value", new IntegerRange(min, max));
|
template.addModifier("value", new IntegerRange(min, max));
|
||||||
this.target_effects.push(template);
|
this.target_effects.push(template);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ module TS.SpaceTac.Game {
|
||||||
let dy = target.y - this.ship.arena_y;
|
let dy = target.y - this.ship.arena_y;
|
||||||
let distance = Math.sqrt(dx * dx + dy * dy);
|
let distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
let result = new MoveFireResult();
|
let result = new MoveFireResult();
|
||||||
let ap = this.ship.ap_current.current;
|
let ap = this.ship.values.power.get();
|
||||||
|
|
||||||
if (distance > action.getRangeRadius(this.ship)) {
|
if (distance > action.getRangeRadius(this.ship)) {
|
||||||
result.need_move = true;
|
result.need_move = true;
|
||||||
|
|
|
@ -65,32 +65,32 @@ module TS.SpaceTac.Game.Specs {
|
||||||
slot = ship.addSlot(SlotType.Power);
|
slot = ship.addSlot(SlotType.Power);
|
||||||
equipment = new Equipment();
|
equipment = new Equipment();
|
||||||
equipment.slot = slot.type;
|
equipment.slot = slot.type;
|
||||||
equipment.permanent_effects.push(new AttributeMaxEffect(AttributeCode.Power, 4));
|
equipment.permanent_effects.push(new AttributeEffect("power_capacity", 4));
|
||||||
slot.attach(equipment);
|
slot.attach(equipment);
|
||||||
|
|
||||||
slot = ship.addSlot(SlotType.Power);
|
slot = ship.addSlot(SlotType.Power);
|
||||||
equipment = new Equipment();
|
equipment = new Equipment();
|
||||||
equipment.slot = slot.type;
|
equipment.slot = slot.type;
|
||||||
equipment.permanent_effects.push(new AttributeMaxEffect(AttributeCode.Power, 5));
|
equipment.permanent_effects.push(new AttributeEffect("power_capacity", 5));
|
||||||
slot.attach(equipment);
|
slot.attach(equipment);
|
||||||
|
|
||||||
ship.updateAttributes();
|
ship.updateAttributes();
|
||||||
expect(ship.ap_current.maximal).toBe(9);
|
expect(ship.attributes.power_capacity.get()).toBe(9);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("repairs hull and recharges shield", function () {
|
it("repairs hull and recharges shield", function () {
|
||||||
var ship = new Ship(null, "Test");
|
var ship = new Ship(null, "Test");
|
||||||
|
|
||||||
ship.hull.setMaximal(120);
|
ship.setAttribute("hull_capacity", 120);
|
||||||
ship.shield.setMaximal(150);
|
ship.setAttribute("shield_capacity", 150);
|
||||||
|
|
||||||
expect(ship.hull.current).toEqual(0);
|
expect(ship.values.hull.get()).toEqual(0);
|
||||||
expect(ship.shield.current).toEqual(0);
|
expect(ship.values.shield.get()).toEqual(0);
|
||||||
|
|
||||||
ship.restoreHealth();
|
ship.restoreHealth();
|
||||||
|
|
||||||
expect(ship.hull.current).toEqual(120);
|
expect(ship.values.hull.get()).toEqual(120);
|
||||||
expect(ship.shield.current).toEqual(150);
|
expect(ship.values.shield.get()).toEqual(150);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("applies and logs hull and shield damage", function () {
|
it("applies and logs hull and shield damage", function () {
|
||||||
|
@ -98,24 +98,24 @@ module TS.SpaceTac.Game.Specs {
|
||||||
var battle = new Battle(fleet);
|
var battle = new Battle(fleet);
|
||||||
var ship = new Ship(fleet);
|
var ship = new Ship(fleet);
|
||||||
|
|
||||||
ship.hull.setMaximal(50);
|
ship.setAttribute("hull_capacity", 50);
|
||||||
ship.shield.setMaximal(100);
|
ship.setAttribute("shield_capacity", 100);
|
||||||
ship.restoreHealth();
|
ship.restoreHealth();
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
|
|
||||||
ship.addDamage(10, 20);
|
ship.addDamage(10, 20);
|
||||||
expect(ship.hull.current).toEqual(40);
|
expect(ship.values.hull.get()).toEqual(40);
|
||||||
expect(ship.shield.current).toEqual(80);
|
expect(ship.values.shield.get()).toEqual(80);
|
||||||
expect(battle.log.events.length).toBe(3);
|
expect(battle.log.events.length).toBe(3);
|
||||||
expect(battle.log.events[0]).toEqual(new AttributeChangeEvent(ship, ship.shield));
|
expect(battle.log.events[0]).toEqual(new ValueChangeEvent(ship, ship.values.shield));
|
||||||
expect(battle.log.events[1]).toEqual(new AttributeChangeEvent(ship, ship.hull));
|
expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship, ship.values.hull));
|
||||||
expect(battle.log.events[2]).toEqual(new DamageEvent(ship, 10, 20));
|
expect(battle.log.events[2]).toEqual(new DamageEvent(ship, 10, 20));
|
||||||
|
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
|
|
||||||
ship.addDamage(15, 25, false);
|
ship.addDamage(15, 25, false);
|
||||||
expect(ship.hull.current).toEqual(25);
|
expect(ship.values.hull.get()).toEqual(25);
|
||||||
expect(ship.shield.current).toEqual(55);
|
expect(ship.values.shield.get()).toEqual(55);
|
||||||
expect(battle.log.events.length).toBe(0);
|
expect(battle.log.events.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -164,13 +164,13 @@ module TS.SpaceTac.Game.Specs {
|
||||||
|
|
||||||
expect(ship.alive).toBe(true);
|
expect(ship.alive).toBe(true);
|
||||||
|
|
||||||
ship.hull.set(10);
|
ship.values.hull.set(10);
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
ship.addDamage(5, 0);
|
ship.addDamage(5, 0);
|
||||||
|
|
||||||
expect(ship.alive).toBe(true);
|
expect(ship.alive).toBe(true);
|
||||||
expect(battle.log.events.length).toBe(2);
|
expect(battle.log.events.length).toBe(2);
|
||||||
expect(battle.log.events[0].code).toEqual("attr");
|
expect(battle.log.events[0].code).toEqual("value");
|
||||||
expect(battle.log.events[1].code).toEqual("damage");
|
expect(battle.log.events[1].code).toEqual("damage");
|
||||||
|
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
|
@ -178,7 +178,7 @@ module TS.SpaceTac.Game.Specs {
|
||||||
|
|
||||||
expect(ship.alive).toBe(false);
|
expect(ship.alive).toBe(false);
|
||||||
expect(battle.log.events.length).toBe(3);
|
expect(battle.log.events.length).toBe(3);
|
||||||
expect(battle.log.events[0].code).toEqual("attr");
|
expect(battle.log.events[0].code).toEqual("value");
|
||||||
expect(battle.log.events[1].code).toEqual("damage");
|
expect(battle.log.events[1].code).toEqual("damage");
|
||||||
expect(battle.log.events[2].code).toEqual("death");
|
expect(battle.log.events[2].code).toEqual("death");
|
||||||
});
|
});
|
||||||
|
@ -189,12 +189,12 @@ module TS.SpaceTac.Game.Specs {
|
||||||
expect(ship.isAbleToPlay()).toBe(false);
|
expect(ship.isAbleToPlay()).toBe(false);
|
||||||
expect(ship.isAbleToPlay(false)).toBe(true);
|
expect(ship.isAbleToPlay(false)).toBe(true);
|
||||||
|
|
||||||
ship.ap_current.set(5);
|
ship.values.power.set(5);
|
||||||
|
|
||||||
expect(ship.isAbleToPlay()).toBe(true);
|
expect(ship.isAbleToPlay()).toBe(true);
|
||||||
expect(ship.isAbleToPlay(false)).toBe(true);
|
expect(ship.isAbleToPlay(false)).toBe(true);
|
||||||
|
|
||||||
ship.hull.set(10);
|
ship.values.hull.set(10);
|
||||||
ship.addDamage(8, 0);
|
ship.addDamage(8, 0);
|
||||||
|
|
||||||
expect(ship.isAbleToPlay()).toBe(true);
|
expect(ship.isAbleToPlay()).toBe(true);
|
||||||
|
@ -243,16 +243,17 @@ module TS.SpaceTac.Game.Specs {
|
||||||
|
|
||||||
var power_core_template = new Equipments.BasicPowerCore();
|
var power_core_template = new Equipments.BasicPowerCore();
|
||||||
ship.addSlot(SlotType.Power).attach(power_core_template.generateFixed(0));
|
ship.addSlot(SlotType.Power).attach(power_core_template.generateFixed(0));
|
||||||
|
ship.updateAttributes();
|
||||||
|
|
||||||
expect(ship.ap_current.current).toBe(0);
|
expect(ship.values.power.get()).toBe(0);
|
||||||
ship.initializeActionPoints();
|
ship.initializeActionPoints();
|
||||||
expect(ship.ap_current.current).toBe(5);
|
expect(ship.values.power.get()).toBe(5);
|
||||||
ship.ap_current.set(2);
|
ship.values.power.set(2);
|
||||||
expect(ship.ap_current.current).toBe(2);
|
expect(ship.values.power.get()).toBe(2);
|
||||||
ship.recoverActionPoints();
|
ship.recoverActionPoints();
|
||||||
expect(ship.ap_current.current).toBe(6);
|
expect(ship.values.power.get()).toBe(6);
|
||||||
ship.recoverActionPoints();
|
ship.recoverActionPoints();
|
||||||
expect(ship.ap_current.current).toBe(8);
|
expect(ship.values.power.get()).toBe(8);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks if a ship is inside a given circle", function () {
|
it("checks if a ship is inside a given circle", function () {
|
||||||
|
|
256
src/game/Ship.ts
256
src/game/Ship.ts
|
@ -1,90 +1,104 @@
|
||||||
|
/// <reference path="ShipAttribute.ts"/>
|
||||||
|
/// <reference path="ShipValue.ts"/>
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
module TS.SpaceTac.Game {
|
||||||
// A single ship in a Fleet
|
|
||||||
|
/**
|
||||||
|
* Set of ShipAttribute for a ship
|
||||||
|
*/
|
||||||
|
export class ShipAttributes {
|
||||||
|
// Attribute controlling the play order
|
||||||
|
initiative = new ShipAttribute("initiative")
|
||||||
|
// Maximal hull value
|
||||||
|
hull_capacity = new ShipAttribute("hull capacity")
|
||||||
|
// Maximal shield value
|
||||||
|
shield_capacity = new ShipAttribute("shield capacity")
|
||||||
|
// Maximal power value
|
||||||
|
power_capacity = new ShipAttribute("power capacity")
|
||||||
|
// Initial power value at the start of a battle
|
||||||
|
power_initial = new ShipAttribute("initial power")
|
||||||
|
// Power value recovered each turn
|
||||||
|
power_recovery = new ShipAttribute("power recovery")
|
||||||
|
// Skills
|
||||||
|
skill_material = new ShipAttribute("material skill")
|
||||||
|
skill_energy = new ShipAttribute("energy skill")
|
||||||
|
skill_electronics = new ShipAttribute("electronics skill")
|
||||||
|
skill_human = new ShipAttribute("human skill")
|
||||||
|
skill_time = new ShipAttribute("time skill")
|
||||||
|
skill_gravity = new ShipAttribute("gravity skill")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of ShipValue for a ship
|
||||||
|
*/
|
||||||
|
export class ShipValues {
|
||||||
|
hull = new ShipValue("hull")
|
||||||
|
shield = new ShipValue("shield")
|
||||||
|
power = new ShipValue("power")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static attributes and values object for name queries
|
||||||
|
*/
|
||||||
|
export const SHIP_ATTRIBUTES = new ShipAttributes();
|
||||||
|
export const SHIP_VALUES = new ShipValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single ship in a fleet
|
||||||
|
*/
|
||||||
export class Ship {
|
export class Ship {
|
||||||
// Fleet this ship is a member of
|
// Fleet this ship is a member of
|
||||||
fleet: Fleet;
|
fleet: Fleet
|
||||||
|
|
||||||
// Level of this ship
|
// Level of this ship
|
||||||
level: number;
|
level: number
|
||||||
|
|
||||||
// Name of the ship
|
// Name of the ship
|
||||||
name: string;
|
name: string
|
||||||
|
|
||||||
// Code of the ShipModel used to create it
|
// Code of the ShipModel used to create it
|
||||||
model: string;
|
model: string
|
||||||
|
|
||||||
// Flag indicating if the ship is alive
|
// Flag indicating if the ship is alive
|
||||||
alive: boolean;
|
alive: boolean
|
||||||
|
|
||||||
// Position in the arena
|
// Position in the arena
|
||||||
arena_x: number;
|
arena_x: number
|
||||||
arena_y: number;
|
arena_y: number
|
||||||
|
|
||||||
// Facing direction in the arena
|
// Facing direction in the arena
|
||||||
arena_angle: number;
|
arena_angle: number
|
||||||
|
|
||||||
// Initiative (high numbers will allow this ship to play sooner)
|
|
||||||
initiative: Attribute;
|
|
||||||
|
|
||||||
// Current number of action points
|
|
||||||
ap_current: Attribute;
|
|
||||||
|
|
||||||
// Initial number of action points, at the start of a battle
|
|
||||||
ap_initial: Attribute;
|
|
||||||
|
|
||||||
// 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 can absorb some damage to protect the hull)
|
|
||||||
shield: Attribute;
|
|
||||||
|
|
||||||
// Sticky effects that applies a given number of times
|
// Sticky effects that applies a given number of times
|
||||||
sticky_effects: StickyEffect[];
|
sticky_effects: StickyEffect[]
|
||||||
|
|
||||||
// Capabilities level
|
|
||||||
cap_material: Attribute;
|
|
||||||
cap_energy: Attribute;
|
|
||||||
cap_electronics: Attribute;
|
|
||||||
cap_human: Attribute;
|
|
||||||
cap_time: Attribute;
|
|
||||||
cap_gravity: Attribute;
|
|
||||||
|
|
||||||
// List of slots, able to contain equipment
|
// List of slots, able to contain equipment
|
||||||
slots: Slot[];
|
slots: Slot[]
|
||||||
|
|
||||||
// Collection of available attributes
|
// Ship attributes
|
||||||
attributes: AttributeCollection;
|
attributes = new ShipAttributes()
|
||||||
|
|
||||||
|
// Ship values
|
||||||
|
values = new ShipValues()
|
||||||
|
|
||||||
// Boolean set to true if the ship is currently playing its turn
|
// Boolean set to true if the ship is currently playing its turn
|
||||||
playing = false;
|
playing = false
|
||||||
|
|
||||||
|
// Priority in play_order
|
||||||
|
play_priority = 0;
|
||||||
|
|
||||||
// Create a new ship inside a fleet
|
// Create a new ship inside a fleet
|
||||||
constructor(fleet: Fleet = null, name: string = null) {
|
constructor(fleet: Fleet = null, name: string = null) {
|
||||||
this.attributes = new AttributeCollection();
|
|
||||||
this.fleet = fleet || new Fleet();
|
this.fleet = fleet || new Fleet();
|
||||||
this.level = 1;
|
this.level = 1;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.model = "default";
|
this.model = "default";
|
||||||
this.alive = true;
|
this.alive = true;
|
||||||
this.initiative = this.newAttribute(AttributeCode.Initiative);
|
|
||||||
this.initiative.setMaximal(1);
|
|
||||||
this.ap_current = this.newAttribute(AttributeCode.Power);
|
|
||||||
this.ap_initial = this.newAttribute(AttributeCode.Power_Initial);
|
|
||||||
this.ap_recover = this.newAttribute(AttributeCode.Power_Recovery);
|
|
||||||
this.hull = this.newAttribute(AttributeCode.Hull);
|
|
||||||
this.shield = this.newAttribute(AttributeCode.Shield);
|
|
||||||
this.cap_material = this.newAttribute(AttributeCode.Cap_Material);
|
|
||||||
this.cap_energy = this.newAttribute(AttributeCode.Cap_Energy);
|
|
||||||
this.cap_electronics = this.newAttribute(AttributeCode.Cap_Electronics);
|
|
||||||
this.cap_human = this.newAttribute(AttributeCode.Cap_Human);
|
|
||||||
this.cap_time = this.newAttribute(AttributeCode.Cap_Time);
|
|
||||||
this.cap_gravity = this.newAttribute(AttributeCode.Cap_Gravity);
|
|
||||||
this.sticky_effects = [];
|
this.sticky_effects = [];
|
||||||
this.slots = [];
|
this.slots = [];
|
||||||
|
|
||||||
|
this.attributes.initiative.set(1); // TODO Should not be needed
|
||||||
|
|
||||||
this.arena_x = 0;
|
this.arena_x = 0;
|
||||||
this.arena_y = 0;
|
this.arena_y = 0;
|
||||||
this.arena_angle = 0;
|
this.arena_angle = 0;
|
||||||
|
@ -97,15 +111,10 @@ module TS.SpaceTac.Game {
|
||||||
// Returns true if the ship is able to play
|
// Returns true if the ship is able to play
|
||||||
// If *check_ap* is true, ap_current=0 will make this function return false
|
// If *check_ap* is true, ap_current=0 will make this function return false
|
||||||
isAbleToPlay(check_ap: boolean = true): boolean {
|
isAbleToPlay(check_ap: boolean = true): boolean {
|
||||||
var ap_checked = !check_ap || this.ap_current.current > 0;
|
var ap_checked = !check_ap || this.values.power.get() > 0;
|
||||||
return this.alive && ap_checked;
|
return this.alive && ap_checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and register an attribute
|
|
||||||
newAttribute(code: AttributeCode): Attribute {
|
|
||||||
return this.attributes.getRawAttr(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set position in the arena
|
// Set position in the arena
|
||||||
// This does not consumes action points
|
// This does not consumes action points
|
||||||
setArenaPosition(x: number, y: number) {
|
setArenaPosition(x: number, y: number) {
|
||||||
|
@ -125,7 +134,7 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
// Make an initiative throw, to resolve play order in a battle
|
// Make an initiative throw, to resolve play order in a battle
|
||||||
throwInitiative(gen: RandomGenerator): void {
|
throwInitiative(gen: RandomGenerator): void {
|
||||||
this.initiative.set(gen.throw(this.initiative.maximal));
|
this.play_priority = gen.throw(this.attributes.initiative.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the player owning this ship
|
// Return the player owning this ship
|
||||||
|
@ -171,28 +180,68 @@ module TS.SpaceTac.Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an attribute value
|
* Get a ship value
|
||||||
|
*/
|
||||||
|
getValue(name: keyof ShipValues): number {
|
||||||
|
return this.values[name].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a ship value
|
||||||
*
|
*
|
||||||
* If *offset* is true, the value will be added to current 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
|
* If *log* is true, an attribute event will be added to the battle log
|
||||||
*
|
*
|
||||||
* Returns true if the attribute changed.
|
* Returns true if the value changed.
|
||||||
*/
|
*/
|
||||||
setAttribute(attr: Attribute | AttributeCode, value: number, offset = false, log = true): boolean {
|
setValue(name: keyof ShipValues, value: number, offset = false, log = true): boolean {
|
||||||
if (!(attr instanceof Attribute)) {
|
let changed: boolean;
|
||||||
attr = this.attributes.getRawAttr(attr);
|
let val = this.values[name];
|
||||||
}
|
|
||||||
|
|
||||||
var changed: boolean;
|
|
||||||
|
|
||||||
if (offset) {
|
if (offset) {
|
||||||
changed = attr.add(value);
|
changed = val.add(value);
|
||||||
} else {
|
} else {
|
||||||
changed = attr.set(value);
|
changed = val.set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed && log) {
|
if (changed && log) {
|
||||||
this.addBattleEvent(new AttributeChangeEvent(this, attr));
|
this.addBattleEvent(new ValueChangeEvent(this, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a ship attribute's current value
|
||||||
|
*/
|
||||||
|
getAttribute(name: keyof ShipAttributes): number {
|
||||||
|
return this.attributes[name].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a ship attribute
|
||||||
|
*
|
||||||
|
* If *log* is true, an attribute event will be added to the battle log
|
||||||
|
*
|
||||||
|
* Returns true if the value changed.
|
||||||
|
*/
|
||||||
|
setAttribute(name: keyof ShipAttributes, value: number, log = true): boolean {
|
||||||
|
let changed: boolean;
|
||||||
|
let attr = this.attributes[name];
|
||||||
|
|
||||||
|
changed = attr.set(value);
|
||||||
|
|
||||||
|
// TODO more generic
|
||||||
|
if (name == "power_capacity") {
|
||||||
|
this.values.power.setMaximal(attr.get());
|
||||||
|
} else if (name == "shield_capacity") {
|
||||||
|
this.values.shield.setMaximal(attr.get());
|
||||||
|
} else if (name == "hull_capacity") {
|
||||||
|
this.values.hull.setMaximal(attr.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed && log) {
|
||||||
|
this.addBattleEvent(new ValueChangeEvent(this, attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -203,9 +252,9 @@ module TS.SpaceTac.Game {
|
||||||
// If no value is provided, the attribute ap_initial will be used
|
// If no value is provided, the attribute ap_initial will be used
|
||||||
initializeActionPoints(value: number = null): void {
|
initializeActionPoints(value: number = null): void {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
value = this.ap_initial.current;
|
value = this.attributes.power_initial.get();
|
||||||
}
|
}
|
||||||
this.setAttribute(this.ap_current, value);
|
this.setValue("power", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recover action points
|
// Recover action points
|
||||||
|
@ -213,14 +262,14 @@ module TS.SpaceTac.Game {
|
||||||
// If no value is provided, the current attribute ap_recovery will be used
|
// If no value is provided, the current attribute ap_recovery will be used
|
||||||
recoverActionPoints(value: number = null): void {
|
recoverActionPoints(value: number = null): void {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
value = this.ap_recover.current;
|
value = this.attributes.power_recovery.get();
|
||||||
}
|
}
|
||||||
this.setAttribute(this.ap_current, value, true);
|
this.setValue("power", value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consumes action points
|
// Consumes action points
|
||||||
useActionPoints(value: number): void {
|
useActionPoints(value: number): void {
|
||||||
this.setAttribute(this.ap_current, -value, true);
|
this.setValue("power", -value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method called at the start of battle
|
// Method called at the start of battle
|
||||||
|
@ -256,6 +305,7 @@ module TS.SpaceTac.Game {
|
||||||
this.playing = false;
|
this.playing = false;
|
||||||
|
|
||||||
// Recover action points for next turn
|
// Recover action points for next turn
|
||||||
|
this.updateAttributes();
|
||||||
this.recoverActionPoints();
|
this.recoverActionPoints();
|
||||||
|
|
||||||
// Apply sticky effects
|
// Apply sticky effects
|
||||||
|
@ -317,14 +367,14 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
// Apply damages to hull and/or shield
|
// Apply damages to hull and/or shield
|
||||||
addDamage(hull: number, shield: number, log: boolean = true): void {
|
addDamage(hull: number, shield: number, log: boolean = true): void {
|
||||||
this.setAttribute(this.shield, -shield, true, log);
|
this.setValue("shield", -shield, true, log);
|
||||||
this.setAttribute(this.hull, -hull, true, log);
|
this.setValue("hull", -hull, true, log);
|
||||||
|
|
||||||
if (log) {
|
if (log) {
|
||||||
this.addBattleEvent(new DamageEvent(this, hull, shield));
|
this.addBattleEvent(new DamageEvent(this, hull, shield));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hull.current === 0) {
|
if (this.values.hull.get() === 0) {
|
||||||
// Ship is dead
|
// Ship is dead
|
||||||
this.setDead(log);
|
this.setDead(log);
|
||||||
}
|
}
|
||||||
|
@ -384,47 +434,49 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
// Update attributes, taking into account attached equipment and active effects
|
// Update attributes, taking into account attached equipment and active effects
|
||||||
updateAttributes(): void {
|
updateAttributes(): void {
|
||||||
// TODO Something more generic
|
// Sum all attribute effects
|
||||||
|
var new_attrs = new ShipAttributes();
|
||||||
// Compute new maximal values for attributes
|
this.collectEffects("attr").forEach((effect: AttributeEffect) => {
|
||||||
var new_attrs = new AttributeCollection();
|
new_attrs[effect.attrcode].add(effect.value);
|
||||||
this.collectEffects("attrmax").forEach((effect: AttributeMaxEffect) => {
|
|
||||||
new_attrs.addValue(effect.attrcode, effect.value);
|
|
||||||
});
|
});
|
||||||
this.initiative.setMaximal(new_attrs.getValue(AttributeCode.Initiative));
|
|
||||||
this.ap_current.setMaximal(new_attrs.getValue(AttributeCode.Power));
|
|
||||||
this.hull.setMaximal(new_attrs.getValue(AttributeCode.Hull));
|
|
||||||
this.shield.setMaximal(new_attrs.getValue(AttributeCode.Shield));
|
|
||||||
|
|
||||||
// Compute new current values for attributes
|
// Apply limit attributes
|
||||||
new_attrs = new AttributeCollection();
|
this.collectEffects("attrlimit").forEach((effect: AttributeLimitEffect) => {
|
||||||
this.collectEffects("attr").forEach((effect: AttributeMaxEffect) => {
|
new_attrs[effect.attrcode].setMaximal(effect.value);
|
||||||
new_attrs.addValue(effect.attrcode, effect.value);
|
});
|
||||||
|
|
||||||
|
// TODO better typing
|
||||||
|
iteritems(<any>new_attrs, (key, value) => {
|
||||||
|
this.setAttribute(<keyof ShipAttributes>key, (<ShipAttribute>value).get());
|
||||||
});
|
});
|
||||||
this.ap_initial.set(new_attrs.getValue(AttributeCode.Power_Initial));
|
|
||||||
this.ap_recover.set(new_attrs.getValue(AttributeCode.Power_Recovery));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fully restore hull and shield
|
// Fully restore hull and shield
|
||||||
restoreHealth(): void {
|
restoreHealth(): void {
|
||||||
this.hull.set(this.hull.maximal);
|
this.values.hull.set(this.attributes.hull_capacity.get());
|
||||||
this.shield.set(this.shield.maximal);
|
this.values.shield.set(this.attributes.shield_capacity.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all effects to apply for updateAttributes
|
// Collect all effects to apply for updateAttributes
|
||||||
private collectEffects(code: string = null): BaseEffect[] {
|
private collectEffects(code: string): BaseEffect[] {
|
||||||
var result: BaseEffect[] = [];
|
var result: BaseEffect[] = [];
|
||||||
|
|
||||||
this.slots.forEach((slot: Slot) => {
|
this.slots.forEach(slot => {
|
||||||
if (slot.attached) {
|
if (slot.attached) {
|
||||||
slot.attached.permanent_effects.forEach((effect: BaseEffect) => {
|
slot.attached.permanent_effects.forEach(effect => {
|
||||||
if (effect.code === code) {
|
if (effect.code == code) {
|
||||||
result.push(effect);
|
result.push(effect);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.sticky_effects.forEach(effect => {
|
||||||
|
if (effect.base.code == code) {
|
||||||
|
result.push(effect.base);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/game/ShipAttribute.ts
Normal file
16
src/game/ShipAttribute.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/// <reference path="ShipValue.ts"/>
|
||||||
|
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
/**
|
||||||
|
* A ship attribute is a value computed by a sum of contributions from equipments and sticky effects.
|
||||||
|
*
|
||||||
|
* A value may be limited by other effects.
|
||||||
|
*/
|
||||||
|
export class ShipAttribute extends ShipValue {
|
||||||
|
// Raw contributions value (without limits)
|
||||||
|
private raw = 0
|
||||||
|
|
||||||
|
// Temporary limits
|
||||||
|
private limits: number[] = []
|
||||||
|
}
|
||||||
|
}
|
72
src/game/ShipValue.spec.ts
Normal file
72
src/game/ShipValue.spec.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
describe("ShipValue", function () {
|
||||||
|
it("is initially not limited", function () {
|
||||||
|
var attr = new ShipValue("test");
|
||||||
|
|
||||||
|
attr.set(8888888);
|
||||||
|
expect(attr.get()).toBe(8888888);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies minimal and maximal value", function () {
|
||||||
|
var attr = new ShipValue("test", 50, 100);
|
||||||
|
expect(attr.get()).toBe(50);
|
||||||
|
|
||||||
|
attr.add(8);
|
||||||
|
expect(attr.get()).toBe(58);
|
||||||
|
|
||||||
|
attr.add(60);
|
||||||
|
expect(attr.get()).toBe(100);
|
||||||
|
|
||||||
|
attr.add(-72);
|
||||||
|
expect(attr.get()).toBe(28);
|
||||||
|
|
||||||
|
attr.add(-60);
|
||||||
|
expect(attr.get()).toBe(0);
|
||||||
|
|
||||||
|
attr.set(8);
|
||||||
|
expect(attr.get()).toBe(8);
|
||||||
|
|
||||||
|
attr.set(-4);
|
||||||
|
expect(attr.get()).toBe(0);
|
||||||
|
|
||||||
|
attr.set(105);
|
||||||
|
expect(attr.get()).toBe(100);
|
||||||
|
|
||||||
|
attr.setMaximal(50);
|
||||||
|
expect(attr.get()).toBe(50);
|
||||||
|
|
||||||
|
attr.setMaximal(80);
|
||||||
|
expect(attr.get()).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("tells if value changed", function () {
|
||||||
|
var result: boolean;
|
||||||
|
var attr = new ShipValue("test", 50, 100);
|
||||||
|
expect(attr.get()).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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
72
src/game/ShipValue.ts
Normal file
72
src/game/ShipValue.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
/**
|
||||||
|
* A ship value is a number that may vary and be constrained in a given range.
|
||||||
|
*/
|
||||||
|
export class ShipValue {
|
||||||
|
// Name of the value
|
||||||
|
name: string
|
||||||
|
|
||||||
|
// Current value
|
||||||
|
private current: number
|
||||||
|
|
||||||
|
// Upper bound
|
||||||
|
private maximal: number | null
|
||||||
|
|
||||||
|
constructor(code: string, current = 0, maximal: number | null = null) {
|
||||||
|
this.name = code;
|
||||||
|
this.current = current;
|
||||||
|
this.maximal = maximal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current value
|
||||||
|
*/
|
||||||
|
get(): number {
|
||||||
|
return this.current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the upper bound the value must not cross
|
||||||
|
*/
|
||||||
|
setMaximal(value: number): void {
|
||||||
|
this.maximal = value;
|
||||||
|
this.fix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 be positive and lower than maximal
|
||||||
|
*/
|
||||||
|
private fix(): void {
|
||||||
|
if (this.maximal !== null && this.current > this.maximal) {
|
||||||
|
this.current = this.maximal;
|
||||||
|
}
|
||||||
|
if (this.current < 0) {
|
||||||
|
this.current = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,13 +23,13 @@ module TS.SpaceTac.Game.Specs {
|
||||||
|
|
||||||
var equipment = new Equipment();
|
var equipment = new Equipment();
|
||||||
equipment.slot = SlotType.Shield;
|
equipment.slot = SlotType.Shield;
|
||||||
equipment.requirements.push(new Attribute(AttributeCode.Cap_Gravity, 5));
|
equipment.requirements["skill_gravity"] = 5;
|
||||||
|
|
||||||
expect(slot.attached).toBeNull();
|
expect(slot.attached).toBeNull();
|
||||||
slot.attach(equipment);
|
slot.attach(equipment);
|
||||||
expect(slot.attached).toBeNull();
|
expect(slot.attached).toBeNull();
|
||||||
|
|
||||||
ship.cap_gravity.set(6);
|
ship.attributes.skill_gravity.set(6);
|
||||||
|
|
||||||
slot.attach(equipment);
|
slot.attach(equipment);
|
||||||
expect(slot.attached).toBe(equipment);
|
expect(slot.attached).toBe(equipment);
|
||||||
|
|
|
@ -46,23 +46,18 @@ module TS.SpaceTac.Game {
|
||||||
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
||||||
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.BasicPowerCore());
|
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.BasicPowerCore());
|
||||||
|
|
||||||
equipment.permanent_effects.forEach((effect: BaseEffect) => {
|
equipment.permanent_effects.forEach(effect => {
|
||||||
if (effect.code === "attrmax") {
|
if (effect instanceof AttributeEffect) {
|
||||||
var meffect = <AttributeMaxEffect>effect;
|
if (effect.attrcode === "power_capacity") {
|
||||||
if (meffect.attrcode === AttributeCode.Power) {
|
effect.value = points;
|
||||||
meffect.value = points;
|
} else if (effect.attrcode === "power_recovery") {
|
||||||
}
|
effect.value = recovery;
|
||||||
} else if (effect.code === "attr") {
|
|
||||||
var veffect = <AttributeValueEffect>effect;
|
|
||||||
if (veffect.attrcode === AttributeCode.Power_Recovery) {
|
|
||||||
veffect.value = recovery;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ship.ap_current.setMaximal(points);
|
ship.updateAttributes();
|
||||||
ship.ap_current.set(points);
|
ship.setValue("power", points);
|
||||||
ship.ap_recover.set(recovery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a ship hull and shield points, adding/updating an equipment if needed
|
// Set a ship hull and shield points, adding/updating an equipment if needed
|
||||||
|
@ -70,19 +65,17 @@ module TS.SpaceTac.Game {
|
||||||
var armor = TestTools.getOrGenEquipment(ship, SlotType.Armor, new Equipments.IronHull());
|
var armor = TestTools.getOrGenEquipment(ship, SlotType.Armor, new Equipments.IronHull());
|
||||||
var shield = TestTools.getOrGenEquipment(ship, SlotType.Shield, new Equipments.BasicForceField());
|
var shield = TestTools.getOrGenEquipment(ship, SlotType.Shield, new Equipments.BasicForceField());
|
||||||
|
|
||||||
armor.permanent_effects.forEach((effect: BaseEffect) => {
|
armor.permanent_effects.forEach(effect => {
|
||||||
if (effect.code === "attrmax") {
|
if (effect instanceof AttributeEffect) {
|
||||||
var meffect = <AttributeMaxEffect>effect;
|
if (effect.attrcode === "hull_capacity") {
|
||||||
if (meffect.attrcode === AttributeCode.Hull) {
|
effect.value = hull_points;
|
||||||
meffect.value = hull_points;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
shield.permanent_effects.forEach((effect: BaseEffect) => {
|
shield.permanent_effects.forEach((effect: BaseEffect) => {
|
||||||
if (effect.code === "attrmax") {
|
if (effect instanceof AttributeEffect) {
|
||||||
var meffect = <AttributeMaxEffect>effect;
|
if (effect.attrcode === "shield_capacity") {
|
||||||
if (meffect.attrcode === AttributeCode.Shield) {
|
effect.value = shield_points;
|
||||||
meffect.value = shield_points;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,22 +6,22 @@ module TS.SpaceTac.Game {
|
||||||
var action = new BaseAction("test", "Test", false, equipment);
|
var action = new BaseAction("test", "Test", false, equipment);
|
||||||
var ship = new Ship();
|
var ship = new Ship();
|
||||||
ship.addSlot(SlotType.Armor).attach(equipment);
|
ship.addSlot(SlotType.Armor).attach(equipment);
|
||||||
ship.ap_current.setMaximal(10);
|
ship.values.power.setMaximal(10);
|
||||||
|
|
||||||
expect(action.canBeUsed(null, ship)).toBe(false);
|
expect(action.canBeUsed(null, ship)).toBe(false);
|
||||||
|
|
||||||
ship.ap_current.set(5);
|
ship.values.power.set(5);
|
||||||
|
|
||||||
expect(action.canBeUsed(null, ship)).toBe(true);
|
expect(action.canBeUsed(null, ship)).toBe(true);
|
||||||
expect(action.canBeUsed(null, ship, 4)).toBe(true);
|
expect(action.canBeUsed(null, ship, 4)).toBe(true);
|
||||||
expect(action.canBeUsed(null, ship, 3)).toBe(true);
|
expect(action.canBeUsed(null, ship, 3)).toBe(true);
|
||||||
expect(action.canBeUsed(null, ship, 2)).toBe(false);
|
expect(action.canBeUsed(null, ship, 2)).toBe(false);
|
||||||
|
|
||||||
ship.ap_current.set(3);
|
ship.values.power.set(3);
|
||||||
|
|
||||||
expect(action.canBeUsed(null, ship)).toBe(true);
|
expect(action.canBeUsed(null, ship)).toBe(true);
|
||||||
|
|
||||||
ship.ap_current.set(2);
|
ship.values.power.set(2);
|
||||||
|
|
||||||
expect(action.canBeUsed(null, ship)).toBe(false);
|
expect(action.canBeUsed(null, ship)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,7 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
// Check AP usage
|
// Check AP usage
|
||||||
if (remaining_ap === null) {
|
if (remaining_ap === null) {
|
||||||
remaining_ap = ship.ap_current.current;
|
remaining_ap = ship.values.power.get();
|
||||||
}
|
}
|
||||||
var ap_usage = this.equipment ? this.equipment.ap_usage : 0;
|
var ap_usage = this.equipment ? this.equipment.ap_usage : 0;
|
||||||
return remaining_ap >= ap_usage;
|
return remaining_ap >= ap_usage;
|
||||||
|
|
|
@ -58,7 +58,7 @@ module TS.SpaceTac.Game {
|
||||||
new DroneDeployedEvent(drone)
|
new DroneDeployedEvent(drone)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(ship.ap_current.current).toEqual(1);
|
expect(ship.values.power.get()).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ module TS.SpaceTac.Game {
|
||||||
var ship = new Ship();
|
var ship = new Ship();
|
||||||
var battle = new Battle(ship.fleet);
|
var battle = new Battle(ship.fleet);
|
||||||
battle.playing_ship = ship;
|
battle.playing_ship = ship;
|
||||||
ship.ap_current.setMaximal(20);
|
ship.values.power.setMaximal(20);
|
||||||
ship.ap_current.set(6);
|
ship.values.power.set(6);
|
||||||
ship.arena_x = 0;
|
ship.arena_x = 0;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
var engine = new Equipment();
|
var engine = new Equipment();
|
||||||
|
@ -21,7 +21,7 @@ module TS.SpaceTac.Game {
|
||||||
result = action.checkTarget(battle, ship, Target.newFromLocation(0, 8));
|
result = action.checkTarget(battle, ship, Target.newFromLocation(0, 8));
|
||||||
expect(result).toEqual(Target.newFromLocation(0, 3));
|
expect(result).toEqual(Target.newFromLocation(0, 3));
|
||||||
|
|
||||||
ship.ap_current.set(0);
|
ship.values.power.set(0);
|
||||||
result = action.checkTarget(battle, ship, Target.newFromLocation(0, 8));
|
result = action.checkTarget(battle, ship, Target.newFromLocation(0, 8));
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
});
|
});
|
||||||
|
@ -41,8 +41,8 @@ module TS.SpaceTac.Game {
|
||||||
it("applies to ship location, battle log and AP", function () {
|
it("applies to ship location, battle log and AP", function () {
|
||||||
var ship = new Ship();
|
var ship = new Ship();
|
||||||
var battle = new Battle(ship.fleet);
|
var battle = new Battle(ship.fleet);
|
||||||
ship.ap_current.setMaximal(20);
|
ship.values.power.setMaximal(20);
|
||||||
ship.ap_current.set(5);
|
ship.values.power.set(5);
|
||||||
ship.arena_x = 0;
|
ship.arena_x = 0;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
var engine = new Equipment();
|
var engine = new Equipment();
|
||||||
|
@ -55,13 +55,13 @@ module TS.SpaceTac.Game {
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001);
|
expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001);
|
||||||
expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001);
|
expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001);
|
||||||
expect(ship.ap_current.current).toEqual(0);
|
expect(ship.values.power.get()).toEqual(0);
|
||||||
|
|
||||||
result = action.apply(battle, ship, Target.newFromLocation(10, 10));
|
result = action.apply(battle, ship, Target.newFromLocation(10, 10));
|
||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001);
|
expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001);
|
||||||
expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001);
|
expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001);
|
||||||
expect(ship.ap_current.current).toEqual(0);
|
expect(ship.values.power.get()).toEqual(0);
|
||||||
|
|
||||||
expect(battle.log.events.length).toBe(2);
|
expect(battle.log.events.length).toBe(2);
|
||||||
|
|
||||||
|
@ -71,10 +71,10 @@ module TS.SpaceTac.Game {
|
||||||
expect(battle.log.events[0].target.x).toBeCloseTo(3.535533, 0.00001);
|
expect(battle.log.events[0].target.x).toBeCloseTo(3.535533, 0.00001);
|
||||||
expect(battle.log.events[0].target.y).toBeCloseTo(3.535533, 0.00001);
|
expect(battle.log.events[0].target.y).toBeCloseTo(3.535533, 0.00001);
|
||||||
|
|
||||||
expect(battle.log.events[1].code).toEqual("attr");
|
expect(battle.log.events[1].code).toEqual("value");
|
||||||
expect(battle.log.events[1].ship).toBe(ship);
|
expect(battle.log.events[1].ship).toBe(ship);
|
||||||
expect((<AttributeChangeEvent>battle.log.events[1]).attribute).toEqual(
|
expect((<ValueChangeEvent>battle.log.events[1]).value).toEqual(
|
||||||
new Attribute(AttributeCode.Power, 0, 20));
|
new ShipValue("power", 0, 20));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can't move too much near another ship", function () {
|
it("can't move too much near another ship", function () {
|
||||||
|
|
|
@ -18,7 +18,7 @@ module TS.SpaceTac.Game {
|
||||||
|
|
||||||
// Check AP usage
|
// Check AP usage
|
||||||
if (remaining_ap === null) {
|
if (remaining_ap === null) {
|
||||||
remaining_ap = ship.ap_current.current;
|
remaining_ap = ship.values.power.get();
|
||||||
}
|
}
|
||||||
return remaining_ap > 0.0001;
|
return remaining_ap > 0.0001;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ module TS.SpaceTac.Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
getRangeRadius(ship: Ship): number {
|
getRangeRadius(ship: Ship): number {
|
||||||
return ship.ap_current.current * this.equipment.distance / this.equipment.ap_usage;
|
return ship.values.power.get() * this.equipment.distance / this.equipment.ap_usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,8 +43,8 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
engine.ap_usage = 3;
|
engine.ap_usage = 3;
|
||||||
engine.distance = 1;
|
engine.distance = 1;
|
||||||
ship.addSlot(SlotType.Engine).attach(engine);
|
ship.addSlot(SlotType.Engine).attach(engine);
|
||||||
ship.ap_current.setMaximal(10);
|
ship.values.power.setMaximal(10);
|
||||||
ship.ap_current.set(8);
|
ship.values.power.set(8);
|
||||||
var enemy = new Ship();
|
var enemy = new Ship();
|
||||||
var ai = new BullyAI(ship.fleet);
|
var ai = new BullyAI(ship.fleet);
|
||||||
ai.ship = ship;
|
ai.ship = ship;
|
||||||
|
@ -54,7 +54,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
weapon.distance = 3;
|
weapon.distance = 3;
|
||||||
|
|
||||||
// enemy in range, the ship can fire without moving
|
// enemy in range, the ship can fire without moving
|
||||||
ship.ap_current.set(8);
|
ship.values.power.set(8);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 3;
|
enemy.arena_x = 3;
|
||||||
|
@ -65,7 +65,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
expect(result.fire.equipment).toBe(weapon);
|
expect(result.fire.equipment).toBe(weapon);
|
||||||
|
|
||||||
// enemy out of range, but moving can bring it in range
|
// enemy out of range, but moving can bring it in range
|
||||||
ship.ap_current.set(8);
|
ship.values.power.set(8);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 6;
|
enemy.arena_x = 6;
|
||||||
|
@ -77,7 +77,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
|
|
||||||
// enemy out of range, but moving can bring it in range, except for the safety margin
|
// enemy out of range, but moving can bring it in range, except for the safety margin
|
||||||
ai.move_margin = 0.1;
|
ai.move_margin = 0.1;
|
||||||
ship.ap_current.set(8);
|
ship.values.power.set(8);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 6;
|
enemy.arena_x = 6;
|
||||||
|
@ -87,7 +87,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
ai.move_margin = 0;
|
ai.move_margin = 0;
|
||||||
|
|
||||||
// enemy totally out of range
|
// enemy totally out of range
|
||||||
ship.ap_current.set(8);
|
ship.values.power.set(8);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 30;
|
enemy.arena_x = 30;
|
||||||
|
@ -96,7 +96,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
|
|
||||||
// enemy in range but not enough AP to fire
|
// enemy in range but not enough AP to fire
|
||||||
ship.ap_current.set(1);
|
ship.values.power.set(1);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 3;
|
enemy.arena_x = 3;
|
||||||
|
@ -105,7 +105,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
|
|
||||||
// can move in range of enemy, but not enough AP to fire
|
// can move in range of enemy, but not enough AP to fire
|
||||||
ship.ap_current.set(7);
|
ship.values.power.set(7);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 6;
|
enemy.arena_x = 6;
|
||||||
|
@ -115,7 +115,7 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
|
|
||||||
// no engine, can't move
|
// no engine, can't move
|
||||||
ship.slots[0].attached.detach();
|
ship.slots[0].attached.detach();
|
||||||
ship.ap_current.set(8);
|
ship.values.power.set(8);
|
||||||
ship.arena_x = 1;
|
ship.arena_x = 1;
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
enemy.arena_x = 6;
|
enemy.arena_x = 6;
|
||||||
|
@ -152,8 +152,8 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
weapon2.ap_usage = 1;
|
weapon2.ap_usage = 1;
|
||||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon2);
|
ai.ship.addSlot(SlotType.Weapon).attach(weapon2);
|
||||||
|
|
||||||
ai.ship.ap_current.setMaximal(10);
|
ai.ship.values.power.setMaximal(10);
|
||||||
ai.ship.ap_current.set(8);
|
ai.ship.values.power.set(8);
|
||||||
|
|
||||||
result = ai.listAllManeuvers();
|
result = ai.listAllManeuvers();
|
||||||
expect(result.length).toBe(3);
|
expect(result.length).toBe(3);
|
||||||
|
@ -219,11 +219,11 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
weapon.action = new FireWeaponAction(weapon);
|
weapon.action = new FireWeaponAction(weapon);
|
||||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon);
|
ai.ship.addSlot(SlotType.Weapon).attach(weapon);
|
||||||
|
|
||||||
ai.ship.ap_current.setMaximal(10);
|
ai.ship.values.power.setMaximal(10);
|
||||||
ai.ship.ap_current.set(6);
|
ai.ship.values.power.set(6);
|
||||||
|
|
||||||
ship2.hull.set(15);
|
ship2.values.hull.set(15);
|
||||||
ship2.shield.set(10);
|
ship2.values.shield.set(10);
|
||||||
|
|
||||||
var move = ai.checkBullyManeuver(ship2, weapon);
|
var move = ai.checkBullyManeuver(ship2, weapon);
|
||||||
expect(move).not.toBeNull();
|
expect(move).not.toBeNull();
|
||||||
|
@ -235,17 +235,17 @@ module TS.SpaceTac.Game.AI.Specs {
|
||||||
expect(battle.log.events.length).toBe(7);
|
expect(battle.log.events.length).toBe(7);
|
||||||
|
|
||||||
expect(battle.log.events[0]).toEqual(new MoveEvent(ship1, 2, 0));
|
expect(battle.log.events[0]).toEqual(new MoveEvent(ship1, 2, 0));
|
||||||
expect(battle.log.events[1]).toEqual(new AttributeChangeEvent(ship1,
|
expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship1,
|
||||||
new Attribute(AttributeCode.Power, 2, 10)));
|
new ShipValue("power", 2, 10)));
|
||||||
|
|
||||||
expect(battle.log.events[2]).toEqual(new FireEvent(ship1, weapon, Target.newFromShip(ship2)));
|
expect(battle.log.events[2]).toEqual(new FireEvent(ship1, weapon, Target.newFromShip(ship2)));
|
||||||
expect(battle.log.events[3]).toEqual(new AttributeChangeEvent(ship2,
|
expect(battle.log.events[3]).toEqual(new ValueChangeEvent(ship2,
|
||||||
new Attribute(AttributeCode.Shield, 0)));
|
new ShipValue("shield", 0)));
|
||||||
expect(battle.log.events[4]).toEqual(new AttributeChangeEvent(ship2,
|
expect(battle.log.events[4]).toEqual(new ValueChangeEvent(ship2,
|
||||||
new Attribute(AttributeCode.Hull, 5)));
|
new ShipValue("hull", 5)));
|
||||||
expect(battle.log.events[5]).toEqual(new DamageEvent(ship2, 10, 10));
|
expect(battle.log.events[5]).toEqual(new DamageEvent(ship2, 10, 10));
|
||||||
expect(battle.log.events[6]).toEqual(new AttributeChangeEvent(ship1,
|
expect(battle.log.events[6]).toEqual(new ValueChangeEvent(ship1,
|
||||||
new Attribute(AttributeCode.Power, 1, 10)));
|
new ShipValue("power", 1, 10)));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ module TS.SpaceTac.Game.AI {
|
||||||
var distance = target.getDistanceTo(Target.newFromShip(this.ship));
|
var distance = target.getDistanceTo(Target.newFromShip(this.ship));
|
||||||
var move: Target;
|
var move: Target;
|
||||||
var engine: Equipment;
|
var engine: Equipment;
|
||||||
var remaining_ap = this.ship.ap_current.current;
|
var remaining_ap = this.ship.values.power.get();
|
||||||
if (distance <= weapon.distance) {
|
if (distance <= weapon.distance) {
|
||||||
// No need to move
|
// No need to move
|
||||||
move = null;
|
move = null;
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
describe("AttributeAddEffect", function () {
|
|
||||||
it("adds an amount to an attribute value", function () {
|
|
||||||
let effect = new AttributeAddEffect(AttributeCode.Shield, 20);
|
|
||||||
|
|
||||||
let ship = new Ship();
|
|
||||||
ship.shield.maximal = 80;
|
|
||||||
ship.setAttribute(AttributeCode.Shield, 55);
|
|
||||||
expect(ship.shield.current).toEqual(55);
|
|
||||||
|
|
||||||
effect.applyOnShip(ship);
|
|
||||||
expect(ship.shield.current).toEqual(75);
|
|
||||||
|
|
||||||
effect.applyOnShip(ship);
|
|
||||||
expect(ship.shield.current).toEqual(80);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/// <reference path="BaseEffect.ts"/>
|
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
/**
|
|
||||||
* Effect to add (or subtract if negative) an amount to an attribute value.
|
|
||||||
*
|
|
||||||
* The effect is "permanent", and will not be removed when the effect ends.
|
|
||||||
*/
|
|
||||||
export class AttributeAddEffect extends BaseEffect {
|
|
||||||
// Affected attribute
|
|
||||||
attrcode: AttributeCode;
|
|
||||||
|
|
||||||
// Value to add (or subtract if negative)
|
|
||||||
value: number;
|
|
||||||
|
|
||||||
constructor(attrcode: AttributeCode, value: number) {
|
|
||||||
super("attradd");
|
|
||||||
|
|
||||||
this.attrcode = attrcode;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyOnShip(ship: Ship): boolean {
|
|
||||||
return ship.setAttribute(this.attrcode, this.value, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
isBeneficial(): boolean {
|
|
||||||
return this.value >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullCode(): string {
|
|
||||||
return this.code + "-" + AttributeCode[this.attrcode].toLowerCase().replace("_", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
0
src/game/effects/AttributeEffect.spec.ts
Normal file
0
src/game/effects/AttributeEffect.spec.ts
Normal file
36
src/game/effects/AttributeEffect.ts
Normal file
36
src/game/effects/AttributeEffect.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/// <reference path="BaseEffect.ts"/>
|
||||||
|
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
/**
|
||||||
|
* Effect to modify an attribute.
|
||||||
|
*
|
||||||
|
* Attribute effects are stacking, and the value of an attribute is in fact the sum of all active attribute effects.
|
||||||
|
*/
|
||||||
|
export class AttributeEffect extends BaseEffect {
|
||||||
|
// Affected attribute
|
||||||
|
attrcode: keyof ShipAttributes;
|
||||||
|
|
||||||
|
// Base value
|
||||||
|
value: number;
|
||||||
|
|
||||||
|
constructor(attrcode: keyof ShipAttributes, value: number) {
|
||||||
|
super("attr");
|
||||||
|
|
||||||
|
this.attrcode = attrcode;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyOnShip(ship: Ship): boolean {
|
||||||
|
ship.updateAttributes();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isBeneficial(): boolean {
|
||||||
|
return this.value >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFullCode(): string {
|
||||||
|
return this.code + "-" + this.attrcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,19 @@
|
||||||
/// <reference path="BaseEffect.ts"/>
|
/// <reference path="BaseEffect.ts"/>
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
module TS.SpaceTac.Game {
|
||||||
// Hard limitation on attribute value
|
/**
|
||||||
// For example, this could be used to slow a target by limiting its action points
|
* Enforce a limitation on ship attribute final value
|
||||||
|
*
|
||||||
|
* For example, this could be used to slow a target by limiting its action points
|
||||||
|
*/
|
||||||
export class AttributeLimitEffect extends BaseEffect {
|
export class AttributeLimitEffect extends BaseEffect {
|
||||||
// Affected attribute
|
// Affected attribute
|
||||||
attrcode: AttributeCode;
|
attrcode: keyof ShipAttributes;
|
||||||
|
|
||||||
// Limit of the attribute value
|
// Limit of the attribute value
|
||||||
value: number;
|
value: number;
|
||||||
|
|
||||||
constructor(attrcode: AttributeCode, value: number = 0) {
|
constructor(attrcode: keyof ShipAttributes, value = 0) {
|
||||||
super("attrlimit");
|
super("attrlimit");
|
||||||
|
|
||||||
this.attrcode = attrcode;
|
this.attrcode = attrcode;
|
||||||
|
@ -18,19 +21,17 @@ module TS.SpaceTac.Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
applyOnShip(ship: Ship): boolean {
|
applyOnShip(ship: Ship): boolean {
|
||||||
var current = ship.attributes.getValue(this.attrcode);
|
ship.updateAttributes();
|
||||||
if (current > this.value) {
|
|
||||||
ship.setAttribute(ship.attributes.getRawAttr(this.attrcode), this.value);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFullCode(): string {
|
getFullCode(): string {
|
||||||
return this.code + "-" + AttributeCode[this.attrcode].toLowerCase().replace("_", "");
|
return this.code + "-" + this.attrcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription(): string {
|
getDescription(): string {
|
||||||
return `limit ${ATTRIBUTE_NAMES[this.attrcode]} to ${this.value}`;
|
let attrname = SHIP_ATTRIBUTES[this.attrcode].name;
|
||||||
|
return `limit ${attrname} to ${this.value}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/// <reference path="BaseEffect.ts"/>
|
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
// Effect on attribute maximum
|
|
||||||
// Typically, these effects are summed up to define an attribute maximum
|
|
||||||
export class AttributeMaxEffect extends BaseEffect {
|
|
||||||
// Affected attribute
|
|
||||||
attrcode: AttributeCode;
|
|
||||||
|
|
||||||
// Value to add to the maximum
|
|
||||||
value: number;
|
|
||||||
|
|
||||||
constructor(attrcode: AttributeCode, value: number) {
|
|
||||||
super("attrmax");
|
|
||||||
|
|
||||||
this.attrcode = attrcode;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullCode(): string {
|
|
||||||
return this.code + "-" + AttributeCode[this.attrcode].toLowerCase().replace("_", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
/// <reference path="BaseEffect.ts"/>
|
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
// Effect on attribute value
|
|
||||||
// Typically, these effects are summed up to define an attribute value
|
|
||||||
export class AttributeValueEffect extends BaseEffect {
|
|
||||||
// Affected attribute
|
|
||||||
attrcode: AttributeCode;
|
|
||||||
|
|
||||||
// Value to contribute
|
|
||||||
value: number;
|
|
||||||
|
|
||||||
constructor(attrcode: AttributeCode, value: number) {
|
|
||||||
super("attr");
|
|
||||||
|
|
||||||
this.attrcode = attrcode;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullCode(): string {
|
|
||||||
return this.code + "-" + AttributeCode[this.attrcode].toLowerCase().replace("_", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,11 @@
|
||||||
/// <reference path="BaseEffect.ts"/>
|
/// <reference path="BaseEffect.ts"/>
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
module TS.SpaceTac.Game {
|
||||||
// Apply damage to a ship
|
/**
|
||||||
|
* Apply damage on a ship.
|
||||||
|
*
|
||||||
|
* Damage is applied on shield while there is some, then on the hull.
|
||||||
|
*/
|
||||||
export class DamageEffect extends BaseEffect {
|
export class DamageEffect extends BaseEffect {
|
||||||
// Base damage points
|
// Base damage points
|
||||||
value: number;
|
value: number;
|
||||||
|
@ -18,16 +22,16 @@ module TS.SpaceTac.Game {
|
||||||
var shield: number;
|
var shield: number;
|
||||||
|
|
||||||
// Apply on shields
|
// Apply on shields
|
||||||
if (damage >= ship.shield.current) {
|
if (damage >= ship.values.shield.get()) {
|
||||||
shield = ship.shield.current;
|
shield = ship.values.shield.get();
|
||||||
} else {
|
} else {
|
||||||
shield = damage;
|
shield = damage;
|
||||||
}
|
}
|
||||||
damage -= shield;
|
damage -= shield;
|
||||||
|
|
||||||
// Apply on hull
|
// Apply on hull
|
||||||
if (damage >= ship.hull.current) {
|
if (damage >= ship.values.hull.get()) {
|
||||||
hull = ship.hull.current;
|
hull = ship.values.hull.get();
|
||||||
} else {
|
} else {
|
||||||
hull = damage;
|
hull = damage;
|
||||||
}
|
}
|
||||||
|
|
18
src/game/effects/ValueEffect.spec.ts
Normal file
18
src/game/effects/ValueEffect.spec.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
describe("ValueEffect", function () {
|
||||||
|
it("adds an amount to a ship value", function () {
|
||||||
|
let effect = new ValueEffect("shield", 20);
|
||||||
|
|
||||||
|
let ship = new Ship();
|
||||||
|
ship.values.shield.setMaximal(80);
|
||||||
|
ship.setValue("shield", 55);
|
||||||
|
expect(ship.values.shield.get()).toEqual(55);
|
||||||
|
|
||||||
|
effect.applyOnShip(ship);
|
||||||
|
expect(ship.values.shield.get()).toEqual(75);
|
||||||
|
|
||||||
|
effect.applyOnShip(ship);
|
||||||
|
expect(ship.values.shield.get()).toEqual(80);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
35
src/game/effects/ValueEffect.ts
Normal file
35
src/game/effects/ValueEffect.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/// <reference path="BaseEffect.ts"/>
|
||||||
|
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
/**
|
||||||
|
* Effect to add (or subtract if negative) an amount to a ship value.
|
||||||
|
*
|
||||||
|
* The effect is immediate and permanent.
|
||||||
|
*/
|
||||||
|
export class ValueEffect extends BaseEffect {
|
||||||
|
// Affected value
|
||||||
|
valuetype: keyof ShipValues;
|
||||||
|
|
||||||
|
// Value to add (or subtract if negative)
|
||||||
|
value: number;
|
||||||
|
|
||||||
|
constructor(valuetype: keyof ShipValues, value: number) {
|
||||||
|
super("value");
|
||||||
|
|
||||||
|
this.valuetype = valuetype;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyOnShip(ship: Ship): boolean {
|
||||||
|
return ship.setValue(this.valuetype, this.value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
isBeneficial(): boolean {
|
||||||
|
return this.value >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFullCode(): string {
|
||||||
|
return `${this.code}-${this.valuetype}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ module TS.SpaceTac.Game.Specs {
|
||||||
|
|
||||||
it("can't fire without sufficient AP", function () {
|
it("can't fire without sufficient AP", function () {
|
||||||
var ship = new Ship();
|
var ship = new Ship();
|
||||||
ship.ap_current.set(3);
|
ship.values.power.set(3);
|
||||||
|
|
||||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50);
|
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50);
|
||||||
|
|
||||||
|
@ -104,15 +104,15 @@ module TS.SpaceTac.Game.Specs {
|
||||||
var fleet2 = new Fleet(new Player());
|
var fleet2 = new Fleet(new Player());
|
||||||
|
|
||||||
var ship1 = new Ship(fleet1);
|
var ship1 = new Ship(fleet1);
|
||||||
ship1.ap_current.set(50);
|
ship1.values.power.set(50);
|
||||||
|
|
||||||
var ship2 = new Ship(fleet2);
|
var ship2 = new Ship(fleet2);
|
||||||
ship2.hull.setMaximal(100);
|
ship2.setAttribute("hull_capacity", 100);
|
||||||
ship2.shield.setMaximal(30);
|
ship2.setAttribute("shield_capacity", 30);
|
||||||
ship2.restoreHealth();
|
ship2.restoreHealth();
|
||||||
|
|
||||||
expect(ship2.hull.current).toEqual(100);
|
expect(ship2.values.hull.get()).toEqual(100);
|
||||||
expect(ship2.shield.current).toEqual(30);
|
expect(ship2.values.shield.get()).toEqual(30);
|
||||||
|
|
||||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 20);
|
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 20);
|
||||||
weapon.ap_usage = new IntegerRange(1, 1);
|
weapon.ap_usage = new IntegerRange(1, 1);
|
||||||
|
@ -120,19 +120,19 @@ module TS.SpaceTac.Game.Specs {
|
||||||
var equipment = weapon.generateFixed(0);
|
var equipment = weapon.generateFixed(0);
|
||||||
|
|
||||||
equipment.action.apply(null, ship1, Target.newFromShip(ship2));
|
equipment.action.apply(null, ship1, Target.newFromShip(ship2));
|
||||||
expect(ship2.hull.current).toEqual(100);
|
expect(ship2.values.hull.get()).toEqual(100);
|
||||||
expect(ship2.shield.current).toEqual(10);
|
expect(ship2.values.shield.get()).toEqual(10);
|
||||||
expect(ship1.ap_current.current).toEqual(49);
|
expect(ship1.values.power.get()).toEqual(49);
|
||||||
|
|
||||||
equipment.action.apply(null, ship1, Target.newFromShip(ship2));
|
equipment.action.apply(null, ship1, Target.newFromShip(ship2));
|
||||||
expect(ship2.hull.current).toEqual(90);
|
expect(ship2.values.hull.get()).toEqual(90);
|
||||||
expect(ship2.shield.current).toEqual(0);
|
expect(ship2.values.shield.get()).toEqual(0);
|
||||||
expect(ship1.ap_current.current).toEqual(48);
|
expect(ship1.values.power.get()).toEqual(48);
|
||||||
|
|
||||||
equipment.action.apply(null, ship1, Target.newFromShip(ship2));
|
equipment.action.apply(null, ship1, Target.newFromShip(ship2));
|
||||||
expect(ship2.hull.current).toEqual(70);
|
expect(ship2.values.hull.get()).toEqual(70);
|
||||||
expect(ship2.shield.current).toEqual(0);
|
expect(ship2.values.shield.get()).toEqual(0);
|
||||||
expect(ship1.ap_current.current).toEqual(47);
|
expect(ship1.values.power.get()).toEqual(47);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
|
|
||||||
this.min_level = new IntegerRange(1, 3);
|
this.min_level = new IntegerRange(1, 3);
|
||||||
|
|
||||||
this.addPermanentAttributeMaxEffect(AttributeCode.Shield, 100, 200);
|
this.addAttributeEffect("shield_capacity", 100, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
|
|
||||||
this.min_level = new IntegerRange(1, 1);
|
this.min_level = new IntegerRange(1, 1);
|
||||||
|
|
||||||
this.addPermanentAttributeMaxEffect(AttributeCode.Initiative, 1);
|
this.addAttributeEffect("initiative", 1);
|
||||||
this.addPermanentAttributeMaxEffect(AttributeCode.Power, 8);
|
this.addAttributeEffect("power_capacity", 8);
|
||||||
this.addPermanentAttributeValueEffect(AttributeCode.Power_Initial, 5);
|
this.addAttributeEffect("power_initial", 5);
|
||||||
this.addPermanentAttributeValueEffect(AttributeCode.Power_Recovery, 4);
|
this.addAttributeEffect("power_recovery", 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
this.distance = new Range(100, 100);
|
this.distance = new Range(100, 100);
|
||||||
this.ap_usage = new IntegerRange(1);
|
this.ap_usage = new IntegerRange(1);
|
||||||
|
|
||||||
this.addPermanentAttributeMaxEffect(AttributeCode.Initiative, 1);
|
this.addAttributeEffect("initiative", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getActionForEquipment(equipment: Equipment): BaseAction {
|
protected getActionForEquipment(equipment: Equipment): BaseAction {
|
||||||
|
|
|
@ -7,7 +7,7 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
|
|
||||||
this.min_level = new IntegerRange(1, 3);
|
this.min_level = new IntegerRange(1, 3);
|
||||||
|
|
||||||
this.addPermanentAttributeMaxEffect(AttributeCode.Hull, 100, 200);
|
this.addAttributeEffect("hull_capacity", 100, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,29 +9,29 @@ module TS.SpaceTac.Game.Specs {
|
||||||
TestTools.setShipAP(target, 7, 2);
|
TestTools.setShipAP(target, 7, 2);
|
||||||
spyOn(equipment.action, "canBeUsed").and.returnValue(true);
|
spyOn(equipment.action, "canBeUsed").and.returnValue(true);
|
||||||
|
|
||||||
expect(target.ap_current.current).toBe(7);
|
expect(target.values.power.get()).toBe(7);
|
||||||
expect(target.sticky_effects).toEqual([]);
|
expect(target.sticky_effects).toEqual([]);
|
||||||
|
|
||||||
// Attribute is immediately limited
|
// Attribute is immediately limited
|
||||||
equipment.action.apply(null, ship, Target.newFromShip(target));
|
equipment.action.apply(null, ship, Target.newFromShip(target));
|
||||||
|
|
||||||
expect(target.ap_current.current).toBe(4);
|
expect(target.values.power.get()).toBe(4);
|
||||||
expect(target.sticky_effects).toEqual([
|
expect(target.sticky_effects).toEqual([
|
||||||
new StickyEffect(new AttributeLimitEffect(AttributeCode.Power, 4), 1, true, false)
|
new StickyEffect(new AttributeLimitEffect("power_capacity", 4), 1, true, false)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Attribute is limited for one turn, and prevents AP recovery
|
// Attribute is limited for one turn, and prevents AP recovery
|
||||||
target.ap_current.set(6);
|
target.values.power.set(6);
|
||||||
target.recoverActionPoints();
|
target.recoverActionPoints();
|
||||||
target.startTurn();
|
target.startTurn();
|
||||||
|
|
||||||
expect(target.ap_current.current).toBe(4);
|
expect(target.values.power.get()).toBe(4);
|
||||||
expect(target.sticky_effects).toEqual([]);
|
expect(target.sticky_effects).toEqual([]);
|
||||||
|
|
||||||
// Effect vanished, so AP recovery happens
|
// Effect vanished, so AP recovery happens
|
||||||
target.endTurn();
|
target.endTurn();
|
||||||
|
|
||||||
expect(target.ap_current.current).toBe(6);
|
expect(target.values.power.get()).toBe(6);
|
||||||
expect(target.sticky_effects).toEqual([]);
|
expect(target.sticky_effects).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
this.ap_usage = new IntegerRange(4, 5);
|
this.ap_usage = new IntegerRange(4, 5);
|
||||||
this.min_level = new IntegerRange(1, 3);
|
this.min_level = new IntegerRange(1, 3);
|
||||||
|
|
||||||
this.addSticky(new AttributeLimitEffect(AttributeCode.Power), 4, 3, 1, 2, true);
|
this.addSticky(new AttributeLimitEffect("power_capacity"), 4, 3, 1, 2, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
let template = new RepairDrone();
|
let template = new RepairDrone();
|
||||||
|
|
||||||
let equipment = template.generateFixed(0);
|
let equipment = template.generateFixed(0);
|
||||||
expect(equipment.target_effects).toEqual([new AttributeAddEffect(AttributeCode.Hull, 10)]);
|
expect(equipment.target_effects).toEqual([new ValueEffect("hull", 10)]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ module TS.SpaceTac.Game.Equipments {
|
||||||
this.setEffectRadius(40, 80);
|
this.setEffectRadius(40, 80);
|
||||||
this.setPowerConsumption(4, 5);
|
this.setPowerConsumption(4, 5);
|
||||||
|
|
||||||
this.addAttributeAddEffect(AttributeCode.Hull, 10, 20);
|
this.addValueEffectOnTarget("hull", 10, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,17 +21,17 @@ module TS.SpaceTac.Game.Specs {
|
||||||
(<DamageEffect>equipment.target_effects[0]).value = 20;
|
(<DamageEffect>equipment.target_effects[0]).value = 20;
|
||||||
|
|
||||||
var checkHP = (h1: number, s1: number, h2: number, s2: number, h3: number, s3: number): void => {
|
var checkHP = (h1: number, s1: number, h2: number, s2: number, h3: number, s3: number): void => {
|
||||||
expect(ship.hull.current).toBe(h1);
|
expect(ship.values.hull.get()).toBe(h1);
|
||||||
expect(ship.shield.current).toBe(s1);
|
expect(ship.values.shield.get()).toBe(s1);
|
||||||
expect(enemy1.hull.current).toBe(h2);
|
expect(enemy1.values.hull.get()).toBe(h2);
|
||||||
expect(enemy1.shield.current).toBe(s2);
|
expect(enemy1.values.shield.get()).toBe(s2);
|
||||||
expect(enemy2.hull.current).toBe(h3);
|
expect(enemy2.values.hull.get()).toBe(h3);
|
||||||
expect(enemy2.shield.current).toBe(s3);
|
expect(enemy2.values.shield.get()).toBe(s3);
|
||||||
};
|
};
|
||||||
checkHP(50, 30, 50, 30, 50, 30);
|
checkHP(50, 30, 50, 30, 50, 30);
|
||||||
|
|
||||||
battle.log.clear();
|
battle.log.clear();
|
||||||
battle.log.addFilter("attr");
|
battle.log.addFilter("value");
|
||||||
|
|
||||||
// Fire at a ship
|
// Fire at a ship
|
||||||
var t = Target.newFromShip(enemy1);
|
var t = Target.newFromShip(enemy1);
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
/// <reference path="BaseLogEvent.ts"/>
|
|
||||||
|
|
||||||
module TS.SpaceTac.Game {
|
|
||||||
// Event logged when a ship moves
|
|
||||||
export class AttributeChangeEvent extends BaseLogEvent {
|
|
||||||
// Saved version of the attribute
|
|
||||||
attribute: Attribute;
|
|
||||||
|
|
||||||
constructor(ship: Ship, attribute: Attribute) {
|
|
||||||
super("attr", ship);
|
|
||||||
|
|
||||||
this.attribute = copy(attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
15
src/game/events/ValueChangeEvent.ts
Normal file
15
src/game/events/ValueChangeEvent.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/// <reference path="BaseLogEvent.ts"/>
|
||||||
|
|
||||||
|
module TS.SpaceTac.Game {
|
||||||
|
// Event logged when a ship value or attribute changed
|
||||||
|
export class ValueChangeEvent extends BaseLogEvent {
|
||||||
|
// Saved version of the value
|
||||||
|
value: ShipValue;
|
||||||
|
|
||||||
|
constructor(ship: Ship, value: ShipValue) {
|
||||||
|
super("value", ship);
|
||||||
|
|
||||||
|
this.value = copy(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,8 +47,8 @@ module TS.SpaceTac.View.Specs {
|
||||||
battleview.battle.playing_ship = ship;
|
battleview.battle.playing_ship = ship;
|
||||||
battleview.player = ship.getPlayer();
|
battleview.player = ship.getPlayer();
|
||||||
|
|
||||||
ship.ap_current.setMaximal(10);
|
ship.setAttribute("power_capacity", 10);
|
||||||
ship.ap_current.set(9);
|
ship.setValue("power", 9);
|
||||||
bar.setShip(ship);
|
bar.setShip(ship);
|
||||||
|
|
||||||
expect(bar.actions.length).toBe(4);
|
expect(bar.actions.length).toBe(4);
|
||||||
|
@ -75,19 +75,19 @@ module TS.SpaceTac.View.Specs {
|
||||||
bar.actionEnded();
|
bar.actionEnded();
|
||||||
|
|
||||||
// Not enough AP for both weapons
|
// Not enough AP for both weapons
|
||||||
ship.ap_current.set(7);
|
ship.setValue("power", 7);
|
||||||
bar.actions[2].processClick();
|
bar.actions[2].processClick();
|
||||||
checkFading([1, 2], [0, 3]);
|
checkFading([1, 2], [0, 3]);
|
||||||
bar.actionEnded();
|
bar.actionEnded();
|
||||||
|
|
||||||
// Not enough AP to move
|
// Not enough AP to move
|
||||||
ship.ap_current.set(3);
|
ship.setValue("power", 3);
|
||||||
bar.actions[1].processClick();
|
bar.actions[1].processClick();
|
||||||
checkFading([0, 1, 2], [3]);
|
checkFading([0, 1, 2], [3]);
|
||||||
bar.actionEnded();
|
bar.actionEnded();
|
||||||
|
|
||||||
// Dynamic AP usage for move actions
|
// Dynamic AP usage for move actions
|
||||||
ship.ap_current.set(6);
|
ship.setValue("power", 6);
|
||||||
bar.actions[0].processClick();
|
bar.actions[0].processClick();
|
||||||
checkFading([], [0, 1, 2, 3]);
|
checkFading([], [0, 1, 2, 3]);
|
||||||
bar.actions[0].processHover(Game.Target.newFromLocation(2, 8));
|
bar.actions[0].processHover(Game.Target.newFromLocation(2, 8));
|
||||||
|
|
|
@ -65,8 +65,8 @@ module TS.SpaceTac.View {
|
||||||
// Update the action points indicator
|
// Update the action points indicator
|
||||||
updateActionPoints(): void {
|
updateActionPoints(): void {
|
||||||
if (this.ship) {
|
if (this.ship) {
|
||||||
this.actionpoints.setValue(this.ship.ap_current.current, this.ship.ap_current.maximal);
|
this.actionpoints.setValue(this.ship.values.power.get(), this.ship.attributes.power_capacity.get());
|
||||||
this.actionpointstemp.setValue(this.ship.ap_current.current, this.ship.ap_current.maximal);
|
this.actionpointstemp.setValue(this.ship.values.power.get(), this.ship.attributes.power_capacity.get());
|
||||||
this.actionpoints.visible = true;
|
this.actionpoints.visible = true;
|
||||||
this.actionpointstemp.visible = true;
|
this.actionpointstemp.visible = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,7 +78,7 @@ module TS.SpaceTac.View {
|
||||||
// Update fading flags
|
// Update fading flags
|
||||||
// ap_usage is the consumption of currently selected action
|
// ap_usage is the consumption of currently selected action
|
||||||
updateFadings(ap_usage: number): void {
|
updateFadings(ap_usage: number): void {
|
||||||
var remaining_ap = this.ship.ap_current.current - ap_usage;
|
var remaining_ap = this.ship.values.power.get() - ap_usage;
|
||||||
if (remaining_ap < 0) {
|
if (remaining_ap < 0) {
|
||||||
remaining_ap = 0;
|
remaining_ap = 0;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ module TS.SpaceTac.View {
|
||||||
this.actions.forEach((icon: ActionIcon) => {
|
this.actions.forEach((icon: ActionIcon) => {
|
||||||
icon.updateFadingStatus(remaining_ap);
|
icon.updateFadingStatus(remaining_ap);
|
||||||
});
|
});
|
||||||
this.actionpointstemp.setValue(remaining_ap, this.ship.ap_current.maximal);
|
this.actionpointstemp.setValue(remaining_ap, this.ship.attributes.power_capacity.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set action icons from selected ship
|
// Set action icons from selected ship
|
||||||
|
|
|
@ -143,7 +143,7 @@ module TS.SpaceTac.View {
|
||||||
}
|
}
|
||||||
this.setSelected(false);
|
this.setSelected(false);
|
||||||
this.updateActiveStatus();
|
this.updateActiveStatus();
|
||||||
this.updateFadingStatus(this.ship.ap_current.current);
|
this.updateFadingStatus(this.ship.values.power.get());
|
||||||
this.battleview.arena.range_hint.clearPrimary();
|
this.battleview.arena.range_hint.clearPrimary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,8 @@ module TS.SpaceTac.View {
|
||||||
case "move":
|
case "move":
|
||||||
this.processMoveEvent(<Game.MoveEvent>event);
|
this.processMoveEvent(<Game.MoveEvent>event);
|
||||||
break;
|
break;
|
||||||
case "attr":
|
case "value":
|
||||||
this.processAttributeChangedEvent(<Game.AttributeChangeEvent>event);
|
this.processValueChangedEvent(<Game.ValueChangeEvent>event);
|
||||||
break;
|
break;
|
||||||
case "death":
|
case "death":
|
||||||
this.processDeathEvent(<Game.DeathEvent>event);
|
this.processDeathEvent(<Game.DeathEvent>event);
|
||||||
|
@ -97,12 +97,13 @@ module TS.SpaceTac.View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ship attribute changed
|
// Ship value changed
|
||||||
private processAttributeChangedEvent(event: Game.AttributeChangeEvent): void {
|
private processValueChangedEvent(event: Game.ValueChangeEvent): void {
|
||||||
var item = this.view.ship_list.findItem(event.ship);
|
var item = this.view.ship_list.findItem(event.ship);
|
||||||
if (item) {
|
if (item) {
|
||||||
item.attributeChanged(event.attribute);
|
item.updateAttributes();
|
||||||
}
|
}
|
||||||
|
// TODO Update tooltip
|
||||||
}
|
}
|
||||||
|
|
||||||
// A ship died
|
// A ship died
|
||||||
|
|
|
@ -4,15 +4,15 @@ module TS.SpaceTac.View {
|
||||||
// Reference to the ship game object
|
// Reference to the ship game object
|
||||||
ship: Game.Ship;
|
ship: Game.Ship;
|
||||||
|
|
||||||
// Energy display
|
|
||||||
energy: ValueBar;
|
|
||||||
|
|
||||||
// Hull display
|
// Hull display
|
||||||
hull: ValueBar;
|
hull: ValueBar;
|
||||||
|
|
||||||
// Shield display
|
// Shield display
|
||||||
shield: ValueBar;
|
shield: ValueBar;
|
||||||
|
|
||||||
|
// Power display
|
||||||
|
power: ValueBar;
|
||||||
|
|
||||||
// Portrait
|
// Portrait
|
||||||
layer_portrait: Phaser.Image;
|
layer_portrait: Phaser.Image;
|
||||||
|
|
||||||
|
@ -52,8 +52,8 @@ module TS.SpaceTac.View {
|
||||||
this.shield = ValueBar.newStyled(this.game, "battle-shiplist-shield", 98, 39, true);
|
this.shield = ValueBar.newStyled(this.game, "battle-shiplist-shield", 98, 39, true);
|
||||||
this.addChild(this.shield);
|
this.addChild(this.shield);
|
||||||
|
|
||||||
this.energy = ValueBar.newStyled(this.game, "battle-shiplist-energy", 106, 39, true);
|
this.power = ValueBar.newStyled(this.game, "battle-shiplist-energy", 106, 39, true);
|
||||||
this.addChild(this.energy);
|
this.addChild(this.power);
|
||||||
|
|
||||||
this.updateAttributes();
|
this.updateAttributes();
|
||||||
this.updateEffects();
|
this.updateEffects();
|
||||||
|
@ -63,9 +63,9 @@ module TS.SpaceTac.View {
|
||||||
|
|
||||||
// Update attributes from associated ship
|
// Update attributes from associated ship
|
||||||
updateAttributes() {
|
updateAttributes() {
|
||||||
this.attributeChanged(this.ship.hull);
|
this.hull.setValue(this.ship.values.hull.get(), this.ship.attributes.hull_capacity.get());
|
||||||
this.attributeChanged(this.ship.shield);
|
this.shield.setValue(this.ship.values.shield.get(), this.ship.attributes.shield_capacity.get());
|
||||||
this.attributeChanged(this.ship.ap_current);
|
this.power.setValue(this.ship.values.power.get(), this.ship.attributes.power_capacity.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update effects applied on the ship
|
// Update effects applied on the ship
|
||||||
|
@ -81,17 +81,6 @@ module TS.SpaceTac.View {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when an attribute for this ship changed through the battle log
|
|
||||||
attributeChanged(attribute: Game.Attribute): void {
|
|
||||||
if (attribute.code === Game.AttributeCode.Hull) {
|
|
||||||
this.hull.setValue(attribute.current, attribute.maximal);
|
|
||||||
} else if (attribute.code === Game.AttributeCode.Shield) {
|
|
||||||
this.shield.setValue(attribute.current, attribute.maximal);
|
|
||||||
} else if (attribute.code === Game.AttributeCode.Power) {
|
|
||||||
this.energy.setValue(attribute.current, attribute.maximal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flash a damage indicator
|
// Flash a damage indicator
|
||||||
setDamageHit() {
|
setDamageHit() {
|
||||||
this.game.tweens.create(this.layer_damage).to({ alpha: 1 }, 100).to({ alpha: 0 }, 150).repeatAll(2).start();
|
this.game.tweens.create(this.layer_damage).to({ alpha: 1 }, 100).to({ alpha: 0 }, 150).repeatAll(2).start();
|
||||||
|
|
|
@ -92,15 +92,15 @@ module TS.SpaceTac.View {
|
||||||
|
|
||||||
// Fill info
|
// Fill info
|
||||||
this.title.setText(ship.name);
|
this.title.setText(ship.name);
|
||||||
this.attr_hull.setText(ship.hull.current.toString());
|
this.attr_hull.setText(ship.values.hull.get().toString());
|
||||||
this.attr_shield.setText(ship.shield.current.toString());
|
this.attr_shield.setText(ship.values.shield.get().toString());
|
||||||
this.attr_power.setText(ship.ap_current.current.toString());
|
this.attr_power.setText(ship.values.power.get().toString());
|
||||||
this.attr_materials.setText(ship.cap_material.current.toString());
|
this.attr_materials.setText(ship.attributes.skill_material.get().toString());
|
||||||
this.attr_electronics.setText(ship.cap_electronics.current.toString());
|
this.attr_electronics.setText(ship.attributes.skill_electronics.get().toString());
|
||||||
this.attr_energy.setText(ship.cap_energy.current.toString());
|
this.attr_energy.setText(ship.attributes.skill_energy.get().toString());
|
||||||
this.attr_human.setText(ship.cap_human.current.toString());
|
this.attr_human.setText(ship.attributes.skill_human.get().toString());
|
||||||
this.attr_gravity.setText(ship.cap_gravity.current.toString());
|
this.attr_gravity.setText(ship.attributes.skill_gravity.get().toString());
|
||||||
this.attr_time.setText(ship.cap_time.current.toString());
|
this.attr_time.setText(ship.attributes.skill_time.get().toString());
|
||||||
this.active_effects.removeAll(true);
|
this.active_effects.removeAll(true);
|
||||||
ship.sticky_effects.forEach((effect, index) => {
|
ship.sticky_effects.forEach((effect, index) => {
|
||||||
this.addEffect(effect, index);
|
this.addEffect(effect, index);
|
||||||
|
@ -123,7 +123,7 @@ module TS.SpaceTac.View {
|
||||||
this.active_effects.addChild(effect_group);
|
this.active_effects.addChild(effect_group);
|
||||||
|
|
||||||
if (effect.base instanceof Game.AttributeLimitEffect) {
|
if (effect.base instanceof Game.AttributeLimitEffect) {
|
||||||
let attr_name = Game.AttributeCode[effect.base.attrcode].toLowerCase().replace('_', '');
|
let attr_name = effect.base.attrcode.replace('_', '');
|
||||||
let attr_icon = new Phaser.Image(this.game, 30, effect_group.height / 2, `battle-attributes-${attr_name}`);
|
let attr_icon = new Phaser.Image(this.game, 30, effect_group.height / 2, `battle-attributes-${attr_name}`);
|
||||||
attr_icon.anchor.set(0.5, 0.5);
|
attr_icon.anchor.set(0.5, 0.5);
|
||||||
attr_icon.scale.set(0.17, 0.17);
|
attr_icon.scale.set(0.17, 0.17);
|
||||||
|
|
Loading…
Reference in a new issue