diff --git a/src/namedef.h b/src/namedef.h index eab87c503..8def090fa 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -585,6 +585,8 @@ xx(Ifitem) xx(Choice) xx(Link) xx(Goodbye) +xx(Require) +xx(Exclude) // Special menus xx(Mainmenu) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index f216d9d78..0bc2b98a8 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -516,6 +516,8 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); reply->ItemCheck[k].Amount = rsp->Count[k]; } + reply->ItemCheckRequire.Clear(); + reply->ItemCheckExclude.Clear(); // If the first item check has a positive amount required, then // add that to the reply string. Otherwise, use the reply as-is. @@ -656,6 +658,38 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE) else if (self > 1.f) self = 1.f; } +//============================================================================ +// +// ShouldSkipReply +// +// Determines whether this reply should be skipped or not. +// +//============================================================================ + +static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) +{ + if (reply->Reply == nullptr) + return true; + + int i; + for (i = 0; i < (int)reply->ItemCheckRequire.Size(); ++i) + { + if (!CheckStrifeItem(player, reply->ItemCheckRequire[i].Item, reply->ItemCheckRequire[i].Amount)) + { + return true; + } + } + + for (i = 0; i < (int)reply->ItemCheckExclude.Size(); ++i) + { + if (CheckStrifeItem(player, reply->ItemCheckExclude[i].Item, reply->ItemCheckExclude[i].Amount)) + { + return true; + } + } + return false; +} + //============================================================================ // // The conversation menu @@ -673,6 +707,7 @@ class DConversationMenu : public DMenu bool mShowGold; FStrifeDialogueNode *mCurNode; int mYpos; + player_t *mPlayer; public: static int mSelection; @@ -683,9 +718,10 @@ public: // //============================================================================= - DConversationMenu(FStrifeDialogueNode *CurNode) + DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player) { mCurNode = CurNode; + mPlayer = player; mDialogueLines = NULL; mShowGold = false; @@ -720,7 +756,7 @@ public: int i,j; for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next) { - if (reply->Reply == NULL) + if (ShouldSkipReply(reply, mPlayer)) { continue; } @@ -778,6 +814,13 @@ public: } ConversationMenuY = mYpos; //ConversationMenu.indent = 50; + + // Because replies can be selectively hidden mResponses.Size() won't be consistent. + // So make sure mSelection doesn't exceed mResponses.Size(). [FishyClockwork] + if (mSelection >= (int)mResponses.Size()) + { + mSelection = mResponses.Size() - 1; + } } //============================================================================= @@ -839,12 +882,24 @@ public: } else { - // Send dialogue and reply numbers across the wire. assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); + + // This is needed because mSelection represents the replies currently being displayed which will + // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] + FStrifeDialogueReply *reply = mCurNode->Children; + int replynum = mSelection; + for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) + { + if (ShouldSkipReply(reply, mPlayer)) + replynum++; + else + i++; + } + // Send dialogue and reply numbers across the wire. Net_WriteByte(DEM_CONVREPLY); Net_WriteWord(mCurNode->ThisNodeNum); - Net_WriteByte(mSelection); + Net_WriteByte(replynum); } Close(); return true; @@ -1169,7 +1224,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); } - DConversationMenu *cmenu = new DConversationMenu(CurNode); + DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player); if (CurNode != PrevNode) diff --git a/src/p_conversation.h b/src/p_conversation.h index 5b068fb04..bd674aa10 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -45,6 +45,8 @@ struct FStrifeDialogueReply int ActionSpecial; int Args[5]; TArray ItemCheck; + TArray ItemCheckRequire; + TArray ItemCheckExclude; char *Reply; char *QuickYes; int NextNode; // index into StrifeDialogues diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index dccec7c21..245240273 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -76,11 +76,11 @@ class USDFParser : public UDMFParserBase //=========================================================================== // - // Parse a cost block + // Parse a cost/require/exclude block // //=========================================================================== - bool ParseCost(FStrifeDialogueReply *response) + bool ParseCostRequireExclude(FStrifeDialogueReply *response, FName type) { FStrifeDialogueItemCheck check; check.Item = NULL; @@ -101,7 +101,12 @@ class USDFParser : public UDMFParserBase } } - response->ItemCheck.Push(check); + switch (type) + { + case NAME_Cost: response->ItemCheck.Push(check); break; + case NAME_Require: response->ItemCheckRequire.Push(check); break; + case NAME_Exclude: response->ItemCheckExclude.Push(check); break; + } return true; } @@ -206,7 +211,9 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Cost: - ParseCost(reply); + case NAME_Require: + case NAME_Exclude: + ParseCostRequireExclude(reply, key); break; default: