Skip to content

Commit

Permalink
Fix crash on medic dialog. More comments/doc blocks. Dialog manager u…
Browse files Browse the repository at this point in the history
…pdate - use enum/separate folder/corrected types and codestyle.
  • Loading branch information
Neloreck committed Jun 20, 2023
1 parent 8b96932 commit 38f041d
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 184 deletions.
1 change: 1 addition & 0 deletions src/engine/configs/gameplay/dialogs_zaton.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="windows-1251" ?>

<game_dialogs>
<dialog id="zat_b51_stalker_nimble_get_order">
<has_info>zat_b51_order_ready</has_info>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -30,35 +35,6 @@ import {

const logger: LuaLogger = new LuaLogger($filename);

/**
* todo;
*/
export interface IPhrasesDescriptor {
id: TStringId;
name: TName;
npc_community: LuaArray<any> | "not_set";
level: LuaArray<any> | "not_set";
actor_community: LuaArray<any> | "not_set" | "all";
wounded: string;
once: string;
info: LuaArray<IConfigCondition>;
smart: Optional<string>;
told?: boolean;
}

/**
* todo;
*/
export type TPHRTable = LuaTable<string, IPhrasesDescriptor>;

/**
* todo;
*/
export type TPRTTable = LuaTable<
number,
LuaTable<string, number> & { told?: boolean; ignore_once?: Optional<boolean>; id?: -1 }
>;

/**
* todo;
*/
Expand All @@ -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<TNumberId, LuaTable<string, boolean>> = new LuaTable();

public phrasesMap: LuaTable<TName, TPHRTable> = $fromObject<TName, TPHRTable>({
public phrasesMap: LuaTable<EGenericDialogCategory, TPHRTable> = $fromObject({
hello: new LuaTable(),
job: new LuaTable(),
anomalies: new LuaTable(),
place: new LuaTable(),
information: new LuaTable(),
});
} as Record<EGenericDialogCategory, TPHRTable>);

public priorityTable: LuaTable<TName, TPRTTable> = $fromObject<TName, TPRTTable>({
public priorityTable: LuaTable<EGenericDialogCategory, TPRTTable> = $fromObject({
hello: new LuaTable(),
job: new LuaTable(),
anomalies: new LuaTable(),
place: new LuaTable(),
information: new LuaTable(),
});
} as Record<EGenericDialogCategory, TPRTTable>);

/**
* todo;
Expand All @@ -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,
Expand All @@ -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<string>,
smart: null as Optional<TName>,
};

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);
Expand All @@ -168,7 +136,11 @@ export class DialogManager extends AbstractCoreManager {

eventsManager.unregisterCallback(EGameEvent.NPC_INTERACTION, this.onInteractWithObject);

const actorTable: LuaArray<TName> = $fromArray(["job", "anomalies", "information"]);
const actorTable: LuaArray<EGenericDialogCategory> = $fromArray<EGenericDialogCategory>([
EGenericDialogCategory.JOB,
EGenericDialogCategory.ANOMALIES,
EGenericDialogCategory.INFORMATION,
]);
const startPhraseTable: LuaArray<TName> = $fromArray([
"dm_universal_npc_start_0",
"dm_universal_npc_start_1",
Expand All @@ -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");
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand All @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions src/engine/core/managers/interaction/dialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "@/engine/core/managers/interaction/dialog/DialogManager";
export * from "@/engine/core/managers/interaction/dialog/types";
43 changes: 43 additions & 0 deletions src/engine/core/managers/interaction/dialog/types.ts
Original file line number Diff line number Diff line change
@@ -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<any> | "not_set";
level: LuaArray<any> | "not_set";
actor_community: LuaArray<any> | "not_set" | "all";
wounded: string;
once: string;
info: LuaArray<IConfigCondition>;
smart: Optional<string>;
told?: boolean;
}

/**
* todo;
*/
export type TPHRTable = LuaTable<string, IPhrasesDescriptor>;

/**
* todo;
*/
export type TPRTTable = LuaTable<
number,
LuaTable<string, number> & { told?: boolean; ignore_once?: Optional<boolean>; id?: -1 }
>;

/**
* todo;
*/
export enum EGenericDialogCategory {
HELLO = "hello",
ANOMALIES = "anomalies",
PLACE = "place",
JOB = "job",
INFORMATION = "information",
DEFAULT = "default",
}
8 changes: 4 additions & 4 deletions src/engine/core/managers/world/ReleaseBodyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
Optional,
ServerObject,
TCount,
TDistance,
TIndex,
TName,
TNumberId,
Expand Down Expand Up @@ -192,8 +193,9 @@ export class ReleaseBodyManager extends AbstractCoreManager {
for (const [index, releaseDescriptor] of releaseObjectsRegistry) {
const object: Optional<ServerObject> = 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 &&
Expand All @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/engine/core/objects/binders/creature/StalkerBinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
7 changes: 7 additions & 0 deletions src/engine/core/utils/check/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
*/
Expand Down
Loading

0 comments on commit 38f041d

Please sign in to comment.