diff --git a/src/g_level.cpp b/src/g_level.cpp index 49047a487..5e8780f58 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -79,6 +79,7 @@ #include "events.h" #include "i_music.h" #include "a_dynlight.h" +#include "p_conversation.h" #include "gi.h" @@ -759,6 +760,9 @@ void G_DoCompleted (void) if (automapactive) AM_Stop (); + + // Close the conversation menu if open. + P_FreeStrifeConversations (); wminfo.finished_ep = level.cluster - 1; wminfo.LName0 = TexMan.CheckForTexture(level.info->PName, ETextureType::MiscPatch); diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 22e952f5e..a88a789be 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -53,6 +53,10 @@ class DACSThinker; class DFraggleThinker; class DSpotState; +struct FStrifeDialogueNode; + +typedef TMap FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS) +typedef TMap FDialogueMap; // maps actor class names to dialogue array index struct FLevelData { @@ -105,9 +109,15 @@ struct FLevelData FBehaviorContainer Behaviors; FTagManager tagManager; AActor *TIDHash[128]; + + TArray StrifeDialogues; + FDialogueIDMap DialogueRoots; + FDialogueMap ClassRoots; + }; + struct FLevelLocals : public FLevelData { void Tick(); @@ -123,6 +133,10 @@ struct FLevelLocals : public FLevelData void TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1); bool IsTIDUsed(int tid); int FindUniqueTID(int start_tid, int limit); + int GetConversation(int conv_id); + int GetConversation(FName classname); + void SetConversation(int convid, PClassActor *Class, int dlgindex); + int FindNode (const FStrifeDialogueNode *node); FSectorTagIterator GetSectorTagIterator(int tag) { diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index e5aedbacd..0dd419091 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3046,7 +3046,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) LoadMapinfoACSLump(); - P_LoadStrifeConversations(map, lumpname); + P_LoadStrifeConversations(Level, map, lumpname); FMissingTextureTracker missingtex; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 5bb9dec50..e65321d8c 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -96,28 +96,21 @@ struct TeaserSpeech static FRandom pr_randomspeech("RandomSpeech"); -TArray StrifeDialogues; - -typedef TMap FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS) -typedef TMap FDialogueMap; // maps actor class names to dialogue array index - FClassMap StrifeTypes; -static FDialogueIDMap DialogueRoots; -static FDialogueMap ClassRoots; static int ConversationMenuY; -static int ConversationPauseTic; +// These two should be moved to player_t... +static FStrifeDialogueNode *PrevNode; static int StaticLastReply; -static bool LoadScriptFile(int lumpnum, FileReader &lump, int numnodes, bool include, int type); -static FStrifeDialogueNode *ReadRetailNode (FileReader &lump, uint32_t &prevSpeakerType); -static FStrifeDialogueNode *ReadTeaserNode (FileReader &lump, uint32_t &prevSpeakerType); +static bool LoadScriptFile(FLevelLocals *Level, int lumpnum, FileReader &lump, int numnodes, bool include, int type); +static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType); +static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType); static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses); static bool DrawConversationMenu (); static void PickConversationReply (int replyindex); static void TerminalResponse (const char *str); -static FStrifeDialogueNode *PrevNode; //============================================================================ // @@ -137,7 +130,7 @@ void ClearStrifeTypes() StrifeTypes.Clear(); } -void SetConversation(int convid, PClassActor *Class, int dlgindex) +void FLevelLocals::SetConversation(int convid, PClassActor *Class, int dlgindex) { if (convid != -1) { @@ -156,14 +149,14 @@ PClassActor *GetStrifeType (int typenum) else return *ptype; } -int GetConversation(int conv_id) +int FLevelLocals::GetConversation(int conv_id) { int *pindex = DialogueRoots.CheckKey(conv_id); if (pindex == NULL) return -1; else return *pindex; } -int GetConversation(FName classname) +int FLevelLocals::GetConversation(FName classname) { int *pindex = ClassRoots.CheckKey(classname); if (pindex == NULL) return -1; @@ -178,12 +171,11 @@ int GetConversation(FName classname) // //============================================================================ -void P_LoadStrifeConversations (MapData *map, const char *mapname) +void P_LoadStrifeConversations (FLevelLocals *Level, MapData *map, const char *mapname) { - P_FreeStrifeConversations (); if (map->Size(ML_CONVERSATION) > 0) { - LoadScriptFile (map->lumpnum, map->Reader(ML_CONVERSATION), map->Size(ML_CONVERSATION), false, 0); + LoadScriptFile (Level, map->lumpnum, map->Reader(ML_CONVERSATION), map->Size(ML_CONVERSATION), false, 0); } else { @@ -192,8 +184,8 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) char scriptname_b[9] = { 'S','C','R','I','P','T',mapname[3],mapname[4],0 }; char scriptname_t[9] = { 'D','I','A','L','O','G',mapname[3],mapname[4],0 }; - if ( LoadScriptFile(scriptname_t, false, 2) - || LoadScriptFile(scriptname_b, false, 1)) + if ( LoadScriptFile(Level, scriptname_t, false, 2) + || LoadScriptFile(Level, scriptname_b, false, 1)) { return; } @@ -201,13 +193,13 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) if (gameinfo.Dialogue.IsNotEmpty()) { - if (LoadScriptFile(gameinfo.Dialogue, false, 0)) + if (LoadScriptFile(Level, gameinfo.Dialogue, false, 0)) { return; } } - LoadScriptFile("SCRIPT00", false, 1); + LoadScriptFile(Level, "SCRIPT00", false, 1); } } @@ -219,7 +211,7 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) // //============================================================================ -bool LoadScriptFile (const char *name, bool include, int type) +bool LoadScriptFile (FLevelLocals *Level, const char *name, bool include, int type) { int lumpnum = Wads.CheckNumForName (name); const bool found = lumpnum >= 0 @@ -236,11 +228,11 @@ bool LoadScriptFile (const char *name, bool include, int type) } FileReader lump = Wads.ReopenLumpReader (lumpnum); - bool res = LoadScriptFile(lumpnum, lump, Wads.LumpLength(lumpnum), include, type); + bool res = LoadScriptFile(Level, lumpnum, lump, Wads.LumpLength(lumpnum), include, type); return res; } -static bool LoadScriptFile(int lumpnum, FileReader &lump, int numnodes, bool include, int type) +static bool LoadScriptFile(FLevelLocals *Level, int lumpnum, FileReader &lump, int numnodes, bool include, int type) { int i; uint32_t prevSpeakerType; @@ -261,13 +253,13 @@ static bool LoadScriptFile(int lumpnum, FileReader &lump, int numnodes, bool inc if (!isbinary) { - P_ParseUSDF(lumpnum, lump, numnodes); + P_ParseUSDF(Level, lumpnum, lump, numnodes); } else { if (!include) { - LoadScriptFile("SCRIPT00", true, 1); + LoadScriptFile(Level, "SCRIPT00", true, 1); } if (!(gameinfo.flags & GI_SHAREWARE)) { @@ -297,13 +289,13 @@ static bool LoadScriptFile(int lumpnum, FileReader &lump, int numnodes, bool inc { if (!(gameinfo.flags & GI_SHAREWARE)) { - node = ReadRetailNode (lump, prevSpeakerType); + node = ReadRetailNode (Level, lump, prevSpeakerType); } else { - node = ReadTeaserNode (lump, prevSpeakerType); + node = ReadTeaserNode (Level, lump, prevSpeakerType); } - node->ThisNodeNum = StrifeDialogues.Push(node); + node->ThisNodeNum = Level->StrifeDialogues.Push(node); } } return true; @@ -317,7 +309,7 @@ static bool LoadScriptFile(int lumpnum, FileReader &lump, int numnodes, bool inc // //============================================================================ -static FStrifeDialogueNode *ReadRetailNode (FileReader &lump, uint32_t &prevSpeakerType) +static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType) { FStrifeDialogueNode *node; Speech speech; @@ -343,9 +335,9 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader &lump, uint32_t &prevSpea { if (type != NULL) { - ClassRoots[type->TypeName] = StrifeDialogues.Size(); + Level->ClassRoots[type->TypeName] = Level->StrifeDialogues.Size(); } - DialogueRoots[speech.SpeakerType] = StrifeDialogues.Size(); + Level->DialogueRoots[speech.SpeakerType] = Level->StrifeDialogues.Size(); prevSpeakerType = speech.SpeakerType; } @@ -393,7 +385,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader &lump, uint32_t &prevSpea // //============================================================================ -static FStrifeDialogueNode *ReadTeaserNode (FileReader &lump, uint32_t &prevSpeakerType) +static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType) { FStrifeDialogueNode *node; TeaserSpeech speech; @@ -418,9 +410,9 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader &lump, uint32_t &prevSpea { if (type != NULL) { - ClassRoots[type->TypeName] = StrifeDialogues.Size(); + Level->ClassRoots[type->TypeName] = Level->StrifeDialogues.Size(); } - DialogueRoots[speech.SpeakerType] = StrifeDialogues.Size(); + Level->DialogueRoots[speech.SpeakerType] = Level->StrifeDialogues.Size(); prevSpeakerType = speech.SpeakerType; } @@ -581,7 +573,7 @@ FStrifeDialogueNode::~FStrifeDialogueNode () // //============================================================================ -static int FindNode (const FStrifeDialogueNode *node) +int FLevelLocals::FindNode (const FStrifeDialogueNode *node) { int rootnode = 0; @@ -725,16 +717,6 @@ DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply) void P_FreeStrifeConversations () { - FStrifeDialogueNode *node; - - while (StrifeDialogues.Pop (node)) - { - delete node; - } - - DialogueRoots.Clear(); - ClassRoots.Clear(); - PrevNode = NULL; if (CurrentMenu != NULL && CurrentMenu->IsKindOf("ConversationMenu")) { @@ -756,7 +738,8 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang int i; // Make sure this is actually a player. - if (pc->player == NULL) return; + if (pc == nullptr || pc->player == nullptr || npc == nullptr) return; + auto Level = &level; // [CW] If an NPC is talking to a PC already, then don't let // anyone else talk to the NPC. @@ -818,7 +801,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang if (jump && CurNode->ItemCheckNode > 0) { int root = pc->player->ConversationNPC->ConversationRoot; - CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1]; + CurNode = Level->StrifeDialogues[root + CurNode->ItemCheckNode - 1]; } else { @@ -904,14 +887,14 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply AActor *npc; bool takestuff; int i; - - if (player->ConversationNPC == NULL || (unsigned)nodenum >= StrifeDialogues.Size()) + auto Level = &level; + if (player->ConversationNPC == nullptr || (unsigned)nodenum >= Level->StrifeDialogues.Size()) { return; } // Find the reply. - node = StrifeDialogues[nodenum]; + node = Level->StrifeDialogues[nodenum]; for (i = 0, reply = node->Children; reply != NULL && i != replynum; ++i, reply = reply->Next) { } npc = player->ConversationNPC; @@ -1041,9 +1024,9 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply const bool isNegative = reply->NextNode < 0; const unsigned next = (unsigned)(rootnode + (isNegative ? -1 : 1) * reply->NextNode - 1); - if (next < StrifeDialogues.Size()) + if (next < Level->StrifeDialogues.Size()) { - npc->Conversation = StrifeDialogues[next]; + npc->Conversation = Level->StrifeDialogues[next]; if (isNegative) { diff --git a/src/p_conversation.h b/src/p_conversation.h index 2a516e06e..ace3e4788 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -57,19 +57,14 @@ struct FStrifeDialogueReply bool NeedsGold = false; }; -extern TArray StrifeDialogues; - struct MapData; void SetStrifeType(int convid, PClassActor *Class); -void SetConversation(int convid, PClassActor *Class, int dlgindex); PClassActor *GetStrifeType (int typenum); -int GetConversation(int conv_id); -int GetConversation(FName classname); -bool LoadScriptFile (const char *name, bool include, int type = 0); +bool LoadScriptFile (FLevelLocals *Level, const char *name, bool include, int type = 0); -void P_LoadStrifeConversations (MapData *map, const char *mapname); +void P_LoadStrifeConversations (FLevelLocals *Level, MapData *map, const char *mapname); void P_FreeStrifeConversations (); void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle); @@ -78,7 +73,7 @@ void P_ResumeConversation (); void P_ConversationCommand (int netcode, int player, uint8_t **stream); class FileReader; -bool P_ParseUSDF(int lumpnum, FileReader &lump, int lumplen); +bool P_ParseUSDF(FLevelLocals *Level, int lumpnum, FileReader &lump, int lumplen); #endif diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index eb58f6125..b369ffceb 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3377,9 +3377,9 @@ FUNC(LS_Thing_SetConversation) if (arg1 != 0) { - dlg_index = GetConversation(arg1); + dlg_index = Level->GetConversation(arg1); if (dlg_index == -1) return false; - node = StrifeDialogues[dlg_index]; + node = Level->StrifeDialogues[dlg_index]; } if (arg0 != 0) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 10d17b30c..e0f58fe73 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4374,10 +4374,10 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a actor->SpawnOrder = level.spawnindex++; // Set default dialogue - actor->ConversationRoot = GetConversation(actor->GetClass()->TypeName); + actor->ConversationRoot = level.GetConversation(actor->GetClass()->TypeName); if (actor->ConversationRoot != -1) { - actor->Conversation = StrifeDialogues[actor->ConversationRoot]; + actor->Conversation = level.StrifeDialogues[actor->ConversationRoot]; } else { @@ -5462,11 +5462,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) if (mthing->Conversation > 0) { // Make sure that this does not partially overwrite the default dialogue settings. - int root = GetConversation(mthing->Conversation); + int root = level.GetConversation(mthing->Conversation); if (root != -1) { mobj->ConversationRoot = root; - mobj->Conversation = StrifeDialogues[mobj->ConversationRoot]; + mobj->Conversation = level.StrifeDialogues[mobj->ConversationRoot]; } } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 0412eae9d..eebefbfdc 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -263,6 +263,16 @@ void FLevelLocals::ClearLevelData() total_monsters = total_items = total_secrets = killed_monsters = found_items = found_secrets = wminfo.maxfrags = 0; + + FStrifeDialogueNode *node; + + while (StrifeDialogues.Pop (node)) + { + delete node; + } + + DialogueRoots.Clear(); + ClassRoots.Clear(); // delete allocated data in the level arrays. if (sectors.Size() > 0) @@ -342,7 +352,6 @@ void P_FreeLevelData () SN_StopAllSequences (); DThinker::DestroyAllThinkers (); - P_FreeStrifeConversations (); level.ClearLevelData(); } diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 9520c869c..cf579e790 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -40,12 +40,15 @@ #include "actor.h" #include "a_pickups.h" #include "w_wad.h" +#include "g_levellocals.h" #define Zd 1 #define St 2 class USDFParser : public UDMFParserBase { + FLevelLocals *Level; + //=========================================================================== // // Checks an actor type (different representation depending on namespace) @@ -300,7 +303,7 @@ class USDFParser : public UDMFParserBase FStrifeDialogueNode *node = new FStrifeDialogueNode; FStrifeDialogueReply **replyptr = &node->Children; - node->ThisNodeNum = StrifeDialogues.Push(node); + node->ThisNodeNum = Level->StrifeDialogues.Push(node); node->ItemCheckNode = -1; FString SpeakerName; @@ -403,7 +406,7 @@ class USDFParser : public UDMFParserBase PClassActor *type = nullptr; int dlgid = -1; FName clsid = NAME_None; - unsigned int startpos = StrifeDialogues.Size(); + unsigned int startpos = Level->StrifeDialogues.Size(); while (!sc.CheckToken('}')) { @@ -455,11 +458,11 @@ class USDFParser : public UDMFParserBase sc.ScriptMessage("No valid actor type defined in conversation."); return false; } - SetConversation(dlgid, type, startpos); - for(;startpos < StrifeDialogues.Size(); startpos++) + Level->SetConversation(dlgid, type, startpos); + for(;startpos < Level->StrifeDialogues.Size(); startpos++) { - StrifeDialogues[startpos]->SpeakerType = type; - StrifeDialogues[startpos]->MenuClassName = clsid; + Level->StrifeDialogues[startpos]->SpeakerType = type; + Level->StrifeDialogues[startpos]->MenuClassName = clsid; } return true; } @@ -471,8 +474,9 @@ class USDFParser : public UDMFParserBase //=========================================================================== public: - bool Parse(int lumpnum, FileReader &lump, int lumplen) + bool Parse(FLevelLocals *l, int lumpnum, FileReader &lump, int lumplen) { + Level = l; sc.OpenMem(Wads.GetLumpFullName(lumpnum), lump.Read(lumplen)); sc.SetCMode(true); // Namespace must be the first field because everything else depends on it. @@ -512,7 +516,7 @@ public: { sc.MustGetToken('='); sc.MustGetToken(TK_StringConst); - LoadScriptFile(sc.String, true); + LoadScriptFile(Level, sc.String, true); sc.MustGetToken(';'); } else @@ -526,13 +530,13 @@ public: -bool P_ParseUSDF(int lumpnum, FileReader &lump, int lumplen) +bool P_ParseUSDF(FLevelLocals *l, int lumpnum, FileReader &lump, int lumplen) { USDFParser parse; try { - if (!parse.Parse(lumpnum, lump, lumplen)) + if (!parse.Parse(l, lumpnum, lump, lumplen)) { // clean up the incomplete dialogue structures here return false; diff --git a/src/serializer.cpp b/src/serializer.cpp index 73e8e8eb4..3f390bf1c 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -1968,13 +1968,13 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDial } else if (val->IsUint()) { - if (val->GetUint() >= StrifeDialogues.Size()) + if (val->GetUint() >= level.StrifeDialogues.Size()) { node = nullptr; } else { - node = StrifeDialogues[val->GetUint()]; + node = level.StrifeDialogues[val->GetUint()]; } } else