1
0
Fork 0
This commit is contained in:
Michaël Lemaire 2018-07-10 16:23:32 +02:00
parent fc0f9210dd
commit 2c31ee8579
38 changed files with 147 additions and 104 deletions

View file

@ -4,6 +4,26 @@ module TK.SpaceTac.Specs {
check.equals(got.y, expected_y, `y differs (${got.x},${got.y}) (${expected_x},${expected_y})`); check.equals(got.y, expected_y, `y differs (${got.x},${got.y}) (${expected_x},${expected_y})`);
} }
testing("ArenaGrid", test =>  {
test.case("checks if a location is in range of another", check => {
let grid = new ArenaGrid();
check.in("first order", check => {
check.equals(grid.inRange({ x: 0, y: 0 }, { x: 4, y: 4 }, 5), false, "<5");
check.equals(grid.inRange({ x: 0, y: 0 }, { x: 4, y: 4 }, 8), true, "<8");
});
check.in("second order", check => {
check.equals(grid.inRange({ x: 4, y: 4 }, { x: 0, y: 0 }, 5), false, "<5");
check.equals(grid.inRange({ x: 4, y: 4 }, { x: 0, y: 0 }, 8), true, "<8");
});
check.equals(grid.inRange({ x: 0, y: 0 }, { x: 0.99999999999999, y: 0 }, 1), true, "0.99999999999999");
check.equals(grid.inRange({ x: 0, y: 0 }, { x: 1.00000000000001, y: 0 }, 1), true, "1.00000000000001");
check.equals(grid.inRange({ x: 0, y: 0 }, { x: 1.000001, y: 0 }, 1), false, "1.000001");
})
});
testing("HexagonalArenaGrid", test => { testing("HexagonalArenaGrid", test => {
test.case("checks coordinates", check => { test.case("checks coordinates", check => {
let grid = new HexagonalArenaGrid(5, 1); let grid = new HexagonalArenaGrid(5, 1);

View file

@ -36,6 +36,13 @@ module TK.SpaceTac {
measure(loc1: IArenaLocation, loc2: IArenaLocation): number { measure(loc1: IArenaLocation, loc2: IArenaLocation): number {
return arenaDistance(this.snap(loc1), this.snap(loc2)); return arenaDistance(this.snap(loc1), this.snap(loc2));
} }
/**
* Check that a location is in range of another
*/
inRange(loc1: IArenaLocation, loc2: IArenaLocation, range: number): boolean {
return this.measure(loc1, loc2) - range < 1e-8;
}
} }
/** /**
@ -48,12 +55,24 @@ module TK.SpaceTac {
super(); super();
} }
getUnit(): number {
return this.unit;
}
snap(loc: IArenaLocation): IArenaLocation { snap(loc: IArenaLocation): IArenaLocation {
return new ArenaLocation(Math.round(loc.x), Math.round(loc.y)); return new ArenaLocation(Math.round(loc.x), Math.round(loc.y));
} }
measure(loc1: IArenaLocation, loc2: IArenaLocation): number { measure(loc1: IArenaLocation, loc2: IArenaLocation): number {
return Math.round(super.measure(loc1, loc2) / this.unit); let d = super.measure(loc1, loc2) / this.unit;
let r = Math.round(d);
if (r >= d) {
return Math.floor(d);
} else if (r - d < 1e-8) {
return r;
} else {
return Math.ceil(d);
}
} }
} }

View file

@ -5,22 +5,6 @@ module TK.SpaceTac.Specs {
check.nears(arenaAngle({ x: 0, y: 0 }, { x: 1, y: 1 }), Math.PI / 4); check.nears(arenaAngle({ x: 0, y: 0 }, { x: 1, y: 1 }), Math.PI / 4);
}) })
test.case("checks if a location is in range of another", check => {
check.in("first order", check => {
check.equals(arenaInRange({ x: 0, y: 0 }, { x: 4, y: 4 }, 5), false, "<5");
check.equals(arenaInRange({ x: 0, y: 0 }, { x: 4, y: 4 }, 8), true, "<8");
});
check.in("second order", check => {
check.equals(arenaInRange({ x: 4, y: 4 }, { x: 0, y: 0 }, 5), false, "<5");
check.equals(arenaInRange({ x: 4, y: 4 }, { x: 0, y: 0 }, 8), true, "<8");
});
check.equals(arenaInRange({ x: 0, y: 0 }, { x: 0.99999999999999, y: 0 }, 1), true, "0.99999999999999");
check.equals(arenaInRange({ x: 0, y: 0 }, { x: 1.00000000000001, y: 0 }, 1), true, "1.00000000000001");
check.equals(arenaInRange({ x: 0, y: 0 }, { x: 1.000001, y: 0 }, 1), false, "1.000001");
})
test.case("computes an angular difference", check => { test.case("computes an angular difference", check => {
check.equals(angularDifference(0.5, 1.5), 1.0); check.equals(angularDifference(0.5, 1.5), 1.0);
check.nears(angularDifference(0.5, 1.5 + Math.PI * 6), 1.0); check.nears(angularDifference(0.5, 1.5 + Math.PI * 6), 1.0);

View file

@ -75,13 +75,6 @@ module TK.SpaceTac {
return Math.sqrt(dx * dx + dy * dy); return Math.sqrt(dx * dx + dy * dy);
} }
/**
* Check if a location is in range of another (accounting for rounding errors)
*/
export function arenaInRange(loc1: IArenaLocation, loc2: IArenaLocation, range: number): boolean {
return arenaDistance(loc1, loc2) - range < 1e-8;
}
/** /**
* Check if a location is inside an area * Check if a location is inside an area
*/ */

View file

@ -280,6 +280,7 @@ module TK.SpaceTac {
test.case("lists area effects", check => { test.case("lists area effects", check => {
let battle = new Battle(); let battle = new Battle();
battle.grid = new PixelGrid();
let ship = battle.fleets[0].addShip(); let ship = battle.fleets[0].addShip();
let peer = battle.fleets[1].addShip(); let peer = battle.fleets[1].addShip();
peer.setArenaPosition(100, 50); peer.setArenaPosition(100, 50);

View file

@ -332,8 +332,7 @@ module TK.SpaceTac {
*/ */
getAreaEffects(ship: Ship): [Ship | Drone, BaseEffect][] { getAreaEffects(ship: Ship): [Ship | Drone, BaseEffect][] {
let drone_effects = this.drones.list().map(drone => { let drone_effects = this.drones.list().map(drone => {
// TODO Should apply filterImpactedShips from drone action if (contains(drone.getAffectedShips(this), ship)) {
if (drone.isInRange(ship.arena_x, ship.arena_y)) {
return drone.effects.map((effect): [Ship | Drone, BaseEffect] => [drone, effect]); return drone.effects.map((effect): [Ship | Drone, BaseEffect] => [drone, effect]);
} else { } else {
return []; return [];

View file

@ -72,6 +72,7 @@ module TK.SpaceTac.Specs {
test.case("applies vigilance actions", check => { test.case("applies vigilance actions", check => {
let battle = new Battle(); let battle = new Battle();
battle.grid = new PixelGrid();
let ship1 = battle.fleets[0].addShip(); let ship1 = battle.fleets[0].addShip();
ship1.setArenaPosition(100, 100); ship1.setArenaPosition(100, 100);
TestTools.setShipModel(ship1, 10, 0, 5); TestTools.setShipModel(ship1, 10, 0, 5);

View file

@ -50,6 +50,15 @@ module TK.SpaceTac {
]); ]);
}); });
test.case("applies targetting filter", check => {
let battle = TestTools.createBattle();
battle.fleets[1].addShip().setDead();
let drone = new Drone(nn(battle.playing_ship));
check.equals(drone.getAffectedShips(battle), [battle.fleets[0].ships[0], battle.fleets[1].ships[0]]);
drone.filter = ActionTargettingFilter.ENEMIES;
check.equals(drone.getAffectedShips(battle), [battle.fleets[1].ships[0]]);
});
test.case("builds a textual description", check => { test.case("builds a textual description", check => {
let drone = new Drone(new Ship()); let drone = new Drone(new Ship());
check.equals(drone.getDescription(), "While deployed:\n• do nothing"); check.equals(drone.getDescription(), "While deployed:\n• do nothing");

View file

@ -12,13 +12,16 @@ module TK.SpaceTac {
// Location in arena // Location in arena
x = 0 x = 0
y = 0 y = 0
// Radius and ship filter
radius = 0 radius = 0
filter = ActionTargettingFilter.ALL
// Effects to apply // Effects to apply
effects: BaseEffect[] = [] effects: BaseEffect[] = []
// Action that triggered that drone // Action that triggered that drone
parent: DeployDroneAction | null = null; parent: DeployDroneAction | null = null
constructor(owner: Ship, code = "drone") { constructor(owner: Ship, code = "drone") {
super(); super();
@ -45,19 +48,20 @@ module TK.SpaceTac {
return `While deployed:\n${effects}`; return `While deployed:\n${effects}`;
} }
/**
* Check if a location is in range
*/
isInRange(x: number, y: number): boolean {
return Target.newFromLocation(x, y).getDistanceTo(this) <= this.radius;
}
/** /**
* Get the list of affected ships. * Get the list of affected ships.
*/ */
getAffectedShips(battle: Battle): Ship[] { getAffectedShips(battle: Battle): Ship[] {
let ships = ifilter(battle.iships(), ship => ship.alive && ship.isInCircle(this.x, this.y, this.radius)); let ships = battle.ships.list();
return imaterialize(ships); ships = ships.filter(ship => ship.alive);
ships = ships.filter(ship => battle.grid.inRange(this, ship.location, this.radius));
let owner = battle.getShip(this.owner);
if (owner) {
ships = BaseAction.filterTargets(owner, ships, this.filter);
} else {
ships = [];
}
return ships;
} }
} }
} }

View file

@ -28,12 +28,5 @@ module TK.SpaceTac.Specs {
var t2 = Target.newFromLocation(4, 5); var t2 = Target.newFromLocation(4, 5);
check.nears(t1.getAngleTo(t2), Math.PI / 4); check.nears(t1.getAngleTo(t2), Math.PI / 4);
}); });
test.case("checks if a target is in range of another", check => {
var t1 = Target.newFromLocation(5, 4);
check.equals(t1.isInRange(7, 3, 2), false);
check.equals(t1.isInRange(7, 3, 3), true);
check.equals(t1.isInRange(5, 5, 2), true);
});
}); });
} }

View file

@ -79,10 +79,5 @@ module TK.SpaceTac {
return null; return null;
} }
} }
// Check if a target is in range from a specific point
isInRange(x: number, y: number, radius: number): boolean {
return arenaInRange(this, new ArenaLocation(x, y), radius);
}
} }
} }

View file

@ -164,7 +164,7 @@ module TK.SpaceTac {
} }
/** /**
* Get the range of this action, for targetting purpose * Get the range of this action, in raw arena coordinates, for targetting purpose
*/ */
getRangeRadius(ship: Ship): number { getRangeRadius(ship: Ship): number {
return 0; return 0;

View file

@ -51,7 +51,8 @@ module TK.SpaceTac.Specs {
ship.setArenaPosition(0, 0); ship.setArenaPosition(0, 0);
TestTools.setShipModel(ship, 100, 0, 3); TestTools.setShipModel(ship, 100, 0, 3);
let action = new DeployDroneAction("testdrone", { power: 2 }, { deploy_distance: 8, drone_radius: 4, drone_effects: [new DamageEffect(50)] }); let action = new DeployDroneAction("testdrone", { power: 2, filter: ActionTargettingFilter.ALLIES_BUT_SELF },
{ deploy_distance: 8, drone_radius: 4, drone_effects: [new DamageEffect(50)] });
ship.actions.addCustom(action); ship.actions.addCustom(action);
TestTools.actionChain(check, battle, [ TestTools.actionChain(check, battle, [
@ -71,6 +72,7 @@ module TK.SpaceTac.Specs {
check.equals(drone.x, 5); check.equals(drone.x, 5);
check.equals(drone.y, 0); check.equals(drone.y, 0);
check.equals(drone.radius, 4); check.equals(drone.radius, 4);
check.equals(drone.filter, ActionTargettingFilter.ALLIES_BUT_SELF);
compare_effects(check, drone.effects, [new DamageEffect(50)]); compare_effects(check, drone.effects, [new DamageEffect(50)]);
} }
]) ])

View file

@ -62,11 +62,15 @@ module TK.SpaceTac {
} }
getRangeRadius(ship: Ship): number { getRangeRadius(ship: Ship): number {
return ship.actions.isToggled(this) ? 0 : this.deploy_distance; if (ship.actions.isToggled(this)) {
return 0;
} else {
return this.deploy_distance * ship.grid.getUnit();
}
} }
filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] { filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
let result = ships.filter(iship => arenaDistance(iship.location, target) <= this.radius); let result = ships.filter(iship => ship.grid.inRange(target, iship.location, this.drone_radius));
result = BaseAction.filterTargets(ship, result, this.filter); result = BaseAction.filterTargets(ship, result, this.filter);
return result; return result;
} }
@ -83,7 +87,7 @@ module TK.SpaceTac {
if (ship.actions.isToggled(this)) { if (ship.actions.isToggled(this)) {
return false; return false;
} else { } else {
return arenaInRange(ship.location, target, this.deploy_distance); return ship.grid.inRange(ship.location, target, this.deploy_distance);
} }
} }
@ -103,6 +107,7 @@ module TK.SpaceTac {
drone.x = target.x; drone.x = target.x;
drone.y = target.y; drone.y = target.y;
drone.radius = this.drone_radius; drone.radius = this.drone_radius;
drone.filter = this.filter;
drone.effects = this.drone_effects; drone.effects = this.drone_effects;
result.push(new DroneDeployedDiff(drone)); result.push(new DroneDeployedDiff(drone));

View file

@ -6,8 +6,7 @@ module TK.SpaceTac.Specs {
battle.grid = new PixelGrid(); battle.grid = new PixelGrid();
TestTools.setShipPlaying(battle, ship); TestTools.setShipPlaying(battle, ship);
ship.setValue("power", 6); ship.setValue("power", 6);
ship.arena_x = 0; ship.setArenaPosition(0, 0);
ship.arena_y = 0;
var action = new MoveAction("Engine", { distance_per_power: 10 }); var action = new MoveAction("Engine", { distance_per_power: 10 });
ship.actions.addCustom(action); ship.actions.addCustom(action);
@ -68,7 +67,7 @@ module TK.SpaceTac.Specs {
ship.setArenaPosition(500, 500); ship.setArenaPosition(500, 500);
enemy.setArenaPosition(1000, 500); enemy.setArenaPosition(1000, 500);
var action = new MoveAction("Engine", { distance_per_power: 1000, safety_distance: 200 }); var action = new MoveAction("Engine", { distance_per_power: 1000 });
var result = action.checkLocationTarget(ship, Target.newFromLocation(700, 500)); var result = action.checkLocationTarget(ship, Target.newFromLocation(700, 500));
check.equals(result, true); check.equals(result, true);

View file

@ -83,17 +83,21 @@ module TK.SpaceTac {
} }
getRangeRadius(ship: Ship): number { getRangeRadius(ship: Ship): number {
return ship.getValue("power") * this.distance_per_power * ship.grid.getUnit(); return ship.getValue("power") * this.getDistancePerPower(ship);
}
getDistancePerPower(ship: Ship): number {
return this.distance_per_power * ship.grid.getUnit();
} }
checkLocationTarget(ship: Ship, target: Target): boolean { checkLocationTarget(ship: Ship, target: Target): boolean {
if (!ship.grid.check(target)) { if (!ship.grid.check(target) || ship.grid.measure(ship.location, target) < 1e-8) {
return false; return false;
} }
// TODO Check the space is not occupied // TODO Check the space is not occupied
return true; return ship.getValue("power") >= this.getPowerUsage(ship, target);
} }
protected getSpecificDiffs(ship: Ship, battle: Battle, target: Target): BaseBattleDiff[] { protected getSpecificDiffs(ship: Ship, battle: Battle, target: Target): BaseBattleDiff[] {

View file

@ -21,6 +21,7 @@ module TK.SpaceTac.Specs {
test.case("collects impacted ships", check => { test.case("collects impacted ships", check => {
let action = new ToggleAction("testtoggle", { radius: 50 }); let action = new ToggleAction("testtoggle", { radius: 50 });
let battle = new Battle(); let battle = new Battle();
battle.grid = new PixelGrid();
let ship1 = battle.fleets[0].addShip(); let ship1 = battle.fleets[0].addShip();
ship1.setArenaPosition(0, 0); ship1.setArenaPosition(0, 0);
let ship2 = battle.fleets[0].addShip(); let ship2 = battle.fleets[0].addShip();

View file

@ -62,7 +62,7 @@ module TK.SpaceTac {
} }
filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] { filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
let result = ships.filter(iship => arenaDistance(iship.location, source) <= this.radius); let result = ships.filter(iship => ship.grid.inRange(source, iship.location, this.radius));
result = BaseAction.filterTargets(ship, result, this.filter); result = BaseAction.filterTargets(ship, result, this.filter);
return result; return result;
} }

View file

@ -28,6 +28,7 @@ module TK.SpaceTac.Specs {
ship3.alive = false; ship3.alive = false;
let battle = new Battle(fleet); let battle = new Battle(fleet);
battle.grid = new PixelGrid();
battle.play_order = [ship, ship1, ship2, ship3]; battle.play_order = [ship, ship1, ship2, ship3];
TestTools.setShipPlaying(battle, ship); TestTools.setShipPlaying(battle, ship);
fleet.setBattle(battle); fleet.setBattle(battle);

View file

@ -87,7 +87,11 @@ module TK.SpaceTac {
} }
getRangeRadius(ship: Ship): number { getRangeRadius(ship: Ship): number {
return this.range; return this.range * ship.grid.getUnit();
}
getBlastRadius(ship: Ship): number {
return this.blast * ship.grid.getUnit();
} }
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): ActionUnavailability | null { checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): ActionUnavailability | null {
@ -107,12 +111,12 @@ module TK.SpaceTac {
filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] { filterImpactedShips(ship: Ship, source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
if (this.blast) { if (this.blast) {
return ships.filter(ship => arenaDistance(ship.location, target) <= this.blast); return ships.filter(iship => ship.grid.measure(iship.location, target) <= this.blast);
} else if (this.angle) { } else if (this.angle) {
let angle = arenaAngle(source, target); let angle = arenaAngle(source, target);
let maxangle = (this.angle * 0.5) * Math.PI / 180; let maxangle = (this.angle * 0.5) * Math.PI / 180;
return ships.filter(iship => { return ships.filter(iship => {
let dist = arenaDistance(source, iship.location); let dist = ship.grid.measure(source, iship.location);
if (dist < 0.000001 || dist > this.range) { if (dist < 0.000001 || dist > this.range) {
return false; return false;
} else { } else {
@ -126,7 +130,7 @@ module TK.SpaceTac {
checkLocationTarget(ship: Ship, target: Target): boolean { checkLocationTarget(ship: Ship, target: Target): boolean {
if (target && (this.blast > 0 || this.angle > 0)) { if (target && (this.blast > 0 || this.angle > 0)) {
return arenaInRange(ship.location, target, this.range); return ship.grid.inRange(ship.location, target, this.range);
} else { } else {
return false; return false;
} }
@ -141,7 +145,7 @@ module TK.SpaceTac {
if (this.blast > 0 || this.angle > 0) { if (this.blast > 0 || this.angle > 0) {
return this.checkLocationTarget(ship, new Target(target.x, target.y)); return this.checkLocationTarget(ship, new Target(target.x, target.y));
} else { } else {
return arenaInRange(ship.location, target, this.range); return ship.grid.inRange(ship.location, target, this.range);
} }
} }
} }

View file

@ -47,6 +47,7 @@ module TK.SpaceTac.Specs {
test.case("handles the vigilance effect to know who to target", check => { test.case("handles the vigilance effect to know who to target", check => {
let battle = new Battle(); let battle = new Battle();
battle.grid = new PixelGrid();
let ship1a = battle.fleets[0].addShip(); let ship1a = battle.fleets[0].addShip();
ship1a.setArenaPosition(0, 0); ship1a.setArenaPosition(0, 0);
TestTools.setShipModel(ship1a, 10, 0, 5); TestTools.setShipModel(ship1a, 10, 0, 5);

View file

@ -86,7 +86,7 @@ module TK.SpaceTac.Specs {
let ship = battle.fleets[0].addShip(); let ship = battle.fleets[0].addShip();
let action1 = new DeployDroneAction("Drone"); let action1 = new DeployDroneAction("Drone");
let action2 = new ToggleAction("Toggle"); let action2 = new ToggleAction("Toggle");
let action3 = new VigilanceAction("Vigilance", { radius: 150 }); let action3 = new VigilanceAction("Vigilance", { radius: 3 });
TestTools.setShipModel(ship, 100, 0, 10, 1, [action1, action2, action3]); TestTools.setShipModel(ship, 100, 0, 10, 1, [action1, action2, action3]);
TestTools.addEngine(ship, 1000); TestTools.addEngine(ship, 1000);
TestTools.setShipPlaying(battle, ship); TestTools.setShipPlaying(battle, ship);
@ -173,6 +173,7 @@ module TK.SpaceTac.Specs {
test.case("evaluates damage to enemies", check => { test.case("evaluates damage to enemies", check => {
let battle = new Battle(); let battle = new Battle();
battle.grid = new PixelGrid();
let ship = battle.fleets[0].addShip(); let ship = battle.fleets[0].addShip();
let action = TestTools.addWeapon(ship, 50, 5, 500, 100); let action = TestTools.addWeapon(ship, 50, 5, 500, 100);
@ -198,13 +199,14 @@ module TK.SpaceTac.Specs {
test.case("evaluates ship clustering", check => { test.case("evaluates ship clustering", check => {
let battle = new Battle(); let battle = new Battle();
battle.grid = new PixelGrid();
let ship = battle.fleets[0].addShip(); let ship = battle.fleets[0].addShip();
TestTools.setShipModel(ship, 100, 0, 10); TestTools.setShipModel(ship, 100, 0, 10);
TestTools.addEngine(ship, 100); TestTools.addEngine(ship, 100);
let weapon = TestTools.addWeapon(ship, 100, 1, 100, 10); let weapon = TestTools.addWeapon(ship, 100, 1, 100, 10);
let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(200, 0)); let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(200, 0));
check.equals(maneuver.simulation.move_location.x, 100); check.equals(maneuver.simulation.move_location.x, 101);
check.equals(maneuver.simulation.move_location.y, 0); check.equals(maneuver.simulation.move_location.y, 0);
check.equals(TacticalAIHelpers.evaluateClustering(ship, battle, maneuver), 0); check.equals(TacticalAIHelpers.evaluateClustering(ship, battle, maneuver), 0);

View file

@ -21,14 +21,14 @@ module TK.SpaceTac {
let charged_shot = new TriggerAction("Charged Shot", { let charged_shot = new TriggerAction("Charged Shot", {
effects: [new DamageEffect(3)], effects: [new DamageEffect(3)],
power: 4, power: 4,
range: 900, range: 18,
}, "gatlinggun"); }, "gatlinggun");
charged_shot.configureCooldown(2, 2); charged_shot.configureCooldown(2, 2);
let long_range_missile = new TriggerAction("Long Range Missile", { let long_range_missile = new TriggerAction("Long Range Missile", {
effects: [new DamageEffect(2)], effects: [new DamageEffect(2)],
power: 4, power: 4,
range: 700, blast: 120, range: 14, blast: 2,
}, "submunitionmissile"); }, "submunitionmissile");
long_range_missile.configureCooldown(1, 2); long_range_missile.configureCooldown(1, 2);

View file

@ -20,14 +20,14 @@ module TK.SpaceTac {
let gatling = new TriggerAction("Gatling Gun", { let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(2, DamageEffectMode.SHIELD_THEN_HULL)], effects: [new DamageEffect(2, DamageEffectMode.SHIELD_THEN_HULL)],
power: 2, power: 2,
range: 200, range: 4,
}, "gatlinggun"); }, "gatlinggun");
gatling.configureCooldown(2, 1); gatling.configureCooldown(2, 1);
let shield_steal = new TriggerAction("Shield Steal", { let shield_steal = new TriggerAction("Shield Steal", {
effects: [new ValueTransferEffect("shield", -1)], effects: [new ValueTransferEffect("shield", -1)],
power: 1, power: 1,
blast: 300 blast: 6
}, "shieldtransfer"); }, "shieldtransfer");
shield_steal.configureCooldown(1, 2); shield_steal.configureCooldown(1, 2);

View file

@ -19,11 +19,11 @@ module TK.SpaceTac {
let laser = new TriggerAction("Wingspan Laser", { let laser = new TriggerAction("Wingspan Laser", {
effects: [new DamageEffect(3, DamageEffectMode.SHIELD_THEN_HULL)], effects: [new DamageEffect(3, DamageEffectMode.SHIELD_THEN_HULL)],
power: 4, power: 4,
range: 250, angle: 140, range: 5, angle: 140,
}, "prokhorovlaser"); }, "prokhorovlaser");
laser.configureCooldown(3, 1); laser.configureCooldown(3, 1);
let interceptors = new VigilanceAction("Interceptors Field", { radius: 200, power: 3, filter: ActionTargettingFilter.ENEMIES }, { let interceptors = new VigilanceAction("Interceptors Field", { radius: 4, power: 3, filter: ActionTargettingFilter.ENEMIES }, {
intruder_count: 1, intruder_count: 1,
intruder_effects: [new DamageEffect(4, DamageEffectMode.SHIELD_THEN_HULL)] intruder_effects: [new DamageEffect(4, DamageEffectMode.SHIELD_THEN_HULL)]
}, "interceptors"); }, "interceptors");
@ -31,7 +31,7 @@ module TK.SpaceTac {
let power_steal = new TriggerAction("Power Thief", { let power_steal = new TriggerAction("Power Thief", {
effects: [new ValueTransferEffect("power", -1)], effects: [new ValueTransferEffect("power", -1)],
power: 1, power: 1,
blast: 250 blast: 5
}, "powerdepleter"); }, "powerdepleter");
power_steal.configureCooldown(1, 1); power_steal.configureCooldown(1, 1);

View file

@ -19,20 +19,20 @@ module TK.SpaceTac {
let gatling = new TriggerAction("Gatling Gun", { let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(1)], effects: [new DamageEffect(1)],
power: 2, power: 2,
range: 200, range: 4,
}, "gatlinggun"); }, "gatlinggun");
gatling.configureCooldown(1, 1); gatling.configureCooldown(1, 1);
let repulse = new TriggerAction("Repulser", { let repulse = new TriggerAction("Repulser", {
effects: [new RepelEffect(150)], effects: [new RepelEffect(150)],
power: 2, power: 2,
blast: 350, blast: 7,
}, "gravitshield"); }, "gravitshield");
repulse.configureCooldown(1, 1); repulse.configureCooldown(1, 1);
let repairdrone = new DeployDroneAction("Repair Drone", { power: 3, filter: ActionTargettingFilter.ALLIES }, { let repairdrone = new DeployDroneAction("Repair Drone", { power: 3, filter: ActionTargettingFilter.ALLIES }, {
deploy_distance: 300, deploy_distance: 6,
drone_radius: 150, drone_radius: 3,
drone_effects: [ drone_effects: [
new ValueEffect("hull", 0, 0, 0, 1) new ValueEffect("hull", 0, 0, 0, 1)
] ]

View file

@ -19,7 +19,7 @@ module TK.SpaceTac {
let missile = new TriggerAction("SubMunition Missile", { let missile = new TriggerAction("SubMunition Missile", {
effects: [new DamageEffect(3)], effects: [new DamageEffect(3)],
power: 3, power: 3,
range: 250, blast: 150, range: 5, blast: 3,
}, "submunitionmissile"); }, "submunitionmissile");
missile.configureCooldown(2, 2); missile.configureCooldown(2, 2);
@ -27,7 +27,7 @@ module TK.SpaceTac {
let gatling = new TriggerAction("Multi-head Gatling", { let gatling = new TriggerAction("Multi-head Gatling", {
effects: [new DamageEffect(2)], effects: [new DamageEffect(2)],
power: 2, power: 2,
range: 350, blast: 150, range: 7, blast: 3,
}, "gatlinggun"); }, "gatlinggun");
gatling.configureCooldown(3, 2); gatling.configureCooldown(3, 2);

View file

@ -19,21 +19,21 @@ module TK.SpaceTac {
let depleter = new TriggerAction("Power Depleter", { let depleter = new TriggerAction("Power Depleter", {
effects: [new StickyEffect(new AttributeLimitEffect("power_capacity", 3))], effects: [new StickyEffect(new AttributeLimitEffect("power_capacity", 3))],
power: 2, power: 2,
range: 450, range: 9,
}, "powerdepleter"); }, "powerdepleter");
depleter.configureCooldown(1, 1); depleter.configureCooldown(1, 1);
let shield_basher = new TriggerAction("Shield Basher", { let shield_basher = new TriggerAction("Shield Basher", {
effects: [new DamageEffect(2, DamageEffectMode.SHIELD_ONLY, false)], effects: [new DamageEffect(2, DamageEffectMode.SHIELD_ONLY, false)],
power: 3, power: 3,
range: 300, range: 6,
}, "shieldbash"); }, "shieldbash");
shield_basher.configureCooldown(2, 1); shield_basher.configureCooldown(2, 1);
let engine_hijack = new TriggerAction("Engine Hijacking", { let engine_hijack = new TriggerAction("Engine Hijacking", {
effects: [new StickyEffect(new PinnedEffect(), 2)], effects: [new StickyEffect(new PinnedEffect(), 2)],
power: 2, power: 2,
range: 400, range: 8,
}, "pin"); }, "pin");
engine_hijack.configureCooldown(1, 2); engine_hijack.configureCooldown(1, 2);

View file

@ -19,13 +19,13 @@ module TK.SpaceTac {
let missile = new TriggerAction("SubMunition Missile", { let missile = new TriggerAction("SubMunition Missile", {
effects: [new DamageEffect(2)], effects: [new DamageEffect(2)],
power: 3, power: 3,
range: 400, blast: 120, range: 8, blast: 2,
}, "submunitionmissile"); }, "submunitionmissile");
let protector = new TriggerAction("Damage Reductor", { let protector = new TriggerAction("Damage Reductor", {
effects: [new StickyEffect(new AttributeEffect("evasion", 1), 2)], effects: [new StickyEffect(new AttributeEffect("evasion", 1), 2)],
power: 3, power: 3,
range: 300, blast: 150 range: 6, blast: 3
}, "damageprotector"); }, "damageprotector");
protector.configureCooldown(1, 3); protector.configureCooldown(1, 3);

View file

@ -19,14 +19,14 @@ module TK.SpaceTac {
let gatling = new TriggerAction("Gatling Gun", { let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(2)], effects: [new DamageEffect(2)],
power: 3, power: 3,
range: 400, range: 8,
}, "gatlinggun"); }, "gatlinggun");
gatling.configureCooldown(2, 2); gatling.configureCooldown(2, 2);
let laser = new TriggerAction("Prokhorov Laser", { let laser = new TriggerAction("Prokhorov Laser", {
effects: [new DamageEffect(3)], effects: [new DamageEffect(3)],
power: 4, power: 4,
range: 250, angle: 60, range: 5, angle: 60,
}, "prokhorovlaser"); }, "prokhorovlaser");
return [ return [

View file

@ -18,20 +18,20 @@ module TK.SpaceTac {
let gatling1 = new TriggerAction("Primary Gatling", { let gatling1 = new TriggerAction("Primary Gatling", {
effects: [new DamageEffect(3)], effects: [new DamageEffect(3)],
power: 2, range: 400 power: 2, range: 8
}, "gatlinggun"); }, "gatlinggun");
gatling1.configureCooldown(1, 2); gatling1.configureCooldown(1, 2);
let gatling2 = new TriggerAction("Secondary Gatling", { let gatling2 = new TriggerAction("Secondary Gatling", {
effects: [new DamageEffect(2)], effects: [new DamageEffect(2)],
power: 1, range: 200 power: 1, range: 4
}, "gatlinggun"); }, "gatlinggun");
gatling2.configureCooldown(1, 2); gatling2.configureCooldown(1, 2);
let missile = new TriggerAction("Diffuse Missiles", { let missile = new TriggerAction("Diffuse Missiles", {
effects: [new DamageEffect(2)], effects: [new DamageEffect(2)],
power: 2, power: 2,
range: 200, blast: 100, range: 4, blast: 2,
}, "submunitionmissile"); }, "submunitionmissile");
missile.configureCooldown(1, 2); missile.configureCooldown(1, 2);

View file

@ -19,7 +19,7 @@ module TK.SpaceTac {
let protector = new ToggleAction("Damage Protector", { let protector = new ToggleAction("Damage Protector", {
power: 4, power: 4,
radius: 300, radius: 6,
effects: [new AttributeEffect("evasion", 1)], effects: [new AttributeEffect("evasion", 1)],
filter: ActionTargettingFilter.ALLIES filter: ActionTargettingFilter.ALLIES
}); });
@ -27,14 +27,14 @@ module TK.SpaceTac {
let depleter = new TriggerAction("Power Depleter", { let depleter = new TriggerAction("Power Depleter", {
effects: [new StickyEffect(new AttributeLimitEffect("power_capacity", 3))], effects: [new StickyEffect(new AttributeLimitEffect("power_capacity", 3))],
power: 2, power: 2,
range: 200, range: 4,
}, "powerdepleter"); }, "powerdepleter");
depleter.configureCooldown(1, 1); depleter.configureCooldown(1, 1);
let missile = new TriggerAction("Defense Missiles", { let missile = new TriggerAction("Defense Missiles", {
effects: [new DamageEffect(3, DamageEffectMode.SHIELD_THEN_HULL)], effects: [new DamageEffect(3, DamageEffectMode.SHIELD_THEN_HULL)],
power: 3, power: 3,
range: 200, blast: 180, range: 4, blast: 4,
}, "submunitionmissile"); }, "submunitionmissile");
return [ return [

View file

@ -19,7 +19,7 @@ module TK.SpaceTac {
let laser = new TriggerAction("Prokhorov Laser", { let laser = new TriggerAction("Prokhorov Laser", {
effects: [new DamageEffect(2, DamageEffectMode.SHIELD_THEN_HULL)], effects: [new DamageEffect(2, DamageEffectMode.SHIELD_THEN_HULL)],
power: 3, power: 3,
range: 250, angle: 80, range: 5, angle: 80,
}); });
let hull = new TriggerAction("Hull Shedding", { let hull = new TriggerAction("Hull Shedding", {

View file

@ -82,7 +82,7 @@ module TK.SpaceTac.UI.Specs {
view.splash = false; view.splash = false;
let battle = Battle.newQuickRandom(); let battle = Battle.newQuickRandom();
battle.grid = new PixelGrid(); battle.grid = new ArenaGrid();
battle.placeShips(); battle.placeShips();
let player = new Player(); let player = new Player();
nn(battle.playing_ship).fleet.setPlayer(player); nn(battle.playing_ship).fleet.setPlayer(player);

View file

@ -16,7 +16,7 @@ module TK.SpaceTac.UI.Specs {
ActionTooltip.fill(tooltip.getBuilder(), ship, action1, 0); ActionTooltip.fill(tooltip.getBuilder(), ship, action1, 0);
checkText(check, tooltip.container.content.list[1], "Use Thruster"); checkText(check, tooltip.container.content.list[1], "Use Thruster");
checkText(check, tooltip.container.content.list[2], "Cost: 1 power per 0km"); checkText(check, tooltip.container.content.list[2], "Cost: 1 power per 0km");
checkText(check, tooltip.container.content.list[3], "Move: 0km per power point (safety: 120km)"); checkText(check, tooltip.container.content.list[3], "Move: 0km per power point");
checkText(check, tooltip.container.content.list[4], "[ 1 ]"); checkText(check, tooltip.container.content.list[4], "[ 1 ]");
tooltip.hide(); tooltip.hide();

View file

@ -26,17 +26,19 @@ module TK.SpaceTac.UI {
let builder = new UIBuilder(battleview, this); let builder = new UIBuilder(battleview, this);
let radius = drone.radius * battleview.battle.grid.getUnit();
this.radius = builder.graphics("radius"); this.radius = builder.graphics("radius");
this.radius.fillStyle(0xe9f2f9, 0.1); this.radius.fillStyle(0xe9f2f9, 0.1);
this.radius.fillCircle(0, 0, drone.radius); this.radius.fillCircle(0, 0, radius);
this.radius.lineStyle(2, 0xe9f2f9, 0.5); this.radius.lineStyle(2, 0xe9f2f9, 0.5);
this.radius.strokeCircle(0, 0, drone.radius); this.radius.strokeCircle(0, 0, radius);
this.activation = builder.graphics("activation", 0, 0, false); this.activation = builder.graphics("activation", 0, 0, false);
this.activation.fillStyle(0xe9f2f9, 0.0); this.activation.fillStyle(0xe9f2f9, 0.0);
this.activation.fillCircle(0, 0, drone.radius); this.activation.fillCircle(0, 0, radius);
this.activation.lineStyle(2, 0xe9f2f9, 0.7); this.activation.lineStyle(2, 0xe9f2f9, 0.7);
this.activation.strokeCircle(0, 0, drone.radius); this.activation.strokeCircle(0, 0, radius);
this.sprite = builder.button(`action-${drone.code}`, 0, 0, undefined, () => this.drone.getDescription(), undefined, { center: true }); this.sprite = builder.button(`action-${drone.code}`, 0, 0, undefined, () => this.drone.getDescription(), undefined, { center: true });
this.sprite.setScale(0.1, 0.1); this.sprite.setScale(0.1, 0.1);

View file

@ -123,7 +123,7 @@ module TK.SpaceTac.UI {
let move = part.action instanceof MoveAction; let move = part.action instanceof MoveAction;
let color = (enabled && part.possible) ? (move ? 0xe09c47 : 0xdc6441) : 0x8e8e8e; let color = (enabled && part.possible) ? (move ? 0xe09c47 : 0xdc6441) : 0x8e8e8e;
let src = previous ? previous.target : this.ship.location; 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.getDistancePerPower(this.ship) : 0;
this.drawVector(color, src.x, src.y, part.target.x, part.target.y, gradation); this.drawVector(color, src.x, src.y, part.target.x, part.target.y, gradation);
} }
@ -171,6 +171,9 @@ module TK.SpaceTac.UI {
} }
if (radius) { if (radius) {
if (this.ship) {
radius *= this.ship.grid.getUnit();
}
if (angle) { if (angle) {
area.addCircleArc({ area.addCircleArc({
radius: radius, radius: radius,

View file

@ -159,7 +159,7 @@ module TK.SpaceTac.UI {
let missile = this.builder.image("battle-effects-default", this.source.x, this.source.y, true); let missile = this.builder.image("battle-effects-default", this.source.x, this.source.y, true);
missile.setRotation(arenaAngle(this.source, this.destination)); missile.setRotation(arenaAngle(this.source, this.destination));
let blast_radius = this.action.blast; let blast_radius = this.action.getBlastRadius(this.ship);
let projectile_duration = (arenaDistance(this.source, this.destination) * 1.5) || 1; let projectile_duration = (arenaDistance(this.source, this.destination) * 1.5) || 1;
await this.view.animations.addAnimation(missile, { x: this.destination.x, y: this.destination.y }, projectile_duration / speed); await this.view.animations.addAnimation(missile, { x: this.destination.x, y: this.destination.y }, projectile_duration / speed);
@ -186,7 +186,8 @@ module TK.SpaceTac.UI {
delay: ship => { delay: ship => {
let result = (arenaDistance(this.source, this.destination) * 1.5) || 1; let result = (arenaDistance(this.source, this.destination) * 1.5) || 1;
if (this.action.blast) { if (this.action.blast) {
result += 300 * Phaser.Math.Easing.Quintic.Out(arenaDistance(this.destination, ship.location) / this.action.blast); let d = arenaDistance(this.destination, ship.location) / this.action.getBlastRadius(this.ship);
result += 300 * Phaser.Math.Easing.Quintic.Out(d);
} }
return result; return result;
} }
@ -206,7 +207,7 @@ module TK.SpaceTac.UI {
let laser = this.builder.image("battle-effects-laser", this.source.x, this.source.y); let laser = this.builder.image("battle-effects-laser", this.source.x, this.source.y);
laser.setOrigin(0, 0.5); laser.setOrigin(0, 0.5);
laser.setRotation(angle - dangle); laser.setRotation(angle - dangle);
laser.setScale(this.action.range / laser.width); laser.setScale(this.action.getRangeRadius(this.ship) / laser.width);
let dest_angle = laser.rotation + angularDifference(laser.rotation, angle + dangle); let dest_angle = laser.rotation + angularDifference(laser.rotation, angle + dangle);
return this.view.animations.addAnimation(laser, { rotation: dest_angle }, duration).then(() => laser.destroy()); return this.view.animations.addAnimation(laser, { rotation: dest_angle }, duration).then(() => laser.destroy());
} }