| 
									
										
										
										
											2020-10-07 06:36:02 +00:00
										 |  |  | /* eslint-disable no-unused-vars */ | 
					
						
							|  |  |  | import { Signal } from "../core/signal"; | 
					
						
							|  |  |  | import { RandomNumberGenerator } from "../core/rng"; | 
					
						
							|  |  |  | import { createLogger } from "../core/logging"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Type hints
 | 
					
						
							|  |  |  | /* typehints:start */ | 
					
						
							|  |  |  | import { GameTime } from "./time/game_time"; | 
					
						
							|  |  |  | import { EntityManager } from "./entity_manager"; | 
					
						
							|  |  |  | import { GameSystemManager } from "./game_system_manager"; | 
					
						
							| 
									
										
										
										
											2021-02-22 14:06:33 +00:00
										 |  |  | import { AchievementManager } from "./achievement_manager"; | 
					
						
							| 
									
										
										
										
											2020-10-07 06:36:02 +00:00
										 |  |  | import { GameHUD } from "./hud/hud"; | 
					
						
							|  |  |  | import { MapView } from "./map_view"; | 
					
						
							|  |  |  | import { Camera } from "./camera"; | 
					
						
							|  |  |  | import { InGameState } from "../states/ingame"; | 
					
						
							|  |  |  | import { AutomaticSave } from "./automatic_save"; | 
					
						
							|  |  |  | import { Application } from "../application"; | 
					
						
							|  |  |  | import { SoundProxy } from "./sound_proxy"; | 
					
						
							|  |  |  | import { Savegame } from "../savegame/savegame"; | 
					
						
							|  |  |  | import { GameLogic } from "./logic"; | 
					
						
							|  |  |  | import { ShapeDefinitionManager } from "./shape_definition_manager"; | 
					
						
							|  |  |  | import { HubGoals } from "./hub_goals"; | 
					
						
							|  |  |  | import { BufferMaintainer } from "../core/buffer_maintainer"; | 
					
						
							|  |  |  | import { ProductionAnalytics } from "./production_analytics"; | 
					
						
							|  |  |  | import { Entity } from "./entity"; | 
					
						
							|  |  |  | import { ShapeDefinition } from "./shape_definition"; | 
					
						
							|  |  |  | import { BaseItem } from "./base_item"; | 
					
						
							|  |  |  | import { DynamicTickrate } from "./dynamic_tickrate"; | 
					
						
							|  |  |  | import { KeyActionMapper } from "./key_action_mapper"; | 
					
						
							|  |  |  | import { Vector } from "../core/vector"; | 
					
						
							|  |  |  | import { GameMode } from "./game_mode"; | 
					
						
							|  |  |  | /* typehints:end */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const logger = createLogger("game/root"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {Array<Layer>} */ | 
					
						
							|  |  |  | export const layers = ["regular", "wires"]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * The game root is basically the whole game state at a given point, | 
					
						
							|  |  |  |  * combining all important classes. We don't have globals, but this | 
					
						
							|  |  |  |  * class is passed to almost all game classes. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export class GameRoot { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Constructs a new game root | 
					
						
							|  |  |  |      * @param {Application} app | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     constructor(app) { | 
					
						
							|  |  |  |         this.app = app; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {Savegame} */ | 
					
						
							|  |  |  |         this.savegame = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {InGameState} */ | 
					
						
							|  |  |  |         this.gameState = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {KeyActionMapper} */ | 
					
						
							|  |  |  |         this.keyMapper = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Store game dimensions
 | 
					
						
							|  |  |  |         this.gameWidth = 500; | 
					
						
							|  |  |  |         this.gameHeight = 500; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Stores whether the current session is a fresh game (true), or was continued (false)
 | 
					
						
							|  |  |  |         /** @type {boolean} */ | 
					
						
							|  |  |  |         this.gameIsFresh = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Stores whether the logic is already initialized
 | 
					
						
							|  |  |  |         /** @type {boolean} */ | 
					
						
							|  |  |  |         this.logicInitialized = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Stores whether the game is already initialized, that is, all systems etc have been created
 | 
					
						
							|  |  |  |         /** @type {boolean} */ | 
					
						
							|  |  |  |         this.gameInitialized = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** | 
					
						
							|  |  |  |          * Whether a bulk operation is running | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         this.bulkOperationRunning = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //////// Other properties ///////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {Camera} */ | 
					
						
							|  |  |  |         this.camera = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {HTMLCanvasElement} */ | 
					
						
							|  |  |  |         this.canvas = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {CanvasRenderingContext2D} */ | 
					
						
							|  |  |  |         this.context = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {MapView} */ | 
					
						
							|  |  |  |         this.map = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {GameLogic} */ | 
					
						
							|  |  |  |         this.logic = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {EntityManager} */ | 
					
						
							|  |  |  |         this.entityMgr = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {GameHUD} */ | 
					
						
							|  |  |  |         this.hud = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {GameSystemManager} */ | 
					
						
							|  |  |  |         this.systemMgr = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {GameTime} */ | 
					
						
							|  |  |  |         this.time = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {HubGoals} */ | 
					
						
							|  |  |  |         this.hubGoals = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {BufferMaintainer} */ | 
					
						
							|  |  |  |         this.buffers = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {AutomaticSave} */ | 
					
						
							|  |  |  |         this.automaticSave = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {SoundProxy} */ | 
					
						
							|  |  |  |         this.soundProxy = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-22 14:06:33 +00:00
										 |  |  |         /** @type {AchievementManager} */ | 
					
						
							|  |  |  |         this.achievementMgr = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 06:36:02 +00:00
										 |  |  |         /** @type {ShapeDefinitionManager} */ | 
					
						
							|  |  |  |         this.shapeDefinitionMgr = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {ProductionAnalytics} */ | 
					
						
							|  |  |  |         this.productionAnalytics = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {DynamicTickrate} */ | 
					
						
							|  |  |  |         this.dynamicTickrate = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {Layer} */ | 
					
						
							|  |  |  |         this.currentLayer = "regular"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {GameMode} */ | 
					
						
							|  |  |  |         this.gameMode = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.signals = { | 
					
						
							|  |  |  |             // Entities
 | 
					
						
							|  |  |  |             entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |             entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |             entityChanged: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |             entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |             entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |             entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |             entityDestroyed: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Global
 | 
					
						
							|  |  |  |             resized: /** @type {TypedSignal<[number, number]>} */ (new Signal()), | 
					
						
							|  |  |  |             readyToRender: /** @type {TypedSignal<[]>} */ (new Signal()), | 
					
						
							|  |  |  |             aboutToDestruct: /** @type {TypedSignal<[]>} */ new Signal(), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Game Hooks
 | 
					
						
							|  |  |  |             gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved
 | 
					
						
							|  |  |  |             gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             gameFrameStarted: /** @type {TypedSignal<[]>} */ (new Signal()), // New frame
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()), | 
					
						
							|  |  |  |             upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Called right after game is initialized
 | 
					
						
							|  |  |  |             postLoadHook: /** @type {TypedSignal<[]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), | 
					
						
							|  |  |  |             itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             editModeChanged: /** @type {TypedSignal<[Layer]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Called to check if an entity can be placed, second parameter is an additional offset.
 | 
					
						
							|  |  |  |             // Use to introduce additional placement checks
 | 
					
						
							|  |  |  |             prePlacementCheck: /** @type {TypedSignal<[Entity, Vector]>} */ (new Signal()), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Called before actually placing an entity, use to perform additional logic
 | 
					
						
							|  |  |  |             // for freeing space before actually placing.
 | 
					
						
							|  |  |  |             freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()), | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // RNG's
 | 
					
						
							|  |  |  |         /** @type {Object.<string, Object.<string, RandomNumberGenerator>>} */ | 
					
						
							|  |  |  |         this.rngs = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Work queue
 | 
					
						
							|  |  |  |         this.queue = { | 
					
						
							|  |  |  |             requireRedraw: false, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Destructs the game root | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     destruct() { | 
					
						
							|  |  |  |         logger.log("destructing root"); | 
					
						
							|  |  |  |         this.signals.aboutToDestruct.dispatch(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.reset(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Resets the whole root and removes all properties | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     reset() { | 
					
						
							|  |  |  |         if (this.signals) { | 
					
						
							|  |  |  |             // Destruct all signals
 | 
					
						
							|  |  |  |             for (let i = 0; i < this.signals.length; ++i) { | 
					
						
							|  |  |  |                 this.signals[i].removeAll(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this.hud) { | 
					
						
							|  |  |  |             this.hud.cleanup(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (this.camera) { | 
					
						
							|  |  |  |             this.camera.cleanup(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Finally free all properties
 | 
					
						
							|  |  |  |         for (let prop in this) { | 
					
						
							|  |  |  |             if (this.hasOwnProperty(prop)) { | 
					
						
							|  |  |  |                 delete this[prop]; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |