From 38f041d0251ed1cba2364fe0e8b88314ae6f0e8f Mon Sep 17 00:00:00 2001 From: Neloreck Date: Tue, 20 Jun 2023 04:17:09 +0300 Subject: [PATCH] Fix crash on medic dialog. More comments/doc blocks. Dialog manager update - use enum/separate folder/corrected types and codestyle. --- src/engine/configs/gameplay/dialogs_zaton.xml | 1 + .../interaction/{ => dialog}/DialogManager.ts | 152 +++++++---------- .../core/managers/interaction/dialog/index.ts | 2 + .../core/managers/interaction/dialog/types.ts | 43 +++++ .../core/managers/world/ReleaseBodyManager.ts | 8 +- .../objects/binders/creature/StalkerBinder.ts | 2 +- src/engine/core/utils/check/is.ts | 7 + .../core/utils/object/object_general.ts | 8 +- .../declarations/dialogs/dialog_manager.ts | 154 +++++++++++------- .../scripts/declarations/dialogs/dialogs.ts | 48 +++--- .../scripts/register/managers_registrator.ts | 2 +- 11 files changed, 243 insertions(+), 184 deletions(-) rename src/engine/core/managers/interaction/{ => dialog}/DialogManager.ts (78%) create mode 100644 src/engine/core/managers/interaction/dialog/index.ts create mode 100644 src/engine/core/managers/interaction/dialog/types.ts diff --git a/src/engine/configs/gameplay/dialogs_zaton.xml b/src/engine/configs/gameplay/dialogs_zaton.xml index 3e44329d9..113469ad1 100644 --- a/src/engine/configs/gameplay/dialogs_zaton.xml +++ b/src/engine/configs/gameplay/dialogs_zaton.xml @@ -1,4 +1,5 @@ + zat_b51_order_ready diff --git a/src/engine/core/managers/interaction/DialogManager.ts b/src/engine/core/managers/interaction/dialog/DialogManager.ts similarity index 78% rename from src/engine/core/managers/interaction/DialogManager.ts rename to src/engine/core/managers/interaction/dialog/DialogManager.ts index b7fc0d5fa..9d80e75a3 100644 --- a/src/engine/core/managers/interaction/DialogManager.ts +++ b/src/engine/core/managers/interaction/dialog/DialogManager.ts @@ -4,11 +4,16 @@ import { closeLoadMarker, closeSaveMarker, DIALOG_MANAGER_LTX, openSaveMarker, r import { openLoadMarker } from "@/engine/core/database/save_markers"; import { AbstractCoreManager } from "@/engine/core/managers/base/AbstractCoreManager"; import { EGameEvent, EventsManager } from "@/engine/core/managers/events"; -import { abort } from "@/engine/core/utils/assertion"; +import { + EGenericDialogCategory, + IPhrasesDescriptor, + TPHRTable, + TPRTTable, +} from "@/engine/core/managers/interaction/dialog/types"; +import { assert } from "@/engine/core/utils/assertion"; import { isObjectWounded } from "@/engine/core/utils/check/check"; import { hasAlifeInfo } from "@/engine/core/utils/info_portion"; import { parseInfoPortions, parseStringsList } from "@/engine/core/utils/ini/parse"; -import { IConfigCondition } from "@/engine/core/utils/ini/types"; import { LuaLogger } from "@/engine/core/utils/logging"; import { getCharacterCommunity } from "@/engine/core/utils/object/object_general"; import { FALSE, TRUE } from "@/engine/lib/constants/words"; @@ -30,35 +35,6 @@ import { const logger: LuaLogger = new LuaLogger($filename); -/** - * todo; - */ -export interface IPhrasesDescriptor { - id: TStringId; - name: TName; - npc_community: LuaArray | "not_set"; - level: LuaArray | "not_set"; - actor_community: LuaArray | "not_set" | "all"; - wounded: string; - once: string; - info: LuaArray; - smart: Optional; - told?: boolean; -} - -/** - * todo; - */ -export type TPHRTable = LuaTable; - -/** - * todo; - */ -export type TPRTTable = LuaTable< - number, - LuaTable & { told?: boolean; ignore_once?: Optional; id?: -1 } ->; - /** * todo; */ @@ -74,21 +50,21 @@ export class DialogManager extends AbstractCoreManager { // -- temporary table of phrases which have been disabled during a conversation | npc id -> phrase id -> boolean public questDisabledPhrases: LuaTable> = new LuaTable(); - public phrasesMap: LuaTable = $fromObject({ + public phrasesMap: LuaTable = $fromObject({ hello: new LuaTable(), job: new LuaTable(), anomalies: new LuaTable(), place: new LuaTable(), information: new LuaTable(), - }); + } as Record); - public priorityTable: LuaTable = $fromObject({ + public priorityTable: LuaTable = $fromObject({ hello: new LuaTable(), job: new LuaTable(), anomalies: new LuaTable(), place: new LuaTable(), information: new LuaTable(), - }); + } as Record); /** * todo; @@ -100,32 +76,28 @@ export class DialogManager extends AbstractCoreManager { eventsManager.registerCallback(EGameEvent.NPC_INTERACTION, this.onInteractWithObject, this); - let category: string = ""; - for (const it of $range(0, DIALOG_MANAGER_LTX.line_count("list") - 1)) { - const [temp1, id, temp2] = DIALOG_MANAGER_LTX.r_line("list", it, "", ""); - - if (DIALOG_MANAGER_LTX.line_exist(id, "category")) { - category = DIALOG_MANAGER_LTX.r_string(id, "category"); - - if (category === "hello") { - category = "hello"; - } else if (category === "anomalies") { - category = "anomalies"; - } else if (category === "place") { - category = "place"; - } else if (category === "job") { - category = "job"; - } else if (category === "information") { - category = "information"; - } else { - category = "default"; - } - } else { - abort("Dialog manager error. ! categoried section [%s].", id); + const [, id] = DIALOG_MANAGER_LTX.r_line("list", it, "", ""); + + assert(DIALOG_MANAGER_LTX.line_exist(id, "category"), "Dialog manager error. ! categoried section [%s].", id); + + let category: EGenericDialogCategory = DIALOG_MANAGER_LTX.r_string(id, "category") as EGenericDialogCategory; + + switch (category) { + case EGenericDialogCategory.HELLO: + case EGenericDialogCategory.ANOMALIES: + case EGenericDialogCategory.PLACE: + case EGenericDialogCategory.JOB: + case EGenericDialogCategory.INFORMATION: + // nothing + break; + + default: + category = EGenericDialogCategory.DEFAULT; + break; } - if (category !== "default") { + if (category !== EGenericDialogCategory.DEFAULT) { const phrases: IPhrasesDescriptor = { id: tostring(this.getNextPhraseId()), name: id, @@ -141,19 +113,15 @@ export class DialogManager extends AbstractCoreManager { wounded: DIALOG_MANAGER_LTX.line_exist(id, "wounded") ? DIALOG_MANAGER_LTX.r_string(id, "wounded") : FALSE, once: DIALOG_MANAGER_LTX.line_exist(id, "once") ? DIALOG_MANAGER_LTX.r_string(id, "once") : "always", info: new LuaTable(), - smart: null as Optional, + smart: null as Optional, }; if (DIALOG_MANAGER_LTX.line_exist(id, "info") && DIALOG_MANAGER_LTX.r_string(id, "info") !== "") { parseInfoPortions(phrases.info, DIALOG_MANAGER_LTX.r_string(id, "info")); } - if (category === "anomalies" || category === "place") { - if (DIALOG_MANAGER_LTX.line_exist(id, "smart")) { - phrases.smart = DIALOG_MANAGER_LTX.r_string(id, "smart"); - } else { - phrases.smart = ""; - } + if (category === EGenericDialogCategory.ANOMALIES || category === EGenericDialogCategory.PLACE) { + phrases.smart = DIALOG_MANAGER_LTX.line_exist(id, "smart") ? DIALOG_MANAGER_LTX.r_string(id, "smart") : ""; } this.phrasesMap.get(category).set(phrases.id, phrases); @@ -168,7 +136,11 @@ export class DialogManager extends AbstractCoreManager { eventsManager.unregisterCallback(EGameEvent.NPC_INTERACTION, this.onInteractWithObject); - const actorTable: LuaArray = $fromArray(["job", "anomalies", "information"]); + const actorTable: LuaArray = $fromArray([ + EGenericDialogCategory.JOB, + EGenericDialogCategory.ANOMALIES, + EGenericDialogCategory.INFORMATION, + ]); const startPhraseTable: LuaArray = $fromArray([ "dm_universal_npc_start_0", "dm_universal_npc_start_1", @@ -191,13 +163,13 @@ export class DialogManager extends AbstractCoreManager { npcPhraseScript.AddPrecondition(precondTable.get(j)); - for (const i of $range(1, actorTable.length())) { + for (const it of $range(1, actorTable.length())) { const index: TIndex = this.getNextPhraseId(); - const str: string = actorTable.get(i); + const str: string = actorTable.get(it); let phrase: Phrase = dialog.AddPhrase("dm_" + str + "_general", tostring(index), tostring(j), -10000); let script: PhraseScript = phrase.GetPhraseScript(); - if (str === "anomalies") { + if (str === EGenericDialogCategory.ANOMALIES) { script.AddPrecondition("dialogs.npc_stalker"); } @@ -227,8 +199,8 @@ export class DialogManager extends AbstractCoreManager { scriptDoNotKnow.AddPrecondition("dialog_manager.precondition_" + str + "_dialogs_do_not_know"); } - for (const [k, v] of this.phrasesMap.get(str)) { - phrase = dialog.AddPhrase(v.name, tostring(v.id), tostring(index), -10000); + for (const [, phraseDescriptor] of this.phrasesMap.get(str as EGenericDialogCategory)) { + phrase = dialog.AddPhrase(phraseDescriptor.name, tostring(phraseDescriptor.id), tostring(index), -10000); // todo: Unreal condition? if (phrase !== null) { @@ -246,8 +218,8 @@ export class DialogManager extends AbstractCoreManager { /** * todo; */ - public initializeStartDialogs(dialog: PhraseDialog, data: string): void { - logger.info("Initialize start dialogs"); + public initializeStartDialogs(dialog: PhraseDialog, data: EGenericDialogCategory): void { + logger.info("Initialize start dialogs:", data); dialog.AddPhrase("", tostring(0), "", -10000); @@ -258,27 +230,27 @@ export class DialogManager extends AbstractCoreManager { let ph: boolean = false; - for (const [k, v] of this.phrasesMap.get(data)) { + for (const [, phraseDescriptor] of this.phrasesMap.get(data)) { ph = true; - phrase = dialog.AddPhrase(v.name, tostring(v.id), tostring(1), -10000); + phrase = dialog.AddPhrase(phraseDescriptor.name, tostring(phraseDescriptor.id), tostring(1), -10000); script = phrase.GetPhraseScript(); script.AddPrecondition(string.format("dialog_manager.precondition_%s_dialogs", data)); script.AddAction(string.format("dialog_manager.action_%s_dialogs", data)); - if (v.wounded === TRUE) { + if (phraseDescriptor.wounded === TRUE) { script.AddPrecondition("dialogs.is_wounded"); const medkitId: TNumberId = this.getNextPhraseId(); const sorryId: TNumberId = this.getNextPhraseId(); - phrase = dialog.AddPhrase("dm_wounded_medkit", tostring(medkitId), tostring(v.id), -10000); + phrase = dialog.AddPhrase("dm_wounded_medkit", tostring(medkitId), tostring(phraseDescriptor.id), -10000); script = phrase.GetPhraseScript(); script.AddPrecondition("dialogs.actor_have_medkit"); script.AddAction("dialogs.transfer_medkit"); script.AddAction("dialogs.break_dialog"); - phrase = dialog.AddPhrase("dm_wounded_sorry", tostring(sorryId), tostring(v.id), -10000); + phrase = dialog.AddPhrase("dm_wounded_sorry", tostring(sorryId), tostring(phraseDescriptor.id), -10000); script = phrase.GetPhraseScript(); script.AddAction("dialogs.break_dialog"); } else { @@ -371,18 +343,10 @@ export class DialogManager extends AbstractCoreManager { if (PTIDSubtable.wounded === TRUE) { // --if (!(ActionWoundManager.is_heavy_wounded_by_id(npc.id())) { - if (!isObjectWounded(object)) { - priority = -1; - } else { - priority = priority + 1; - } + priority = isObjectWounded(object) ? priority + 1 : -1; } else { // --if(ActionWoundManager.is_heavy_wounded_by_id(npc.id())) { - if (isObjectWounded(object)) { - priority = -1; - } else { - priority = priority + 1; - } + priority = isObjectWounded(object) ? -1 : priority + 1; } if (fComm === false || fLevel === false) { @@ -423,7 +387,7 @@ export class DialogManager extends AbstractCoreManager { /** * todo; */ - public isTold(object: ClientObject, phrase: TStringId): boolean { + public isTold(object: ClientObject, phrase: EGenericDialogCategory): boolean { return this.priorityTable.get(phrase).get(object.id())?.told === true; } @@ -442,11 +406,11 @@ export class DialogManager extends AbstractCoreManager { const objectId: TNumberId = object.id(); - packet.w_bool(this.priorityTable.get("hello").get(objectId) !== null); - packet.w_bool(this.priorityTable.get("job").get(objectId) !== null); - packet.w_bool(this.priorityTable.get("anomalies").get(objectId) !== null); - packet.w_bool(this.priorityTable.get("place").get(objectId) !== null); - packet.w_bool(this.priorityTable.get("information").get(objectId) !== null); + packet.w_bool(this.priorityTable.get(EGenericDialogCategory.HELLO).get(objectId) !== null); + packet.w_bool(this.priorityTable.get(EGenericDialogCategory.JOB).get(objectId) !== null); + packet.w_bool(this.priorityTable.get(EGenericDialogCategory.ANOMALIES).get(objectId) !== null); + packet.w_bool(this.priorityTable.get(EGenericDialogCategory.PLACE).get(objectId) !== null); + packet.w_bool(this.priorityTable.get(EGenericDialogCategory.INFORMATION).get(objectId) !== null); closeSaveMarker(packet, DialogManager.name); } diff --git a/src/engine/core/managers/interaction/dialog/index.ts b/src/engine/core/managers/interaction/dialog/index.ts new file mode 100644 index 000000000..fe2c6ff52 --- /dev/null +++ b/src/engine/core/managers/interaction/dialog/index.ts @@ -0,0 +1,2 @@ +export * from "@/engine/core/managers/interaction/dialog/DialogManager"; +export * from "@/engine/core/managers/interaction/dialog/types"; diff --git a/src/engine/core/managers/interaction/dialog/types.ts b/src/engine/core/managers/interaction/dialog/types.ts new file mode 100644 index 000000000..bb224bb0a --- /dev/null +++ b/src/engine/core/managers/interaction/dialog/types.ts @@ -0,0 +1,43 @@ +import { IConfigCondition } from "@/engine/core/utils/ini/types"; +import { LuaArray, Optional, TName, TStringId } from "@/engine/lib/types"; + +/** + * todo; + */ +export interface IPhrasesDescriptor { + id: TStringId; + name: TName; + npc_community: LuaArray | "not_set"; + level: LuaArray | "not_set"; + actor_community: LuaArray | "not_set" | "all"; + wounded: string; + once: string; + info: LuaArray; + smart: Optional; + told?: boolean; +} + +/** + * todo; + */ +export type TPHRTable = LuaTable; + +/** + * todo; + */ +export type TPRTTable = LuaTable< + number, + LuaTable & { told?: boolean; ignore_once?: Optional; id?: -1 } +>; + +/** + * todo; + */ +export enum EGenericDialogCategory { + HELLO = "hello", + ANOMALIES = "anomalies", + PLACE = "place", + JOB = "job", + INFORMATION = "information", + DEFAULT = "default", +} diff --git a/src/engine/core/managers/world/ReleaseBodyManager.ts b/src/engine/core/managers/world/ReleaseBodyManager.ts index 0f6b431cc..834e09298 100644 --- a/src/engine/core/managers/world/ReleaseBodyManager.ts +++ b/src/engine/core/managers/world/ReleaseBodyManager.ts @@ -26,6 +26,7 @@ import { Optional, ServerObject, TCount, + TDistance, TIndex, TName, TNumberId, @@ -192,8 +193,9 @@ export class ReleaseBodyManager extends AbstractCoreManager { for (const [index, releaseDescriptor] of releaseObjectsRegistry) { const object: Optional = alife().object(releaseDescriptor.id); - if (object !== null) { - const distanceToCorpse: number = actorPosition.distance_to_sqr(object.position); + // May also contain objects that are being registered after game load. + if (object) { + const distanceToCorpse: TDistance = actorPosition.distance_to_sqr(object.position); if ( distanceToCorpse > maximalDistance && @@ -203,8 +205,6 @@ export class ReleaseBodyManager extends AbstractCoreManager { maximalDistance = distanceToCorpse; releaseObjectIndex = index; } - } else { - logger.warn("Captured not present in alife object for release:", releaseDescriptor.id); } } diff --git a/src/engine/core/objects/binders/creature/StalkerBinder.ts b/src/engine/core/objects/binders/creature/StalkerBinder.ts index e80184f3d..026ef2329 100644 --- a/src/engine/core/objects/binders/creature/StalkerBinder.ts +++ b/src/engine/core/objects/binders/creature/StalkerBinder.ts @@ -30,7 +30,7 @@ import { loadObjectLogic, saveObjectLogic } from "@/engine/core/database/logic"; import { openLoadMarker } from "@/engine/core/database/save_markers"; import { registerStalker, unregisterStalker } from "@/engine/core/database/stalker"; import { EGameEvent, EventsManager } from "@/engine/core/managers/events"; -import { DialogManager } from "@/engine/core/managers/interaction/DialogManager"; +import { DialogManager } from "@/engine/core/managers/interaction/dialog/DialogManager"; import { SimulationBoardManager } from "@/engine/core/managers/interaction/SimulationBoardManager"; import { TradeManager } from "@/engine/core/managers/interaction/TradeManager"; import { MapDisplayManager } from "@/engine/core/managers/interface/MapDisplayManager"; diff --git a/src/engine/core/utils/check/is.ts b/src/engine/core/utils/check/is.ts index 152b6ae89..56bd07da7 100644 --- a/src/engine/core/utils/check/is.ts +++ b/src/engine/core/utils/check/is.ts @@ -29,6 +29,13 @@ export function isGameStarted(): boolean { return alife() !== null; } +/** + * Check whether actor is absolutely healthy - without radiation/bleeding/damaged health. + */ +export function isActorAbsolutelyHealthy(actor: ClientObject = registry.actor): boolean { + return actor.health < 1 || actor.radiation > 0 || actor.bleeding > 0; +} + /** * todo; */ diff --git a/src/engine/core/utils/object/object_general.ts b/src/engine/core/utils/object/object_general.ts index 705cb92da..4752b31bf 100644 --- a/src/engine/core/utils/object/object_general.ts +++ b/src/engine/core/utils/object/object_general.ts @@ -560,9 +560,13 @@ export function isObjectScriptCaptured(object: ClientObject): boolean { } /** - * todo; + * Check whether object is in provided smart terrain (name). + * + * @param object - client object to check + * @param smartTerrainName - desired smart terrain to check + * @returns whether object is assigned to smart terrain with desired name */ -export function isObjectInSmart(object: ClientObject, smartTerrainName: TName): boolean { +export function isObjectInSmartTerrain(object: ClientObject, smartTerrainName: TName): boolean { const smartTerrain: Optional = getObjectSmartTerrain(object); return smartTerrain ? smartTerrain.name() === smartTerrainName : false; diff --git a/src/engine/scripts/declarations/dialogs/dialog_manager.ts b/src/engine/scripts/declarations/dialogs/dialog_manager.ts index aafec7728..92c911bd1 100644 --- a/src/engine/scripts/declarations/dialogs/dialog_manager.ts +++ b/src/engine/scripts/declarations/dialogs/dialog_manager.ts @@ -2,10 +2,11 @@ import { game } from "xray16"; import { DialogManager, + EGenericDialogCategory, IPhrasesDescriptor, TPHRTable, TPRTTable, -} from "@/engine/core/managers/interaction/DialogManager"; +} from "@/engine/core/managers/interaction/dialog"; import { SmartTerrain } from "@/engine/core/objects"; import { extern } from "@/engine/core/utils/binding"; import { LuaLogger } from "@/engine/core/utils/logging"; @@ -152,19 +153,19 @@ export function getHighestPriorityPhrase( const objectId: TNumberId = object.id(); if (PRTsubtable.get(objectId) !== null) { - let id: string | 0 = 0; - let pr: number = -1; - - for (const [phrId, priority] of PRTsubtable.get(objectId)) { - if (phrId !== "ignore_once" && phrId !== "told") { - if (priority > pr) { - pr = priority; - id = phrId; + let id: TStringId | 0 = 0; + let priority: TRate = -1; + + for (const [phraseId, phrasePriority] of PRTsubtable.get(objectId)) { + if (phraseId !== "ignore_once" && phraseId !== "told") { + if (phrasePriority > priority) { + priority = phrasePriority; + id = phraseId; } } } - return $multi(pr, id); + return $multi(priority, id); } else { resetPhrasePriority(PTsubtable, PRTsubtable, object, null); @@ -175,12 +176,12 @@ export function getHighestPriorityPhrase( /** * todo; */ -export function preconditionNoMore(object: ClientObject, str: string): boolean { +export function preconditionNoMore(object: ClientObject, category: EGenericDialogCategory): boolean { const dialogManager: DialogManager = DialogManager.getInstance(); const [priority, id] = getHighestPriorityPhrase( - dialogManager.phrasesMap.get(str), - dialogManager.priorityTable.get(str), + dialogManager.phrasesMap.get(category), + dialogManager.priorityTable.get(category), object ); @@ -197,7 +198,7 @@ extern("dialog_manager.init_new_dialog", (dialog: PhraseDialog): void => { /** * todo; */ -extern("dialog_manager.initializeStartDialogs", (dialog: PhraseDialog, data: string): void => { +extern("dialog_manager.initializeStartDialogs", (dialog: PhraseDialog, data: EGenericDialogCategory): void => { DialogManager.getInstance().initializeStartDialogs(dialog, data); }); @@ -205,7 +206,7 @@ extern("dialog_manager.initializeStartDialogs", (dialog: PhraseDialog, data: str * todo; */ extern("dialog_manager.init_hello_dialogs", (dialog: PhraseDialog): void => { - DialogManager.getInstance().initializeStartDialogs(dialog, "hello"); + DialogManager.getInstance().initializeStartDialogs(dialog, EGenericDialogCategory.HELLO); }); /** @@ -218,8 +219,8 @@ extern( dialogManager.fillPriorityTable( object, - dialogManager.phrasesMap.get("hello"), - dialogManager.priorityTable.get("hello") + dialogManager.phrasesMap.get(EGenericDialogCategory.HELLO), + dialogManager.priorityTable.get(EGenericDialogCategory.HELLO) ); } ); @@ -229,10 +230,14 @@ extern( */ extern( "dialog_manager.fill_priority_job_table", - (actor: ClientObject, npc: ClientObject, dialogName: string, phraseId: string): void => { + (actor: ClientObject, npc: ClientObject, dialogName: TName, phraseId: TStringId): void => { const dialogManager: DialogManager = DialogManager.getInstance(); - dialogManager.fillPriorityTable(npc, dialogManager.phrasesMap.get("job"), dialogManager.priorityTable.get("job")); + dialogManager.fillPriorityTable( + npc, + dialogManager.phrasesMap.get(EGenericDialogCategory.JOB), + dialogManager.priorityTable.get(EGenericDialogCategory.JOB) + ); } ); @@ -241,13 +246,13 @@ extern( */ extern( "dialog_manager.fill_priority_anomalies_table", - (actor: ClientObject, object: ClientObject, dialogName: string, phraseId: string): void => { + (actor: ClientObject, object: ClientObject, dialogName: TName, phraseId: TStringId): void => { const dialogManager: DialogManager = DialogManager.getInstance(); dialogManager.fillPriorityTable( object, - dialogManager.phrasesMap.get("anomalies"), - dialogManager.priorityTable.get("anomalies") + dialogManager.phrasesMap.get(EGenericDialogCategory.ANOMALIES), + dialogManager.priorityTable.get(EGenericDialogCategory.ANOMALIES) ); } ); @@ -257,13 +262,13 @@ extern( */ extern( "dialog_manager.fill_priority_information_table", - (actor: ClientObject, object: ClientObject, dialogName: string, phraseId: string): void => { + (actor: ClientObject, object: ClientObject, dialogName: TName, phraseId: TStringId): void => { const dialogManager: DialogManager = DialogManager.getInstance(); dialogManager.fillPriorityTable( object, - dialogManager.phrasesMap.get("information"), - dialogManager.priorityTable.get("information") + dialogManager.phrasesMap.get(EGenericDialogCategory.INFORMATION), + dialogManager.priorityTable.get(EGenericDialogCategory.INFORMATION) ); } ); @@ -273,10 +278,15 @@ extern( */ extern( "dialog_manager.precondition_hello_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { const dialogManager: DialogManager = DialogManager.getInstance(); - return precondition(object, dialogManager.phrasesMap.get("hello"), dialogManager.priorityTable.get("hello"), id); + return precondition( + object, + dialogManager.phrasesMap.get(EGenericDialogCategory.HELLO), + dialogManager.priorityTable.get(EGenericDialogCategory.HELLO), + id + ); } ); @@ -285,10 +295,15 @@ extern( */ extern( "dialog_manager.action_hello_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, id: string): void => { + (object: ClientObject, actor: ClientObject, dialogName: TName, id: TStringId): void => { const dialogManager: DialogManager = DialogManager.getInstance(); - action(dialogManager.phrasesMap.get("hello"), dialogManager.priorityTable.get("hello"), id, object); + action( + dialogManager.phrasesMap.get(EGenericDialogCategory.HELLO), + dialogManager.priorityTable.get(EGenericDialogCategory.HELLO), + id, + object + ); } ); @@ -297,10 +312,10 @@ extern( */ extern( "dialog_manager.precondition_job_dialogs_no_more", - (npc: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string) => { + (npc: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId) => { const dialogManager: DialogManager = DialogManager.getInstance(); - return dialogManager.isTold(npc, "job"); + return dialogManager.isTold(npc, EGenericDialogCategory.JOB); } ); @@ -309,8 +324,8 @@ extern( */ extern( "dialog_manager.precondition_job_dialogs_do_not_know", - (npc: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string) => { - return preconditionNoMore(npc, "job"); + (npc: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId) => { + return preconditionNoMore(npc, EGenericDialogCategory.JOB); } ); @@ -319,10 +334,15 @@ extern( */ extern( "dialog_manager.precondition_job_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { const dialogManager: DialogManager = DialogManager.getInstance(); - return precondition(object, dialogManager.phrasesMap.get("job"), dialogManager.priorityTable.get("job"), id); + return precondition( + object, + dialogManager.phrasesMap.get(EGenericDialogCategory.JOB), + dialogManager.priorityTable.get(EGenericDialogCategory.JOB), + id + ); } ); @@ -334,8 +354,13 @@ extern( (npc: ClientObject, actor: ClientObject, dialogName: string, id: string): void => { const dialogManager: DialogManager = DialogManager.getInstance(); - action(dialogManager.phrasesMap.get("job"), dialogManager.priorityTable.get("job"), id, npc); - told(dialogManager.priorityTable.get("job"), npc); + action( + dialogManager.phrasesMap.get(EGenericDialogCategory.JOB), + dialogManager.priorityTable.get(EGenericDialogCategory.JOB), + id, + npc + ); + told(dialogManager.priorityTable.get(EGenericDialogCategory.JOB), npc); } ); @@ -344,8 +369,8 @@ extern( */ extern( "dialog_manager.precondition_anomalies_dialogs_no_more", - (npc: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { - return DialogManager.getInstance().isTold(npc, "anomalies"); + (npc: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { + return DialogManager.getInstance().isTold(npc, EGenericDialogCategory.ANOMALIES); } ); @@ -354,10 +379,10 @@ extern( */ extern( "dialog_manager.precondition_anomalies_dialogs_do_not_know", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { const dialogManager: DialogManager = DialogManager.getInstance(); - return preconditionNoMore(object, "anomalies"); + return preconditionNoMore(object, EGenericDialogCategory.ANOMALIES); } ); @@ -366,23 +391,23 @@ extern( */ extern( "dialog_manager.precondition_anomalies_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { const dialogManager: DialogManager = DialogManager.getInstance(); const smartTerrain: Optional = getObjectSmartTerrain(object); if ( smartTerrain !== null && - tostring(smartTerrain.name()) === dialogManager.phrasesMap.get("anomalies").get(id).smart + tostring(smartTerrain.name()) === dialogManager.phrasesMap.get(EGenericDialogCategory.ANOMALIES).get(id).smart ) { - dialogManager.priorityTable.get("anomalies").get(object.id()).id = -1; + dialogManager.priorityTable.get(EGenericDialogCategory.ANOMALIES).get(object.id()).id = -1; return false; } return precondition( object, - dialogManager.phrasesMap.get("anomalies"), - dialogManager.priorityTable.get("anomalies"), + dialogManager.phrasesMap.get(EGenericDialogCategory.ANOMALIES), + dialogManager.priorityTable.get(EGenericDialogCategory.ANOMALIES), id ); } @@ -393,11 +418,16 @@ extern( */ extern( "dialog_manager.action_anomalies_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, id: string): void => { + (object: ClientObject, actor: ClientObject, dialogName: TName, id: TStringId): void => { const dialogManager: DialogManager = DialogManager.getInstance(); - action(dialogManager.phrasesMap.get("anomalies"), dialogManager.priorityTable.get("anomalies"), id, object); - told(dialogManager.priorityTable.get("anomalies"), object); + action( + dialogManager.phrasesMap.get(EGenericDialogCategory.ANOMALIES), + dialogManager.priorityTable.get(EGenericDialogCategory.ANOMALIES), + id, + object + ); + told(dialogManager.priorityTable.get(EGenericDialogCategory.ANOMALIES), object); } ); @@ -407,8 +437,8 @@ extern( */ extern( "dialog_manager.precondition_information_dialogs_no_more", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { - return DialogManager.getInstance().isTold(object, "information"); + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { + return DialogManager.getInstance().isTold(object, EGenericDialogCategory.INFORMATION); } ); @@ -417,8 +447,8 @@ extern( */ extern( "dialog_manager.precondition_information_dialogs_do_not_know", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { - return preconditionNoMore(object, "information"); + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { + return preconditionNoMore(object, EGenericDialogCategory.INFORMATION); } ); @@ -427,13 +457,13 @@ extern( */ extern( "dialog_manager.precondition_information_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, parentId: string, id: string): boolean => { + (object: ClientObject, actor: ClientObject, dialogName: TName, parentId: TStringId, id: TStringId): boolean => { const dialogManager: DialogManager = DialogManager.getInstance(); return precondition( object, - dialogManager.phrasesMap.get("information"), - dialogManager.priorityTable.get("information"), + dialogManager.phrasesMap.get(EGenericDialogCategory.INFORMATION), + dialogManager.priorityTable.get(EGenericDialogCategory.INFORMATION), id ); } @@ -444,11 +474,16 @@ extern( */ extern( "dialog_manager.action_information_dialogs", - (object: ClientObject, actor: ClientObject, dialogName: string, id: string): void => { + (object: ClientObject, actor: ClientObject, dialogName: TName, id: TStringId): void => { const dialogManager: DialogManager = DialogManager.getInstance(); - action(dialogManager.phrasesMap.get("information"), dialogManager.priorityTable.get("information"), id, object); - told(dialogManager.priorityTable.get("information"), object); + action( + dialogManager.phrasesMap.get(EGenericDialogCategory.INFORMATION), + dialogManager.priorityTable.get(EGenericDialogCategory.INFORMATION), + id, + object + ); + told(dialogManager.priorityTable.get(EGenericDialogCategory.INFORMATION), object); } ); @@ -533,6 +568,7 @@ let rnd: number = 0; /** * todo; + * todo: Just use 'pick random' from list. */ extern("dialog_manager.create_bye_phrase", (): string => { logger.info("Create bye phrase"); diff --git a/src/engine/scripts/declarations/dialogs/dialogs.ts b/src/engine/scripts/declarations/dialogs/dialogs.ts index b940f19ce..b69a055f0 100644 --- a/src/engine/scripts/declarations/dialogs/dialogs.ts +++ b/src/engine/scripts/declarations/dialogs/dialogs.ts @@ -10,11 +10,13 @@ import { ISchemeMeetState } from "@/engine/core/schemes/meet"; import { SchemeMeet } from "@/engine/core/schemes/meet/SchemeMeet"; import { ISchemeWoundedState } from "@/engine/core/schemes/wounded"; import { SchemeWounded } from "@/engine/core/schemes/wounded/SchemeWounded"; -import { extern, getExtern } from "@/engine/core/utils/binding"; +import { extern } from "@/engine/core/utils/binding"; +import { isActorAbsolutelyHealthy } from "@/engine/core/utils/check"; import { isObjectWounded, isStalkerAlive } from "@/engine/core/utils/check/check"; import { createAutoSave } from "@/engine/core/utils/game_save"; import { giveInfo, hasAlifeInfo } from "@/engine/core/utils/info_portion"; -import { getCharacterCommunity, isObjectInSmart } from "@/engine/core/utils/object/object_general"; +import { LuaLogger } from "@/engine/core/utils/logging"; +import { getCharacterCommunity, isObjectInSmartTerrain } from "@/engine/core/utils/object/object_general"; import { actorHasMedKit, getActorAvailableMedKit, @@ -29,6 +31,8 @@ import { pistols, TPistol } from "@/engine/lib/constants/items/weapons"; import { levels } from "@/engine/lib/constants/levels"; import { ClientObject, EClientObjectRelation, EScheme, Optional, TNumberId } from "@/engine/lib/types"; +const logger: LuaLogger = new LuaLogger($filename); + extern("dialogs", {}); /** @@ -541,98 +545,98 @@ extern("dialogs.monolith_leader_dead_or_dolg", (firstSpeaker: ClientObject, seco * todo; */ extern("dialogs.squad_not_in_smart_b101", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b101"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b101"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b103", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b103"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b103"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b104", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b104"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b104"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b213", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b213"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b213"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b214", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b214"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b214"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b304", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "pri_b304_monsters_smart_terrain"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "pri_b304_monsters_smart_terrain"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b303", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "pri_b303"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "pri_b303"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b40", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b40_smart_terrain"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b40_smart_terrain"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b18", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b18"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_b18"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b6", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b41"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b41"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b205", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b205_smart_terrain"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b205_smart_terrain"); }); /** * todo; */ extern("dialogs.squad_not_in_smart_b47", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b47"); + return !isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_b47"); }); /** * todo; */ extern("dialogs.squad_in_smart_zat_base", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_stalker_base_smart"); + return isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "zat_stalker_base_smart"); }); /** * todo; */ extern("dialogs.squad_in_smart_jup_b25", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return isObjectInSmart(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_a6"); + return isObjectInSmartTerrain(getNpcSpeaker(firstSpeaker, secondSpeaker), "jup_a6"); }); /** @@ -733,7 +737,7 @@ extern( ); /** - * todo; + * Heal actor, stop bleeding and radiation, restore power. */ extern("dialogs.medic_magic_potion", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): void => { const actor: ClientObject = registry.actor; @@ -745,19 +749,17 @@ extern("dialogs.medic_magic_potion", (firstSpeaker: ClientObject, secondSpeaker: }); /** - * todo; + * Check whether actor needs healing, radiation or bleeding help. */ extern("dialogs.actor_needs_bless", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - const actor: ClientObject = registry.actor; - - return actor.health < 1 || actor.radiation > 0 || actor.bleeding > 0; + return isActorAbsolutelyHealthy(); }); /** - * todo; + * Check whether actor is absolutely healthy, without bleeding and radiation contamination. */ extern("dialogs.actor_is_damn_healthy", (firstSpeaker: ClientObject, secondSpeaker: ClientObject): boolean => { - return !getExtern("actor_needs_bless", getExtern("dialogs")); + return !isActorAbsolutelyHealthy(); }); /** diff --git a/src/engine/scripts/register/managers_registrator.ts b/src/engine/scripts/register/managers_registrator.ts index bca8febc3..c8722e0d5 100644 --- a/src/engine/scripts/register/managers_registrator.ts +++ b/src/engine/scripts/register/managers_registrator.ts @@ -3,7 +3,7 @@ import { EventsManager } from "@/engine/core/managers"; import { TAbstractCoreManagerConstructor } from "@/engine/core/managers/base/AbstractCoreManager"; import { SaveManager } from "@/engine/core/managers/base/SaveManager"; import { AchievementsManager } from "@/engine/core/managers/interaction/achievements"; -import { DialogManager } from "@/engine/core/managers/interaction/DialogManager"; +import { DialogManager } from "@/engine/core/managers/interaction/dialog/DialogManager"; import { SimulationBoardManager } from "@/engine/core/managers/interaction/SimulationBoardManager"; import { SleepManager } from "@/engine/core/managers/interaction/SleepManager"; import { TaskManager } from "@/engine/core/managers/interaction/tasks";