178 lines
6.9 KiB
TypeScript

import { Engine } from '../Bastion';
import * as PIXI from 'pixi.js';
import GameObject from '../GameObject';
import { CreepResistancesDefinition, GemType, TowerDefinition } from '../Definitions';
import { Cell } from './Grid';
import { TowerBehaviours } from './TowerManager';
import Projectile, { calculateAngleToPoint } from './Projectile';
import Creep from './Creep';
import Gem from './Gem';
import {
DebuffTowerBehaviour,
BasicTowerBehaviour,
CircleTowerBehaviour,
ElectricTowerBehaviour,
BuffTowerBehaviour,
RailTowerBehaviour,
StrongTowerBehaviour,
TrapperTowerBehaviour,
} from './TowerBehaviours';
export function distance(x1, y1, x2, y2) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
export class Tower extends GameObject {
public row: number;
public column: number;
public setAsSold: boolean = false;
public sold: boolean = false;
public definition: TowerDefinition;
public slottedGems: Array<Gem> = [];
public damageDealt: number = 0;
public projectiles: Projectile[] = [];
public behaviour: string;
public sprite: PIXI.Sprite;
public millisecondsUntilNextShot: number;
public graphics: PIXI.Graphics = new PIXI.Graphics();
public computedDamageToDeal: number = 0;
public computedCooldown: number = 0;
public computedRange: number = 0;
public computedTimeToLive: number = 0;
public computedPierce: number = 0;
public totalGemResistanceModifications: CreepResistancesDefinition = {
fire: 0,
frostfire: 0,
divine: 0,
ice: 0,
physical: 0,
};
public parent: Cell;
constructor(row, column, texture, definition, behaviour) {
super();
this.row = row;
this.column = column;
this.behaviour = behaviour;
this.definition = definition;
this.millisecondsUntilNextShot = 0;
this.parent = Engine.Grid.getCellByRowAndCol(row, column);
this.sprite = new PIXI.Sprite({
texture: texture,
height: Engine.GridCellSize,
width: Engine.GridCellSize,
zIndex: 130,
});
this.container.addChild(this.sprite);
this.computedDamageToDeal = this.definition.stats.damage;
this.computedRange = this.definition.stats.range;
this.parent.container.addChild(this.container);
this.container.interactiveChildren = true;
this.parent.clickDetector.on('pointerenter', this.onParentCellEnter);
this.parent.clickDetector.on('pointerleave', this.onParentCellLeave);
Engine.GameMaster.currentScene.stage.addChild(this.graphics);
}
private onParentCellEnter = (e) => {
if (
!Engine.TowerManager.isPlacingTower &&
Engine.Grid.gridInteractionEnabled &&
!Engine.GameScene.towerPanel.isShown
)
this.parent.showRangePreview(false, this.computedRange);
};
private onParentCellLeave = (e) => {
this.graphics.clear();
};
public SlotGem(gem: Gem, index: number) {
this.slottedGems[index] = gem;
Engine.GameScene.towerPanel.Hide();
Engine.GameScene.towerPanel.Show(this);
}
public UnslotGem(index) {
const gem = this.slottedGems.splice(index, 1)[0];
if (gem == null || !gem) return console.warn('UnslotGem: Gem is null.');
Engine.GameScene.MissionStats.giveGem(gem, true);
for (let i = index; i < this.slottedGems.length - 1; i++) {
if (this.slottedGems[i] == null) {
this.slottedGems[i] = this.slottedGems[i + 1];
this.slottedGems[i + 1] = null;
}
}
Engine.GameScene.sidebar.gemTab.selectingGemTowerObject = this;
this.slottedGems = this.slottedGems.filter((gem) => gem != null);
Engine.NotificationManager.Notify(
`Lv. ${gem.level} ${gem.definition.name} unslotted and placed back in your inventory.`,
'info'
);
}
public GetCreepsInRange() {
let creeps = Engine.Grid.creeps;
return creeps.filter((creep) => {
const x = creep.x;
const y = creep.y;
const towerX = this.column * Engine.GridCellSize + Engine.GridCellSize / 2;
const towerY = this.row * Engine.GridCellSize + Engine.GridCellSize / 2;
const radius = this.computedRange * Engine.GridCellSize;
const d = distance(towerX, towerY, x, y);
return d < radius + (Engine.GridCellSize * 2) / 3;
});
}
public Shoot(angle) {
let x = this.column * Engine.GridCellSize + Engine.GridCellSize / 2;
let y = this.row * Engine.GridCellSize + Engine.GridCellSize / 2;
let combinedTint = new PIXI.Color('white');
if (this.slottedGems.length > 0) {
let color = new PIXI.Color(this.slottedGems[0].definition.color);
for (let i = 1; i < this.slottedGems.length; i++) {
const element = this.slottedGems[i];
color.multiply(element.definition.color);
}
combinedTint = color;
}
let proj = new Projectile(
x,
y,
this.definition.projectileTextures,
angle,
this.computedDamageToDeal,
combinedTint,
this.computedTimeToLive,
this.computedPierce,
this.totalGemResistanceModifications
);
const time = new Date().toISOString();
console.log(`${time} ${this.definition.name} shot at ${angle} degrees`);
this.projectiles.push(proj);
return proj;
}
public Sell() {
this.setAsSold = true;
// Selling logic is handled in TowerManager.update()
}
public update(elapsedMS: any): void {
if (this.sold) return;
if (this.setAsSold) {
this.sold = true;
}
if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) BasicTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.CircleTowerBehaviour) CircleTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.ElectricTowerBehaviour) ElectricTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.BuffTowerBehaviour) BuffTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.StrongTowerBehaviour) StrongTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.RailTowerBehaviour) RailTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.TrapperTowerBehaviour) TrapperTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.DebuffTowerBehaviour) DebuffTowerBehaviour(this, elapsedMS);
}
public destroy(): void {
super.destroy();
this.parent.clickDetector.off('pointerenter', this.onParentCellEnter);
this.parent.clickDetector.off('pointerleave', this.onParentCellLeave);
this.graphics.destroy();
}
}