1
0
Fork 0

Move distance is now dependent on maneuvrability

This commit is contained in:
Michaël Lemaire 2017-08-18 00:53:21 +02:00
parent d3cbcb0c04
commit 2106b93439
12 changed files with 94 additions and 42 deletions

View file

@ -58,7 +58,6 @@ Ships models and equipments
* Add permanent effects and actions to ship models
* Add critical hit/miss
* Add damage over time effect (tricky to make intuitive)
* Move distance should increase with maneuvrability
* Chance to hit should increase with precision
* Add actions with cost dependent of distance (like current move actions)
* Add "cone" targetting

View file

@ -82,6 +82,7 @@ module TS.SpaceTac {
if (equipment.action instanceof MoveAction) {
simpleFactor(equipment.action, 'distance_per_power');
simpleFactor(equipment.action, 'maneuvrability_factor', true);
}
if (equipment.cooldown.overheat) {

View file

@ -84,13 +84,13 @@ module TS.SpaceTac.Specs {
it("adds move actions", function () {
let template = new LootTemplate(SlotType.Engine, "Engine");
template.addMoveAction(irange(undefined, 100, 10));
template.addMoveAction(irange(undefined, 100, 10), istep(50, irepeat(10)), irepeat(95));
let result = template.generate(1);
expect(result.action).toEqual(new MoveAction(result, 100));
expect(result.action).toEqual(new MoveAction(result, 100, 50, 95));
result = template.generate(2);
expect(result.action).toEqual(new MoveAction(result, 110));
expect(result.action).toEqual(new MoveAction(result, 110, 60, 95));
});
it("adds fire actions", function () {

View file

@ -193,9 +193,9 @@ module TS.SpaceTac {
/**
* Add a move action.
*/
addMoveAction(distance_per_power: LeveledValue, safety_distance: LeveledValue = irepeat(120)): void {
addMoveAction(distance_per_power: LeveledValue, safety_distance: LeveledValue = irepeat(120), maneuvrability_factor: LeveledValue = irepeat(80)): void {
this.base_modifiers.push((equipment, level) => {
equipment.action = new MoveAction(equipment, resolveForLevel(distance_per_power, level), resolveForLevel(safety_distance, level));
equipment.action = new MoveAction(equipment, resolveForLevel(distance_per_power, level), resolveForLevel(safety_distance, level), resolveForLevel(maneuvrability_factor, level));
});
}

View file

@ -60,7 +60,7 @@ module TS.SpaceTac {
if (engines.length == 0) {
return null;
} else {
return maxBy(engines, engine => (engine.action instanceof MoveAction) ? engine.action.distance_per_power : 0);
return maxBy(engines, engine => (engine.action instanceof MoveAction) ? engine.action.getDistanceByActionPoint(this.ship) : 0);
}
}

View file

@ -35,10 +35,12 @@ module TS.SpaceTac {
return equipment;
}
// Add an engine, allowing a ship to move *distance*, for each action points
/**
* 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.RocketEngine(), true);
(<MoveAction>equipment.action).distance_per_power = distance;
let equipment = ship.addSlot(SlotType.Engine).attach(new Equipment(SlotType.Engine));
equipment.action = new MoveAction(equipment, distance);
return equipment;
}

View file

@ -9,18 +9,18 @@ module TS.SpaceTac {
ship.arena_x = 0;
ship.arena_y = 0;
var engine = new Equipment();
var action = new MoveAction(engine, 0.5);
var action = new MoveAction(engine, 10);
expect(action.getDistanceByActionPoint(ship)).toBe(0.5);
expect(action.getDistanceByActionPoint(ship)).toBe(10);
var result = action.checkTarget(ship, Target.newFromLocation(0, 2));
expect(result).toEqual(Target.newFromLocation(0, 2));
var result = action.checkTarget(ship, Target.newFromLocation(0, 20));
expect(result).toEqual(Target.newFromLocation(0, 20));
result = action.checkTarget(ship, Target.newFromLocation(0, 8));
expect(result).toEqual(Target.newFromLocation(0, 2.9));
result = action.checkTarget(ship, Target.newFromLocation(0, 80));
expect(nn(result).y).toBeCloseTo(59.9, 0.000001);
ship.values.power.set(0);
result = action.checkTarget(ship, Target.newFromLocation(0, 8));
result = action.checkTarget(ship, Target.newFromLocation(0, 80));
expect(result).toBeNull();
});
@ -141,5 +141,36 @@ module TS.SpaceTac {
result = action.checkLocationTarget(ship, Target.newFromLocation(0, 1400));
expect(result).toEqual(Target.newFromLocation(0, 1400));
});
it("applies ship maneuvrability to determine distance per power point", function () {
let ship = new Ship();
let action = new MoveAction(new Equipment(), 100, undefined, 60);
ship.setAttribute("maneuvrability", 0);
expect(action.getDistanceByActionPoint(ship)).toBeCloseTo(40, 0.01);
ship.setAttribute("maneuvrability", 1);
expect(action.getDistanceByActionPoint(ship)).toBeCloseTo(60, 0.01);
ship.setAttribute("maneuvrability", 2);
expect(action.getDistanceByActionPoint(ship)).toBeCloseTo(70, 0.01);
ship.setAttribute("maneuvrability", 10);
expect(action.getDistanceByActionPoint(ship)).toBeCloseTo(90, 0.01);
action = new MoveAction(new Equipment(), 100, undefined, 0);
ship.setAttribute("maneuvrability", 0);
expect(action.getDistanceByActionPoint(ship)).toBeCloseTo(100, 0.01);
ship.setAttribute("maneuvrability", 10);
expect(action.getDistanceByActionPoint(ship)).toBeCloseTo(100, 0.01);
});
it("builds a textual description", function () {
let action = new MoveAction(new Equipment(), 58, 0, 0);
expect(action.getEffectsDescription()).toEqual("Move: 58km per power point");
action = new MoveAction(new Equipment(), 58, 12, 0);
expect(action.getEffectsDescription()).toEqual("Move: 58km per power point (safety: 12km)");
action = new MoveAction(new Equipment(), 58, 12, 80);
expect(action.getEffectsDescription()).toEqual("Move: 58km per power point (safety: 12km, maneuvrability influence: 80%)");
});
});
}

View file

@ -1,7 +1,7 @@
module TS.SpaceTac {
// Action to move to a given location
export class MoveAction extends BaseAction {
// Distance allowed for each power point
// Distance allowed for each power point (raw, without applying maneuvrability)
distance_per_power: number
// Safety distance from other ships
@ -10,11 +10,15 @@ module TS.SpaceTac {
// Equipment cannot be null (engine)
equipment: Equipment
constructor(equipment: Equipment, distance_per_power = 0, safety_distance = 120) {
// Impact of maneuvrability (in % of distance)
maneuvrability_factor: number
constructor(equipment: Equipment, distance_per_power = 0, safety_distance = 120, maneuvrability_factor = 0) {
super("move", "Move", true, equipment);
this.distance_per_power = distance_per_power;
this.safety_distance = safety_distance;
this.maneuvrability_factor = maneuvrability_factor;
}
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): string | null {
@ -40,18 +44,20 @@ module TS.SpaceTac {
}
var distance = Target.newFromShip(ship).getDistanceTo(target);
return Math.ceil(distance / this.distance_per_power);
return Math.ceil(distance / this.getDistanceByActionPoint(ship));
}
getRangeRadius(ship: Ship): number {
return ship.values.power.get() * this.distance_per_power;
return ship.getValue("power") * this.getDistanceByActionPoint(ship);
}
/**
* Get the distance that may be traveled with 1 action point
*/
getDistanceByActionPoint(ship: Ship): number {
return this.distance_per_power;
let maneuvrability = Math.max(ship.getAttribute("maneuvrability"), 0);
let factor = maneuvrability / (maneuvrability + 2);
return Math.ceil(this.distance_per_power * (1 - this.maneuvrability_factor * 0.01 * (1 - factor)));
}
/**
@ -92,7 +98,20 @@ module TS.SpaceTac {
}
getEffectsDescription(): string {
return `Move: ${this.distance_per_power}km per power point (safety: ${this.safety_distance}km)`;
let result = `Move: ${this.distance_per_power}km per power point`;
let precisions = [];
if (this.safety_distance) {
precisions.push(`safety: ${this.safety_distance}km`);
}
if (this.maneuvrability_factor) {
precisions.push(`maneuvrability influence: ${this.maneuvrability_factor}%`);
}
if (precisions.length) {
result += ` (${precisions.join(", ")})`;
}
return result;
}
}
}

View file

@ -7,60 +7,60 @@ module TS.SpaceTac.Equipments {
expect(equipment.requirements).toEqual({ "skill_materials": 1 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 2)]);
expect(equipment.cooldown).toEqual(new Cooldown(2, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 200));
expect(equipment.action).toEqual(new MoveAction(equipment, 200, 120, 70));
expect(equipment.price).toEqual(120);
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_materials": 2 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 4)]);
expect(equipment.cooldown).toEqual(new Cooldown(2, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 220));
expect(equipment.action).toEqual(new MoveAction(equipment, 220, 120, 70));
expect(equipment.price).toEqual(320);
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_materials": 3 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 6)]);
expect(equipment.cooldown).toEqual(new Cooldown(2, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 240));
expect(equipment.action).toEqual(new MoveAction(equipment, 240, 120, 70));
expect(equipment.price).toEqual(720);
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_materials": 10 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 20)]);
expect(equipment.cooldown).toEqual(new Cooldown(2, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 380));
expect(equipment.action).toEqual(new MoveAction(equipment, 380, 120, 70));
expect(equipment.price).toEqual(9120);
});
it("generates IonEngine based on level", function () {
let template = new IonEngine();
it("generates IonThruster based on level", function () {
let template = new IonThruster();
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_photons": 1 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 1)]);
expect(equipment.cooldown).toEqual(new Cooldown(3, 1));
expect(equipment.action).toEqual(new MoveAction(equipment, 120));
expect(equipment.action).toEqual(new MoveAction(equipment, 120, 120, 80));
expect(equipment.price).toEqual(150);
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_photons": 2 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 2)]);
expect(equipment.cooldown).toEqual(new Cooldown(3, 1));
expect(equipment.action).toEqual(new MoveAction(equipment, 135));
expect(equipment.action).toEqual(new MoveAction(equipment, 135, 120, 80));
expect(equipment.price).toEqual(380);
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_photons": 3 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 3)]);
expect(equipment.cooldown).toEqual(new Cooldown(3, 1));
expect(equipment.action).toEqual(new MoveAction(equipment, 150));
expect(equipment.action).toEqual(new MoveAction(equipment, 150, 120, 80));
expect(equipment.price).toEqual(840);
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_photons": 10 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 10)]);
expect(equipment.cooldown).toEqual(new Cooldown(3, 1));
expect(equipment.action).toEqual(new MoveAction(equipment, 255));
expect(equipment.action).toEqual(new MoveAction(equipment, 255, 120, 80));
expect(equipment.price).toEqual(10500);
});
@ -71,28 +71,28 @@ module TS.SpaceTac.Equipments {
expect(equipment.requirements).toEqual({ "skill_gravity": 2 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", -5)]);
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 250));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 250, 0));
expect(equipment.price).toEqual(340);
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_gravity": 4 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", -5)]);
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 240));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 240, 0));
expect(equipment.price).toEqual(500);
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_gravity": 6 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", -4)]);
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 230));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 230, 0));
expect(equipment.price).toEqual(820);
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_gravity": 20 });
expect(equipment.effects).toEqual([new AttributeEffect("maneuvrability", 2)]);
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 160));
expect(equipment.action).toEqual(new MoveAction(equipment, 2000, 160, 0));
expect(equipment.price).toEqual(7540);
});
});

View file

@ -8,11 +8,11 @@ module TS.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_materials": 1 });
this.setCooldown(irepeat(2), 0);
this.addAttributeEffect("maneuvrability", 2);
this.addMoveAction(istep(200, irepeat(20)));
this.addMoveAction(istep(200, irepeat(20)), undefined, irepeat(70));
}
}
export class IonEngine extends LootTemplate {
export class IonThruster extends LootTemplate {
constructor() {
super(SlotType.Engine, "Ion Thruster", "Electric propulsion based on accelerating ions through an electrostatic grid", 150, 230);
@ -30,7 +30,7 @@ module TS.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_gravity": 2 });
this.setCooldown(irepeat(1), 0);
this.addAttributeEffect("maneuvrability", istep(-5, irepeat(0.8)));
this.addMoveAction(irepeat(2000), istep(250, irepeat(-10)));
this.addMoveAction(irepeat(2000), istep(250, irepeat(-10)), irepeat(0));
}
}
}

View file

@ -17,7 +17,7 @@ module TS.SpaceTac.UI {
if (ship.getValue("power") == 0) {
cost = "Not enough power";
} else {
cost = `Cost: 1 power per ${action.distance_per_power}km`;
cost = `Cost: 1 power per ${action.getDistanceByActionPoint(ship)}km`;
}
} else if (action.equipment) {
let power_usage = action.getActionPointsUsage(ship, null);

View file

@ -108,7 +108,7 @@ module TS.SpaceTac.UI {
let move = part.action instanceof MoveAction;
let color = (enabled && part.possible) ? (move ? 0xe09c47 : 0xdc6441) : 0x8e8e8e;
let src = previous ? previous.target : this.ship.location;
let gradation = part.action instanceof MoveAction ? part.action.distance_per_power : 0;
let gradation = (part.action instanceof MoveAction) ? part.action.getDistanceByActionPoint(this.ship) : 0;
this.drawVector(color, src.x, src.y, part.target.x, part.target.y, gradation);
}