Incomplete WIP
This commit is contained in:
parent
aa640e23f2
commit
0e3e9bc199
|
@ -82,9 +82,9 @@ module TK.SpaceTac.Specs {
|
|||
ship2.setArenaPosition(1000, 1000);
|
||||
TestTools.setShipModel(ship2, 10);
|
||||
|
||||
let vig1 = ship1.actions.addCustom(new VigilanceAction("Vig1", { radius: 100, filter: ActionTargettingFilter.ENEMIES }, { intruder_effects: [new DamageEffect(1)] }));
|
||||
let vig2 = ship1.actions.addCustom(new VigilanceAction("Vig2", { radius: 50, filter: ActionTargettingFilter.ENEMIES }, { intruder_effects: [new DamageEffect(2)] }));
|
||||
let vig3 = ship1.actions.addCustom(new VigilanceAction("Vig3", { radius: 100, filter: ActionTargettingFilter.ALLIES }, { intruder_effects: [new DamageEffect(3)] }));
|
||||
let vig1 = ship1.actions.addCustom(new VigilanceAction("Vig1", { radius: 100, filter: ActionImpactFilter.ENEMIES }, { intruder_effects: [new DamageEffect(1)] }));
|
||||
let vig2 = ship1.actions.addCustom(new VigilanceAction("Vig2", { radius: 50, filter: ActionImpactFilter.ENEMIES }, { intruder_effects: [new DamageEffect(2)] }));
|
||||
let vig3 = ship1.actions.addCustom(new VigilanceAction("Vig3", { radius: 100, filter: ActionImpactFilter.ALLIES }, { intruder_effects: [new DamageEffect(3)] }));
|
||||
battle.applyOneAction(vig1.id);
|
||||
battle.applyOneAction(vig2.id);
|
||||
battle.applyOneAction(vig3.id);
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
module TK.SpaceTac.Specs {
|
||||
testing("Target", test => {
|
||||
test.case("initializes from ship or location", check => {
|
||||
var target: Target;
|
||||
|
||||
target = Target.newFromLocation(2, 3);
|
||||
check.equals(target.x, 2);
|
||||
check.equals(target.y, 3);
|
||||
check.equals(target.ship_id, null);
|
||||
|
||||
var ship = new Ship();
|
||||
ship.arena_x = 4;
|
||||
ship.arena_y = -2.1;
|
||||
target = Target.newFromShip(ship);
|
||||
check.equals(target.x, 4);
|
||||
check.equals(target.y, -2.1);
|
||||
check.equals(target.ship_id, ship.id);
|
||||
});
|
||||
|
||||
test.case("gets distance to another target", check => {
|
||||
var t1 = Target.newFromLocation(5, 1);
|
||||
var t2 = Target.newFromLocation(6, 2);
|
||||
check.nears(t1.getDistanceTo(t2), Math.sqrt(2));
|
||||
});
|
||||
|
||||
test.case("gets angle to another target", check => {
|
||||
var t1 = Target.newFromLocation(2, 3);
|
||||
var t2 = Target.newFromLocation(4, 5);
|
||||
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);
|
||||
});
|
||||
|
||||
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,174 +0,0 @@
|
|||
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 {
|
||||
// Coordinates of the target
|
||||
x: number
|
||||
y: number
|
||||
|
||||
// If the target is a ship, this attribute will be set
|
||||
ship_id: RObjectId | null
|
||||
|
||||
// Standard constructor
|
||||
constructor(x: number, y: number, ship: Ship | null = null) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.ship_id = ship ? ship.id : null;
|
||||
}
|
||||
|
||||
jasmineToString() {
|
||||
if (this.ship_id) {
|
||||
return `(${this.x},${this.y}) ship_id=${this.ship_id}}`;
|
||||
} else {
|
||||
return `(${this.x},${this.y})`;
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor to target a single ship
|
||||
static newFromShip(ship: Ship): Target {
|
||||
return new Target(ship.arena_x, ship.arena_y, ship);
|
||||
}
|
||||
|
||||
// Constructor to target a location in space
|
||||
static newFromLocation(x: number, y: number): Target {
|
||||
return new Target(x, y, null);
|
||||
}
|
||||
|
||||
// Get distance to another target
|
||||
getDistanceTo(other: { x: number, y: number }): number {
|
||||
var dx = other.x - this.x;
|
||||
var dy = other.y - this.y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
// Get the normalized angle, in radians, to another target
|
||||
getAngleTo(other: { x: number, y: number }): number {
|
||||
var dx = other.x - this.x;
|
||||
var dy = other.y - this.y;
|
||||
return Math.atan2(dy, dx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the target is a ship
|
||||
*/
|
||||
isShip(): boolean {
|
||||
return this.ship_id !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the targetted ship in a battle
|
||||
*/
|
||||
getShip(battle: Battle): Ship | null {
|
||||
if (this.isShip()) {
|
||||
return battle.getShip(this.ship_id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a target is in range from a specific point
|
||||
isInRange(x: number, y: number, radius: number): boolean {
|
||||
var dx = this.x - x;
|
||||
var dy = this.y - y;
|
||||
var length = Math.sqrt(dx * dx + dy * dy);
|
||||
return (length <= 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -68,15 +68,15 @@ module TK.SpaceTac.Specs {
|
|||
let ship2b = fleet2.addShip();
|
||||
let ships = [ship1a, ship1b, ship2a, ship2b];
|
||||
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionTargettingFilter.ALL),
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionImpactFilter.ALL),
|
||||
[ship1a, ship1b, ship2a, ship2b], "ALL");
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionTargettingFilter.ALL_BUT_SELF),
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionImpactFilter.ALL_BUT_SELF),
|
||||
[ship1b, ship2a, ship2b], "ALL_BUT_SELF");
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionTargettingFilter.ALLIES),
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionImpactFilter.ALLIES),
|
||||
[ship1a, ship1b], "ALLIES");
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionTargettingFilter.ALLIES_BUT_SELF),
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionImpactFilter.ALLIES_BUT_SELF),
|
||||
[ship1b], "ALLIES_BUT_SELF");
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionTargettingFilter.ENEMIES),
|
||||
check.equals(BaseAction.filterTargets(ship1a, ships, ActionImpactFilter.ENEMIES),
|
||||
[ship2a, ship2b], "ENEMIES");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,33 +5,34 @@ module TK.SpaceTac {
|
|||
export enum ActionCategory {
|
||||
MOVE,
|
||||
PASSIVE,
|
||||
ACTIVE
|
||||
ACTIVE,
|
||||
}
|
||||
|
||||
/**
|
||||
* Targetting mode for an action.
|
||||
*
|
||||
* This is a hint as to what type of target is required for this action.
|
||||
* Target for an action
|
||||
*/
|
||||
export enum ActionTargettingMode {
|
||||
// Apply immediately on the ship owning the action, without confirmation
|
||||
export type ActionTarget = Readonly<{
|
||||
distance?: number
|
||||
angle?: number
|
||||
}>
|
||||
|
||||
/**
|
||||
* Target for an action, as applied from an hypothetical location
|
||||
*/
|
||||
export type ActionTargetFrom = Readonly<{
|
||||
location: IArenaLocation
|
||||
distance?: number
|
||||
angle?: number
|
||||
}>
|
||||
|
||||
/**
|
||||
* Impact filter for an action.
|
||||
*
|
||||
* This will filter ships inside the targetted area, to determine which ones will receive the action effects.
|
||||
*/
|
||||
export enum ActionImpactFilter {
|
||||
// Apply only on casting ship
|
||||
SELF,
|
||||
// Apply on the ship owning the action, with a confirmation
|
||||
SELF_CONFIRM,
|
||||
// Apply on one selected ship
|
||||
SHIP,
|
||||
// Apply on a space area
|
||||
SPACE,
|
||||
// Apply on the ship owning the action, but has an effect on surroundings
|
||||
SURROUNDINGS
|
||||
}
|
||||
|
||||
/**
|
||||
* Targetting filter for an action.
|
||||
*
|
||||
* This will filter ships inside the targetted area, to determine which will receive the action effects.
|
||||
*/
|
||||
export enum ActionTargettingFilter {
|
||||
// Apply on all ships
|
||||
ALL,
|
||||
// Apply on all ships except the actor
|
||||
|
@ -41,7 +42,49 @@ module TK.SpaceTac {
|
|||
// Apply on all allies, except the actor
|
||||
ALLIES_BUT_SELF,
|
||||
// Apply on all enemies
|
||||
ENEMIES
|
||||
ENEMIES,
|
||||
};
|
||||
|
||||
/**
|
||||
* Priority of ships in the target area.
|
||||
*
|
||||
* If there are more ships that the action limit, the most prioritized ones will be affected.
|
||||
*/
|
||||
export enum ActionImpactPriority {
|
||||
// Nearest ships are priority
|
||||
NEAREST,
|
||||
// Farthest ships are priority
|
||||
FARTHEST,
|
||||
// Ships with the most hull are priority
|
||||
TOUGHEST,
|
||||
// Ships with the less hull are priority
|
||||
WEAKEST,
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for the target of an action
|
||||
*/
|
||||
export interface BaseActionConfig {
|
||||
// Identifying code (for assets and effects)
|
||||
code: string
|
||||
// Human-friendly name
|
||||
name: string
|
||||
// Power cost
|
||||
power_cost?: number
|
||||
// Maximal distance the target can be set
|
||||
min_distance?: number
|
||||
// Minimal distance the target can be set
|
||||
max_distance?: number
|
||||
// Angle that will span the affected area (around the target direction)
|
||||
angular_span?: number
|
||||
// Radius of the affected area (around the target location)
|
||||
radius?: number
|
||||
// Filtering of ships in the affected area
|
||||
ship_filter?: ActionImpactFilter
|
||||
// Maximal number of ships impacted in the affected area
|
||||
ship_limit?: number
|
||||
// Priority of ships in affected area
|
||||
ship_priority?: ActionImpactPriority
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,22 +108,28 @@ module TK.SpaceTac {
|
|||
*
|
||||
* An action should be the only way to modify a battle state.
|
||||
*/
|
||||
export class BaseAction extends RObject {
|
||||
// Identifier code for the type of action
|
||||
readonly code: string
|
||||
|
||||
// Full name of the action
|
||||
readonly name: string
|
||||
export class BaseAction extends RObject implements BaseActionConfig {
|
||||
code = "nothing"
|
||||
name = "Nothing"
|
||||
power_cost = 0
|
||||
min_distance = 0
|
||||
max_distance = Infinity
|
||||
angular_span = undefined
|
||||
radius = undefined
|
||||
ship_filter = ActionImpactFilter.ALL
|
||||
ship_limit = undefined
|
||||
ship_priority = ActionImpactPriority.NEAREST
|
||||
|
||||
// Cooldown configuration
|
||||
private cooldown = new Cooldown()
|
||||
|
||||
// Create the action
|
||||
constructor(name = "Nothing", code?: string) {
|
||||
constructor(config?: Partial<Readonly<BaseActionConfig>>) {
|
||||
super();
|
||||
|
||||
this.code = code ? code : name.toLowerCase().replace(" ", "");
|
||||
this.name = name;
|
||||
if (config) {
|
||||
this.configure(config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,17 +154,17 @@ module TK.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the targetting mode
|
||||
* Get a default target for this action
|
||||
*/
|
||||
getTargettingMode(ship: Ship): ActionTargettingMode {
|
||||
return ActionTargettingMode.SELF;
|
||||
getDefaultTarget(ship: Ship): ActionTargetFrom {
|
||||
return { location: ship.location };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a default target for this action
|
||||
* Configure the base settings for this action
|
||||
*/
|
||||
getDefaultTarget(ship: Ship): Target {
|
||||
return Target.newFromShip(ship);
|
||||
configure(config: Partial<Readonly<BaseActionConfig>>): void {
|
||||
copyfields(config, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,13 +183,13 @@ module TK.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check basic conditions to know if the ship can use this action at all
|
||||
* Check basic conditions to know if the ship can use this action at all, not accounting for power
|
||||
*
|
||||
* Method to extend to set conditions
|
||||
*
|
||||
* Returns an unavalability reason, null otherwise
|
||||
*/
|
||||
checkCannotBeApplied(ship: Ship, remaining_ap: number | null = null): ActionUnavailability | null {
|
||||
checkCannotBeApplied(ship: Ship): ActionUnavailability | null {
|
||||
if (!ship.actions.getById(this.id)) {
|
||||
return ActionUnavailability.NO_SUCH_ACTION;
|
||||
}
|
||||
|
@ -154,17 +203,10 @@ module TK.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the power cost of this action
|
||||
* Get the power cost of this action for the current state
|
||||
*/
|
||||
getPowerUsage(ship: Ship): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range of this action, for targetting purpose
|
||||
*/
|
||||
getRangeRadius(ship: Ship): number {
|
||||
return 0;
|
||||
return this.power_cost;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,36 +214,20 @@ module TK.SpaceTac {
|
|||
*
|
||||
* This may be used as an indicator for helping the player in targetting, or to effectively apply the effects
|
||||
*/
|
||||
filterImpactedShips(ship: Ship, source: IArenaLocation, target: Target, ships: Ship[]): Ship[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of ships impacted by this action
|
||||
*/
|
||||
getImpactedShips(ship: Ship, target: Target, source: IArenaLocation = ship.location): Ship[] {
|
||||
let battle = ship.getBattle();
|
||||
if (battle) {
|
||||
return this.filterImpactedShips(ship, source, target, imaterialize(battle.iships(true)));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to apply a targetting filter on a list of ships, to determine which ones are impacted
|
||||
*/
|
||||
static filterTargets(source: Ship, ships: Ship[], filter: ActionTargettingFilter): Ship[] {
|
||||
filterImpactedShips(ships: readonly Ship[], source: Ship, target: ActionTargetFrom): readonly Ship[] {
|
||||
// TODO Allow to work with ghosts (location instead of ships?)
|
||||
// TODO Apply radius and angle
|
||||
// TODO Apply limit and priority
|
||||
return ships.filter(ship => {
|
||||
if (filter == ActionTargettingFilter.ALL) {
|
||||
if (this.ship_filter == ActionImpactFilter.ALL) {
|
||||
return true;
|
||||
} else if (filter == ActionTargettingFilter.ALL_BUT_SELF) {
|
||||
} else if (this.ship_filter == ActionImpactFilter.ALL_BUT_SELF) {
|
||||
return !ship.is(source);
|
||||
} else if (filter == ActionTargettingFilter.ALLIES) {
|
||||
} else if (this.ship_filter == ActionImpactFilter.ALLIES) {
|
||||
return ship.fleet.player.is(source.fleet.player);
|
||||
} else if (filter == ActionTargettingFilter.ALLIES_BUT_SELF) {
|
||||
} else if (this.ship_filter == ActionImpactFilter.ALLIES_BUT_SELF) {
|
||||
return ship.fleet.player.is(source.fleet.player) && !ship.is(source);
|
||||
} else if (filter == ActionTargettingFilter.ENEMIES) {
|
||||
} else if (this.ship_filter == ActionImpactFilter.ENEMIES) {
|
||||
return !ship.fleet.player.is(source.fleet.player);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -212,16 +238,17 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Get a name to represent the group of ships specified by a target filter
|
||||
*/
|
||||
static getFilterDesc(filter: ActionTargettingFilter, plural = true): string {
|
||||
if (filter == ActionTargettingFilter.ALL) {
|
||||
static getFilterDesc(filter: ActionImpactFilter, plural = true): string {
|
||||
// TODO limit and priority
|
||||
if (filter == ActionImpactFilter.ALL) {
|
||||
return plural ? "ships" : "ship";
|
||||
} else if (filter == ActionTargettingFilter.ALL_BUT_SELF) {
|
||||
} else if (filter == ActionImpactFilter.ALL_BUT_SELF) {
|
||||
return plural ? "other ships" : "other ship";
|
||||
} else if (filter == ActionTargettingFilter.ALLIES) {
|
||||
} else if (filter == ActionImpactFilter.ALLIES) {
|
||||
return plural ? "team members" : "team member";
|
||||
} else if (filter == ActionTargettingFilter.ALLIES_BUT_SELF) {
|
||||
} else if (filter == ActionImpactFilter.ALLIES_BUT_SELF) {
|
||||
return plural ? "teammates" : "teammates";
|
||||
} else if (filter == ActionTargettingFilter.ENEMIES) {
|
||||
} else if (filter == ActionImpactFilter.ENEMIES) {
|
||||
return plural ? "enemies" : "enemy";
|
||||
} else {
|
||||
return "";
|
||||
|
@ -231,9 +258,9 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Check if a target is suitable for this action
|
||||
*
|
||||
* Will call checkLocationTarget or checkShipTarget by default
|
||||
* Returns a suggested fixed target (may be the same as the input)
|
||||
*/
|
||||
checkTarget(ship: Ship, target: Target): Target | null {
|
||||
checkTarget(ship: Ship, target: ActionTargetFrom): ActionTargetFrom | null {
|
||||
if (this.checkCannotBeApplied(ship)) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -245,24 +272,12 @@ module TK.SpaceTac {
|
|||
}
|
||||
}
|
||||
|
||||
// Method to reimplement to check if a space target is suitable
|
||||
// Must return null if the target can't be applied, an altered target, or the original target
|
||||
protected checkLocationTarget(ship: Ship, target: Target): Target | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Method to reimplement to check if a ship target is suitable
|
||||
// Must return null if the target can't be applied, an altered target, or the original target
|
||||
protected checkShipTarget(ship: Ship, target: Target): Target | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full list of diffs caused by applying this action
|
||||
*
|
||||
* This does not perform any check, and assumes the action is doable
|
||||
*/
|
||||
getDiffs(ship: Ship, battle: Battle, target = this.getDefaultTarget(ship)): BaseBattleDiff[] {
|
||||
getDiffs(ship: Ship, battle: Battle, target: ActionTargetFrom): BaseBattleDiff[] {
|
||||
let result: BaseBattleDiff[] = [];
|
||||
|
||||
// Action usage
|
||||
|
@ -277,7 +292,7 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Method to reimplement to return the diffs specific to this action
|
||||
*/
|
||||
protected getSpecificDiffs(ship: Ship, battle: Battle, target: Target): BaseBattleDiff[] {
|
||||
protected getSpecificDiffs(ship: Ship, battle: Battle, target: ActionTargetFrom): BaseBattleDiff[] {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -286,7 +301,7 @@ module TK.SpaceTac {
|
|||
*
|
||||
* This will first check that the action can be done, then get the battle diffs and apply them.
|
||||
*/
|
||||
apply(battle: Battle, ship: Ship, target = this.getDefaultTarget(ship)): boolean {
|
||||
apply(battle: Battle, ship: Ship, target: ActionTarget): boolean {
|
||||
let reject = this.checkCannotBeApplied(ship);
|
||||
if (reject) {
|
||||
console.warn(`Action rejected - ${reject}`, ship, this, target);
|
||||
|
|
|
@ -12,7 +12,7 @@ module TK.SpaceTac {
|
|||
// Effects applied
|
||||
effects: BaseEffect[]
|
||||
// Filtering ships that will receive the effects
|
||||
filter: ActionTargettingFilter
|
||||
filter: ActionImpactFilter
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ module TK.SpaceTac {
|
|||
power = 1
|
||||
radius = 0
|
||||
effects: BaseEffect[] = []
|
||||
filter = ActionTargettingFilter.ALL
|
||||
filter = ActionImpactFilter.ALL
|
||||
|
||||
constructor(name: string, config?: Partial<ToggleActionConfig>, code?: string) {
|
||||
super(name, code);
|
||||
|
|
|
@ -38,7 +38,7 @@ module TK.SpaceTac.Specs {
|
|||
});
|
||||
check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 on the first 3 incoming ships");
|
||||
|
||||
action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120, filter: ActionTargettingFilter.ALLIES }, {
|
||||
action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120, filter: ActionImpactFilter.ALLIES }, {
|
||||
intruder_count: 3,
|
||||
intruder_effects: [new ValueEffect("hull", -1)]
|
||||
});
|
||||
|
@ -61,7 +61,7 @@ module TK.SpaceTac.Specs {
|
|||
TestTools.setShipModel(ship2b, 10, 0, 5);
|
||||
let engine = ship2b.actions.addCustom(new MoveAction("Move", { max_distance: 1000 }));
|
||||
|
||||
let action = ship1a.actions.addCustom(new VigilanceAction("Reactive Shot", { radius: 1000, filter: ActionTargettingFilter.ENEMIES }, {
|
||||
let action = ship1a.actions.addCustom(new VigilanceAction("Reactive Shot", { radius: 1000, filter: ActionImpactFilter.ENEMIES }, {
|
||||
intruder_effects: [new DamageEffect(1)]
|
||||
}));
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ module TK.SpaceTac {
|
|||
}, "prokhorovlaser");
|
||||
laser.configureCooldown(3, 1);
|
||||
|
||||
let interceptors = new VigilanceAction("Interceptors Field", { radius: 400, power: 3, filter: ActionTargettingFilter.ENEMIES }, {
|
||||
let interceptors = new VigilanceAction("Interceptors Field", { radius: 400, power: 3, filter: ActionImpactFilter.ENEMIES }, {
|
||||
intruder_count: 1,
|
||||
intruder_effects: [new DamageEffect(4, DamageEffectMode.SHIELD_THEN_HULL)]
|
||||
}, "interceptors");
|
||||
|
|
|
@ -30,7 +30,7 @@ module TK.SpaceTac {
|
|||
}, "gravitshield");
|
||||
repulse.configureCooldown(1, 1);
|
||||
|
||||
let repairdrone = new DeployDroneAction("Repair Drone", { power: 3, filter: ActionTargettingFilter.ALLIES }, {
|
||||
let repairdrone = new DeployDroneAction("Repair Drone", { power: 3, filter: ActionImpactFilter.ALLIES }, {
|
||||
deploy_distance: 600,
|
||||
drone_radius: 300,
|
||||
drone_effects: [
|
||||
|
|
|
@ -21,7 +21,7 @@ module TK.SpaceTac {
|
|||
power: 4,
|
||||
radius: 400,
|
||||
effects: [new AttributeEffect("evasion", 1)],
|
||||
filter: ActionTargettingFilter.ALLIES
|
||||
filter: ActionImpactFilter.ALLIES
|
||||
});
|
||||
|
||||
let depleter = new TriggerAction("Power Depleter", {
|
||||
|
|
Loading…
Reference in a new issue