1
0
Fork 0
spacetac/src/core/actions/FireWeaponAction.ts

128 lines
4.4 KiB
TypeScript

/// <reference path="BaseAction.ts"/>
module TS.SpaceTac {
/**
* Action to fire a weapon on another ship, or in space
*/
export class FireWeaponAction extends BaseAction {
// Power consumption
power: number
// Maximal range of the weapon
range: number
// Blast radius
blast: number
// Effects applied on target
effects: BaseEffect[]
// Equipment cannot be null
equipment: Equipment
constructor(equipment: Equipment, power = 1, range = 0, blast = 0, effects: BaseEffect[] = [], name = "Fire") {
super("fire-" + equipment.code, name, equipment);
this.power = power;
this.range = range;
this.effects = effects;
this.blast = blast;
}
getDefaultTarget(ship: Ship): Target {
if (this.range == 0) {
return Target.newFromShip(ship);
} else {
let battle = ship.getBattle();
if (battle) {
let harmful = any(this.effects, effect => !effect.isBeneficial());
let player = ship.getPlayer();
let ships = imaterialize(harmful ? battle.ienemies(player, true) : ifilter(battle.iallies(player, true), iship => iship != ship));
let nearest = minBy(ships, iship => arenaDistance(ship.location, iship.location));
return Target.newFromShip(nearest);
} else {
return Target.newFromShip(ship);
}
}
}
getActionPointsUsage(ship: Ship, target: Target | null): number {
return this.power;
}
getRangeRadius(ship: Ship): number {
return this.range;
}
getBlastRadius(ship: Ship): number {
return this.blast;
}
checkLocationTarget(ship: Ship, target: Target): Target | null {
if (target && this.blast > 0) {
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.range);
return target;
} else {
return null;
}
}
checkShipTarget(ship: Ship, target: Target): Target | null {
if (this.range > 0 && ship == target.ship) {
// No self fire
return null;
} else {
// Check if target is in range
if (this.blast > 0) {
return this.checkLocationTarget(ship, new Target(target.x, target.y));
} else if (target.isInRange(ship.arena_x, ship.arena_y, this.range)) {
return target;
} else {
return null;
}
}
}
/**
* Collect the effects applied by this action
*/
getEffects(ship: Ship, target: Target): [Ship, BaseEffect][] {
let result: [Ship, BaseEffect][] = [];
let blast = this.getBlastRadius(ship);
let battle = ship.getBattle();
let ships = (blast && battle) ? battle.collectShipsInCircle(target, blast, true) : ((target.ship && target.ship.alive) ? [target.ship] : []);
ships.forEach(ship => {
this.effects.forEach(effect => result.push([ship, effect]));
});
return result;
}
protected customApply(ship: Ship, target: Target) {
if (arenaDistance(ship.location, target) > 0.000001) {
// Face the target
ship.rotate(arenaAngle(ship.location, target), first(ship.listEquipment(SlotType.Engine), () => true));
}
// Fire event
ship.addBattleEvent(new FireEvent(ship, this.equipment, target));
// Apply effects
let effects = this.getEffects(ship, target);
effects.forEach(([ship_target, effect]) => effect.applyOnShip(ship_target, ship));
}
getEffectsDescription(): string {
if (this.effects.length == 0) {
return "";
}
let desc = `${this.name} (power usage ${this.power}, max range ${this.range}km)`;
let effects = this.effects.map(effect => {
let suffix = this.blast ? `in ${this.blast}km radius` : "on target";
return "• " + effect.getDescription() + " " + suffix;
});
return `${desc}:\n${effects.join("\n")}`;
}
}
}