import { InvalidArgument } from "@sammo/util"; import { City } from "./City.js"; import type { IGeneralEntity } from "./GeneralEntity.js"; import type { IResourceController } from "./ResourceController.js"; import { DiplomaticPermission, type CityID, type GeneralID, type GeneralName, type NationID, OfficerLevel, type TroopID } from "./defs.js"; import { must } from "@sammo/util"; import { Nation } from "./Nation.js"; import { Troop } from "./Troop.js"; export class General { private _raw: IGeneralEntity; private _city: WeakRef; private _troop: WeakRef | undefined; private _nation: WeakRef; public get raw(): Readonly { return this._raw; } constructor( raw: IGeneralEntity, private resourceController: IResourceController ){ this._raw = raw; this._city = new WeakRef(must(resourceController.getCity(raw.cityID))); this._nation = new WeakRef(must(resourceController.getNation(raw.nationID))); if(raw.troopID){ this._troop = new WeakRef(must(resourceController.getTroop(raw.troopID, raw.nationID))); } } public get id(): GeneralID { return this._raw.id; } public get name(): GeneralName { return this._raw.name; } public update(callback: (oldRaw: IGeneralEntity) => void, force = false) { const oldCityID = this._raw.cityID; const oldTroopID = this._raw.troopID; const oldNationID = this._raw.nationID; callback(this._raw); if(!force){ if(oldCityID !== this._raw.cityID){ throw new Error("City change by update() is not allowed"); } if(oldTroopID !== this._raw.troopID){ throw new Error("Troop change by update() is not allowed"); } if(oldNationID !== this._raw.nationID){ throw new Error("Nation change by update() is not allowed"); } } this.resourceController.setDirtyGeneral(this._raw); } public changeCity(city: CityID | City){ const cityObj: City = (()=>{ if(city instanceof City){ return city; } const cityObj = this.resourceController.getCity(city); if(!cityObj){ throw new InvalidArgument(`City not found: ${city}`); } return cityObj; })(); this._city = new WeakRef(cityObj); //TODO: ResourceController에게 알려야 하는가? this.update((raw) => { raw.cityID = cityObj.id; }, true); } public quitTroop(){ if(!this._troop){ return; } const troop = must(this._troop.deref()); if(troop.leader.id === this._raw.id){ troop.destructTroop(false); } else{ troop.members.delete(this._raw.id); } this._troop = undefined; this.update((raw) => { raw.troopID = undefined; }, true); } public changeTroop(troop: TroopID | Troop){ this.quitTroop(); const troopObj: Troop = (()=>{ if(troop instanceof Troop){ return troop; } const troopObj = this.resourceController.getTroop(troop, this._raw.nationID); if(!troopObj){ throw new InvalidArgument(`Troop not found: ${troop}`); } return troopObj; })(); troopObj.members.set(this._raw.id, new WeakRef(this)); this._troop = new WeakRef(troopObj); this.update((raw) => { raw.troopID = troopObj.id; }, true); } public changeNation(nation: NationID | Nation){ const nationObj: Nation = (()=>{ if(nation instanceof Nation){ return nation; } const nationObj = this.resourceController.getNation(nation); if(!nationObj){ throw new InvalidArgument(`Nation not found: ${nation}`); } return nationObj; })(); this._nation = new WeakRef(nationObj); this.quitTroop(); this.update((raw) => { raw.nationID = nationObj.id; raw.diplomaticPermission = DiplomaticPermission.none; if(nationObj.id == 0){ raw.officerLevel = OfficerLevel.none; } else{ raw.officerLevel = OfficerLevel.normal; } raw.nationBelong = 0; }, true); } }