import * as PIXI from 'pixi.js'; import { Engine } from '../Bastion'; import { TerrainType, TowerDefinition } from '../Definitions'; import GameAssets from '../Assets'; import { Tower, TowerEvents } from './Tower'; import { Cell, GridEvents } from './Grid'; export enum TowerBehaviours { BasicTowerBehaviour = 'BasicTowerBehaviour', } export default class TowerManager { public isPlacingTower: boolean = false; public canPlaceTowers: boolean = true; public selectedTower: TowerDefinition | null = null; private previewSprite: PIXI.Sprite = new PIXI.Sprite({ parent: Engine.GameMaster.currentScene.stage, zIndex: 10, width: 64, height: 64, alpha: 0.8, }); private towers: Tower[] = []; constructor() { Engine.TowerManager = this; Engine.GameScene.events.on(GridEvents.CellMouseOver, (cell: Cell) => { if (this.isPlacingTower) { let cantPlace = cell.checkIfCantPlace(); if (cantPlace) { cell.rangePreview.clear(); cell.showRangePreview(true, this.selectedTower.stats.range); this.previewSprite.tint = 0xff0000; } else { cell.showRangePreview(false, this.selectedTower.stats.range); this.previewSprite.tint = 0xffffff; } this.previewSprite.x = cell.column * Engine.GridCellSize; this.previewSprite.y = cell.row * Engine.GridCellSize; this.previewSprite.texture = this.selectedTower.texture; } }); } public ResetChooseTower() { this.selectedTower = null; this.isPlacingTower = false; Engine.Grid.toggleGrid('hide'); } public ToggleChoosingTowerLocation(towerName: string) { if (!this.canPlaceTowers) return; Engine.Grid.toggleGrid(); if (!this.isPlacingTower) { GameAssets.Towers.forEach((item) => { if (item.name == towerName) { this.selectedTower = item; console.log(this.selectedTower); } }); } else { this.previewSprite.texture = null; this.selectedTower = null; } this.isPlacingTower = !this.isPlacingTower; } public PlayerClickOnGrid(row, column) { if (!this.canPlaceTowers) return; if (this.isPlacingTower) { if (!this.selectedTower) { Engine.NotificationManager.Notify( 'TowerManager.selectedTower is null when trying to place tower.', 'danger' ); throw console.warn('TowerManager.selectedTower is null when trying to place tower.'); } this.PlaceTower(this.selectedTower, row, column, this.selectedTower.behaviour); } } public GetTowerByRowAndCol(row, col) { // i just want to say that this is really stupid, why do i need to define a type for a local // variable i will temporarily use? TS is weird let returnTower: Tower | null = null; this.towers.forEach((tower) => { if (tower.row == row && tower.column == col) returnTower = tower; }); // console.log(returnTower, row, col); return returnTower; } public PlaceTower(definition: TowerDefinition, row, column, behaviour: string, ignoreCost?) { const sprite = this.selectedTower.texture; if (!Engine.GameScene.MissionStats.hasEnoughGold(definition.stats.cost) && !ignoreCost) return Engine.NotificationManager.Notify('Not enough gold.', 'warn'); if ( !this.GetTowerByRowAndCol(row, column) && Engine.Grid.getCellByRowAndCol(row, column).type != TerrainType.Path && Engine.Grid.getCellByRowAndCol(row, column).type != TerrainType.Restricted ) { Engine.GameScene.MissionStats.spendGold(definition.stats.cost); let tower = new Tower(row, column, sprite, definition, behaviour); this.towers.push(tower); this.ToggleChoosingTowerLocation('RESET'); this.selectedTower = null; this.previewSprite.x = -100; Engine.GameScene.events.emit(TowerEvents.TowerPlacedEvent, definition.name, row, column); } else { Engine.NotificationManager.Notify( 'Can not place tower on path or other tower, choose another spot.', 'warn' ); console.warn('Can not place tower on occupied spot or path. Try again.'); } } public update(elapsedMS) { this.towers.forEach((twr) => { twr.update(elapsedMS); }); } }