WIP
This commit is contained in:
parent
7079001885
commit
c608ac2a08
|
@ -1,43 +0,0 @@
|
|||
module TK.SpaceTac.Specs {
|
||||
testing("ExclusionAreas", test => {
|
||||
test.case("constructs from a ship or battle", check => {
|
||||
let battle = new Battle();
|
||||
battle.border = 17;
|
||||
battle.ship_separation = 31;
|
||||
let ship1 = battle.fleets[0].addShip();
|
||||
ship1.setArenaPosition(12, 5);
|
||||
let ship2 = battle.fleets[1].addShip();
|
||||
ship2.setArenaPosition(43, 89);
|
||||
|
||||
let exclusion = ExclusionAreas.fromBattle(battle);
|
||||
check.equals(exclusion.hard_border, 17);
|
||||
check.equals(exclusion.effective_obstacle, 31);
|
||||
check.equals(exclusion.obstacles, [new ArenaLocationAngle(12, 5), new ArenaLocationAngle(43, 89)]);
|
||||
|
||||
exclusion = ExclusionAreas.fromBattle(battle, [ship1], 120);
|
||||
check.equals(exclusion.hard_border, 17);
|
||||
check.equals(exclusion.effective_obstacle, 120);
|
||||
check.equals(exclusion.obstacles, [new ArenaLocationAngle(43, 89)]);
|
||||
|
||||
exclusion = ExclusionAreas.fromBattle(battle, [ship2], 10);
|
||||
check.equals(exclusion.hard_border, 17);
|
||||
check.equals(exclusion.effective_obstacle, 31);
|
||||
check.equals(exclusion.obstacles, [new ArenaLocationAngle(12, 5)]);
|
||||
|
||||
exclusion = ExclusionAreas.fromShip(ship1);
|
||||
check.equals(exclusion.hard_border, 17);
|
||||
check.equals(exclusion.effective_obstacle, 31);
|
||||
check.equals(exclusion.obstacles, [new ArenaLocationAngle(43, 89)]);
|
||||
|
||||
exclusion = ExclusionAreas.fromShip(ship2, 99);
|
||||
check.equals(exclusion.hard_border, 17);
|
||||
check.equals(exclusion.effective_obstacle, 99);
|
||||
check.equals(exclusion.obstacles, [new ArenaLocationAngle(12, 5)]);
|
||||
|
||||
exclusion = ExclusionAreas.fromShip(ship2, 10, false);
|
||||
check.equals(exclusion.hard_border, 17);
|
||||
check.equals(exclusion.effective_obstacle, 31);
|
||||
check.equals(exclusion.obstacles, [new ArenaLocationAngle(12, 5), new ArenaLocationAngle(43, 89)]);
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
module TK.SpaceTac {
|
||||
/**
|
||||
* Helper for working with exclusion areas (areas where a ship cannot go)
|
||||
*
|
||||
* There are three types of exclusion:
|
||||
* - Hard border exclusion, that prevents a ship from being too close to the battle edges
|
||||
* - Hard obstacle exclusion, that prevents two ships from being too close to each other
|
||||
* - Soft obstacle exclusion, usually associated with an engine, that prevents a ship from moving too close to others
|
||||
*/
|
||||
export class ExclusionAreas {
|
||||
xmin: number
|
||||
xmax: number
|
||||
ymin: number
|
||||
ymax: number
|
||||
active: boolean
|
||||
hard_border = 50
|
||||
hard_obstacle = 100
|
||||
effective_obstacle = this.hard_obstacle
|
||||
obstacles: ArenaLocation[] = []
|
||||
|
||||
constructor(width: number, height: number) {
|
||||
this.xmin = 0;
|
||||
this.xmax = width - 1;
|
||||
this.ymin = 0;
|
||||
this.ymax = height - 1;
|
||||
this.active = width > 0 && height > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an exclusion helper from a battle.
|
||||
*/
|
||||
static fromBattle(battle: Battle, ignore_ships: Ship[] = [], soft_distance = 0): ExclusionAreas {
|
||||
let result = new ExclusionAreas(battle.width, battle.height);
|
||||
result.hard_border = battle.border;
|
||||
result.hard_obstacle = battle.ship_separation;
|
||||
let obstacles = imap(ifilter(battle.iships(true), ship => !contains(ignore_ships, ship)), ship => ship.location);
|
||||
result.configure(imaterialize(obstacles), soft_distance);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an exclusion helper for a ship.
|
||||
*
|
||||
* If *ignore_self* is True, the ship will itself not be included in exclusion areas.
|
||||
*/
|
||||
static fromShip(ship: Ship, soft_distance = 0, ignore_self = true): ExclusionAreas {
|
||||
let battle = ship.getBattle();
|
||||
if (battle) {
|
||||
return ExclusionAreas.fromBattle(battle, ignore_self ? [ship] : [], soft_distance);
|
||||
} else {
|
||||
return new ExclusionAreas(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the areas for next check calls.
|
||||
*/
|
||||
configure(obstacles: ArenaLocation[], soft_distance: number) {
|
||||
this.obstacles = obstacles;
|
||||
this.effective_obstacle = Math.max(soft_distance, this.hard_obstacle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep a location outside exclusion areas, when coming from a source.
|
||||
*
|
||||
* It will return the furthest location on the [source, location] segment, that is not inside an exclusion
|
||||
* area.
|
||||
*/
|
||||
stopBefore(location: ArenaLocation, source: ArenaLocation): ArenaLocation {
|
||||
if (!this.active) {
|
||||
return location;
|
||||
}
|
||||
|
||||
let target = Target.newFromLocation(location.x, location.y);
|
||||
|
||||
// Keep out of arena borders
|
||||
target = target.keepInsideRectangle(this.xmin + this.hard_border, this.ymin + this.hard_border,
|
||||
this.xmax - this.hard_border, this.ymax - this.hard_border,
|
||||
source.x, source.y);
|
||||
|
||||
// Apply collision prevention
|
||||
let obstacles = sorted(this.obstacles, (a, b) => cmp(arenaDistance(a, source), arenaDistance(b, source), true));
|
||||
obstacles.forEach(s => {
|
||||
let new_target = target.moveOutOfCircle(s.x, s.y, this.effective_obstacle, source.x, source.y);
|
||||
if (target != new_target && arenaDistance(s, source) < this.effective_obstacle) {
|
||||
// Already inside the nearest ship's exclusion area
|
||||
target = Target.newFromLocation(source.x, source.y);
|
||||
} else {
|
||||
target = new_target;
|
||||
}
|
||||
});
|
||||
|
||||
return new ArenaLocation(target.x, target.y);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,28 +35,5 @@ module TK.SpaceTac.Specs {
|
|||
check.equals(t1.isInRange(7, 3, 3), true);
|
||||
check.equals(t1.isInRange(5, 5, 2), true);
|
||||
});
|
||||
|
||||
test.case("constraints a target to a limited range", check => {
|
||||
var target = Target.newFromLocation(5, 9);
|
||||
check.equals(target.constraintInRange(1, 1, Math.sqrt(80) * 0.5), Target.newFromLocation(3, 5));
|
||||
check.same(target.constraintInRange(1, 1, 70), target);
|
||||
});
|
||||
|
||||
test.case("pushes a target out of a given circle", check => {
|
||||
var target = Target.newFromLocation(5, 5);
|
||||
check.same(target.moveOutOfCircle(0, 0, 3, 0, 0), target);
|
||||
check.equals(target.moveOutOfCircle(6, 6, 3, 0, 0), Target.newFromLocation(3.8786796564403576, 3.8786796564403576));
|
||||
check.equals(target.moveOutOfCircle(4, 4, 3, 10, 10), Target.newFromLocation(6.121320343559642, 6.121320343559642));
|
||||
check.equals(target.moveOutOfCircle(5, 8, 6, 5, 0), Target.newFromLocation(5, 2));
|
||||
check.equals(target.moveOutOfCircle(5, 2, 6, 5, 10), Target.newFromLocation(5, 8));
|
||||
check.equals(target.moveOutOfCircle(8, 5, 6, 0, 5), Target.newFromLocation(2, 5));
|
||||
check.equals(target.moveOutOfCircle(2, 5, 6, 10, 5), Target.newFromLocation(8, 5));
|
||||
});
|
||||
|
||||
test.case("keeps a target inside a rectangle", check => {
|
||||
var target = Target.newFromLocation(5, 5);
|
||||
check.same(target.keepInsideRectangle(0, 0, 10, 10, 0, 0), target);
|
||||
check.equals(target.keepInsideRectangle(8, 0, 13, 10, 10, 5), Target.newFromLocation(8, 5));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,34 +1,4 @@
|
|||
module TK.SpaceTac {
|
||||
// Find the nearest intersection between a line and a circle
|
||||
// Circle is supposed to be centered at (0,0)
|
||||
// Nearest intersection to (x1,y1) is returned
|
||||
function intersectLineCircle(x1: number, y1: number, x2: number, y2: number, r: number): [number, number] | null {
|
||||
let a = y2 - y1;
|
||||
let b = -(x2 - x1);
|
||||
let c = -(a * x1 + b * y1);
|
||||
let x0 = -a * c / (a * a + b * b), y0 = -b * c / (a * a + b * b);
|
||||
let EPS = 10e-8;
|
||||
if (c * c > r * r * (a * a + b * b) + EPS) {
|
||||
return null;
|
||||
} else if (Math.abs(c * c - r * r * (a * a + b * b)) < EPS) {
|
||||
return [x0, y0];
|
||||
} else {
|
||||
let d = r * r - c * c / (a * a + b * b);
|
||||
let mult = Math.sqrt(d / (a * a + b * b));
|
||||
let ax, ay, bx, by;
|
||||
ax = x0 + b * mult;
|
||||
bx = x0 - b * mult;
|
||||
ay = y0 - a * mult;
|
||||
by = y0 + a * mult;
|
||||
|
||||
let candidates: [number, number][] = [
|
||||
[x0 + b * mult, y0 - a * mult],
|
||||
[x0 - b * mult, y0 + a * mult]
|
||||
]
|
||||
return minBy(candidates, ([x, y]) => Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)));
|
||||
}
|
||||
}
|
||||
|
||||
// Target for a capability
|
||||
// This could be a location in space, or a ship
|
||||
export class Target {
|
||||
|
@ -114,72 +84,5 @@ module TK.SpaceTac {
|
|||
isInRange(x: number, y: number, radius: number): boolean {
|
||||
return arenaInRange(this, new ArenaLocation(x, y), radius);
|
||||
}
|
||||
|
||||
// Constraint a target, to be in a given range from a specific point
|
||||
// May return the original target if it's already in radius
|
||||
constraintInRange(x: number, y: number, radius: number): Target {
|
||||
var dx = this.x - x;
|
||||
var dy = this.y - y;
|
||||
var length = Math.sqrt(dx * dx + dy * dy);
|
||||
if (length <= radius) {
|
||||
return this;
|
||||
} else {
|
||||
var factor = radius / length;
|
||||
return Target.newFromLocation(x + dx * factor, y + dy * factor);
|
||||
}
|
||||
}
|
||||
|
||||
// Force a target to stay out of a given circle
|
||||
// If the target is in the circle, it will be moved to the nearest intersection between targetting line
|
||||
// and the circle
|
||||
// May return the original target if it's already out of the circle
|
||||
moveOutOfCircle(circlex: number, circley: number, radius: number, sourcex: number, sourcey: number): Target {
|
||||
var dx = this.x - circlex;
|
||||
var dy = this.y - circley;
|
||||
var length = Math.sqrt(dx * dx + dy * dy);
|
||||
if (length >= radius) {
|
||||
// Already out of circle
|
||||
return this;
|
||||
} else {
|
||||
// Find nearest intersection with circle
|
||||
var res = intersectLineCircle(sourcex - circlex, sourcey - circley, dx, dy, radius);
|
||||
if (res) {
|
||||
return Target.newFromLocation(res[0] + circlex, res[1] + circley);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep the target inside a rectangle
|
||||
*
|
||||
* May return the original target if it's already inside the rectangle
|
||||
*/
|
||||
keepInsideRectangle(xmin: number, ymin: number, xmax: number, ymax: number, sourcex: number, sourcey: number): Target {
|
||||
let length = this.getDistanceTo({ x: sourcex, y: sourcey });
|
||||
let result: Target = this;
|
||||
if (result.x < xmin) {
|
||||
let factor = (xmin - sourcex) / (result.x - sourcex);
|
||||
length *= factor;
|
||||
result = result.constraintInRange(sourcex, sourcey, length);
|
||||
}
|
||||
if (result.x > xmax) {
|
||||
let factor = (xmax - sourcex) / (result.x - sourcex);
|
||||
length *= factor;
|
||||
result = result.constraintInRange(sourcex, sourcey, length);
|
||||
}
|
||||
if (result.y < ymin) {
|
||||
let factor = (ymin - sourcey) / (result.y - sourcey);
|
||||
length *= factor;
|
||||
result = result.constraintInRange(sourcex, sourcey, length);
|
||||
}
|
||||
if (result.y > ymax) {
|
||||
let factor = (ymax - sourcey) / (result.y - sourcey);
|
||||
length *= factor;
|
||||
result = result.constraintInRange(sourcex, sourcey, length);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,11 +87,8 @@ module TK.SpaceTac.Specs {
|
|||
});
|
||||
|
||||
test.case("builds a textual description", check => {
|
||||
let action = new MoveAction("Engine", { distance_per_power: 58, safety_distance: 0 });
|
||||
let action = new MoveAction("Engine", { distance_per_power: 58 });
|
||||
check.equals(action.getEffectsDescription(), "Move: 58km per power point");
|
||||
|
||||
action = new MoveAction("Engine", { distance_per_power: 58, safety_distance: 12 });
|
||||
check.equals(action.getEffectsDescription(), "Move: 58km per power point (safety: 12km)");
|
||||
});
|
||||
|
||||
test.case("can't be used while in vigilance", check => {
|
||||
|
|
|
@ -3,10 +3,8 @@ module TK.SpaceTac {
|
|||
* Configuration of a trigger action
|
||||
*/
|
||||
export interface MoveActionConfig {
|
||||
// Distance allowed for each power point (raw, without applying maneuvrability)
|
||||
// Distance allowed for each power point
|
||||
distance_per_power: number
|
||||
// Safety distance from other ships
|
||||
safety_distance: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,8 +12,6 @@ module TK.SpaceTac {
|
|||
*/
|
||||
export class MoveAction extends BaseAction implements MoveActionConfig {
|
||||
distance_per_power = 0
|
||||
safety_distance = 120
|
||||
maneuvrability_factor = 0
|
||||
|
||||
constructor(name = "Engine", config?: Partial<MoveActionConfig>, code = "move") {
|
||||
super(name, code);
|
||||
|
@ -91,42 +87,16 @@ module TK.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the distance reachable with a given power
|
||||
* Get the distance reachable with a given power
|
||||
*/
|
||||
getRangeRadiusForPower(ship: Ship, power = ship.getValue("power")): number {
|
||||
return power * this.distance_per_power;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exclusion helper for this move action
|
||||
*/
|
||||
getExclusionAreas(ship: Ship): ExclusionAreas {
|
||||
return ExclusionAreas.fromShip(ship, this.safety_distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply exclusion areas (neer arena borders, or other ships)
|
||||
*/
|
||||
applyExclusion(ship: Ship, target: Target): Target {
|
||||
let exclusion = this.getExclusionAreas(ship);
|
||||
|
||||
let destination = exclusion.stopBefore(new ArenaLocation(target.x, target.y), ship.location);
|
||||
target = Target.newFromLocation(destination.x, destination.y);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply reachable range, with remaining power
|
||||
*/
|
||||
applyReachableRange(ship: Ship, target: Target, margin = 0.1): Target {
|
||||
let max_distance = this.getRangeRadius(ship);
|
||||
max_distance = Math.max(0, max_distance - margin);
|
||||
return target.constraintInRange(ship.arena_x, ship.arena_y, max_distance);
|
||||
}
|
||||
|
||||
checkLocationTarget(ship: Ship, target: Target): boolean {
|
||||
let fixed_target = this.applyExclusion(ship, this.applyReachableRange(ship, target));
|
||||
return fixed_target.getDistanceTo(target) < 1e-8;
|
||||
// TODO Check it's on the grid
|
||||
// TODO Check the space is not occupied
|
||||
return true;
|
||||
}
|
||||
|
||||
protected getSpecificDiffs(ship: Ship, battle: Battle, target: Target): BaseBattleDiff[] {
|
||||
|
@ -137,11 +107,6 @@ module TK.SpaceTac {
|
|||
|
||||
getEffectsDescription(): string {
|
||||
let result = `Move: ${this.distance_per_power}km per power point`;
|
||||
|
||||
if (this.safety_distance) {
|
||||
result += ` (safety: ${this.safety_distance}km)`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ module TK.SpaceTac.Specs {
|
|||
let ship2b = battle.fleets[1].addShip();
|
||||
ship2b.setArenaPosition(1200, 0);
|
||||
TestTools.setShipModel(ship2b, 10, 0, 5);
|
||||
let engine = ship2b.actions.addCustom(new MoveAction("Move", { distance_per_power: 1000, safety_distance: 100 }));
|
||||
let engine = ship2b.actions.addCustom(new MoveAction("Move", { distance_per_power: 1000 }));
|
||||
|
||||
let action = ship1a.actions.addCustom(new VigilanceAction("Reactive Shot", { radius: 1000, filter: ActionTargettingFilter.ENEMIES }, {
|
||||
intruder_effects: [new DamageEffect(1)]
|
||||
|
|
|
@ -16,9 +16,11 @@ module TK.SpaceTac {
|
|||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
if (ship != source && !any(ship.getEffects(), effect => effect instanceof PinnedEffect && effect.hard)) {
|
||||
let angle = arenaAngle(source.location, ship.location);
|
||||
let destination = new ArenaLocation(ship.arena_x + Math.cos(angle) * this.value, ship.arena_y + Math.sin(angle) * this.value);
|
||||
let exclusions = ExclusionAreas.fromShip(ship);
|
||||
destination = exclusions.stopBefore(destination, ship.location);
|
||||
let destination = new ArenaLocation(
|
||||
ship.arena_x + Math.cos(angle) * this.value,
|
||||
ship.arena_y + Math.sin(angle) * this.value
|
||||
);
|
||||
// TODO Snap to grid (what if space is already occupied ?)
|
||||
// TODO Apply area effect adding/removal
|
||||
return [
|
||||
new ShipMoveDiff(ship, ship.location, new ArenaLocationAngle(destination.x, destination.y, ship.arena_angle))
|
||||
|
|
|
@ -13,7 +13,6 @@ module TK.SpaceTac {
|
|||
getLevelUpgrades(level: number): ShipUpgrade[] {
|
||||
let engine = new MoveAction("Engine", {
|
||||
distance_per_power: 60,
|
||||
safety_distance: 250,
|
||||
});
|
||||
engine.configureCooldown(1, 1);
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ module TK.SpaceTac {
|
|||
if (level == 1) {
|
||||
let engine = new MoveAction("Engine", {
|
||||
distance_per_power: 460,
|
||||
safety_distance: 100
|
||||
});
|
||||
engine.configureCooldown(2, 1);
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ module TK.SpaceTac {
|
|||
if (level == 1) {
|
||||
let engine = new MoveAction("Engine", {
|
||||
distance_per_power: 310,
|
||||
safety_distance: 160,
|
||||
});
|
||||
|
||||
let missile = new TriggerAction("SubMunition Missile", {
|
||||
|
|
|
@ -30,7 +30,6 @@ module TK.SpaceTac {
|
|||
|
||||
let disengage = new MoveAction("Disengage", {
|
||||
distance_per_power: 1000,
|
||||
safety_distance: 200,
|
||||
}, "ionthruster");
|
||||
disengage.configureCooldown(1, 3);
|
||||
|
||||
|
|
|
@ -11,9 +11,6 @@ module TK.SpaceTac.UI {
|
|||
// Boundaries of the arena
|
||||
private boundaries: IBounded = { x: 0, y: 0, width: 1808, height: 948 }
|
||||
|
||||
// Hint for weapon or move range
|
||||
range_hint: RangeHint
|
||||
|
||||
// Input capture
|
||||
private mouse_capture?: UIImage
|
||||
|
||||
|
@ -31,7 +28,6 @@ module TK.SpaceTac.UI {
|
|||
// Layer for particles
|
||||
container: UIContainer
|
||||
layer_garbage: UIContainer
|
||||
layer_hints: UIContainer
|
||||
layer_drones: UIContainer
|
||||
layer_ships: UIContainer
|
||||
layer_weapon_effects: UIContainer
|
||||
|
@ -46,7 +42,6 @@ module TK.SpaceTac.UI {
|
|||
this.view = view;
|
||||
this.playing = null;
|
||||
this.hovered = null;
|
||||
this.range_hint = new RangeHint(this);
|
||||
|
||||
let builder = new UIBuilder(view, container);
|
||||
if (!container) {
|
||||
|
@ -59,13 +54,11 @@ module TK.SpaceTac.UI {
|
|||
this.setupMouseCapture();
|
||||
|
||||
this.layer_garbage = builder.container("garbage");
|
||||
this.layer_hints = builder.container("hints");
|
||||
this.layer_drones = builder.container("drones");
|
||||
this.layer_ships = builder.container("ships");
|
||||
this.layer_weapon_effects = builder.container("effects");
|
||||
this.layer_targetting = builder.container("targetting");
|
||||
|
||||
this.range_hint.setLayer(this.layer_hints);
|
||||
this.addShipSprites();
|
||||
view.battle.drones.list().forEach(drone => this.addDrone(drone, 0));
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ module TK.SpaceTac.UI {
|
|||
this.character_sheet.moveToLayer(this.layer_sheets);
|
||||
|
||||
// Targetting info
|
||||
this.targetting = new Targetting(this, this.action_bar, this.toggle_tactical_mode, this.arena.range_hint);
|
||||
this.targetting = new Targetting(this, this.action_bar, this.toggle_tactical_mode);
|
||||
this.targetting.moveToLayer(this.arena.layer_targetting);
|
||||
|
||||
// BGM
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
module TK.SpaceTac.UI {
|
||||
/**
|
||||
* Graphical hints for movement and weapon range
|
||||
*/
|
||||
export class RangeHint {
|
||||
// Link to the view
|
||||
private view: BaseView
|
||||
|
||||
// Visual information
|
||||
private info: UIGraphics
|
||||
|
||||
// Size of the arena
|
||||
private width: number
|
||||
private height: number
|
||||
|
||||
constructor(arena: Arena) {
|
||||
this.view = arena.view;
|
||||
|
||||
let boundaries = arena.getBoundaries();
|
||||
this.width = boundaries.width;
|
||||
this.height = boundaries.height;
|
||||
|
||||
this.info = new UIGraphics(arena.view, "info", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the layer in which the info will be displayed
|
||||
*/
|
||||
setLayer(layer: UIContainer, x = 0, y = 0) {
|
||||
this.info.setPosition(x, y);
|
||||
layer.add(this.info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear displayed information
|
||||
*/
|
||||
clear() {
|
||||
this.info.clear();
|
||||
this.info.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update displayed information
|
||||
*/
|
||||
update(ship: Ship, action: BaseAction, radius = action.getRangeRadius(ship)): void {
|
||||
let yescolor = 0x000000;
|
||||
let nocolor = 0x242022;
|
||||
this.info.clear();
|
||||
|
||||
if (radius) {
|
||||
this.info.fillStyle(nocolor);
|
||||
this.info.fillRect(0, 0, this.width, this.height);
|
||||
|
||||
this.info.fillStyle(yescolor);
|
||||
this.info.fillCircle(ship.arena_x, ship.arena_y, radius);
|
||||
|
||||
if (action instanceof MoveAction) {
|
||||
let exclusions = action.getExclusionAreas(ship);
|
||||
|
||||
this.info.fillStyle(nocolor);
|
||||
this.info.fillRect(0, 0, this.width, exclusions.hard_border);
|
||||
this.info.fillRect(0, this.height - exclusions.hard_border, this.width, exclusions.hard_border);
|
||||
this.info.fillRect(0, exclusions.hard_border, exclusions.hard_border, this.height - exclusions.hard_border * 2);
|
||||
this.info.fillRect(this.width - exclusions.hard_border, exclusions.hard_border, exclusions.hard_border, this.height - exclusions.hard_border * 2);
|
||||
|
||||
exclusions.obstacles.forEach(obstacle => {
|
||||
this.info.fillCircle(obstacle.x, obstacle.y, exclusions.effective_obstacle);
|
||||
});
|
||||
}
|
||||
|
||||
this.info.visible = true;
|
||||
} else {
|
||||
this.info.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,7 @@ module TK.SpaceTac.UI.Specs {
|
|||
function newTargetting(): Targetting {
|
||||
return new Targetting(testgame.view,
|
||||
testgame.view.action_bar,
|
||||
testgame.view.toggle_tactical_mode,
|
||||
testgame.view.arena.range_hint);
|
||||
testgame.view.toggle_tactical_mode);
|
||||
}
|
||||
|
||||
test.case("draws simulation parts", check => {
|
||||
|
@ -153,36 +152,5 @@ module TK.SpaceTac.UI.Specs {
|
|||
targetting.setTargetFromLocation({ x: 0, y: 0 });
|
||||
check.equals(targetting.target, Target.newFromShip(playing_ship), "self 2");
|
||||
})
|
||||
|
||||
test.case("updates the range hint display", check => {
|
||||
let targetting = newTargetting();
|
||||
let ship = nn(testgame.view.battle.playing_ship);
|
||||
ship.setArenaPosition(0, 0);
|
||||
TestTools.setShipModel(ship, 100, 0, 8);
|
||||
let move = TestTools.addEngine(ship, 100);
|
||||
let fire = TestTools.addWeapon(ship, 50, 2, 300, 100);
|
||||
let last_call: any = null;
|
||||
check.patch(targetting.range_hint, "clear", () => {
|
||||
last_call = null;
|
||||
});
|
||||
check.patch(targetting.range_hint, "update", (ship: Ship, action: BaseAction, radius: number) => {
|
||||
last_call = [ship, action, radius];
|
||||
});
|
||||
|
||||
// move action
|
||||
targetting.setAction(ship, move);
|
||||
targetting.setTargetFromLocation({ x: 200, y: 0 });
|
||||
check.equals(last_call, [ship, move, 800]);
|
||||
|
||||
// fire action
|
||||
targetting.setAction(ship, fire);
|
||||
targetting.setTargetFromLocation({ x: 200, y: 0 });
|
||||
check.equals(last_call, [ship, fire, undefined]);
|
||||
|
||||
// move+fire
|
||||
targetting.setAction(ship, fire);
|
||||
targetting.setTargetFromLocation({ x: 400, y: 0 });
|
||||
check.equals(last_call, [ship, move, 600]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -32,17 +32,15 @@ module TK.SpaceTac.UI {
|
|||
|
||||
// Collaborators to update
|
||||
actionbar: ActionBar
|
||||
range_hint: RangeHint
|
||||
tactical_mode: ToggleClient
|
||||
|
||||
// Access to the parent view
|
||||
view: BaseView
|
||||
|
||||
constructor(view: BaseView, actionbar: ActionBar, tactical_mode: Toggle, range_hint: RangeHint) {
|
||||
constructor(view: BaseView, actionbar: ActionBar, tactical_mode: Toggle) {
|
||||
this.view = view;
|
||||
this.actionbar = actionbar;
|
||||
this.tactical_mode = tactical_mode.manipulate("targetting");
|
||||
this.range_hint = range_hint;
|
||||
|
||||
let builder = new UIBuilder(view);
|
||||
this.container = builder.container("targetting");
|
||||
|
@ -310,16 +308,8 @@ module TK.SpaceTac.UI {
|
|||
if (this.action !== move_action) {
|
||||
power = Math.max(power - this.action.getPowerUsage(this.ship, this.target), 0);
|
||||
}
|
||||
let radius = move_action.getRangeRadiusForPower(this.ship, power);
|
||||
this.range_hint.update(this.ship, move_action, radius);
|
||||
} else {
|
||||
this.range_hint.clear();
|
||||
}
|
||||
} else {
|
||||
this.range_hint.update(this.ship, this.action);
|
||||
}
|
||||
} else {
|
||||
this.range_hint.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue