1
0
Fork 0
spacetac/src/ui/battle/ArenaShip.ts

341 lines
13 KiB
TypeScript

module TS.SpaceTac.UI {
// Ship sprite in the arena (BattleView)
export class ArenaShip extends Phaser.Group {
// Link to the view
arena: Arena
battleview: BattleView
// Link to displayed ship
ship: Ship
// Boolean to indicate if it is an enemy ship
enemy: boolean
// Ship sprite
sprite: Phaser.Button
// Statis effect
stasis: Phaser.Image
// HSP display
hull: ValueBar
toggle_hull: Toggle
shield: ValueBar
toggle_shield: Toggle
power: Phaser.Group
toggle_power: Toggle
// Play order
play_order: Phaser.Text
toggle_play_order: Toggle
// Frame to indicate the owner of the ship, and if it is playing
frame: Phaser.Image
// Effects display
active_effects: ActiveEffectsEvent
active_effects_display: Phaser.Group
effects_radius: Phaser.Graphics
effects_messages: Phaser.Group
// Create a ship sprite usable in the Arena
constructor(parent: Arena, ship: Ship) {
super(parent.game);
this.arena = parent;
this.battleview = parent.battleview;
this.ship = ship;
this.enemy = this.ship.getPlayer() != this.battleview.player;
// Add effects radius
this.effects_radius = new Phaser.Graphics(this.game);
this.add(this.effects_radius);
// Add ship sprite
let info = this.battleview.getImageInfo(`ship-${ship.model.code}-sprite`);
this.sprite = new Phaser.Button(this.game, 0, 0, info.key, undefined, undefined, info.frame, info.frame);
this.sprite.rotation = ship.arena_angle;
this.sprite.anchor.set(0.5, 0.5);
this.sprite.scale.set(0.25);
this.add(this.sprite);
// Add stasis effect
this.stasis = new Phaser.Image(this.game, 0, 0, "battle-arena-ship-frames", 2);
this.stasis.anchor.set(0.5, 0.5);
this.stasis.visible = false;
this.add(this.stasis);
// Add playing effect
this.frame = new Phaser.Image(this.game, 0, 0, "battle-arena-ship-frames", this.enemy ? 0 : 1);
this.frame.anchor.set(0.5, 0.5);
this.add(this.frame);
// HSP display
this.hull = ValueBar.newStyled(this.game, "battle-arena-gauges", -59, -47, true, 0);
this.hull.setValue(this.ship.getValue("hull"), this.ship.getAttribute("hull_capacity"));
this.toggle_hull = this.battleview.animations.newVisibilityToggle(this.hull, 200, false);
this.add(this.hull);
this.shield = ValueBar.newStyled(this.game, "battle-arena-gauges", 40, -47, true, 2);
this.shield.setValue(this.ship.getValue("shield"), this.ship.getAttribute("shield_capacity"));
this.toggle_shield = this.battleview.animations.newVisibilityToggle(this.shield, 200, false);
this.add(this.shield);
this.power = new Phaser.Group(this.game);
this.toggle_power = this.battleview.animations.newVisibilityToggle(this.power, 200, false);
this.add(this.power);
// Play order display
this.play_order = new Phaser.Text(this.game, 55, -47, "", { font: "bold 14pt Arial", fill: "#aaaaaa" });
this.toggle_play_order = this.battleview.animations.newVisibilityToggle(this.play_order, 200, false);
this.add(this.play_order);
// Effects display
this.active_effects = new ActiveEffectsEvent(ship);
this.active_effects_display = new Phaser.Group(this.game);
this.add(this.active_effects_display);
this.effects_messages = new Phaser.Group(this.game);
this.add(this.effects_messages);
this.updateActiveEffects();
this.updatePowerIndicator(ship.getValue("power"));
this.updateEffectsRadius();
// Handle input on ship sprite
UITools.setHoverClick(this.sprite,
() => this.battleview.cursorOnShip(ship),
() => this.battleview.cursorOffShip(ship),
() => this.battleview.cursorClicked()
);
// Set location
if (this.battleview.battle.turn == 1 && ship.alive && ship.fleet.player === this.battleview.player) {
this.position.set(ship.arena_x - 500 * Math.cos(ship.arena_angle), ship.arena_y - 500 * Math.sin(ship.arena_angle));
this.moveTo(ship.arena_x, ship.arena_y, ship.arena_angle);
} else {
this.moveTo(ship.arena_x, ship.arena_y, ship.arena_angle, false);
}
// Log processing
this.battleview.log_processor.register(event => this.processLogEvent(event));
this.battleview.log_processor.registerForShip(ship, event => this.processShipLogEvent(event));
}
/**
* Process a battle log event
*/
private processLogEvent(event: BaseBattleEvent): number {
if (event instanceof ShipChangeEvent) {
if (event.new_ship === this.ship) {
this.play_order.text = "";
} else {
this.play_order.text = this.battleview.battle.getTurnsBefore(this.ship).toString();
}
}
return 0;
}
/**
* Process a log event for this ship
*/
private processShipLogEvent(event: BaseLogShipEvent): number {
if (event instanceof ActiveEffectsEvent) {
this.active_effects = event;
this.updateActiveEffects();
return 0;
} else if (event instanceof ValueChangeEvent) {
if (event.value.name == "hull") {
this.toggle_hull.start(1500, true);
this.hull.setValue(event.value.get(), event.value.getMaximal() || 0);
return 0;
} else if (event.value.name == "shield") {
this.toggle_shield.start(1500, true);
this.shield.setValue(event.value.get(), event.value.getMaximal() || 0);
if (event.value.get() == 0) {
this.displayEffect("Shield failure", false);
}
return 0;
} else if (event.value.name == "power") {
this.toggle_power.start(1500, true);
this.updatePowerIndicator(event.value.get());
return 0;
} else {
this.displayValueChanged(event);
return 0;
}
} else if (event instanceof DamageEvent) {
this.displayEffect(`${event.hull + event.shield} damage`, false);
return 0;
} else if (event instanceof ToggleEvent) {
if (event.action.equipment) {
let equname = event.action.equipment.name;
if (event.activated) {
this.displayEffect(`${equname} ON`, true);
} else {
this.displayEffect(`${equname} OFF`, false);
}
this.updateEffectsRadius();
}
return 0;
} else if (event instanceof MoveEvent && !event.initial) {
this.moveTo(event.start.x, event.start.y, event.start.angle, false);
let duration = this.moveTo(event.end.x, event.end.y, event.end.angle, true);
return duration;
} else {
return 0;
}
}
/**
* Set the hovered state on this ship
*
* This will show the information HUD accordingly
*/
setHovered(hovered: boolean, tactical: boolean) {
if (hovered && this.ship.alive) {
this.toggle_hull.start();
this.toggle_shield.start();
this.toggle_power.start();
if (tactical) {
this.toggle_play_order.start();
}
} else {
this.toggle_hull.stop();
this.toggle_shield.stop();
this.toggle_power.stop();
this.toggle_play_order.stop();
}
}
// Set the playing state on this ship
// This will toggle the "playing" indicator
setPlaying(playing: boolean) {
this.frame.frame = (playing ? 3 : 0) + (this.enemy ? 0 : 1);
}
/**
* Activate the dead effect (stasis)
*/
setDead(dead = true) {
if (dead) {
this.displayEffect("stasis", false);
}
this.frame.alpha = dead ? 0.5 : 1.0;
this.battleview.animations.setVisible(this.stasis, dead, 400);
}
/**
* Check if the ship is dead
*/
isDead(): boolean {
return this.stasis.visible;
}
/**
* Get a ship value
*/
getValue(value: keyof ShipValues): number {
switch (value) {
case "hull":
return this.hull.getValue();
case "shield":
return this.shield.getValue();
default:
return 0;
}
}
/**
* Move the sprite to a location
*
* Return the duration of animation
*/
moveTo(x: number, y: number, facing_angle: number, animate = true): number {
if (animate) {
let duration = Animations.moveInSpace(this, x, y, facing_angle, this.sprite);
return duration;
} else {
this.x = x;
this.y = y;
this.sprite.rotation = facing_angle;
return 0;
}
}
/**
* Briefly show an effect on this ship
*/
displayEffect(message: string, beneficial: boolean) {
let text = new Phaser.Text(this.game, 0, 20 * this.effects_messages.children.length, message, { font: "14pt Arial", fill: beneficial ? "#afe9c6" : "#e9afaf" });
this.effects_messages.addChild(text);
let arena = this.battleview.arena.getBoundaries();
this.effects_messages.position.set(
(this.ship.arena_x < 100) ? -35 : ((this.ship.arena_x > arena.width - 100) ? (35 - this.effects_messages.width) : (-this.effects_messages.width * 0.5)),
(this.ship.arena_y < arena.height * 0.9) ? 50 : (-50 - this.effects_messages.height)
);
this.game.tweens.removeFrom(this.effects_messages);
this.effects_messages.alpha = 1;
let tween = this.game.tweens.create(this.effects_messages).to({ alpha: 0 }, 500).delay(1000).start();
tween.onComplete.addOnce(() => this.effects_messages.removeAll(true));
}
/**
* Display interesting changes in ship values
*/
displayValueChanged(event: ValueChangeEvent) {
let diff = event.diff;
let name = event.value.name;
this.displayEffect(`${name} ${diff < 0 ? "-" : "+"}${Math.abs(diff)}`, diff >= 0);
}
/**
* Update the list of effects active on the ship
*/
updateActiveEffects() {
this.active_effects_display.removeAll();
let effects = this.active_effects.sticky.map(sticky => sticky.base).concat(this.active_effects.area);
let count = effects.length;
if (count) {
let positions = UITools.evenlySpace(70, 10, count);
effects.forEach((effect, index) => {
let dot = new Phaser.Image(this.game, positions[index] - 40, -47, "battle-arena-small-indicators", effect.isBeneficial() ? 1 : 0);
this.active_effects_display.add(dot);
});
}
}
/**
* Update the power indicator
*/
updatePowerIndicator(power: number) {
this.power.removeAll();
if (power) {
let positions = UITools.evenlySpace(70, 10, power);
range(power).forEach(index => {
let dot = new Phaser.Image(this.game, positions[index] - 40, 40, "battle-arena-small-indicators", 2);
this.power.add(dot);
});
}
}
/**
* Update the activated effects radius
*/
updateEffectsRadius(): void {
this.effects_radius.clear();
this.ship.getAvailableActions().forEach(action => {
if (action instanceof ToggleAction && action.activated) {
this.effects_radius.lineStyle(2, 0xe9f2f9, 0.3);
this.effects_radius.beginFill(0xe9f2f9, 0.0);
this.effects_radius.drawCircle(0, 0, action.radius * 2);
this.effects_radius.endFill();
}
});
}
}
}