import { InvalidArgument } from "@sammo/util"; import { City } from "./City.js"; import type { IGeneralEntity } from "./Entity/GeneralEntity.js"; import type { IResourceController } from "./IResourceController.js"; import { DiplomaticPermission, type CityID, type GeneralID, type GeneralName, type NationID, OfficerLevel, type SquadID, NpcType, StaffLevel, CityOfficerLevel } from "./defs.js"; import { must } from "@sammo/util"; import { Nation } from "./Nation.js"; import { Squad } from "./Squad.js"; import { LazyEntityUpdater } from "./LazyEntityUpdater.js"; import type { IAction, IActionKey } from "./IAction.js"; import { addSeconds } from "date-fns"; export class General extends LazyEntityUpdater { protected readonly _indirectNames: (keyof IGeneralEntity)[] = [ "id", "nationID", "squadID", "nationID", "turnTime" ]; protected readonly _entityType = "General"; protected readonly _raw: IGeneralEntity; protected _city!: WeakRef; protected _squad!: WeakRef | undefined; protected _nation!: WeakRef; protected readonly iActionHandlers = new Map; constructor( raw: IGeneralEntity, protected readonly rsc: IResourceController ){ super(); this._raw = raw; } public bootstrap(){ const rsc = this.rsc; const raw = this._raw; this._city = new WeakRef(must(rsc.city(raw.cityID))); this._nation = new WeakRef(must(rsc.nation(raw.nationID))); if(raw.squadID){ this._squad = new WeakRef(must(rsc.squad(raw.squadID, raw.nationID))); } //TODO: iActionHandlers 초기화 } public get id(): GeneralID { return this._raw.id; } public get name(): GeneralName { return this._raw.name; } public get city(): City { return must(this._city.deref()); } public get squad(): Squad | undefined { return this._squad?.deref(); } public get nation(): Nation { return must(this._nation.deref()); } public get isUser(): boolean { return this._raw.npcType <= NpcType.user_borrowed_npc; } public get staffLevel(): StaffLevel | undefined { if(this._raw.officerLevel < OfficerLevel.staffIntel3){ return undefined; } return this._raw.officerLevel as number as StaffLevel; } public get cityOfficerLevel(): CityOfficerLevel | undefined { if(this._raw.officerLevel >= OfficerLevel.staffIntel3){ return undefined; } if(this._raw.officerLevel < OfficerLevel.cityLeadership){ return undefined; } return this._raw.officerLevel as number as CityOfficerLevel; } public changeCity(city: CityID | City){ const cityObj: City = (()=>{ if(city instanceof City){ return city; } const cityObj = this.rsc.city(city); if(!cityObj){ throw new InvalidArgument(`City not found: ${city}`); } return cityObj; })(); this._city = new WeakRef(cityObj); //TODO: ResourceController에게 알려야 하는가? this.forceUpdate((raw) => { raw.cityID = cityObj.id; }); } public quitSquad(){ if(!this._squad){ return; } const squad = must(this._squad.deref()); if(squad.leader.id === this._raw.id){ squad.destroySquad(false); } else{ squad.members.delete(this._raw.id); } this._squad = undefined; this.forceUpdate((raw) => { raw.squadID = undefined; }); } public changeSquad(squad: SquadID | Squad){ this.quitSquad(); const squadObj: Squad = (()=>{ if(squad instanceof Squad){ return squad; } const squadObj = this.rsc.squad(squad, this._raw.nationID); if(!squadObj){ throw new InvalidArgument(`Squad not found: ${squad}`); } return squadObj; })(); squadObj.members.set(this._raw.id, new WeakRef(this)); this._squad = new WeakRef(squadObj); this.forceUpdate((raw) => { raw.squadID = squadObj.id; }); } public changeNation(nation: NationID | Nation){ const nationObj: Nation = (()=>{ if(nation instanceof Nation){ return nation; } const nationObj = this.rsc.nation(nation); if(!nationObj){ throw new InvalidArgument(`Nation not found: ${nation}`); } return nationObj; })(); this._nation = new WeakRef(nationObj); this.quitSquad(); this.forceUpdate((raw) => { raw.nationID = nationObj.id; raw.diplomaticPermission = DiplomaticPermission.none; if(nationObj.id == 0){ raw.officerLevel = OfficerLevel.none; } else{ raw.officerLevel = OfficerLevel.normal; } raw.nationJoinedYearMonth = this.rsc.gameEnv.raw.yearMonth; }); } public updateTurnTime(){ const secondsPerTurn = this.rsc.gameEnv.raw.secondsPerTurn; this.forceUpdate((raw) => { raw.turnTime = addSeconds(raw.turnTime, secondsPerTurn); }); } public compareTurnTime(other: General): number { if(this._raw.turnTime < other._raw.turnTime){ return -1; } if(this._raw.turnTime > other._raw.turnTime){ return 1; } if(this._raw.id < other._raw.id){ return -1; } if(this._raw.id > other._raw.id){ return 1; } return 0; } }