Refactored equipment/action system for leveled equipment generation
This commit is contained in:
parent
b5be5575b3
commit
088ed18391
2
TODO
2
TODO
|
@ -5,6 +5,8 @@
|
|||
* Character sheet: paginate loot and shop items
|
||||
* Character sheet: improve eye-catching for shop and loot section
|
||||
* Shops: add equipment pricing, with usage depreciation
|
||||
* Add permanent effects to ship models to ease balancing
|
||||
* Ships should start battle in formation to force them to move
|
||||
* Fix targetting not resetting when using action shortcuts
|
||||
* Add battle statistics and/or critics in outcome dialog
|
||||
* Add battle experience
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"build": "tsc -p .",
|
||||
"pretest": "tsc -p .",
|
||||
"test": "karma start spec/support/karma.conf.js && remap-istanbul -i out/coverage/coverage.json -o out/coverage -t html",
|
||||
"prestart": "tsc -p .",
|
||||
"prestart": "tsc -p . || true",
|
||||
"start": "live-server out --host=127.0.0.1 --port=8012 --ignore=coverage",
|
||||
"codecov": "remap-istanbul -i out/coverage/coverage.json -o out/coverage/mapped.json -t json && codecov -f out/coverage/mapped.json"
|
||||
},
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2b11ca44c3dcf368baa9099467842750aa176be7
|
||||
Subproject commit 3092ff0f3b8af5fd1525480c5ec7033741cac100
|
|
@ -35,8 +35,7 @@ module TS.SpaceTac.Specs {
|
|||
// Force lucky finds with one template
|
||||
var looter = new LootGenerator(random, false);
|
||||
var template = new LootTemplate(SlotType.Power, "Nuclear Reactor");
|
||||
template.min_level.set(3, 7);
|
||||
template.distance.set(0, 5);
|
||||
template.setSkillsRequirements({ "skill_energy": istep(4) });
|
||||
looter.templates = [template];
|
||||
spyOn(outcome, "getLootGenerator").and.returnValue(looter);
|
||||
|
||||
|
@ -45,11 +44,9 @@ module TS.SpaceTac.Specs {
|
|||
expect(outcome.loot.length).toBe(3);
|
||||
expect(outcome.loot[0].name).toBe("0a");
|
||||
expect(outcome.loot[1].name).toBe("Nuclear Reactor");
|
||||
expect(outcome.loot[1].min_level).toBe(4);
|
||||
expect(outcome.loot[1].distance).toEqual(1);
|
||||
expect(outcome.loot[1].requirements).toEqual({ "skill_energy": 7 });
|
||||
expect(outcome.loot[2].name).toBe("Nuclear Reactor");
|
||||
expect(outcome.loot[2].min_level).toBe(6);
|
||||
expect(outcome.loot[2].distance).toBeCloseTo(4, 0.000001);
|
||||
expect(outcome.loot[2].requirements).toEqual({ "skill_energy": 9 });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ module TS.SpaceTac {
|
|||
// The equipment will be in the dead ship range
|
||||
generateLootItem(random: RandomGenerator, base_level: number): Equipment | null {
|
||||
var generator = this.getLootGenerator(random);
|
||||
var level = new IntegerRange(base_level - 1, base_level + 1);
|
||||
var level = random.randInt(Math.max(base_level - 1, 1), base_level + 1);
|
||||
return generator.generate(level);
|
||||
}
|
||||
}
|
||||
|
|
26
src/core/Cooldown.spec.ts
Normal file
26
src/core/Cooldown.spec.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("Cooldown", function () {
|
||||
it("applies overheat and cooldown", function () {
|
||||
let cooldown = new Cooldown();
|
||||
expect(cooldown.canUse()).toBe(true);
|
||||
|
||||
cooldown.configure(2, 3);
|
||||
expect(cooldown.canUse()).toBe(true);
|
||||
|
||||
cooldown.use();
|
||||
expect(cooldown.canUse()).toBe(true);
|
||||
|
||||
cooldown.use();
|
||||
expect(cooldown.canUse()).toBe(false);
|
||||
|
||||
cooldown.cool();
|
||||
expect(cooldown.canUse()).toBe(false);
|
||||
|
||||
cooldown.cool();
|
||||
expect(cooldown.canUse()).toBe(false);
|
||||
|
||||
cooldown.cool();
|
||||
expect(cooldown.canUse()).toBe(true);
|
||||
});
|
||||
});
|
||||
}
|
53
src/core/Cooldown.ts
Normal file
53
src/core/Cooldown.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
module TS.SpaceTac {
|
||||
/**
|
||||
* Cooldown system for equipments
|
||||
*/
|
||||
export class Cooldown {
|
||||
// Number of uses in the current turn
|
||||
uses = 0
|
||||
|
||||
// Accumulated heat to dissipate (number of turns)
|
||||
heat = 0
|
||||
|
||||
// Maximum number of uses allowed per turn before overheating (0 for unlimited)
|
||||
overheat = 0
|
||||
|
||||
// Number of turns needed to cooldown when overheated
|
||||
cooling = 0
|
||||
|
||||
/**
|
||||
* Check if the equipment can be used in regards to heat
|
||||
*/
|
||||
canUse(): boolean {
|
||||
return this.heat == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the overheat and cooling
|
||||
*/
|
||||
configure(overheat: number, cooling: number) {
|
||||
this.overheat = overheat;
|
||||
this.cooling = cooling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the equipment, increasing the heat
|
||||
*/
|
||||
use(): void {
|
||||
this.uses += 1;
|
||||
if (this.uses >= this.overheat) {
|
||||
this.heat = this.cooling;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply one cooling-down step if necessary
|
||||
*/
|
||||
cool(): void {
|
||||
this.uses = 0;
|
||||
if (this.heat > 0) {
|
||||
this.heat -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("EffectTemplate", () => {
|
||||
it("interpolates between weak and strong effects", () => {
|
||||
var base_effect = new AttributeEffect("hull_capacity", 6);
|
||||
var template = new EffectTemplate(base_effect);
|
||||
|
||||
template.addModifier("value", new Range(2, 8));
|
||||
|
||||
var effect = <AttributeEffect>template.generateFixed(0.0);
|
||||
expect(effect.code).toEqual("attr");
|
||||
expect(effect.value).toEqual(2);
|
||||
|
||||
effect = <AttributeEffect>template.generateFixed(1.0);
|
||||
expect(effect.code).toEqual("attr");
|
||||
expect(effect.value).toEqual(8);
|
||||
|
||||
effect = <AttributeEffect>template.generateFixed(0.5);
|
||||
expect(effect.code).toEqual("attr");
|
||||
expect(effect.value).toEqual(5);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
module TS.SpaceTac {
|
||||
// Modifier for a value of a BaseEffect subclass
|
||||
export class EffectTemplateModifier {
|
||||
// Value name
|
||||
name: string;
|
||||
|
||||
// Range of values (similar to ranges in LootTemplate)
|
||||
range: Range;
|
||||
|
||||
// Basic constructor
|
||||
constructor(name: string, range: Range) {
|
||||
this.name = name;
|
||||
this.range = range;
|
||||
}
|
||||
}
|
||||
|
||||
// Template used to generate a BaseEffect
|
||||
export class EffectTemplate {
|
||||
// Basic instance of the effect
|
||||
effect: BaseEffect;
|
||||
|
||||
// Effect value modifiers
|
||||
modifiers: EffectTemplateModifier[];
|
||||
|
||||
// Basic constructor
|
||||
constructor(effect: BaseEffect) {
|
||||
this.effect = effect;
|
||||
this.modifiers = [];
|
||||
}
|
||||
|
||||
// Add a value modifier for the effect
|
||||
addModifier(name: string, range: Range) {
|
||||
this.modifiers.push(new EffectTemplateModifier(name, range));
|
||||
}
|
||||
|
||||
// Generate an effect with a given power
|
||||
generateFixed(power: number): BaseEffect {
|
||||
return this.effect.getModifiedCopy(this.modifiers, power);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,19 +33,38 @@ module TS.SpaceTac.Specs {
|
|||
});
|
||||
|
||||
it("generates a description of the effects", function () {
|
||||
var equipment = new Equipment();
|
||||
equipment.distance = 3;
|
||||
let equipment = new Equipment();
|
||||
expect(equipment.getActionDescription()).toEqual("does nothing");
|
||||
|
||||
equipment.target_effects.push(new DamageEffect(50));
|
||||
expect(equipment.getActionDescription()).toEqual("- 50 damage on target");
|
||||
let action = new FireWeaponAction(equipment, 1, 200, 0, [
|
||||
new DamageEffect(50)
|
||||
]);
|
||||
equipment.action = action;
|
||||
expect(equipment.getActionDescription()).toEqual("- Fire: 50 damage on target");
|
||||
|
||||
equipment.blast = 20;
|
||||
expect(equipment.getActionDescription()).toEqual("- 50 damage in 20km radius");
|
||||
action.blast = 20;
|
||||
expect(equipment.getActionDescription()).toEqual("- Fire: 50 damage in 20km radius");
|
||||
|
||||
equipment.blast = 0;
|
||||
equipment.target_effects.push(new StickyEffect(new AttributeLimitEffect("shield_capacity", 200), 3));
|
||||
expect(equipment.getActionDescription()).toEqual("- 50 damage on target\n- limit shield capacity to 200 for 3 turns on target");
|
||||
action.blast = 0;
|
||||
action.effects.push(new StickyEffect(new AttributeLimitEffect("shield_capacity", 200), 3));
|
||||
expect(equipment.getActionDescription()).toEqual("- Fire: 50 damage on target\n- Fire: limit shield capacity to 200 for 3 turns on target");
|
||||
});
|
||||
|
||||
it("gets a minimal level, based on skills requirements", function () {
|
||||
let equipment = new Equipment();
|
||||
expect(equipment.getMinimumLevel()).toBe(1);
|
||||
|
||||
equipment.requirements["skill_human"] = 10;
|
||||
expect(equipment.getMinimumLevel()).toBe(1);
|
||||
|
||||
equipment.requirements["skill_time"] = 1;
|
||||
expect(equipment.getMinimumLevel()).toBe(2);
|
||||
|
||||
equipment.requirements["skill_gravity"] = 2;
|
||||
expect(equipment.getMinimumLevel()).toBe(2);
|
||||
|
||||
equipment.requirements["skill_electronics"] = 4;
|
||||
expect(equipment.getMinimumLevel()).toBe(3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,53 +1,37 @@
|
|||
module TS.SpaceTac {
|
||||
// Piece of equipment to attach in slots
|
||||
export class Equipment {
|
||||
// Type of slot this equipment can fit in
|
||||
slot_type: SlotType | null;
|
||||
|
||||
// Actual slot this equipment is attached to
|
||||
attached_to: Slot | null = null;
|
||||
|
||||
// Type of slot this equipment can fit in
|
||||
slot: SlotType | null;
|
||||
|
||||
// Identifiable equipment code (may be used by UI to customize visual effects)
|
||||
code: string;
|
||||
|
||||
// Equipment name
|
||||
name: string;
|
||||
|
||||
// Maximal distance allowed to target
|
||||
distance: number;
|
||||
|
||||
// Effect area's radius
|
||||
blast: number;
|
||||
|
||||
// Duration
|
||||
duration: number;
|
||||
|
||||
// Action Points usage
|
||||
ap_usage: number;
|
||||
|
||||
// Level requirement
|
||||
min_level: number;
|
||||
|
||||
// Minimal attribute to be able to equip this equipment
|
||||
// Minimum skills to be able to equip this
|
||||
requirements: { [key: string]: number };
|
||||
|
||||
// Action associated with this equipment
|
||||
// Permanent effects on the ship that equips this
|
||||
effects: BaseEffect[];
|
||||
|
||||
// Action available when equipped
|
||||
action: BaseAction;
|
||||
|
||||
// Permanent effects on the ship that equips the equipment
|
||||
permanent_effects: BaseEffect[];
|
||||
|
||||
// Effects on target
|
||||
target_effects: BaseEffect[];
|
||||
// Usage made of this equipment (will lower the sell price)
|
||||
usage: number;
|
||||
|
||||
// Basic constructor
|
||||
constructor(slot: SlotType | null = null, code = "equipment") {
|
||||
this.slot = slot;
|
||||
this.slot_type = slot;
|
||||
this.code = code;
|
||||
this.name = code;
|
||||
this.requirements = {};
|
||||
this.permanent_effects = [];
|
||||
this.target_effects = [];
|
||||
this.effects = [];
|
||||
this.action = new BaseAction("nothing", "Do nothing", false);
|
||||
}
|
||||
|
||||
|
@ -55,8 +39,23 @@ module TS.SpaceTac {
|
|||
return this.attached_to ? `${this.attached_to.ship.name} - ${this.name}` : this.name;
|
||||
}
|
||||
|
||||
// Returns true if the equipment can be equipped on a ship
|
||||
// This checks *requirements* against the ship capabilities
|
||||
/**
|
||||
* Get the minimum level at which the requirements in skill may be fulfilled.
|
||||
*
|
||||
* This is informative and is not directly enforced. It will only be enforced by skills requirements.
|
||||
*/
|
||||
getMinimumLevel(): number {
|
||||
let points = sum(values(this.requirements));
|
||||
return ShipLevel.getLevelForPoints(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the equipment can be equipped on a ship.
|
||||
*
|
||||
* This checks *requirements* against the ship skills.
|
||||
*
|
||||
* This does not check where the equipment currently is (except if is it already attached and should be detached first).
|
||||
*/
|
||||
canBeEquipped(ship: Ship): boolean {
|
||||
if (this.attached_to) {
|
||||
return false;
|
||||
|
@ -71,7 +70,9 @@ module TS.SpaceTac {
|
|||
}
|
||||
}
|
||||
|
||||
// Detach from the slot it is attached to
|
||||
/**
|
||||
* Detach from the slot it is attached to
|
||||
*/
|
||||
detach(): void {
|
||||
if (this.attached_to) {
|
||||
this.attached_to.attached = null;
|
||||
|
@ -79,21 +80,21 @@ module TS.SpaceTac {
|
|||
}
|
||||
}
|
||||
|
||||
// Get a human readable description of the effects of this equipment
|
||||
/**
|
||||
* Get a human readable description of the effects of this equipment
|
||||
*/
|
||||
getActionDescription(): string {
|
||||
if (this.permanent_effects.length == 0 && this.target_effects.length == 0) {
|
||||
return "does nothing";
|
||||
} else {
|
||||
var result: string[] = [];
|
||||
this.target_effects.forEach(effect => {
|
||||
let suffix = this.blast ? `in ${this.blast}km radius` : "on target";
|
||||
if (effect instanceof StickyEffect) {
|
||||
suffix = `for ${effect.duration} turn${effect.duration > 1 ? "s" : ""} ${suffix}`;
|
||||
}
|
||||
result.push("- " + effect.getDescription() + " " + suffix);
|
||||
});
|
||||
return result.join("\n");
|
||||
}
|
||||
let parts: string[] = [];
|
||||
|
||||
this.effects.forEach(effect => {
|
||||
parts.push(`- Equip: ${effect.getDescription()}`);
|
||||
});
|
||||
|
||||
this.action.getEffectsDescription().forEach(desc => {
|
||||
parts.push(`- ${this.action.name}: ${desc}`);
|
||||
});
|
||||
|
||||
return parts.length > 0 ? parts.join("\n") : "does nothing";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ module TS.SpaceTac.Specs {
|
|||
constructor() {
|
||||
super(SlotType.Shield, "Hexagrid Shield");
|
||||
|
||||
this.min_level = new IntegerRange(2, 100);
|
||||
this.ap_usage = new Range(6, 15);
|
||||
this.setSkillsRequirements({ "skill_time": istep(2) });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,12 +15,11 @@ module TS.SpaceTac.Specs {
|
|||
generator.templates = [new TestTemplate()];
|
||||
generator.random = new SkewedRandomGenerator([0.5]);
|
||||
|
||||
var equipment = generator.generate(new IntegerRange(3, 6));
|
||||
var equipment = generator.generate(2);
|
||||
if (equipment) {
|
||||
expect(equipment.slot).toBe(SlotType.Shield);
|
||||
expect(equipment.slot_type).toBe(SlotType.Shield);
|
||||
expect(equipment.name).toEqual("Hexagrid Shield");
|
||||
expect(equipment.min_level).toBe(5);
|
||||
expect(equipment.ap_usage).toBeCloseTo(6.2727, 0.00001);
|
||||
expect(equipment.requirements).toEqual({ "skill_time": 3 });
|
||||
} else {
|
||||
fail("No equipment generated");
|
||||
}
|
||||
|
|
|
@ -31,29 +31,15 @@ module TS.SpaceTac {
|
|||
this.templates = templates;
|
||||
}
|
||||
|
||||
// Generate a random equipment
|
||||
// TODO Add generator from skills
|
||||
// TODO Add generator of other qualities
|
||||
|
||||
// Generate a random equipment for a specific level
|
||||
// If slot is specified, it will generate an equipment for this slot type specifically
|
||||
// If level is specified, it will generate an equipment with level requirement inside this range
|
||||
// If no equipment could be generated from available templates, null is returned
|
||||
generate(level: IntegerRange | null = null, slot: SlotType | null = null): Equipment | null {
|
||||
generate(level: number, slot: SlotType | null = null): Equipment | null {
|
||||
// Generate equipments matching conditions, with each template
|
||||
var equipments: Equipment[] = [];
|
||||
this.templates.forEach((template: LootTemplate) => {
|
||||
if (slot !== null && slot != template.slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
var equipment: Equipment | null;
|
||||
if (level) {
|
||||
equipment = template.generateInLevelRange(level, this.random);
|
||||
} else {
|
||||
equipment = template.generate(this.random);
|
||||
}
|
||||
|
||||
if (equipment) {
|
||||
equipments.push(equipment);
|
||||
}
|
||||
});
|
||||
let equipments = this.templates.filter(template => slot == null || slot == template.slot).map(template => template.generate(level));
|
||||
|
||||
// No equipment could be generated with given conditions
|
||||
if (equipments.length === 0) {
|
||||
|
|
|
@ -1,123 +1,84 @@
|
|||
/// <reference path="effects/BaseEffect.ts" />
|
||||
|
||||
module TS.SpaceTac.Specs {
|
||||
class FakeEffect extends BaseEffect {
|
||||
fakevalue: number
|
||||
constructor(val = 5) {
|
||||
super("fake");
|
||||
this.fakevalue = val;
|
||||
}
|
||||
}
|
||||
|
||||
describe("LootTemplate", () => {
|
||||
it("interpolates between weak and strong loot", () => {
|
||||
var template = new LootTemplate(SlotType.Weapon, "Bulletator");
|
||||
it("applies requirements on skills", function () {
|
||||
let template = new LootTemplate(SlotType.Hull, "Hull");
|
||||
template.setSkillsRequirements({ "skill_energy": 1, "skill_gravity": istep(2, istep(1)) });
|
||||
|
||||
template.distance = new Range(1, 3);
|
||||
template.blast = new Range(1, 1);
|
||||
template.duration = new IntegerRange(1, 2);
|
||||
template.ap_usage = new Range(4, 12);
|
||||
template.min_level = new IntegerRange(5, 9);
|
||||
template.addRequirement("skill_energy", 2, 8);
|
||||
template.addRequirement("skill_human", 5);
|
||||
let result = template.generate(1);
|
||||
expect(result.requirements).toEqual({
|
||||
"skill_energy": 1,
|
||||
"skill_gravity": 2
|
||||
});
|
||||
|
||||
var equipment = template.generateFixed(0.0);
|
||||
|
||||
expect(equipment.slot).toEqual(SlotType.Weapon);
|
||||
expect(equipment.code).toEqual("bulletator");
|
||||
expect(equipment.name).toEqual("Bulletator");
|
||||
expect(equipment.distance).toEqual(1);
|
||||
expect(equipment.blast).toEqual(1);
|
||||
expect(equipment.duration).toEqual(1);
|
||||
expect(equipment.ap_usage).toEqual(4);
|
||||
expect(equipment.min_level).toEqual(5);
|
||||
expect(equipment.requirements).toEqual({
|
||||
result = template.generate(2);
|
||||
expect(result.requirements).toEqual({
|
||||
"skill_energy": 2,
|
||||
"skill_human": 5
|
||||
"skill_gravity": 3
|
||||
});
|
||||
|
||||
equipment = template.generateFixed(1.0);
|
||||
|
||||
expect(equipment.slot).toEqual(SlotType.Weapon);
|
||||
expect(equipment.code).toEqual("bulletator");
|
||||
expect(equipment.name).toEqual("Bulletator");
|
||||
expect(equipment.distance).toEqual(3);
|
||||
expect(equipment.blast).toEqual(1);
|
||||
expect(equipment.duration).toEqual(2);
|
||||
expect(equipment.ap_usage).toEqual(12);
|
||||
expect(equipment.min_level).toEqual(9);
|
||||
expect(equipment.requirements).toEqual({
|
||||
"skill_energy": 8,
|
||||
"skill_human": 5
|
||||
});
|
||||
|
||||
equipment = template.generateFixed(0.5);
|
||||
|
||||
expect(equipment.slot).toEqual(SlotType.Weapon);
|
||||
expect(equipment.code).toEqual("bulletator");
|
||||
expect(equipment.name).toEqual("Bulletator");
|
||||
expect(equipment.distance).toEqual(2);
|
||||
expect(equipment.blast).toEqual(1);
|
||||
expect(equipment.duration).toEqual(2);
|
||||
expect(equipment.ap_usage).toEqual(8);
|
||||
expect(equipment.min_level).toEqual(7);
|
||||
expect(equipment.requirements).toEqual({
|
||||
"skill_energy": 5,
|
||||
"skill_human": 5
|
||||
result = template.generate(10);
|
||||
expect(result.requirements).toEqual({
|
||||
"skill_energy": 10,
|
||||
"skill_gravity": 47
|
||||
});
|
||||
});
|
||||
|
||||
it("restricts power range to stay in a level range", () => {
|
||||
var template = new LootTemplate(SlotType.Weapon, "Bulletator");
|
||||
template.min_level = new IntegerRange(4, 7);
|
||||
it("applies attributes permenant effects", function () {
|
||||
let template = new LootTemplate(SlotType.Shield, "Shield");
|
||||
template.addAttributeEffect("shield_capacity", irange(undefined, 50, 10));
|
||||
|
||||
var result: any;
|
||||
let result = template.generate(1);
|
||||
expect(result.effects).toEqual([new AttributeEffect("shield_capacity", 50)]);
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(4, 7));
|
||||
expect(result.min).toBe(0);
|
||||
expect(result.max).toBe(1);
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(1, 10));
|
||||
expect(result.min).toBe(0);
|
||||
expect(result.max).toBe(1);
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(5, 6));
|
||||
expect(result.min).toBeCloseTo(0.25, 0.000001);
|
||||
expect(result.max).toBeCloseTo(0.75, 0.000001);
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(5, 12));
|
||||
expect(result.min).toBeCloseTo(0.25, 0.000001);
|
||||
expect(result.max).toBe(1);
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(3, 6));
|
||||
expect(result.min).toBe(0);
|
||||
expect(result.max).toBeCloseTo(0.75, 0.000001);
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(10, 15));
|
||||
expect(result).toBeNull();
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(1, 3));
|
||||
expect(result).toBeNull();
|
||||
|
||||
result = template.getPowerRangeForLevel(new IntegerRange(5, 5));
|
||||
expect(result.min).toBeCloseTo(0.25, 0.000001);
|
||||
expect(result.max).toBeCloseTo(0.5, 0.000001);
|
||||
result = template.generate(2);
|
||||
expect(result.effects).toEqual([new AttributeEffect("shield_capacity", 60)]);
|
||||
});
|
||||
|
||||
it("adds modulated effects", () => {
|
||||
let template = new LootTemplate(SlotType.Weapon, "Bulletator");
|
||||
template.addEffect(new DamageEffect(), 5, 10, true);
|
||||
it("adds move actions", function () {
|
||||
let template = new LootTemplate(SlotType.Engine, "Engine");
|
||||
template.addMoveAction(irange(undefined, 100, 10));
|
||||
|
||||
expect(template.generateFixed(0).target_effects).toEqual([new DamageEffect(5)]);
|
||||
expect(template.generateFixed(1).target_effects).toEqual([new DamageEffect(10)]);
|
||||
let result = template.generate(1);
|
||||
expect(result.action).toEqual(new MoveAction(result, 100));
|
||||
|
||||
template.addEffect(new AttributeEffect("initiative"), 1, 2, false);
|
||||
|
||||
expect(template.generateFixed(0).permanent_effects).toEqual([new AttributeEffect("initiative", 1)]);
|
||||
expect(template.generateFixed(1).permanent_effects).toEqual([new AttributeEffect("initiative", 2)]);
|
||||
result = template.generate(2);
|
||||
expect(result.action).toEqual(new MoveAction(result, 110));
|
||||
});
|
||||
|
||||
it("adds modulated sticky effects", () => {
|
||||
let template = new LootTemplate(SlotType.Weapon, "Bulletator");
|
||||
template.addStickyEffect(new DamageEffect(), 5, 10, 1, 2, true, false, true);
|
||||
it("adds fire actions", function () {
|
||||
let template = new LootTemplate(SlotType.Weapon, "Weapon");
|
||||
template.addFireAction(istep(1), istep(100), istep(50), [
|
||||
new EffectTemplate(new FakeEffect(3), { "fakevalue": istep(8) })
|
||||
]);
|
||||
|
||||
expect(template.generateFixed(0).target_effects).toEqual([new StickyEffect(new DamageEffect(5), 1, true, false)]);
|
||||
expect(template.generateFixed(1).target_effects).toEqual([new StickyEffect(new DamageEffect(10), 2, true, false)]);
|
||||
let result = template.generate(1);
|
||||
expect(result.action).toEqual(new FireWeaponAction(result, 1, 100, 50, [new FakeEffect(8)]));
|
||||
|
||||
template.addStickyEffect(new AttributeLimitEffect("power_recovery"), 1, 2, 1, null, false, true, false);
|
||||
result = template.generate(2);
|
||||
expect(result.action).toEqual(new FireWeaponAction(result, 2, 101, 51, [new FakeEffect(9)]));
|
||||
});
|
||||
|
||||
expect(template.generateFixed(0).permanent_effects).toEqual([new StickyEffect(new AttributeLimitEffect("power_recovery", 1), 1, false, true)]);
|
||||
expect(template.generateFixed(1).permanent_effects).toEqual([new StickyEffect(new AttributeLimitEffect("power_recovery", 2), 1, false, true)]);
|
||||
it("adds drone actions", function () {
|
||||
let template = new LootTemplate(SlotType.Weapon, "Weapon");
|
||||
template.addDroneAction(istep(1), istep(100), istep(2), istep(50), [
|
||||
new EffectTemplate(new FakeEffect(3), { "fakevalue": istep(8) })
|
||||
]);
|
||||
|
||||
let result = template.generate(1);
|
||||
expect(result.action).toEqual(new DeployDroneAction(result, 1, 100, 2, 50, [new FakeEffect(8)]));
|
||||
|
||||
result = template.generate(2);
|
||||
expect(result.action).toEqual(new DeployDroneAction(result, 2, 101, 3, 51, [new FakeEffect(9)]));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,93 @@
|
|||
module TS.SpaceTac {
|
||||
// Template used to generate a loot equipment
|
||||
/**
|
||||
* Quality of loot.
|
||||
*/
|
||||
export enum LootQuality {
|
||||
WEAK,
|
||||
COMMON,
|
||||
FINE,
|
||||
PREMIUM
|
||||
}
|
||||
|
||||
/**
|
||||
* A leveled value is either a number multiplied by the level, or a custom iterator
|
||||
*/
|
||||
type LeveledValue = number | Iterator<number>;
|
||||
|
||||
/**
|
||||
* Resolve a leveled value
|
||||
*/
|
||||
function resolveForLevel(value: LeveledValue, level: number): number {
|
||||
if (typeof value === "number") {
|
||||
value *= level;
|
||||
} else {
|
||||
value = iat(value, level - 1) || 0;
|
||||
}
|
||||
return Math.floor(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template used to generate a BaseEffect for a given ship level
|
||||
*/
|
||||
export class EffectTemplate<T extends BaseEffect> {
|
||||
// Basic instance of the effect
|
||||
effect: T;
|
||||
|
||||
// Effect value modifiers
|
||||
modifiers: [keyof T, LeveledValue][];
|
||||
|
||||
constructor(effect: T, modifiers: { [attr: string]: LeveledValue }) {
|
||||
this.effect = effect;
|
||||
this.modifiers = [];
|
||||
|
||||
iteritems(modifiers, (key, value) => {
|
||||
if (effect.hasOwnProperty(key)) {
|
||||
this.addModifier(<keyof T>key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add a value modifier for the effect
|
||||
addModifier(name: keyof T, value: LeveledValue) {
|
||||
this.modifiers.push([name, value]);
|
||||
}
|
||||
|
||||
// Generate an effect with a given level
|
||||
generate(level: number): T {
|
||||
let result = copy(this.effect);
|
||||
this.modifiers.forEach(modifier => {
|
||||
let [name, value] = modifier;
|
||||
(<any>result)[name] = resolveForLevel(value, level);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template used to generate a BaseEffect for a given ship level
|
||||
*/
|
||||
export class StickyEffectTemplate<T extends BaseEffect> extends EffectTemplate<BaseEffect> {
|
||||
duration: LeveledValue;
|
||||
|
||||
constructor(effect: T, modifiers: { [attr: string]: LeveledValue }, duration: LeveledValue) {
|
||||
super(effect, modifiers);
|
||||
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
generate(level: number): StickyEffect {
|
||||
let result = copy(this.effect);
|
||||
this.modifiers.forEach(modifier => {
|
||||
let [name, value] = modifier;
|
||||
(<any>result)[name] = resolveForLevel(value, level);
|
||||
});
|
||||
return new StickyEffect(result, resolveForLevel(this.duration, level), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template used to generate a loot equipment
|
||||
*/
|
||||
export class LootTemplate {
|
||||
// Type of slot this equipment will fit in
|
||||
slot: SlotType;
|
||||
|
@ -7,181 +95,83 @@ module TS.SpaceTac {
|
|||
// Base name that will be given to generated equipment
|
||||
name: string;
|
||||
|
||||
// Capability requirement ranges (indexed by attributes)
|
||||
requirements: { [key: string]: IntegerRange };
|
||||
// Modifiers applied to obtain the "common" equipment, based on level
|
||||
protected base_modifiers: ((equipment: Equipment, level: number) => void)[];
|
||||
|
||||
// Distance to target
|
||||
distance: Range;
|
||||
|
||||
// Effect area's radius
|
||||
blast: Range;
|
||||
|
||||
// Duration, in number of turns
|
||||
duration: IntegerRange;
|
||||
|
||||
// Permanent effects (when attached to an equipment slot)
|
||||
permanent_effects: EffectTemplate[];
|
||||
|
||||
// Effects on target
|
||||
target_effects: EffectTemplate[];
|
||||
|
||||
// Action Points usage
|
||||
ap_usage: Range;
|
||||
|
||||
// Level requirement
|
||||
min_level: IntegerRange;
|
||||
|
||||
// Create a loot template
|
||||
constructor(slot: SlotType, name: string) {
|
||||
this.slot = slot;
|
||||
this.name = name;
|
||||
this.requirements = {};
|
||||
this.distance = new Range(0, 0);
|
||||
this.blast = new Range(0, 0);
|
||||
this.duration = new IntegerRange(0, 0);
|
||||
this.ap_usage = new IntegerRange(0, 0);
|
||||
this.min_level = new IntegerRange(0, 0);
|
||||
this.permanent_effects = [];
|
||||
this.target_effects = [];
|
||||
this.base_modifiers = [];
|
||||
}
|
||||
|
||||
// Set a capability requirement
|
||||
addRequirement(capability: keyof ShipAttributes, min: number, max: number | null = null): void {
|
||||
this.requirements[capability] = new IntegerRange(min, max);
|
||||
}
|
||||
/**
|
||||
* Generate a new equipment of a given level and quality
|
||||
*/
|
||||
generate(level: number, quality: LootQuality = LootQuality.COMMON, random = RandomGenerator.global): Equipment {
|
||||
let result = new Equipment();
|
||||
|
||||
// Generate a random equipment with this template
|
||||
generate(random = RandomGenerator.global): Equipment {
|
||||
var power = random.random();
|
||||
return this.generateFixed(power);
|
||||
}
|
||||
|
||||
// Generate a fixed-power equipment with this template
|
||||
generateFixed(power: number): Equipment {
|
||||
var result = new Equipment();
|
||||
|
||||
result.slot = this.slot;
|
||||
result.slot_type = this.slot;
|
||||
result.code = (this.name || "").toLowerCase().replace(/ /g, "");
|
||||
result.name = this.name;
|
||||
|
||||
result.distance = this.distance.getProportional(power);
|
||||
result.blast = this.blast.getProportional(power);
|
||||
result.duration = this.duration.getProportional(power);
|
||||
result.ap_usage = this.ap_usage.getProportional(power);
|
||||
result.min_level = this.min_level.getProportional(power);
|
||||
|
||||
let action = this.getActionForEquipment(result)
|
||||
if (action) {
|
||||
result.action = action;
|
||||
}
|
||||
|
||||
iteritems(this.requirements, (key: string, requirement: IntegerRange) => {
|
||||
if (requirement) {
|
||||
result.requirements[key] = requirement.getProportional(power);
|
||||
}
|
||||
});
|
||||
|
||||
this.permanent_effects.forEach((eff_template: EffectTemplate) => {
|
||||
result.permanent_effects.push(eff_template.generateFixed(power));
|
||||
});
|
||||
this.target_effects.forEach((eff_template: EffectTemplate) => {
|
||||
result.target_effects.push(eff_template.generateFixed(power));
|
||||
});
|
||||
this.base_modifiers.forEach(modifier => modifier(result, level));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find the power range that will result in the level range
|
||||
getPowerRangeForLevel(level: IntegerRange): Range | null {
|
||||
if (level.min > this.min_level.max || level.max < this.min_level.min) {
|
||||
return null;
|
||||
} else {
|
||||
var min: number;
|
||||
var max: number;
|
||||
/**
|
||||
* Set skill requirements that will be added to each level of equipment.
|
||||
*/
|
||||
setSkillsRequirements(skills: { [skill: string]: LeveledValue }): void {
|
||||
this.base_modifiers.push((equipment, level) => {
|
||||
iteritems(skills, (skill, value) => {
|
||||
let resolved = resolveForLevel(value, level);
|
||||
if (resolved > 0) {
|
||||
equipment.requirements[skill] = (equipment.requirements[skill] || 0) + resolved;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (level.min <= this.min_level.min) {
|
||||
min = 0.0;
|
||||
} else {
|
||||
min = this.min_level.getReverseProportional(level.min);
|
||||
/**
|
||||
* Add a permanent attribute effect, when the item is equipped.
|
||||
*/
|
||||
addAttributeEffect(attribute: keyof ShipAttributes, value: LeveledValue): void {
|
||||
this.base_modifiers.push((equipment, level) => {
|
||||
let resolved = resolveForLevel(value, level);
|
||||
if (resolved > 0) {
|
||||
equipment.effects.push(new AttributeEffect(attribute, resolved));
|
||||
}
|
||||
if (level.max >= this.min_level.max) {
|
||||
max = 1.0;
|
||||
} else {
|
||||
max = this.min_level.getReverseProportional(level.max + 1);
|
||||
}
|
||||
|
||||
return new Range(min, max);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an equipment that will have its level requirement in the given range
|
||||
// May return null if level range is not compatible with the template
|
||||
generateInLevelRange(level: IntegerRange, random = RandomGenerator.global): Equipment | null {
|
||||
var random_range = this.getPowerRangeForLevel(level);
|
||||
if (random_range) {
|
||||
var power = random.random() * (random_range.max - random_range.min) + random_range.min;
|
||||
return this.generateFixed(power);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a modulated effect to the equipment
|
||||
* Add a move action.
|
||||
*/
|
||||
addEffect(effect: BaseEffect, min_value: number, max_value: number | null = null, target = true) {
|
||||
var template = new EffectTemplate(effect);
|
||||
template.addModifier("value", new IntegerRange(min_value, max_value));
|
||||
if (target) {
|
||||
this.target_effects.push(template);
|
||||
} else {
|
||||
this.permanent_effects.push(template);
|
||||
}
|
||||
addMoveAction(distance_per_power: LeveledValue): void {
|
||||
this.base_modifiers.push((equipment, level) => {
|
||||
equipment.action = new MoveAction(equipment, resolveForLevel(distance_per_power, level));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a modulated sticky effect to the equipment
|
||||
* Add a fire weapon action.
|
||||
*/
|
||||
addStickyEffect(effect: BaseEffect, min_value: number, max_value: number | null = null, min_duration: number = 1,
|
||||
max_duration: number | null = null, on_stick = false, on_turn_start = false, target = true): void {
|
||||
var template = new EffectTemplate(new StickyEffect(effect, 0, on_stick, on_turn_start));
|
||||
template.addModifier("value", new IntegerRange(min_value, max_value));
|
||||
template.addModifier("duration", new IntegerRange(min_duration, max_duration));
|
||||
if (target) {
|
||||
this.target_effects.push(template);
|
||||
} else {
|
||||
this.permanent_effects.push(template);
|
||||
}
|
||||
addFireAction(power: LeveledValue, range: LeveledValue, blast: LeveledValue, effects: EffectTemplate<BaseEffect>[]): void {
|
||||
this.base_modifiers.push((equipment, level) => {
|
||||
let reffects = effects.map(effect => effect.generate(level));
|
||||
equipment.action = new FireWeaponAction(equipment, resolveForLevel(power, level), resolveForLevel(range, level), resolveForLevel(blast, level), reffects);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add damage on target, immediate or over time
|
||||
* Add a deploy drone action.
|
||||
*/
|
||||
addDamage(min_value: number, max_value: number | null = null, min_duration: number | null = null, max_duration: number | null = null) {
|
||||
if (min_duration != null) {
|
||||
this.addStickyEffect(new DamageEffect(), min_value, max_value, min_duration, max_duration, true, false, true);
|
||||
} else {
|
||||
this.addEffect(new DamageEffect(), min_value, max_value, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add an attribute on the ship that equips the loot
|
||||
*/
|
||||
increaseAttribute(attribute: keyof ShipAttributes, min_value: number, max_value: number | null = null) {
|
||||
this.addEffect(new AttributeEffect(attribute), min_value, max_value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the power consumption
|
||||
*/
|
||||
setPowerConsumption(minimal: number, maximal: number | null = null) {
|
||||
this.ap_usage = new IntegerRange(minimal, maximal);
|
||||
}
|
||||
|
||||
// Method to reimplement to assign an action to a generated equipment
|
||||
protected getActionForEquipment(equipment: Equipment): BaseAction | null {
|
||||
return null;
|
||||
addDroneAction(power: LeveledValue, range: LeveledValue, lifetime: LeveledValue, radius: LeveledValue, effects: EffectTemplate<BaseEffect>[]): void {
|
||||
this.base_modifiers.push((equipment, level) => {
|
||||
let reffects = effects.map(effect => effect.generate(level));
|
||||
equipment.action = new DeployDroneAction(equipment, resolveForLevel(power, level), resolveForLevel(range, level), resolveForLevel(lifetime, level), resolveForLevel(radius, level), reffects);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,7 @@ module TS.SpaceTac.Specs {
|
|||
let ship = new Ship();
|
||||
TestTools.setShipAP(ship, ship_ap);
|
||||
TestTools.addEngine(ship, engine_distance);
|
||||
let action = new FireWeaponAction(new Equipment(), true);
|
||||
action.equipment.distance = distance;
|
||||
action.equipment.ap_usage = weapon_ap;
|
||||
let action = new FireWeaponAction(new Equipment(), weapon_ap, distance);
|
||||
let simulator = new MoveFireSimulator(ship);
|
||||
return [ship, simulator, action];
|
||||
}
|
||||
|
@ -23,7 +21,7 @@ module TS.SpaceTac.Specs {
|
|||
let engine4 = TestTools.addEngine(ship, 70);
|
||||
let best = simulator.findBestEngine();
|
||||
expect(best).toBe(engine3);
|
||||
expect((<Equipment>best).distance).toBe(150);
|
||||
expect((<MoveAction>nn(best).action).distance_per_power).toBe(150);
|
||||
});
|
||||
|
||||
it("fires directly when in range", function () {
|
||||
|
|
|
@ -51,7 +51,7 @@ module TS.SpaceTac {
|
|||
if (engines.length == 0) {
|
||||
return null;
|
||||
} else {
|
||||
engines.sort((a, b) => cmp(b.distance, a.distance));
|
||||
engines.sort((a, b) => (a.action instanceof MoveAction && b.action instanceof MoveAction) ? cmp(b.action.distance_per_power, a.action.distance_per_power) : 0);
|
||||
return engines[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,13 +47,13 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
slot = ship.addSlot(SlotType.Engine);
|
||||
equipment = new Equipment();
|
||||
equipment.slot = slot.type;
|
||||
equipment.slot_type = slot.type;
|
||||
equipment.action = new MoveAction(equipment);
|
||||
slot.attach(equipment);
|
||||
|
||||
slot = ship.addSlot(SlotType.Weapon);
|
||||
equipment = new Equipment();
|
||||
equipment.slot = slot.type;
|
||||
equipment.slot_type = slot.type;
|
||||
slot.attach(equipment);
|
||||
|
||||
actions = ship.getAvailableActions();
|
||||
|
@ -69,14 +69,14 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
slot = ship.addSlot(SlotType.Power);
|
||||
equipment = new Equipment();
|
||||
equipment.slot = slot.type;
|
||||
equipment.permanent_effects.push(new AttributeEffect("power_capacity", 4));
|
||||
equipment.slot_type = slot.type;
|
||||
equipment.effects.push(new AttributeEffect("power_capacity", 4));
|
||||
slot.attach(equipment);
|
||||
|
||||
slot = ship.addSlot(SlotType.Power);
|
||||
equipment = new Equipment();
|
||||
equipment.slot = slot.type;
|
||||
equipment.permanent_effects.push(new AttributeEffect("power_capacity", 5));
|
||||
equipment.slot_type = slot.type;
|
||||
equipment.effects.push(new AttributeEffect("power_capacity", 5));
|
||||
slot.attach(equipment);
|
||||
|
||||
ship.updateAttributes();
|
||||
|
@ -246,9 +246,13 @@ module TS.SpaceTac.Specs {
|
|||
it("recover action points at end of turn", function () {
|
||||
var ship = new Ship();
|
||||
|
||||
var power_core_template = new Equipments.BasicPowerCore();
|
||||
ship.addSlot(SlotType.Power).attach(power_core_template.generateFixed(0));
|
||||
ship.updateAttributes();
|
||||
let power_generator = new Equipment(SlotType.Power);
|
||||
power_generator.effects = [
|
||||
new AttributeEffect("power_capacity", 8),
|
||||
new AttributeEffect("power_recovery", 3),
|
||||
new AttributeEffect("power_initial", 4)
|
||||
]
|
||||
ship.addSlot(SlotType.Power).attach(power_generator);
|
||||
|
||||
expect(ship.values.power.get()).toBe(0);
|
||||
ship.initializeActionPoints();
|
||||
|
|
|
@ -206,6 +206,10 @@ module TS.SpaceTac {
|
|||
* Get a ship value
|
||||
*/
|
||||
getValue(name: keyof ShipValues): number {
|
||||
if (!this.values.hasOwnProperty(name)) {
|
||||
console.error(`No such ship value: ${name}`);
|
||||
return 0;
|
||||
}
|
||||
return this.values[name].get();
|
||||
}
|
||||
|
||||
|
@ -238,6 +242,10 @@ module TS.SpaceTac {
|
|||
* Get a ship attribute's current value
|
||||
*/
|
||||
getAttribute(name: keyof ShipAttributes): number {
|
||||
if (!this.attributes.hasOwnProperty(name)) {
|
||||
console.error(`No such ship attribute: ${name}`);
|
||||
return 0;
|
||||
}
|
||||
return this.attributes[name].get();
|
||||
}
|
||||
|
||||
|
@ -496,7 +504,7 @@ module TS.SpaceTac {
|
|||
* Returns true if successful
|
||||
*/
|
||||
equip(item: Equipment, from_cargo = true): boolean {
|
||||
let free_slot = first(this.slots, slot => slot.type == item.slot && !slot.attached);
|
||||
let free_slot = first(this.slots, slot => slot.type == item.slot_type && !slot.attached);
|
||||
|
||||
if (free_slot && (!from_cargo || remove(this.cargo, item))) {
|
||||
free_slot.attach(item);
|
||||
|
@ -627,7 +635,7 @@ module TS.SpaceTac {
|
|||
|
||||
this.slots.forEach(slot => {
|
||||
if (slot.attached) {
|
||||
slot.attached.permanent_effects.forEach(effect => {
|
||||
slot.attached.effects.forEach(effect => {
|
||||
if (effect.code == code) {
|
||||
result.push(effect);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ module TS.SpaceTac.Specs {
|
|||
expect(ship.slots[0].type).toBe(SlotType.Shield);
|
||||
expect(ship.slots[1].type).toBe(SlotType.Weapon);
|
||||
expect(ship.slots[2].type).toBe(SlotType.Weapon);
|
||||
expect(ship.getAttribute("skill_material")).toBe(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,9 +26,12 @@ module TS.SpaceTac {
|
|||
result.addSlot(slot);
|
||||
});
|
||||
|
||||
// Set all skills to 1 (to be able to use at least basic equipment)
|
||||
keys(result.skills).forEach(skill => result.upgradeSkill(skill));
|
||||
|
||||
// Fill equipment slots
|
||||
result.slots.forEach((slot: Slot) => {
|
||||
var equipment = loot.generate(new IntegerRange(level, level), slot.type);
|
||||
var equipment = loot.generate(level, slot.type);
|
||||
if (equipment) {
|
||||
slot.attach(equipment)
|
||||
if (slot.attached !== equipment) {
|
||||
|
|
|
@ -39,5 +39,24 @@ module TS.SpaceTac.Specs {
|
|||
level.forceLevel(10);
|
||||
expect(level.get()).toEqual(10);
|
||||
});
|
||||
|
||||
it("computes needed level for given points", function () {
|
||||
expect(ShipLevel.getLevelForPoints(0)).toBe(1);
|
||||
expect(ShipLevel.getLevelForPoints(1)).toBe(1);
|
||||
expect(ShipLevel.getLevelForPoints(2)).toBe(1);
|
||||
expect(ShipLevel.getLevelForPoints(5)).toBe(1);
|
||||
expect(ShipLevel.getLevelForPoints(10)).toBe(1);
|
||||
expect(ShipLevel.getLevelForPoints(11)).toBe(2);
|
||||
expect(ShipLevel.getLevelForPoints(15)).toBe(2);
|
||||
expect(ShipLevel.getLevelForPoints(16)).toBe(3);
|
||||
expect(ShipLevel.getLevelForPoints(526)).toBe(105);
|
||||
});
|
||||
|
||||
it("computes needed points for given level", function () {
|
||||
expect(ShipLevel.getPointsForLevel(1)).toBe(10);
|
||||
expect(ShipLevel.getPointsForLevel(2)).toBe(15);
|
||||
expect(ShipLevel.getPointsForLevel(3)).toBe(20);
|
||||
expect(ShipLevel.getPointsForLevel(105)).toBe(530);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,10 +23,24 @@ module TS.SpaceTac {
|
|||
/**
|
||||
* Force experience gain, to reach a given level
|
||||
*/
|
||||
forceLevel(level: number) {
|
||||
forceLevel(level: number): void {
|
||||
while (this.level < level) {
|
||||
this.addExperience(this.getNextGoal());
|
||||
this.checkLevelUp();
|
||||
this.forceLevelUp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a level up
|
||||
*/
|
||||
forceLevelUp(): void {
|
||||
let old_level = this.level;
|
||||
|
||||
this.addExperience(this.getNextGoal() - this.experience);
|
||||
this.checkLevelUp();
|
||||
|
||||
if (old_level >= this.level) {
|
||||
// security against infinite loops
|
||||
throw new Error("No effective level up");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +51,7 @@ module TS.SpaceTac {
|
|||
*/
|
||||
checkLevelUp(): boolean {
|
||||
let changed = false;
|
||||
while (this.experience > this.getNextGoal()) {
|
||||
while (this.experience >= this.getNextGoal()) {
|
||||
this.level++;
|
||||
changed = true;
|
||||
}
|
||||
|
@ -47,7 +61,7 @@ module TS.SpaceTac {
|
|||
/**
|
||||
* Add experience points
|
||||
*/
|
||||
addExperience(points: number) {
|
||||
addExperience(points: number): void {
|
||||
this.experience += points;
|
||||
}
|
||||
|
||||
|
@ -57,5 +71,25 @@ module TS.SpaceTac {
|
|||
getSkillPoints(): number {
|
||||
return 5 + 5 * this.level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the level needed to have a given total of points
|
||||
*/
|
||||
static getLevelForPoints(points: number): number {
|
||||
let lev = new ShipLevel();
|
||||
while (lev.getSkillPoints() < points) {
|
||||
lev.forceLevelUp();
|
||||
}
|
||||
return lev.level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the points available at a given level
|
||||
*/
|
||||
static getPointsForLevel(level: number): number {
|
||||
let lev = new ShipLevel();
|
||||
lev.forceLevel(level);
|
||||
return lev.getSkillPoints();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@ module TS.SpaceTac {
|
|||
* Generate a random stock
|
||||
*/
|
||||
generateStock(items: number) {
|
||||
// TODO other levels
|
||||
let generator = new LootGenerator();
|
||||
this.stock = nna(range(items).map(i => generator.generate()));
|
||||
this.stock = nna(range(items).map(i => generator.generate(1)));
|
||||
|
||||
this.sortStock();
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ module TS.SpaceTac.Specs {
|
|||
var slot = ship.addSlot(SlotType.Engine);
|
||||
|
||||
var equipment = new Equipment();
|
||||
equipment.slot = SlotType.Weapon;
|
||||
equipment.slot_type = SlotType.Weapon;
|
||||
|
||||
expect(slot.attached).toBeNull();
|
||||
slot.attach(equipment);
|
||||
expect(slot.attached).toBeNull();
|
||||
|
||||
equipment.slot = SlotType.Engine;
|
||||
equipment.slot_type = SlotType.Engine;
|
||||
|
||||
slot.attach(equipment);
|
||||
expect(slot.attached).toBe(equipment);
|
||||
|
@ -22,7 +22,7 @@ module TS.SpaceTac.Specs {
|
|||
var slot = ship.addSlot(SlotType.Shield);
|
||||
|
||||
var equipment = new Equipment();
|
||||
equipment.slot = SlotType.Shield;
|
||||
equipment.slot_type = SlotType.Shield;
|
||||
equipment.requirements["skill_gravity"] = 5;
|
||||
|
||||
expect(slot.attached).toBeNull();
|
||||
|
|
|
@ -28,7 +28,7 @@ module TS.SpaceTac {
|
|||
|
||||
// Attach an equipment in this slot
|
||||
attach(equipment: Equipment): Equipment {
|
||||
if (this.type === equipment.slot && equipment.canBeEquipped(this.ship)) {
|
||||
if (this.type === equipment.slot_type && equipment.canBeEquipped(this.ship)) {
|
||||
this.attached = equipment;
|
||||
equipment.attached_to = this;
|
||||
|
||||
|
|
35
src/core/TestTools.spec.ts
Normal file
35
src/core/TestTools.spec.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("TestTools", () => {
|
||||
it("set ship power", () => {
|
||||
let ship = new Ship();
|
||||
|
||||
expect(ship.getAttribute("power_capacity")).toBe(0);
|
||||
expect(ship.getAttribute("power_initial")).toBe(0);
|
||||
expect(ship.getAttribute("power_recovery")).toBe(0);
|
||||
expect(ship.getValue("power")).toBe(0);
|
||||
|
||||
TestTools.setShipAP(ship, 12, 4);
|
||||
|
||||
expect(ship.getAttribute("power_capacity")).toBe(12);
|
||||
expect(ship.getAttribute("power_initial")).toBe(12);
|
||||
expect(ship.getAttribute("power_recovery")).toBe(4);
|
||||
expect(ship.getValue("power")).toBe(12);
|
||||
});
|
||||
|
||||
it("set ship health", () => {
|
||||
let ship = new Ship();
|
||||
|
||||
expect(ship.getAttribute("hull_capacity")).toBe(0);
|
||||
expect(ship.getAttribute("shield_capacity")).toBe(0);
|
||||
expect(ship.getValue("hull")).toBe(0);
|
||||
expect(ship.getValue("shield")).toBe(0);
|
||||
|
||||
TestTools.setShipHP(ship, 100, 200);
|
||||
|
||||
expect(ship.getAttribute("hull_capacity")).toBe(100);
|
||||
expect(ship.getAttribute("shield_capacity")).toBe(200);
|
||||
expect(ship.getValue("hull")).toBe(100);
|
||||
expect(ship.getValue("shield")).toBe(200);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -25,7 +25,8 @@ module TS.SpaceTac {
|
|||
var equipped = ship.listEquipment(slot);
|
||||
var equipment: Equipment;
|
||||
if (force_generate || equipped.length === 0) {
|
||||
equipment = template.generateFixed(0);
|
||||
equipment = template.generate(1);
|
||||
equipment.requirements = {};
|
||||
ship.addSlot(slot).attach(equipment);
|
||||
} else {
|
||||
equipment = equipped[0];
|
||||
|
@ -37,8 +38,7 @@ module TS.SpaceTac {
|
|||
// Add an engine, allowing a ship to move *distance*, for each action points
|
||||
static addEngine(ship: Ship, distance: number): Equipment {
|
||||
var equipment = this.getOrGenEquipment(ship, SlotType.Engine, new Equipments.ConventionalEngine(), true);
|
||||
equipment.ap_usage = 1;
|
||||
equipment.distance = distance;
|
||||
(<MoveAction>equipment.action).distance_per_power = distance;
|
||||
return equipment;
|
||||
}
|
||||
|
||||
|
@ -47,11 +47,7 @@ module TS.SpaceTac {
|
|||
*/
|
||||
static addWeapon(ship: Ship, damage = 100, power_usage = 1, max_distance = 100, blast = 0): Equipment {
|
||||
var equipment = ship.addSlot(SlotType.Weapon).attach(new Equipment(SlotType.Weapon));
|
||||
equipment.action = new FireWeaponAction(equipment, blast != 0, "Test Weapon");
|
||||
equipment.ap_usage = power_usage;
|
||||
equipment.blast = blast;
|
||||
equipment.distance = max_distance;
|
||||
equipment.target_effects.push(new DamageEffect(damage));
|
||||
equipment.action = new FireWeaponAction(equipment, power_usage, max_distance, blast, [new DamageEffect(damage)], "Test Weapon");
|
||||
return equipment;
|
||||
}
|
||||
|
||||
|
@ -59,12 +55,14 @@ module TS.SpaceTac {
|
|||
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
||||
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.BasicPowerCore());
|
||||
|
||||
equipment.permanent_effects.forEach(effect => {
|
||||
equipment.effects.forEach(effect => {
|
||||
if (effect instanceof AttributeEffect) {
|
||||
if (effect.attrcode === "power_capacity") {
|
||||
effect.value = points;
|
||||
} else if (effect.attrcode === "power_recovery") {
|
||||
effect.value = recovery;
|
||||
} else if (effect.attrcode === "power_initial") {
|
||||
effect.value = points;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -78,14 +76,14 @@ module TS.SpaceTac {
|
|||
var armor = TestTools.getOrGenEquipment(ship, SlotType.Hull, new Equipments.IronHull());
|
||||
var shield = TestTools.getOrGenEquipment(ship, SlotType.Shield, new Equipments.BasicForceField());
|
||||
|
||||
armor.permanent_effects.forEach(effect => {
|
||||
armor.effects.forEach(effect => {
|
||||
if (effect instanceof AttributeEffect) {
|
||||
if (effect.attrcode === "hull_capacity") {
|
||||
effect.value = hull_points;
|
||||
}
|
||||
}
|
||||
});
|
||||
shield.permanent_effects.forEach((effect: BaseEffect) => {
|
||||
shield.effects.forEach((effect: BaseEffect) => {
|
||||
if (effect instanceof AttributeEffect) {
|
||||
if (effect.attrcode === "shield_capacity") {
|
||||
effect.value = shield_points;
|
||||
|
|
|
@ -2,8 +2,8 @@ module TS.SpaceTac {
|
|||
describe("BaseAction", function () {
|
||||
it("check if equipment can be used with remaining AP", function () {
|
||||
var equipment = new Equipment(SlotType.Hull);
|
||||
equipment.ap_usage = 3;
|
||||
var action = new BaseAction("test", "Test", false, equipment);
|
||||
spyOn(action, "getActionPointsUsage").and.returnValue(3);
|
||||
var ship = new Ship();
|
||||
ship.addSlot(SlotType.Hull).attach(equipment);
|
||||
ship.values.power.setMaximal(10);
|
||||
|
|
|
@ -39,7 +39,7 @@ module TS.SpaceTac {
|
|||
if (remaining_ap === null) {
|
||||
remaining_ap = ship.values.power.get();
|
||||
}
|
||||
var ap_usage = this.equipment ? this.equipment.ap_usage : 0;
|
||||
var ap_usage = this.getActionPointsUsage(ship, null);
|
||||
if (remaining_ap >= ap_usage) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -49,29 +49,17 @@ module TS.SpaceTac {
|
|||
|
||||
// Get the number of action points the action applied to a target would use
|
||||
getActionPointsUsage(ship: Ship, target: Target | null): number {
|
||||
if (this.equipment) {
|
||||
return this.equipment.ap_usage;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the range of this action
|
||||
getRangeRadius(ship: Ship): number {
|
||||
if (this.equipment) {
|
||||
return this.equipment.distance;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the effect area radius of this action
|
||||
getBlastRadius(ship: Ship): number {
|
||||
if (this.equipment) {
|
||||
return this.equipment.blast;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Method to check if a target is applicable for this action
|
||||
|
@ -129,5 +117,12 @@ module TS.SpaceTac {
|
|||
// Method to reimplement to apply a action
|
||||
protected customApply(ship: Ship, target: Target | null) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get description of effects (one line per effect)
|
||||
*/
|
||||
getEffectsDescription(): string[] {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,7 @@ module TS.SpaceTac {
|
|||
it("allows to deploy in range", function () {
|
||||
let ship = new Ship();
|
||||
ship.setArenaPosition(0, 0);
|
||||
let equipment = new Equipment();
|
||||
equipment.distance = 8;
|
||||
equipment.ap_usage = 0;
|
||||
let action = new DeployDroneAction(equipment);
|
||||
let action = new DeployDroneAction(new Equipment(), 0, 8);
|
||||
|
||||
expect(action.checkTarget(ship, new Target(8, 0, null))).toEqual(new Target(8, 0, null));
|
||||
expect(action.checkTarget(ship, new Target(12, 0, null))).toEqual(new Target(8, 0, null));
|
||||
|
@ -34,14 +31,8 @@ module TS.SpaceTac {
|
|||
ship.setArenaPosition(0, 0);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipAP(ship, 3);
|
||||
let equipment = new Equipment();
|
||||
equipment.code = "testdrone";
|
||||
equipment.distance = 8;
|
||||
equipment.ap_usage = 2;
|
||||
equipment.duration = 2;
|
||||
equipment.blast = 4;
|
||||
equipment.target_effects.push(new DamageEffect(50));
|
||||
let action = new DeployDroneAction(equipment);
|
||||
let equipment = new Equipment(SlotType.Weapon, "testdrone");
|
||||
let action = new DeployDroneAction(equipment, 2, 8, 2, 4, [new DamageEffect(50)]);
|
||||
|
||||
battle.log.clear();
|
||||
battle.log.addFilter("value");
|
||||
|
|
|
@ -5,15 +5,49 @@ module TS.SpaceTac {
|
|||
* Action to deploy a drone in space
|
||||
*/
|
||||
export class DeployDroneAction extends BaseAction {
|
||||
// Power usage
|
||||
power: number;
|
||||
|
||||
// Maximal distance the drone may be deployed
|
||||
deploy_distance: number;
|
||||
|
||||
// Effect radius of the deployed drone
|
||||
effect_radius: number;
|
||||
|
||||
// Duration of the drone in turns, before being destroyed
|
||||
lifetime: number;
|
||||
|
||||
// Effects applied to ships in range of the drone
|
||||
effects: BaseEffect[];
|
||||
|
||||
// Source equipment
|
||||
equipment: Equipment;
|
||||
|
||||
constructor(equipment: Equipment) {
|
||||
constructor(equipment: Equipment, power = 1, deploy_distance = 0, lifetime = 0, effect_radius = 0, effects: BaseEffect[] = []) {
|
||||
super("deploy-" + equipment.code, "Deploy", true, equipment);
|
||||
|
||||
this.power = power;
|
||||
this.deploy_distance = deploy_distance;
|
||||
this.lifetime = lifetime;
|
||||
this.effect_radius = effect_radius;
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
getActionPointsUsage(ship: Ship, target: Target | null): number {
|
||||
return this.power;
|
||||
}
|
||||
|
||||
getRangeRadius(ship: Ship): number {
|
||||
return this.deploy_distance;
|
||||
}
|
||||
|
||||
getBlastRadius(ship: Ship): number {
|
||||
return this.effect_radius;
|
||||
}
|
||||
|
||||
checkLocationTarget(ship: Ship, target: Target): Target {
|
||||
// TODO Not too close to other ships and drones
|
||||
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.equipment.distance);
|
||||
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.deploy_distance);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -21,14 +55,19 @@ module TS.SpaceTac {
|
|||
let drone = new Drone(ship, this.equipment.code);
|
||||
drone.x = target.x;
|
||||
drone.y = target.y;
|
||||
drone.radius = this.equipment.blast;
|
||||
drone.effects = this.equipment.target_effects;
|
||||
drone.duration = this.equipment.duration;
|
||||
drone.radius = this.effect_radius;
|
||||
drone.effects = this.effects;
|
||||
drone.duration = this.lifetime;
|
||||
|
||||
let battle = ship.getBattle();
|
||||
if (battle) {
|
||||
battle.addDrone(drone);
|
||||
}
|
||||
}
|
||||
|
||||
getEffectsDescription(): string[] {
|
||||
let desc = `drone for ${this.lifetime} turn${this.lifetime > 1 ? "s" : ""}, in ${this.deploy_distance}km range, with ${this.effect_radius}km radius effects`;
|
||||
return [desc].concat(this.effects.map(effect => effect.getDescription()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,9 @@ module TS.SpaceTac {
|
|||
let fleet = new Fleet();
|
||||
let ship = new Ship(fleet);
|
||||
let equipment = new Equipment(SlotType.Weapon, "testweapon");
|
||||
equipment.blast = 10;
|
||||
equipment.ap_usage = 5;
|
||||
equipment.distance = 100;
|
||||
let effect = new BaseEffect("testeffect");
|
||||
let mock_apply = spyOn(effect, "applyOnShip").and.stub();
|
||||
equipment.target_effects.push(effect);
|
||||
let action = new FireWeaponAction(equipment, true);
|
||||
let action = new FireWeaponAction(equipment, 5, 100, 10, [effect]);
|
||||
|
||||
TestTools.setShipAP(ship, 10);
|
||||
|
||||
|
|
|
@ -1,23 +1,49 @@
|
|||
/// <reference path="BaseAction.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Action to fire a weapon on another ship, or in space
|
||||
/**
|
||||
* Action to fire a weapon on another ship, or in space
|
||||
*/
|
||||
export class FireWeaponAction extends BaseAction {
|
||||
// Boolean set to true if the weapon can target space
|
||||
can_target_space: boolean;
|
||||
// Power consumption
|
||||
power: number;
|
||||
|
||||
// Maximal range of the weapon
|
||||
range: number
|
||||
|
||||
// Blast radius
|
||||
blast: number;
|
||||
|
||||
// Effects applied on hit
|
||||
effects: BaseEffect[];
|
||||
|
||||
// Equipment cannot be null
|
||||
equipment: Equipment;
|
||||
|
||||
constructor(equipment: Equipment, can_target_space = false, name = "Fire") {
|
||||
constructor(equipment: Equipment, power = 1, range = 0, blast = 0, effects: BaseEffect[] = [], name = "Fire") {
|
||||
super("fire-" + equipment.code, name, true, equipment);
|
||||
|
||||
this.can_target_space = can_target_space;
|
||||
this.power = power;
|
||||
this.range = range;
|
||||
this.effects = effects;
|
||||
this.blast = blast;
|
||||
}
|
||||
|
||||
getActionPointsUsage(ship: Ship, target: Target | null): number {
|
||||
return this.power;
|
||||
}
|
||||
|
||||
getRangeRadius(ship: Ship): number {
|
||||
return this.range;
|
||||
}
|
||||
|
||||
getBlastRadius(ship: Ship): number {
|
||||
return this.blast;
|
||||
}
|
||||
|
||||
checkLocationTarget(ship: Ship, target: Target): Target | null {
|
||||
if (target && this.can_target_space) {
|
||||
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.equipment.distance);
|
||||
if (target && this.blast > 0) {
|
||||
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.range);
|
||||
return target;
|
||||
} else {
|
||||
return null;
|
||||
|
@ -30,9 +56,9 @@ module TS.SpaceTac {
|
|||
return null;
|
||||
} else {
|
||||
// Check if target is in range
|
||||
if (this.can_target_space) {
|
||||
if (this.blast > 0) {
|
||||
return this.checkLocationTarget(ship, new Target(target.x, target.y));
|
||||
} else if (target.isInRange(ship.arena_x, ship.arena_y, this.equipment.distance)) {
|
||||
} else if (target.isInRange(ship.arena_x, ship.arena_y, this.range)) {
|
||||
return target;
|
||||
} else {
|
||||
return null;
|
||||
|
@ -49,7 +75,7 @@ module TS.SpaceTac {
|
|||
let battle = ship.getBattle();
|
||||
let ships = (blast && battle) ? battle.collectShipsInCircle(target, blast, true) : ((target.ship && target.ship.alive) ? [target.ship] : []);
|
||||
ships.forEach(ship => {
|
||||
this.equipment.target_effects.forEach(effect => result.push([ship, effect]));
|
||||
this.effects.forEach(effect => result.push([ship, effect]));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
@ -65,5 +91,15 @@ module TS.SpaceTac {
|
|||
let effects = this.getEffects(ship, target);
|
||||
effects.forEach(([ship, effect]) => effect.applyOnShip(ship));
|
||||
}
|
||||
|
||||
getEffectsDescription(): string[] {
|
||||
return this.effects.map(effect => {
|
||||
let suffix = this.blast ? `in ${this.blast}km radius` : "on target";
|
||||
if (effect instanceof StickyEffect) {
|
||||
suffix = `for ${effect.duration} turn${effect.duration > 1 ? "s" : ""} ${suffix}`;
|
||||
}
|
||||
return effect.getDescription() + " " + suffix;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@ module TS.SpaceTac {
|
|||
ship.arena_x = 0;
|
||||
ship.arena_y = 0;
|
||||
var engine = new Equipment();
|
||||
engine.distance = 1;
|
||||
engine.ap_usage = 2;
|
||||
var action = new MoveAction(engine);
|
||||
var action = new MoveAction(engine, 0.5);
|
||||
|
||||
expect(action.getDistanceByActionPoint(ship)).toBe(0.5);
|
||||
|
||||
|
@ -46,9 +44,7 @@ module TS.SpaceTac {
|
|||
ship.arena_x = 0;
|
||||
ship.arena_y = 0;
|
||||
var engine = new Equipment();
|
||||
engine.distance = 1;
|
||||
engine.ap_usage = 1;
|
||||
var action = new MoveAction(engine);
|
||||
var action = new MoveAction(engine, 1);
|
||||
battle.playing_ship = ship;
|
||||
|
||||
spyOn(console, "warn").and.stub();
|
||||
|
@ -84,12 +80,12 @@ module TS.SpaceTac {
|
|||
var battle = TestTools.createBattle(1, 1);
|
||||
var ship = battle.fleets[0].ships[0];
|
||||
var enemy = battle.fleets[1].ships[0];
|
||||
var engine = TestTools.addEngine(ship, 10);
|
||||
TestTools.setShipAP(ship, 100);
|
||||
ship.setArenaPosition(5, 5);
|
||||
enemy.setArenaPosition(10, 5);
|
||||
|
||||
var action = new MoveAction(engine);
|
||||
var action = new MoveAction(new Equipment());
|
||||
action.distance_per_power = 10;
|
||||
action.safety_distance = 2;
|
||||
|
||||
var result = action.checkLocationTarget(ship, Target.newFromLocation(7, 5));
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
module TS.SpaceTac {
|
||||
// Action to move to a given location
|
||||
export class MoveAction extends BaseAction {
|
||||
// Distance allowed for each power point
|
||||
distance_per_power: number;
|
||||
|
||||
// Safety distance from other ships
|
||||
safety_distance: number;
|
||||
|
@ -8,9 +10,10 @@ module TS.SpaceTac {
|
|||
// Equipment cannot be null (engine)
|
||||
equipment: Equipment;
|
||||
|
||||
constructor(equipment: Equipment) {
|
||||
constructor(equipment: Equipment, distance_per_power = 0) {
|
||||
super("move", "Move", true, equipment);
|
||||
|
||||
this.distance_per_power = distance_per_power;
|
||||
this.safety_distance = 50;
|
||||
}
|
||||
|
||||
|
@ -37,18 +40,18 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
var distance = Target.newFromShip(ship).getDistanceTo(target);
|
||||
return Math.ceil(this.equipment.ap_usage * distance / this.equipment.distance);
|
||||
return Math.ceil(distance / this.distance_per_power);
|
||||
}
|
||||
|
||||
getRangeRadius(ship: Ship): number {
|
||||
return ship.values.power.get() * this.equipment.distance / this.equipment.ap_usage;
|
||||
return ship.values.power.get() * this.distance_per_power;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance that may be traveled with 1 action point
|
||||
*/
|
||||
getDistanceByActionPoint(ship: Ship): number {
|
||||
return this.equipment.distance / this.equipment.ap_usage;
|
||||
return this.distance_per_power;
|
||||
}
|
||||
|
||||
checkLocationTarget(ship: Ship, target: Target): Target {
|
||||
|
|
|
@ -25,10 +25,10 @@ module TS.SpaceTac.Specs {
|
|||
expect(result.length).toBe(0);
|
||||
|
||||
var weapon1 = new Equipment(SlotType.Weapon, "weapon1");
|
||||
weapon1.target_effects.push(new DamageEffect(50));
|
||||
weapon1.action = new FireWeaponAction(weapon1, 1, 1, 1, [new DamageEffect(50)]);
|
||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon1);
|
||||
var weapon2 = new Equipment(SlotType.Weapon, "weapon2");
|
||||
weapon2.target_effects.push(new DamageEffect(100));
|
||||
weapon2.action = new FireWeaponAction(weapon1, 1, 1, 1, [new DamageEffect(100)]);
|
||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon2);
|
||||
var weapon3 = new Equipment(SlotType.Weapon, "weapon3");
|
||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon3);
|
||||
|
@ -207,16 +207,11 @@ module TS.SpaceTac.Specs {
|
|||
ai.move_margin = 0;
|
||||
|
||||
var engine = new Equipment(SlotType.Engine);
|
||||
engine.distance = 1;
|
||||
engine.ap_usage = 2;
|
||||
engine.action = new MoveAction(engine);
|
||||
engine.action = new MoveAction(engine, 0.5);
|
||||
ai.ship.addSlot(SlotType.Engine).attach(engine);
|
||||
|
||||
var weapon = new Equipment(SlotType.Weapon);
|
||||
weapon.distance = 6;
|
||||
weapon.ap_usage = 1;
|
||||
weapon.target_effects.push(new DamageEffect(20));
|
||||
weapon.action = new FireWeaponAction(weapon);
|
||||
weapon.action = new FireWeaponAction(weapon, 1, 6, 0, [new DamageEffect(20)]);
|
||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon);
|
||||
|
||||
ai.ship.values.power.setMaximal(10);
|
||||
|
|
|
@ -53,7 +53,7 @@ module TS.SpaceTac {
|
|||
|
||||
// List all weapons
|
||||
listAllWeapons(): Equipment[] {
|
||||
return this.ship.listEquipment(SlotType.Weapon).filter(equipement => any(equipement.target_effects, effect => effect instanceof DamageEffect));
|
||||
return this.ship.listEquipment(SlotType.Weapon).filter(equipement => equipement.action instanceof FireWeaponAction && any(equipement.action.effects, effect => effect instanceof DamageEffect));
|
||||
}
|
||||
|
||||
// List all available maneuvers for the playing ship
|
||||
|
|
|
@ -38,10 +38,10 @@ module TS.SpaceTac {
|
|||
*/
|
||||
static produceBlastShots(ship: Ship, battle: Battle): TacticalProducer {
|
||||
// TODO Work with groups of 3, 4 ...
|
||||
let weapons = ifilter(iarray(ship.listEquipment(SlotType.Weapon)), weapon => weapon.blast > 0);
|
||||
let weapons = ifilter(iarray(ship.listEquipment(SlotType.Weapon)), weapon => weapon.action instanceof FireWeaponAction && weapon.action.blast > 0);
|
||||
let enemies = battle.ienemies(ship.getPlayer());
|
||||
let couples = ifilter(icombine(enemies, enemies), ([e1, e2]) => e1 != e2);
|
||||
let candidates = ifilter(icombine(weapons, couples), ([weapon, [e1, e2]]) => Target.newFromShip(e1).getDistanceTo(Target.newFromShip(e2)) < weapon.blast * 2);
|
||||
let candidates = ifilter(icombine(weapons, couples), ([weapon, [e1, e2]]) => Target.newFromShip(e1).getDistanceTo(Target.newFromShip(e2)) < weapon.action.getBlastRadius(ship) * 2);
|
||||
let result = imap(candidates, ([weapon, [e1, e2]]) => new Maneuver(ship, weapon, Target.newFromLocation((e1.arena_x + e2.arena_x) / 2, (e1.arena_y + e2.arena_y) / 2)));
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -10,17 +10,6 @@ module TS.SpaceTac {
|
|||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy, modified by template modifiers
|
||||
*/
|
||||
getModifiedCopy(modifiers: EffectTemplateModifier[], power: number): BaseEffect {
|
||||
let result = copy(this);
|
||||
modifiers.forEach(modifier => {
|
||||
result[modifier.name] = modifier.range.getProportional(power);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Apply ponctually the effect on a given ship
|
||||
// Return true if the effect could be applied
|
||||
applyOnShip(ship: Ship): boolean {
|
||||
|
|
|
@ -29,13 +29,6 @@ module TS.SpaceTac {
|
|||
this.on_turn_end = on_turn_end;
|
||||
}
|
||||
|
||||
getModifiedCopy(modifiers: EffectTemplateModifier[], power: number): BaseEffect {
|
||||
let [current, base] = binpartition(modifiers, modifier => modifier.name == "duration");
|
||||
let result = <StickyEffect>super.getModifiedCopy(current, power);
|
||||
result.base = result.base.getModifiedCopy(base, power);
|
||||
return result;
|
||||
}
|
||||
|
||||
applyOnShip(ship: Ship): boolean {
|
||||
ship.addStickyEffect(new StickyEffect(this.base, this.duration, this.on_stick, this.on_turn_end));
|
||||
if (this.on_stick) {
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("AbstractDrone", function () {
|
||||
it("can be configured", function () {
|
||||
let template = new AbstractDrone("test");
|
||||
expect(template.name).toEqual("test");
|
||||
|
||||
template.setDeployDistance(5, 8);
|
||||
expect(template.distance).toEqual(new Range(5, 8));
|
||||
template.setEffectRadius(100, 300);
|
||||
expect(template.blast).toEqual(new IntegerRange(100, 300));
|
||||
template.setLifetime(2, 3);
|
||||
expect(template.duration).toEqual(new IntegerRange(2, 3));
|
||||
});
|
||||
|
||||
it("generates a drone-deploying equipment", function () {
|
||||
let template = new AbstractDrone("Test");
|
||||
template.setDeployDistance(100, 200);
|
||||
template.setEffectRadius(50, 100);
|
||||
template.setLifetime(2, 3);
|
||||
template.addDamage(20, 30);
|
||||
template.setPowerConsumption(3, 5);
|
||||
|
||||
let equipment = template.generateFixed(0);
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment));
|
||||
expect(equipment.ap_usage).toEqual(3);
|
||||
expect(equipment.blast).toEqual(50);
|
||||
expect(equipment.code).toEqual("test");
|
||||
expect(equipment.distance).toEqual(100);
|
||||
expect(equipment.duration).toEqual(2);
|
||||
expect(equipment.name).toEqual("Test");
|
||||
expect(equipment.permanent_effects).toEqual([]);
|
||||
expect(equipment.slot).toEqual(SlotType.Weapon);
|
||||
expect(equipment.target_effects).toEqual([new DamageEffect(20)]);
|
||||
|
||||
equipment = template.generateFixed(1);
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment));
|
||||
expect(equipment.ap_usage).toEqual(5);
|
||||
expect(equipment.blast).toEqual(100);
|
||||
expect(equipment.code).toEqual("test");
|
||||
expect(equipment.distance).toEqual(200);
|
||||
expect(equipment.duration).toEqual(3);
|
||||
expect(equipment.name).toEqual("Test");
|
||||
expect(equipment.permanent_effects).toEqual([]);
|
||||
expect(equipment.slot).toEqual(SlotType.Weapon);
|
||||
expect(equipment.target_effects).toEqual([new DamageEffect(30)]);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module TS.SpaceTac.Equipments {
|
||||
/**
|
||||
* Base class for all weapon equipment that deploys a drone.
|
||||
*/
|
||||
export class AbstractDrone extends LootTemplate {
|
||||
constructor(name: string) {
|
||||
super(SlotType.Weapon, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximal distance at which the drone may be deployed
|
||||
*
|
||||
* Be aware that *min_distance* means the MAXIMAL reachable distance, but on a low-power loot !
|
||||
*/
|
||||
setDeployDistance(min_distance: number, max_distance: number | null = null): void {
|
||||
this.distance = new Range(min_distance, max_distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the effect radius of the deployed drone
|
||||
*/
|
||||
setEffectRadius(min_radius: number, max_radius: number | null = null): void {
|
||||
this.blast = new IntegerRange(min_radius, max_radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the drone lifetime
|
||||
*/
|
||||
setLifetime(min_lifetime: number, max_lifetime: number | null = null): void {
|
||||
this.duration = new IntegerRange(min_lifetime, max_lifetime);
|
||||
}
|
||||
|
||||
protected getActionForEquipment(equipment: Equipment): BaseAction {
|
||||
var result = new DeployDroneAction(equipment);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("AbstractWeapon", function () {
|
||||
it("has fire action, and damage effects on target", function () {
|
||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50, 60);
|
||||
|
||||
var equipment = weapon.generateFixed(0.1);
|
||||
expect(equipment.target_effects.length).toBe(1);
|
||||
|
||||
var effect = <DamageEffect>equipment.target_effects[0];
|
||||
expect(effect.code).toEqual("damage");
|
||||
expect(effect.value).toEqual(51);
|
||||
|
||||
var action = equipment.action;
|
||||
expect(action.code).toEqual("fire-superfireweapon");
|
||||
expect(action.needs_target).toBe(true);
|
||||
});
|
||||
|
||||
it("controls ability to target emptiness", function () {
|
||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50, 60);
|
||||
weapon.setRange(10, 20, true);
|
||||
|
||||
var equipment = weapon.generateFixed(20);
|
||||
var action = <FireWeaponAction>equipment.action;
|
||||
expect(action.can_target_space).toBe(true);
|
||||
|
||||
weapon.setRange(10, 20, false);
|
||||
|
||||
equipment = weapon.generateFixed(20);
|
||||
action = <FireWeaponAction>equipment.action;
|
||||
expect(action.can_target_space).toBe(false);
|
||||
});
|
||||
|
||||
it("can't fire without sufficient AP", function () {
|
||||
var ship = new Ship();
|
||||
ship.values.power.set(3);
|
||||
|
||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50);
|
||||
|
||||
weapon.ap_usage = new Range(2);
|
||||
var equipment = weapon.generateFixed(0);
|
||||
expect(equipment.action.checkCannotBeApplied(ship)).toBe(null);
|
||||
|
||||
weapon.ap_usage = new Range(3);
|
||||
equipment = weapon.generateFixed(0);
|
||||
expect(equipment.action.checkCannotBeApplied(ship)).toBe(null);
|
||||
|
||||
weapon.ap_usage = new Range(4);
|
||||
equipment = weapon.generateFixed(0);
|
||||
expect(equipment.action.checkCannotBeApplied(ship)).toBe("not enough power");
|
||||
});
|
||||
|
||||
it("can't friendly fire", function () {
|
||||
var fleet1 = new Fleet(new Player());
|
||||
var fleet2 = new Fleet(new Player());
|
||||
var ship1a = new Ship(fleet1);
|
||||
var ship1b = new Ship(fleet1);
|
||||
var ship2a = new Ship(fleet2);
|
||||
|
||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50, 60);
|
||||
weapon.setRange(10, 10);
|
||||
var equipment = weapon.generateFixed(0);
|
||||
|
||||
expect(equipment.action.checkShipTarget(ship1a, Target.newFromShip(ship2a))).toEqual(
|
||||
Target.newFromShip(ship2a));
|
||||
expect(equipment.action.checkShipTarget(ship1a, Target.newFromShip(ship1b))).toBeNull();
|
||||
});
|
||||
|
||||
it("can't fire farther than its range", function () {
|
||||
var fleet1 = new Fleet(new Player());
|
||||
var fleet2 = new Fleet(new Player());
|
||||
|
||||
var ship = new Ship(fleet1);
|
||||
ship.setArenaPosition(10, 10);
|
||||
|
||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 50);
|
||||
weapon.setRange(10, 10, true);
|
||||
|
||||
var equipment = weapon.generateFixed(0);
|
||||
expect(equipment.distance).toEqual(10);
|
||||
|
||||
expect(equipment.action.checkLocationTarget(ship, Target.newFromLocation(15, 10))).toEqual(
|
||||
Target.newFromLocation(15, 10));
|
||||
expect(equipment.action.checkLocationTarget(ship, Target.newFromLocation(30, 10))).toEqual(
|
||||
Target.newFromLocation(20, 10));
|
||||
|
||||
// Ship targetting
|
||||
var ship2 = new Ship(fleet2);
|
||||
|
||||
ship2.setArenaPosition(10, 15);
|
||||
expect(equipment.action.checkShipTarget(ship, Target.newFromShip(ship2))).toEqual(
|
||||
Target.newFromLocation(10, 15));
|
||||
|
||||
ship2.setArenaPosition(10, 25);
|
||||
expect(equipment.action.checkShipTarget(ship, Target.newFromShip(ship2))).toEqual(
|
||||
Target.newFromLocation(10, 20));
|
||||
|
||||
// Forbid targetting in space
|
||||
weapon.setRange(10, 10, false);
|
||||
equipment = weapon.generateFixed(0);
|
||||
expect(equipment.action.checkLocationTarget(ship, Target.newFromLocation(15, 10))).toBeNull();
|
||||
});
|
||||
|
||||
it("can target an enemy ship and damage it", function () {
|
||||
var fleet1 = new Fleet(new Player());
|
||||
var fleet2 = new Fleet(new Player());
|
||||
|
||||
var ship1 = new Ship(fleet1);
|
||||
ship1.values.power.set(50);
|
||||
|
||||
var ship2 = new Ship(fleet2);
|
||||
ship2.setAttribute("hull_capacity", 100);
|
||||
ship2.setAttribute("shield_capacity", 30);
|
||||
ship2.restoreHealth();
|
||||
|
||||
expect(ship2.values.hull.get()).toEqual(100);
|
||||
expect(ship2.values.shield.get()).toEqual(30);
|
||||
|
||||
var weapon = new Equipments.AbstractWeapon("Super Fire Weapon", 20);
|
||||
weapon.ap_usage = new IntegerRange(1, 1);
|
||||
|
||||
var equipment = weapon.generateFixed(0);
|
||||
|
||||
equipment.action.apply(ship1, Target.newFromShip(ship2));
|
||||
expect(ship2.values.hull.get()).toEqual(100);
|
||||
expect(ship2.values.shield.get()).toEqual(10);
|
||||
expect(ship1.values.power.get()).toEqual(49);
|
||||
|
||||
equipment.action.apply(ship1, Target.newFromShip(ship2));
|
||||
expect(ship2.values.hull.get()).toEqual(90);
|
||||
expect(ship2.values.shield.get()).toEqual(0);
|
||||
expect(ship1.values.power.get()).toEqual(48);
|
||||
|
||||
equipment.action.apply(ship1, Target.newFromShip(ship2));
|
||||
expect(ship2.values.hull.get()).toEqual(70);
|
||||
expect(ship2.values.shield.get()).toEqual(0);
|
||||
expect(ship1.values.power.get()).toEqual(47);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module TS.SpaceTac.Equipments {
|
||||
// Base convenience class for weapons
|
||||
export class AbstractWeapon extends LootTemplate {
|
||||
// Boolean set to true if the weapon can target space
|
||||
can_target_space: boolean;
|
||||
|
||||
constructor(name: string, min_damage: number = 0, max_damage: number | null = null) {
|
||||
super(SlotType.Weapon, name);
|
||||
|
||||
this.can_target_space = false;
|
||||
|
||||
if (min_damage > 0 || (max_damage != null && max_damage > 0)) {
|
||||
this.addDamage(min_damage, max_damage);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the range for this weapon
|
||||
// Pay attention that *min_distance* means the MAXIMAL reachable distance, but on a low-power loot
|
||||
setRange(min_distance: number, max_distance: number | null = null, can_target_space = false): void {
|
||||
this.distance = new Range(min_distance, max_distance);
|
||||
this.can_target_space = can_target_space;
|
||||
}
|
||||
|
||||
// Set the effect radius (blast) for this weapon
|
||||
setBlast(min_blast: number, max_blast: number | null = null): void {
|
||||
this.blast = new IntegerRange(min_blast, max_blast);
|
||||
}
|
||||
|
||||
protected getActionForEquipment(equipment: Equipment): BaseAction {
|
||||
var result = new FireWeaponAction(equipment, this.can_target_space);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
23
src/core/equipments/BasicForceField.spec.ts
Normal file
23
src/core/equipments/BasicForceField.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("BasicForceField", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new BasicForceField();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 1 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("shield_capacity", 100)]);
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 2 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("shield_capacity", 150)]);
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 3 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("shield_capacity", 200)]);
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 10 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("shield_capacity", 550)]);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,9 +5,8 @@ module TS.SpaceTac.Equipments {
|
|||
constructor() {
|
||||
super(SlotType.Shield, "Basic Force Field");
|
||||
|
||||
this.min_level = new IntegerRange(1, 3);
|
||||
|
||||
this.increaseAttribute("shield_capacity", 100, 200);
|
||||
this.setSkillsRequirements({ "skill_energy": 1 });
|
||||
this.addAttributeEffect("shield_capacity", istep(100, irepeat(50)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
43
src/core/equipments/BasicPowerCore.spec.ts
Normal file
43
src/core/equipments/BasicPowerCore.spec.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("BasicPowerCore", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new BasicPowerCore();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 1 });
|
||||
expect(equipment.effects).toEqual([
|
||||
new AttributeEffect("initiative", 1),
|
||||
new AttributeEffect("power_capacity", 6),
|
||||
new AttributeEffect("power_initial", 4),
|
||||
new AttributeEffect("power_recovery", 3),
|
||||
]);
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 2 });
|
||||
expect(equipment.effects).toEqual([
|
||||
new AttributeEffect("initiative", 2),
|
||||
new AttributeEffect("power_capacity", 7),
|
||||
new AttributeEffect("power_initial", 4),
|
||||
new AttributeEffect("power_recovery", 3),
|
||||
]);
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 3 });
|
||||
expect(equipment.effects).toEqual([
|
||||
new AttributeEffect("initiative", 3),
|
||||
new AttributeEffect("power_capacity", 8),
|
||||
new AttributeEffect("power_initial", 5),
|
||||
new AttributeEffect("power_recovery", 3),
|
||||
]);
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 10 });
|
||||
expect(equipment.effects).toEqual([
|
||||
new AttributeEffect("initiative", 10),
|
||||
new AttributeEffect("power_capacity", 15),
|
||||
new AttributeEffect("power_initial", 8),
|
||||
new AttributeEffect("power_recovery", 5),
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,12 +5,11 @@ module TS.SpaceTac.Equipments {
|
|||
constructor() {
|
||||
super(SlotType.Power, "Basic Power Core");
|
||||
|
||||
this.min_level = new IntegerRange(1, 1);
|
||||
|
||||
this.increaseAttribute("initiative", 1);
|
||||
this.increaseAttribute("power_capacity", 8);
|
||||
this.increaseAttribute("power_initial", 4);
|
||||
this.increaseAttribute("power_recovery", 3);
|
||||
this.setSkillsRequirements({ "skill_energy": 1 });
|
||||
this.addAttributeEffect("initiative", istep(1));
|
||||
this.addAttributeEffect("power_capacity", istep(6));
|
||||
this.addAttributeEffect("power_initial", istep(4, irepeat(0.5)));
|
||||
this.addAttributeEffect("power_recovery", istep(3, irepeat(0.3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
27
src/core/equipments/ConventionalEngine.spec.ts
Normal file
27
src/core/equipments/ConventionalEngine.spec.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("ConventionalEngine", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new ConventionalEngine();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 1 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("initiative", 1)]);
|
||||
expect(equipment.action).toEqual(new MoveAction(equipment, 200));
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 2 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("initiative", 2)]);
|
||||
expect(equipment.action).toEqual(new MoveAction(equipment, 220));
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 3 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("initiative", 3)]);
|
||||
expect(equipment.action).toEqual(new MoveAction(equipment, 240));
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 10 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("initiative", 10)]);
|
||||
expect(equipment.action).toEqual(new MoveAction(equipment, 380));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -6,15 +6,9 @@ module TS.SpaceTac.Equipments {
|
|||
constructor() {
|
||||
super(SlotType.Engine, "Conventional Engine");
|
||||
|
||||
this.min_level = new IntegerRange(1, 1);
|
||||
this.distance = new Range(200, 200);
|
||||
this.ap_usage = new IntegerRange(1);
|
||||
|
||||
this.increaseAttribute("initiative", 1);
|
||||
}
|
||||
|
||||
protected getActionForEquipment(equipment: Equipment): BaseAction {
|
||||
return new MoveAction(equipment);
|
||||
this.setSkillsRequirements({ "skill_energy": 1 });
|
||||
this.addAttributeEffect("initiative", 1);
|
||||
this.addMoveAction(istep(200, irepeat(20)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
src/core/equipments/GatlingGun.spec.ts
Normal file
23
src/core/equipments/GatlingGun.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("GatlingGun", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new GatlingGun();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 1 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 600, 0, [new DamageEffect(50)]));
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 2 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 600, 0, [new DamageEffect(60)]));
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 3 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 600, 0, [new DamageEffect(70)]));
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 10 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 600, 0, [new DamageEffect(140)]));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
/// <reference path="AbstractWeapon.ts"/>
|
||||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module TS.SpaceTac.Equipments {
|
||||
export class GatlingGun extends AbstractWeapon {
|
||||
export class GatlingGun extends LootTemplate {
|
||||
constructor() {
|
||||
super("Gatling Gun", 50, 100);
|
||||
super(SlotType.Weapon, "Gatling Gun");
|
||||
|
||||
this.setRange(600, 600, false);
|
||||
|
||||
this.ap_usage = new IntegerRange(3, 4);
|
||||
this.min_level = new IntegerRange(1, 3);
|
||||
this.setSkillsRequirements({ "skill_material": 1 });
|
||||
this.addFireAction(irepeat(3), irepeat(600), 0, [
|
||||
new EffectTemplate(new DamageEffect(), { "value": istep(50, irepeat(10)) })
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
src/core/equipments/IronHull.spec.ts
Normal file
23
src/core/equipments/IronHull.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("IronHull", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new IronHull();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 1 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("hull_capacity", 200)]);
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 2 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("hull_capacity", 250)]);
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 3 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("hull_capacity", 300)]);
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 10 });
|
||||
expect(equipment.effects).toEqual([new AttributeEffect("hull_capacity", 650)]);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,9 +5,8 @@ module TS.SpaceTac.Equipments {
|
|||
constructor() {
|
||||
super(SlotType.Hull, "Iron Hull");
|
||||
|
||||
this.min_level = new IntegerRange(1, 3);
|
||||
|
||||
this.increaseAttribute("hull_capacity", 200, 300);
|
||||
this.setSkillsRequirements({ "skill_material": 1 });
|
||||
this.addAttributeEffect("hull_capacity", istep(200, irepeat(50)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,28 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
module TS.SpaceTac.Equipments {
|
||||
describe("PowerDepleter", () => {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new PowerDepleter();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 1 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 500, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 2 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 520, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 3 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 540, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_energy": 10 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 680, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
|
||||
});
|
||||
|
||||
it("limits target's AP", () => {
|
||||
var template = new Equipments.PowerDepleter();
|
||||
var equipment = template.generateFixed(0);
|
||||
var template = new PowerDepleter();
|
||||
var equipment = template.generate(1);
|
||||
|
||||
var ship = new Ship();
|
||||
var target = new Ship();
|
||||
|
@ -15,9 +35,9 @@ module TS.SpaceTac.Specs {
|
|||
// Attribute is immediately limited
|
||||
equipment.action.apply(ship, Target.newFromShip(target));
|
||||
|
||||
expect(target.values.power.get()).toBe(4);
|
||||
expect(target.values.power.get()).toBe(3);
|
||||
expect(target.sticky_effects).toEqual([
|
||||
new StickyEffect(new AttributeLimitEffect("power_capacity", 4), 2, true, false)
|
||||
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true, false)
|
||||
]);
|
||||
|
||||
// Attribute is limited for two turns, and prevents AP recovery
|
||||
|
@ -25,14 +45,14 @@ module TS.SpaceTac.Specs {
|
|||
target.recoverActionPoints();
|
||||
target.startTurn();
|
||||
|
||||
expect(target.values.power.get()).toBe(4);
|
||||
expect(target.values.power.get()).toBe(3);
|
||||
expect(target.sticky_effects).toEqual([
|
||||
new StickyEffect(new AttributeLimitEffect("power_capacity", 4), 1, true, false)
|
||||
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 1, true, false)
|
||||
]);
|
||||
|
||||
target.endTurn();
|
||||
target.recoverActionPoints();
|
||||
expect(target.values.power.get()).toBe(4);
|
||||
expect(target.values.power.get()).toBe(3);
|
||||
target.startTurn();
|
||||
|
||||
expect(target.sticky_effects).toEqual([]);
|
||||
|
@ -40,7 +60,7 @@ module TS.SpaceTac.Specs {
|
|||
// Effect vanished, so AP recovery happens
|
||||
target.endTurn();
|
||||
|
||||
expect(target.values.power.get()).toBe(6);
|
||||
expect(target.values.power.get()).toBe(5);
|
||||
expect(target.sticky_effects).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
/// <reference path="AbstractWeapon.ts"/>
|
||||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module TS.SpaceTac.Equipments {
|
||||
export class PowerDepleter extends AbstractWeapon {
|
||||
export class PowerDepleter extends LootTemplate {
|
||||
constructor() {
|
||||
super("Power Depleter");
|
||||
super(SlotType.Weapon, "Power Depleter");
|
||||
|
||||
this.setRange(500, 700, false);
|
||||
|
||||
this.ap_usage = new IntegerRange(4, 5);
|
||||
this.min_level = new IntegerRange(1, 3);
|
||||
|
||||
this.addStickyEffect(new AttributeLimitEffect("power_capacity"), 4, 3, 2, 3, true);
|
||||
this.setSkillsRequirements({ "skill_energy": 1 });
|
||||
this.addFireAction(irepeat(4), istep(500, irepeat(20)), 0, [
|
||||
new StickyEffectTemplate(new AttributeLimitEffect("power_capacity"), { "value": irepeat(3) }, irepeat(2))
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,30 @@
|
|||
module TS.SpaceTac.Equipments {
|
||||
describe("RepairDrone", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new RepairDrone();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 1 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 300, 1, 100, [new ValueEffect("hull", 30)]));
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 2 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 310, 1, 110, [new ValueEffect("hull", 33)]));
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 3 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 320, 1, 120, [new ValueEffect("hull", 36)]));
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_human": 10 });
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 390, 2, 190, [new ValueEffect("hull", 57)]));
|
||||
});
|
||||
|
||||
it("generates a drone that may repair ships hull", function () {
|
||||
let template = new RepairDrone();
|
||||
|
||||
let equipment = template.generateFixed(0);
|
||||
expect(equipment.target_effects).toEqual([new ValueEffect("hull", 30)]);
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.action).toEqual(new DeployDroneAction(equipment, 4, 300, 1, 100, [new ValueEffect("hull", 30)]));
|
||||
|
||||
let battle = new Battle();
|
||||
let ship = battle.fleets[0].addShip();
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
/// <reference path="AbstractDrone.ts"/>
|
||||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module TS.SpaceTac.Equipments {
|
||||
/**
|
||||
* Drone that repairs damage done to the hull.
|
||||
*/
|
||||
export class RepairDrone extends AbstractDrone {
|
||||
export class RepairDrone extends LootTemplate {
|
||||
constructor() {
|
||||
super("Repair Drone");
|
||||
super(SlotType.Weapon, "Repair Drone");
|
||||
|
||||
this.min_level = new IntegerRange(1, 4);
|
||||
|
||||
this.setLifetime(1, 2);
|
||||
this.setDeployDistance(300, 400);
|
||||
this.setEffectRadius(100, 200);
|
||||
this.setPowerConsumption(4, 5);
|
||||
|
||||
this.addEffect(new ValueEffect("hull"), 30, 60);
|
||||
this.setSkillsRequirements({ "skill_human": 1 });
|
||||
this.addDroneAction(irepeat(4), istep(300, irepeat(10)), istep(1, irepeat(0.2)), istep(100, irepeat(10)), [
|
||||
new EffectTemplate(new ValueEffect("hull"), { "value": istep(30, irepeat(3)) })
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,26 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("SubMunitionMissile", () => {
|
||||
it("hits several targets in circle", () => {
|
||||
module TS.SpaceTac.Equipments {
|
||||
describe("SubMunitionMissile", function () {
|
||||
it("generates equipment based on level", function () {
|
||||
let template = new SubMunitionMissile();
|
||||
|
||||
let equipment = template.generate(1);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 1 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 500, 150, [new DamageEffect(30)]));
|
||||
|
||||
equipment = template.generate(2);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 2 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 520, 155, [new DamageEffect(32)]));
|
||||
|
||||
equipment = template.generate(3);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 3 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 540, 160, [new DamageEffect(34)]));
|
||||
|
||||
equipment = template.generate(10);
|
||||
expect(equipment.requirements).toEqual({ "skill_material": 10 });
|
||||
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 680, 195, [new DamageEffect(48)]));
|
||||
});
|
||||
|
||||
it("hits several targets in circle", function () {
|
||||
var battle = TestTools.createBattle(1, 2);
|
||||
|
||||
var ship = battle.fleets[0].ships[0];
|
||||
|
@ -15,10 +35,11 @@ module TS.SpaceTac.Specs {
|
|||
TestTools.setShipHP(enemy2, 50, 30);
|
||||
|
||||
var template = new Equipments.SubMunitionMissile();
|
||||
var equipment = template.generateFixed(0);
|
||||
equipment.distance = 5;
|
||||
equipment.blast = 1.5;
|
||||
(<DamageEffect>equipment.target_effects[0]).value = 20;
|
||||
var equipment = template.generate(1);
|
||||
let action = <FireWeaponAction>equipment.action;
|
||||
action.range = 5;
|
||||
action.blast = 1.5;
|
||||
(<DamageEffect>action.effects[0]).value = 20;
|
||||
|
||||
var checkHP = (h1: number, s1: number, h2: number, s2: number, h3: number, s3: number): void => {
|
||||
expect(ship.values.hull.get()).toBe(h1);
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
/// <reference path="AbstractWeapon.ts"/>
|
||||
/// <reference path="../LootTemplate.ts"/>
|
||||
|
||||
module TS.SpaceTac.Equipments {
|
||||
export class SubMunitionMissile extends AbstractWeapon {
|
||||
export class SubMunitionMissile extends LootTemplate {
|
||||
constructor() {
|
||||
super("SubMunition Missile", 30, 50);
|
||||
super(SlotType.Weapon, "SubMunition Missile");
|
||||
|
||||
this.setRange(500, 700, true);
|
||||
this.setBlast(150, 200);
|
||||
|
||||
this.ap_usage = new IntegerRange(4, 5);
|
||||
this.min_level = new IntegerRange(1, 3);
|
||||
this.setSkillsRequirements({ "skill_material": 1 });
|
||||
this.addFireAction(irepeat(4), istep(500, irepeat(20)), istep(150, irepeat(5)), [
|
||||
new EffectTemplate(new DamageEffect(), { "value": istep(30, irepeat(2)) })
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,16 +19,16 @@ module TS.SpaceTac.UI.Specs {
|
|||
expect(bar.action_icons[0].action.code).toEqual("endturn");
|
||||
|
||||
// Add an engine, with move action
|
||||
ship.addSlot(SlotType.Engine).attach((new Equipments.ConventionalEngine()).generate());
|
||||
TestTools.addEngine(ship, 50);
|
||||
bar.setShip(ship);
|
||||
expect(bar.action_icons.length).toBe(2);
|
||||
expect(bar.action_icons[0].action.code).toEqual("move");
|
||||
|
||||
// Add a weapon, with fire action
|
||||
ship.addSlot(SlotType.Weapon).attach((new Equipments.GatlingGun()).generate());
|
||||
TestTools.addWeapon(ship, 10, 1, 100);
|
||||
bar.setShip(ship);
|
||||
expect(bar.action_icons.length).toBe(3);
|
||||
expect(bar.action_icons[1].action.code).toEqual("fire-gatlinggun");
|
||||
expect(bar.action_icons[1].action.code).toEqual("fire-equipment");
|
||||
});
|
||||
|
||||
it("mark actions that would become unavailable after use", function () {
|
||||
|
@ -37,16 +37,9 @@ module TS.SpaceTac.UI.Specs {
|
|||
var ship = new Ship();
|
||||
ship.arena_x = 1;
|
||||
ship.arena_y = 8;
|
||||
var engine = (new Equipments.ConventionalEngine()).generate();
|
||||
engine.ap_usage = 8;
|
||||
engine.distance = 4;
|
||||
ship.addSlot(SlotType.Engine).attach(engine);
|
||||
var weapon1 = (new Equipments.GatlingGun()).generate();
|
||||
weapon1.ap_usage = 3;
|
||||
ship.addSlot(SlotType.Weapon).attach(weapon1);
|
||||
var weapon2 = (new Equipments.GatlingGun()).generate();
|
||||
weapon2.ap_usage = 5;
|
||||
ship.addSlot(SlotType.Weapon).attach(weapon2);
|
||||
var engine = TestTools.addEngine(ship, 0.5);
|
||||
var weapon1 = TestTools.addWeapon(ship, 100, 3);
|
||||
var weapon2 = TestTools.addWeapon(ship, 100, 5);
|
||||
battleview.battle.playing_ship = ship;
|
||||
battleview.player = ship.getPlayer();
|
||||
|
||||
|
|
|
@ -52,11 +52,12 @@ module TS.SpaceTac.UI {
|
|||
this.position.set(action.x, action.y + action.height + 44);
|
||||
this.main_title.setText(action.action.equipment ? action.action.equipment.name : action.action.name);
|
||||
this.sub_title.setText(action.action.equipment ? action.action.name : "");
|
||||
let cost = action.action.equipment ? `Cost: ${action.action.equipment.ap_usage} power` : "";
|
||||
if (action.action instanceof MoveAction) {
|
||||
cost += ` per ${action.action.equipment.distance}km`;
|
||||
this.cost.setText(`Cost: 1 power per ${action.action.distance_per_power}km`);
|
||||
} else {
|
||||
let cost = action.action.getActionPointsUsage(action.ship, null);
|
||||
this.cost.setText(cost == 0 ? "" : `Cost: ${cost} power`);
|
||||
}
|
||||
this.cost.setText(cost);
|
||||
this.description.setText(action.action.equipment ? action.action.equipment.getActionDescription() : "");
|
||||
|
||||
let position = this.bar.action_icons.indexOf(action);
|
||||
|
|
|
@ -127,13 +127,15 @@ module TS.SpaceTac.UI {
|
|||
missile.rotation = this.source.getAngleTo(this.destination);
|
||||
this.layer.addChild(missile);
|
||||
|
||||
let blast_radius = this.weapon.action.getBlastRadius(this.source.ship || new Ship());
|
||||
|
||||
let tween = this.ui.tweens.create(missile);
|
||||
tween.to({ x: this.destination.x, y: this.destination.y }, 1000);
|
||||
tween.onComplete.addOnce(() => {
|
||||
missile.destroy();
|
||||
if (this.weapon.blast) {
|
||||
if (blast_radius > 0) {
|
||||
let blast = new Phaser.Image(this.ui, this.destination.x, this.destination.y, "battle-weapon-blast");
|
||||
let scaling = this.weapon.blast * 2 / (blast.width * 0.9);
|
||||
let scaling = blast_radius * 2 / (blast.width * 0.9);
|
||||
blast.anchor.set(0.5, 0.5);
|
||||
blast.scale.set(0.001, 0.001);
|
||||
let tween1 = this.ui.tweens.create(blast.scale).to({ x: scaling, y: scaling }, 1500, Phaser.Easing.Quintic.Out);
|
||||
|
@ -146,7 +148,7 @@ module TS.SpaceTac.UI {
|
|||
});
|
||||
tween.start();
|
||||
|
||||
return 1000 + (this.weapon.blast ? 1500 : 0);
|
||||
return 1000 + (blast_radius ? 1500 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,8 +50,8 @@ module TS.SpaceTac.UI {
|
|||
return 0;
|
||||
}
|
||||
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (this.ship != this.sheet.ship && equipment.item.slot !== null) {
|
||||
let slot = this.ship.getFreeSlot(equipment.item.slot);
|
||||
if (this.ship != this.sheet.ship && equipment.item.slot_type !== null) {
|
||||
let slot = this.ship.getFreeSlot(equipment.item.slot_type);
|
||||
if (slot) {
|
||||
if (test) {
|
||||
return true;
|
||||
|
|
|
@ -36,7 +36,7 @@ module TS.SpaceTac.UI {
|
|||
return 66;
|
||||
}
|
||||
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (equipment.item.slot !== null && this.sheet.ship.getFreeSlot(equipment.item.slot)) {
|
||||
if (equipment.item.slot_type !== null && this.sheet.ship.getFreeSlot(equipment.item.slot_type)) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
|
@ -47,7 +47,7 @@ module TS.SpaceTac.UI {
|
|||
}
|
||||
}
|
||||
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (contains(this.sheet.ship.listEquipment(equipment.item.slot), equipment.item)) {
|
||||
if (contains(this.sheet.ship.listEquipment(equipment.item.slot_type), equipment.item)) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue