From b1880964faad779a8f31656e63ebf10668517841 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Fri, 28 Oct 2016 13:42:37 +0200 Subject: [PATCH 01/23] Added two new sub-blocks for Choice blocks Added two new sub-blocks for Choice blocks: Require and Exclude. The syntax for both is the same as Cost blocks. Require defines what item must be present in your inventory in order to show this choice/reply. Exclude defines what item must not be present in your inventory in order to show this choice/reply. If any Require/Exclude blocks are defined then this choice/reply will be hidden until all blocks of both types are satisfied. --- src/namedef.h | 2 ++ src/p_conversation.cpp | 65 ++++++++++++++++++++++++++++++++++++++---- src/p_conversation.h | 2 ++ src/p_usdf.cpp | 15 +++++++--- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index eab87c503b..8def090fa4 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 f216d9d78a..0bc2b98a87 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 5b068fb04b..bd674aa101 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 dccec7c210..245240273a 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: From f1a80770e1f18af2b3d55700d0edbfdd89f7edf5 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Fri, 28 Oct 2016 13:43:46 +0200 Subject: [PATCH 02/23] Updated the USDF specs Updated the USDF specs about 'require' and 'exclude'. --- specs/usdf.txt | 20 ++++++++++++++++++++ specs/usdf_zdoom.txt | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/specs/usdf.txt b/specs/usdf.txt index 093c9e7d74..2c65f25d06 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -122,6 +122,26 @@ conversation // Starts a dialog. amount = ; // Minimum amount of the item needed. } + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. + require + { + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. + } + + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. + exclude + { + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. + } + displaycost = ; // Whether the cost should be // displayed with the option. // If no cost is specified this should diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index c106cdd1af..8a324c0882 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -50,6 +50,16 @@ conversation item = ; } + require + { + item = ; + } + + exclude + { + item = ; + } + giveitem = ; } } From c341bc0d3c127cc0a03c2130b1c2ab2e01071a07 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 15:52:29 +0200 Subject: [PATCH 03/23] Added restriction of Require/Exclude to ZSDF Added restriction of Require/Exclude to ZSDF (namespace = "ZDoom";). A warning will be printed if a Require/Exclude block is detected in USDF (namespace = "Strife";). --- src/p_usdf.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 245240273a..e8ce5ca500 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -210,9 +210,17 @@ class USDFParser : public UDMFParserBase { switch(key) { - case NAME_Cost: case NAME_Require: case NAME_Exclude: + // Print a warning if the namespace is not ZDoom otherwise fall-through. [FishyClockwork] + if (namespace_bits != Zd) + { + sc.ScriptMessage("Detected \"%s\" block, ignoring. Require/Exclude are exclusive to namespace ZDoom.", key == NAME_Require ? "Require" : "Exclude"); + while (!sc.CheckToken('}')) sc.MustGetAnyToken(); // Skip this block + break; + } + + case NAME_Cost: ParseCostRequireExclude(reply, key); break; From f450a60f6630ff823c46b8ed151ec85f4ed5f7af Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 15:54:45 +0200 Subject: [PATCH 04/23] Undone changes to usdf.txt, updated usdf_zdoom.txt Undone changes to usdf.txt, updated usdf_zdoom.txt --- specs/usdf.txt | 20 -------------------- specs/usdf_zdoom.txt | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index 2c65f25d06..093c9e7d74 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -122,26 +122,6 @@ conversation // Starts a dialog. amount = ; // Minimum amount of the item needed. } - // The amount of an item needed for this option to become available. - // You can have as many as needed. All require blocks must be satisfied - // to show this option. - require - { - item = ; // Item that is required to show this option. - amount = ; // Minimum amount of the item needed. - } - - // The undesired amount of an item. This option will become available - // if you have less than the specified amount. You can have as many - // as needed. All exclude blocks must be satisfied to show this option. - // Note: if both require and exclude are defined then all require - // and all exclude blocks must be satisfied to show this option. - exclude - { - item = ; // Item that is unwanted to show this option. - amount = ; // Unwanted minimum amount of the item. - } - displaycost = ; // Whether the cost should be // displayed with the option. // If no cost is specified this should diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 8a324c0882..588ae6cda1 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -50,14 +50,24 @@ conversation item = ; } + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. require { - item = ; + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. } + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. exclude { - item = ; + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. } giveitem = ; From 42be7bee935b7509a5979a77f91b6b8983a9284e Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 17:05:59 +0200 Subject: [PATCH 05/23] For USDF treat Require/Exclude as unknown For USDF treat Require/Exclude as an unknown keyword. --- src/p_usdf.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index e8ce5ca500..a64dc932fe 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -210,19 +210,16 @@ class USDFParser : public UDMFParserBase { switch(key) { + case NAME_Cost: case NAME_Require: case NAME_Exclude: - // Print a warning if the namespace is not ZDoom otherwise fall-through. [FishyClockwork] - if (namespace_bits != Zd) + // Require and Exclude are exclusive to namespace ZDoom. [FishyClockwork] + if (key == NAME_Cost || namespace_bits == Zd) { - sc.ScriptMessage("Detected \"%s\" block, ignoring. Require/Exclude are exclusive to namespace ZDoom.", key == NAME_Require ? "Require" : "Exclude"); - while (!sc.CheckToken('}')) sc.MustGetAnyToken(); // Skip this block + ParseCostRequireExclude(reply, key); break; } - - case NAME_Cost: - ParseCostRequireExclude(reply, key); - break; + // Intentional fall-through default: sc.UnGet(); From 4a56d426c3aedc4dc0593923f3880adcbf98f1f5 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 17:33:34 +0200 Subject: [PATCH 06/23] Actually put the new info in the proper section Actually put the new info in the proper section in usdf_zdoom.txt --- specs/usdf_zdoom.txt | 46 +++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 588ae6cda1..8fe1bd7589 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -50,26 +50,6 @@ conversation item = ; } - // The amount of an item needed for this option to become available. - // You can have as many as needed. All require blocks must be satisfied - // to show this option. - require - { - item = ; // Item that is required to show this option. - amount = ; // Minimum amount of the item needed. - } - - // The undesired amount of an item. This option will become available - // if you have less than the specified amount. You can have as many - // as needed. All exclude blocks must be satisfied to show this option. - // Note: if both require and exclude are defined then all require - // and all exclude blocks must be satisfied to show this option. - exclude - { - item = ; // Item that is unwanted to show this option. - amount = ; // Unwanted minimum amount of the item. - } - giveitem = ; } } @@ -106,6 +86,32 @@ conversation // Starts a dialog. // the standard conversation ID ('actor' property) is used instead // for this purpose but since 'ZDoom' namespace requires the actor // to be a class name it needs a separate field for this. + + page + { + choice + { + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. + require + { + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. + } + + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. + exclude + { + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. + } + } + } } =============================================================================== From 8f2e9be70c30ddd3a5c4e70bd843b27afad15f16 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 17:43:20 +0200 Subject: [PATCH 07/23] Changed a description in usdf_zdoom.txt Changed a description in usdf_zdoom.txt to be more truthful. It's not just one new field anymore. (I really should learn to read these things before changing them.) --- specs/usdf_zdoom.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 8fe1bd7589..2b2e6f6da5 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -76,8 +76,8 @@ namespace = "ZDoom"; III.A : Conversations --------------------- -This block only lists the newly added fields. Currently ZDoom only adds one -field to the specification: +This block only lists the newly added fields. Currently ZDoom only adds a few +fields to the specification: conversation // Starts a dialog. { From 1502eae2ac47c85b0e2c95b8aad60e6de435c449 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sat, 29 Oct 2016 21:08:11 -0500 Subject: [PATCH 08/23] Add XPM (X PixMap) version of ZDoom icon --- src/posix/zdoom.xpm | 83 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/posix/zdoom.xpm diff --git a/src/posix/zdoom.xpm b/src/posix/zdoom.xpm new file mode 100644 index 0000000000..eae49eb77f --- /dev/null +++ b/src/posix/zdoom.xpm @@ -0,0 +1,83 @@ +/* XPM */ +static char * zdoom_xpm[] = { +"48 48 32 1", +" c None", +". c #ADA990", +"+ c #999966", +"@ c #666666", +"# c #393939", +"$ c #555555", +"% c #996666", +"& c #777777", +"* c #5F5F5F", +"= c #333333", +"- c #4D4D4D", +"; c #868686", +"> c #969696", +", c #1C1C1C", +"' c #339933", +") c #336633", +"! c #66CC66", +"~ c #66FF66", +"{ c #66CC33", +"] c #222222", +"^ c #333300", +"/ c #292929", +"( c #040404", +"_ c #0C0C0C", +": c #663333", +"< c #996633", +"[ c #CC9966", +"} c #CC6633", +"| c #CC9999", +"1 c #FFCC99", +"2 c #FF9966", +"3 c #FFCCCC", +" ... ", +" ++@##$+ ", +" +...+%&+ ", +" %*=-*&;$=&* ", +" %**=$@;>@=&*% ", +" &**@$*@@$-.+& ", +" %$%@*..$@.. ", +" ,#@+++@@#& ", +" $,#$$@@$#=$'' ", +" )!!!~!{=],,,,]^)'!{') =/, ", +" )){'~!!'')=],=))'{)'')) /=],( ", +" )'!!'!)~'{'),)''''''')) @@/==](( ", +" ^)''')'{{''')'''''),))) $$@$/,( ", +" ,^))),))''''))'')^,__/$$$-#-(( ", +" :<[}<,_)))))))),___,]#@@-/]] ", +" :<|12<:_,,,,,_,#$$-#/,^^=^}}< ", +" :<[1}::,^,,__,#$-==/,,::^:<<< ", +" ::&+@#^,,__/)#-=/,,,,-::^<::= ", +" :*+12[:==_,$-=/,,,,/,#::::=^ ", +" #*}331}-$]-==/,,,,// ##:=^ ", +" /]<13[---],,,,,,,]_] ", +" ,:--/,___]]]]:^___/ ", +" _______,^^,^,__/# ", +" ______:::::/$,,/# ", +" ____^:::=,^^^^,^^ ", +" __,,:=^,,)))^,,= ", +" _,,),,,,,^)^^^,, ", +" ,^,,),__,^))),,^ ", +" ,,,^^,,,,,)))),, ", +" ,,,,,,,)^))))^ ", +" ,,^,,,^^)))))^ ", +" ,^^,,,,)))))), ", +" ,^,,,,))^))), ", +" ],,,,,$&&&*$# ", +" ],,,]#****$# ", +" ]]]]]^####, ", +" ]]]]*,,,,#* ", +" ,_,#@&&@*/ ", +" __$####=# ", +" ,_/$$$$$# ", +" ,,,$*$$$ ", +" ],,,$**$# ", +" ],,,@&&@# ", +" ],,,$**#= ", +" ,,=+++%$ ", +" *%%%*$ ", +" /$*$#/ ", +" ],,]] "}; From 7c1f7aa81cb152e25f672ccb1d4bb109b65729b2 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sun, 30 Oct 2016 20:27:07 +0100 Subject: [PATCH 09/23] Restricted custom goodbyes to ZSDF --- src/p_usdf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index a64dc932fe..d40c542a14 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -345,7 +345,11 @@ class USDFParser : public UDMFParserBase break; case NAME_Goodbye: - Goodbye = CheckString(key); + // Custom goodbyes are exclusive to namespace ZDoom. [FishyClockwork] + if (namespace_bits == Zd) + { + Goodbye = CheckString(key); + } break; } } From 4fc5d527c6951584dad900cbf14194193c9e53f4 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sun, 30 Oct 2016 20:30:32 +0100 Subject: [PATCH 10/23] Moved 'goodbye' from usdf.txt to usdf_zdoom.txt I have undone all my changes to usdf.txt. It should look like how it did before commit 0df6ba6 --- specs/usdf.txt | 18 ++++++++---------- specs/usdf_zdoom.txt | 3 +++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index 093c9e7d74..4d1d01c1b3 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -87,16 +87,14 @@ conversation // Starts a dialog. page // Starts a new page. Pages are automatically numbered starting at 1. { - name = ; // Name that goes in the upper left hand corner - panel = ; // Name of lump to render as the background. - voice = ; // Narration sound lump. - dialog = ; // Dialog of the page. - goodbye = ; // Custom goodbye message. If omitted then the - // generic goodbyes will be displayed instead. - drop = ; // mobj for the object to drop if the actor is - // killed. - link = ; // Page to jump to if all ifitem conditions are - // satisified. + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are + // satisified. // jumps to the specified page if the player has the specified amount // or more of item in their inventory. This can be repeated as many diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 2b2e6f6da5..f800b5ae79 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -89,6 +89,9 @@ conversation // Starts a dialog. page { + goodbye = ; // Custom goodbye message. If omitted then the + // generic goodbyes will be displayed instead. + choice { // The amount of an item needed for this option to become available. From ede350ba3672c07907ebee319c015f7a365dbc7d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 30 Oct 2016 23:44:55 +0100 Subject: [PATCH 11/23] - there seem to be some problems with the line endings... --- specs/usdf.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index 4d1d01c1b3..1367ccfbf9 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -87,13 +87,13 @@ conversation // Starts a dialog. page // Starts a new page. Pages are automatically numbered starting at 1. { - name = ; // Name that goes in the upper left hand corner - panel = ; // Name of lump to render as the background. - voice = ; // Narration sound lump. - dialog = ; // Dialog of the page. - drop = ; // mobj for the object to drop if the actor is - // killed. - link = ; // Page to jump to if all ifitem conditions are + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are // satisified. // jumps to the specified page if the player has the specified amount From 43b2584f79ba62fbff6e1cb2b69c862dcbd09dd4 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 30 Oct 2016 23:27:29 -0400 Subject: [PATCH 12/23] - Fixed: Reference to freed stack object in R_FindPlane. This caused a massive slowdown (90% drop in total performance) in R_FindPlane when built with optimizations on in GCC6. Although I don't really understand why since the comparison should have been O(1) regardless of memory contents and even if the check failed every plane it would still be pretty fast, this is what they mean when they say that anything can happen when undefined behavior is triggered. --- src/r_plane.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 07efb84b4d..52dfd43323 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -595,9 +595,10 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl fixed_t alpha = FLOAT2FIXED(Alpha); //angle_t angle = (xform.Angle + xform.baseAngle).BAMs(); + FTransform nulltransform; + if (picnum == skyflatnum) // killough 10/98 { // most skies map together - FTransform nulltransform; lightlevel = 0; xform = &nulltransform; nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0; From 6e6249f896d4beda1b172eb0234fe1e98561cf9d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 31 Oct 2016 18:51:58 +0100 Subject: [PATCH 13/23] - reverted WEAPONTOP to its original value of 32 and made the added fudging bit part of the render side. This is needed so that 'offset(0,32)' does what it is supposed to do. --- src/g_shared/a_weapons.cpp | 1 + src/p_pspr.cpp | 3 +-- src/p_pspr.h | 8 +++----- src/r_things.cpp | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index edd250debd..b1ede01874 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -640,6 +640,7 @@ void AWeapon::PostMorphWeapon () pspr = Owner->player->GetPSprite(PSP_WEAPON); pspr->y = WEAPONBOTTOM; + pspr->ResetInterpolation(); pspr->SetState(GetUpState()); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index abbd2284ee..2e591e20d9 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -262,8 +262,7 @@ void DPSprite::NewTick() while (pspr) { pspr->processPending = true; - pspr->oldx = pspr->x; - pspr->oldy = pspr->y; + pspr->ResetInterpolation(); pspr = pspr->Next; } diff --git a/src/p_pspr.h b/src/p_pspr.h index ea03e109f8..64a2702a37 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -29,11 +29,8 @@ #define WEAPONBOTTOM 128. -// [RH] +0x6000 helps it meet the screen bottom -// at higher resolutions while still being in -// the right spot at 320x200. -#define WEAPONTOP (32+6./16) - +#define WEAPONTOP 32. +#define WEAPON_FUDGE_Y 0.375 class AInventory; // @@ -77,6 +74,7 @@ public: DPSprite* GetNext() { return Next; } AActor* GetCaller() { return Caller; } void SetCaller(AActor *newcaller) { Caller = newcaller; } + void ResetInterpolation() { oldx = x; oldy = y; } double x, y; double oldx, oldy; diff --git a/src/r_things.cpp b/src/r_things.cpp index a15921cbab..cad434fa5c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1302,7 +1302,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac; - sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac; + sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac + WEAPON_FUDGE_Y; if (pspr->Flags & PSPF_ADDBOB) { @@ -1610,7 +1610,7 @@ void R_DrawPlayerSprites () else { wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF; - wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF; + wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF + WEAPON_FUDGE_Y; } } else From 8d7e400f8eaa964f359849df34306ade247cf850 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Mon, 31 Oct 2016 22:34:46 -0500 Subject: [PATCH 14/23] Fixed: DCanvas::FillSimplePoly must set dc_destorg - dc_destorg is normally set to the upper-left corner of the view window. If there is a border, then this won't coincide with the upper-left corner of the screen, and DCanvas::FillSimplePoly would merrily write off the end of the screen buffer. --- src/v_draw.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 20e5311cd2..bef7328944 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1330,6 +1330,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, return; } + BYTE *destorgsave = dc_destorg; + dc_destorg = screen->GetBuffer(); + if (dc_destorg == NULL) + { + I_FatalError("Attempt to write to buffer of hardware canvas"); + } + scalex /= tex->Scale.X; scaley /= tex->Scale.Y; @@ -1432,6 +1439,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, pt1 = pt2; pt2--; if (pt2 < 0) pt2 = npoints; } while (pt1 != botpt); + dc_destorg = destorgsave; #endif } From 93885974438ab57d940f1e7cdfd4495fdf5fe4bc Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 1 Nov 2016 00:08:16 -0500 Subject: [PATCH 15/23] Add 1 pixel tall and wide texture support to the renderer - These require manual detection and overriding of the scaling factors to 0, because a right shift of (32-0) bits wraps around to 0 and results in no shift at all rather than leaving the register zeroed out. --- src/asm_ia32/tmap2.asm | 3 +++ src/r_plane.cpp | 45 +++++++++++++++++++++++++++++++--------- src/r_segs.cpp | 18 ++++++++++++++++ src/textures/texture.cpp | 5 +++-- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/asm_ia32/tmap2.asm b/src/asm_ia32/tmap2.asm index 9a7aa55346..ab1695d3cd 100644 --- a/src/asm_ia32/tmap2.asm +++ b/src/asm_ia32/tmap2.asm @@ -198,7 +198,10 @@ SetTiltedSpanSize: mov [y8+2],cl mov [y9+2],cl mov [y10+2],cl + cmp eax,0 ; if x bits is 0, mask must be 0 too. + jz .notted not eax +.notted: pop ecx mov [m1+2],eax diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 52dfd43323..c57af953a9 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -221,10 +221,26 @@ void R_MapPlane (int y, int x1) distance = planeheight * yslope[y]; - ds_xstep = xs_ToFixed(32-ds_xbits, distance * xstepscale); - ds_ystep = xs_ToFixed(32-ds_ybits, distance * ystepscale); - ds_xfrac = xs_ToFixed(32-ds_xbits, distance * basexfrac) + pviewx; - ds_yfrac = xs_ToFixed(32-ds_ybits, distance * baseyfrac) + pviewy; + if (ds_xbits != 0) + { + ds_xstep = xs_ToFixed(32 - ds_xbits, distance * xstepscale); + ds_xfrac = xs_ToFixed(32 - ds_xbits, distance * basexfrac) + pviewx; + } + else + { + ds_xstep = 0; + ds_xfrac = 0; + } + if (ds_ybits != 0) + { + ds_ystep = xs_ToFixed(32 - ds_ybits, distance * ystepscale); + ds_yfrac = xs_ToFixed(32 - ds_ybits, distance * baseyfrac) + pviewy; + } + else + { + ds_ystep = 0; + ds_yfrac = 0; + } if (plane_shade) { @@ -357,7 +373,7 @@ void R_CalcTiltedLighting (double lval, double lend, int width) // //========================================================================== -void R_MapTiltedPlane (int y, int x1) +void R_MapTiltedPlane(int y, int x1) { int x2 = spanend[y]; int width = x2 - x1; @@ -366,18 +382,18 @@ void R_MapTiltedPlane (int y, int x1) DWORD u, v; int i; - iz = plane_sz[2] + plane_sz[1]*(centery-y) + plane_sz[0]*(x1-centerx); + iz = plane_sz[2] + plane_sz[1] * (centery - y) + plane_sz[0] * (x1 - centerx); // Lighting is simple. It's just linear interpolation from start to end if (plane_shade) { - uz = (iz + plane_sz[0]*width) * planelightfloat; + uz = (iz + plane_sz[0] * width) * planelightfloat; vz = iz * planelightfloat; - R_CalcTiltedLighting (vz, uz, width); + R_CalcTiltedLighting(vz, uz, width); } - uz = plane_su[2] + plane_su[1]*(centery-y) + plane_su[0]*(x1-centerx); - vz = plane_sv[2] + plane_sv[1]*(centery-y) + plane_sv[0]*(x1-centerx); + uz = plane_su[2] + plane_su[1] * (centery - y) + plane_su[0] * (x1 - centerx); + vz = plane_sv[2] + plane_sv[1] * (centery - y) + plane_sv[0] * (x1 - centerx); fb = ylookup[y] + x1 + dc_destorg; @@ -1888,6 +1904,15 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t } } + // Hack in support for 1 x Z and Z x 1 texture sizes + if (ds_ybits == 0) + { + plane_sv[2] = plane_sv[1] = plane_sv[0] = 0; + } + if (ds_xbits = 0) + { + plane_su[2] = plane_su[1] = plane_su[0] = 0; + } #if defined(X86_ASM) if (ds_source != ds_curtiltedsource) R_SetTiltedSpanSource_ASM (ds_source); diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 464fb36449..01c03e6d7a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1104,6 +1104,12 @@ void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *l rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setupvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -1456,6 +1462,12 @@ void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_ rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32- rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setupmvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -1631,6 +1643,12 @@ void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, f rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setuptmvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 760437db99..9c1b5fdb42 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -210,8 +210,9 @@ void FTexture::CalcBitSize () } WidthMask = (1 << WidthBits) - 1; - // The minimum height is 2, because we cannot shift right 32 bits. - for (i = 1; (1 << i) < Height; ++i) + //
The minimum height is 2, because we cannot shift right 32 bits. + // Scratch that. Somebody actually made a 1x1 texture, so now we have to handle it. + for (i = 0; (1 << i) < Height; ++i) { } HeightBits = i; From 5df21fda6814431e2dae8955add6ae9587fabf72 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 1 Nov 2016 00:18:56 -0500 Subject: [PATCH 16/23] Fixed: Masked midtexture yscale incorrectly used the texture's X scale --- src/r_segs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 01c03e6d7a..45e3044d3a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2539,7 +2539,7 @@ void R_StoreWallRange (int start, int stop) lwal = (fixed_t *)(openings + ds_p->maskedtexturecol); swal = (float *)(openings + ds_p->swall); FTexture *pic = TexMan(sidedef->GetTexture(side_t::mid), true); - double yscale = pic->Scale.X * sidedef->GetTextureYScale(side_t::mid); + double yscale = pic->Scale.Y * sidedef->GetTextureYScale(side_t::mid); fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid)); if (pic->bWorldPanning) From 46a311b23c7c09ab7e6701d62a5e8c2c331f43c3 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 1 Nov 2016 09:59:59 +0100 Subject: [PATCH 17/23] - Fixed a typo in 1 pixel tall support addition. Found by Clang -Wparentheses warning. --- src/r_plane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index c57af953a9..810aa0003c 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1909,7 +1909,7 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t { plane_sv[2] = plane_sv[1] = plane_sv[0] = 0; } - if (ds_xbits = 0) + if (ds_xbits == 0) { plane_su[2] = plane_su[1] = plane_su[0] = 0; } From 4cf0d76e8cd759bcca5adb27a1b8007ea186937f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Nov 2016 13:33:18 +0100 Subject: [PATCH 18/23] - fixed: RapidJSON in ASCII mode cannot handle extended 8 bit character sets and will produce broken data if the input contains some. This means we need to perform the conversion to UTF-8 on ZDoom's side and run RapidJSON in UTF-8 mode. Daedalus triggers this with a 0x85 character which in Windows CP 1252 is the ellipsis (...) The converter will assume ISO-8859-1, though, but cannot do anything with these characters because they map to the font being used here. --- src/p_acs.cpp | 4 ++ src/serializer.cpp | 173 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 160 insertions(+), 17 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f36aaaf69a..d82e6590c4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -791,6 +791,10 @@ void ACSStringPool::WriteStrings(FSerializer &file, const char *key) const { if (file.BeginObject(nullptr)) { + if (i == 430) + { + int a = 0; + } file("index", i) ("string", entry->Str) ("lockcount", entry->LockCount) diff --git a/src/serializer.cpp b/src/serializer.cpp index 49226ce801..dec81e86fe 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -67,6 +67,143 @@ char nulspace[1024 * 1024 * 4]; bool save_full = false; // for testing. Should be removed afterward. +int utf8_encode(int32_t codepoint, char *buffer, int *size) +{ + if (codepoint < 0) + return -1; + else if (codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if (codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if (codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if (codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +int utf8_decode(const char *src, int *size) +{ + int c = src[0] & 255; + int r; + + *size = 1; + if ((c & 0x80) == 0) + { + return c; + } + + int c1 = src[1] & 255; + + if ((c & 0xE0) == 0xC0) + { + r = ((c & 0x1F) << 6) | c1; + if (r >= 128) + { + *size = 2; + return r; + } + return -1; + } + + int c2 = src[2] & 255; + + if ((c & 0xF0) == 0xE0) + { + r = ((c & 0x0F) << 12) | (c1 << 6) | c2; + if (r >= 2048 && (r < 55296 || r > 57343)) + { + *size = 3; + return r; + } + return -1; + } + + int c3 = src[3] & 255; + + if ((c & 0xF8) == 0xF0) + { + r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; + if (r >= 65536 && r <= 1114111) + { + *size = 4; + return r; + } + } + return -1; +} + +static TArray out; +static const char *StringToUnicode(const char *cc, int size = -1) +{ + int ch; + const char *c = cc; + int count = 0; + int count1 = 0; + out.Clear(); + while (ch = (*c++) & 255) + { + count1++; + if (ch >= 128) + { + if (ch < 0x800) count += 2; + else count += 3; + // The source cannot contain 4-byte chars. + } + else count++; + if (count1 == size && size > 0) break; + } + if (count == count1) return cc; // string is pure ASCII. + // we need to convert + out.Resize(count + 1); + out.Last() = 0; + c = cc; + int i = 0; + while (ch = (*c++) & 255) + { + utf8_encode(ch, &out[i], &count1); + i += count1; + } + return &out[0]; +} + +static const char *UnicodeToString(const char *cc) +{ + out.Resize((unsigned)strlen(cc) + 1); + int ndx = 0; + while (*cc != 0) + { + int size; + int c = utf8_decode(cc, &size); + if (c < 0 || c > 255) c = '?'; + out[ndx++] = c; + cc += size; + } + out[ndx] = 0; + return &out[0]; +} + //========================================================================== // // @@ -99,8 +236,8 @@ struct FJSONObject struct FWriter { - typedef rapidjson::Writer > Writer; - typedef rapidjson::PrettyWriter > PrettyWriter; + typedef rapidjson::Writer > Writer; + typedef rapidjson::PrettyWriter > PrettyWriter; Writer *mWriter1; PrettyWriter *mWriter2; @@ -173,14 +310,16 @@ struct FWriter void String(const char *k) { + k = StringToUnicode(k); if (mWriter1) mWriter1->String(k); else if (mWriter2) mWriter2->String(k); } void String(const char *k, int size) { - if (mWriter1) mWriter1->String(k, size); - else if (mWriter2) mWriter2->String(k, size); + k = StringToUnicode(k, size); + if (mWriter1) mWriter1->String(k); + else if (mWriter2) mWriter2->String(k); } void Bool(bool k) @@ -602,7 +741,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe } else if (i == 0 && aval.IsString()) { - args[i] = -FName(aval.GetString()); + args[i] = -FName(UnicodeToString(aval.GetString())); } else { @@ -654,7 +793,7 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num) } else if (val->IsString()) { - num = -FName(val->GetString()); + num = -FName(UnicodeToString(val->GetString())); } else { @@ -709,7 +848,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d { if (val->IsString()) { - uint32_t name = *reinterpret_cast(val->GetString()); + uint32_t name = *reinterpret_cast(UnicodeToString(val->GetString())); for (auto hint = NumStdSprites; hint-- != 0; ) { if (sprites[hint].dwName == name) @@ -747,7 +886,7 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) { if (val->IsString()) { - charptr = val->GetString(); + charptr = UnicodeToString(val->GetString()); } else { @@ -1403,7 +1542,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe assert(nameval.IsString() && typeval.IsInt()); if (nameval.IsString() && typeval.IsInt()) { - value = TexMan.GetTexture(nameval.GetString(), typeval.GetInt()); + value = TexMan.GetTexture(UnicodeToString(nameval.GetString()), typeval.GetInt()); } else { @@ -1553,7 +1692,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d assert(val->IsString()); if (val->IsString()) { - value = val->GetString(); + value = UnicodeToString(val->GetString()); } else { @@ -1638,7 +1777,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI assert(val->IsString() || val->IsNull()); if (val->IsString()) { - sid = val->GetString(); + sid = UnicodeToString(val->GetString()); } else if (val->IsNull()) { @@ -1687,7 +1826,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor assert(val->IsString() || val->IsNull()); if (val->IsString()) { - clst = PClass::FindActor(val->GetString()); + clst = PClass::FindActor(UnicodeToString(val->GetString())); } else if (val->IsNull()) { @@ -1735,7 +1874,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl { if (val->IsString()) { - clst = PClass::FindClass(val->GetString()); + clst = PClass::FindClass(UnicodeToString(val->GetString())); } else if (val->IsNull()) { @@ -1810,7 +1949,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState assert(cls.IsString() && ndx.IsUint()); if (cls.IsString() && ndx.IsUint()) { - PClassActor *clas = PClass::FindActor(cls.GetString()); + PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString())); if (clas && ndx.GetUint() < (unsigned)clas->NumOwnedStates) { state = clas->OwnedStates + ndx.GetUint(); @@ -1932,7 +2071,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p } else if (val->IsString()) { - pstr = AActor::mStringPropertyData.Alloc(val->GetString()); + pstr = AActor::mStringPropertyData.Alloc(UnicodeToString(val->GetString())); } else { @@ -1974,7 +2113,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString } else if (val->IsString()) { - pstr = val->GetString(); + pstr = UnicodeToString(val->GetString()); } else { @@ -2023,7 +2162,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr } else if (val->IsString()) { - pstr = copystring(val->GetString()); + pstr = copystring(UnicodeToString(val->GetString())); } else { From 3f57269a8b806d0c775381ef766364b9a18e4bb5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Nov 2016 13:36:33 +0100 Subject: [PATCH 19/23] - fixed: ACSStringPool::AddString did not check for NULL pointers as input. Let's just map them to the empty string, that's a lot better than crashing. --- src/p_acs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index d82e6590c4..9281bfad0e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -375,6 +375,7 @@ void ACSStringPool::Clear() int ACSStringPool::AddString(const char *str) { + if (str == nullptr) str = ""; size_t len = strlen(str); unsigned int h = SuperFastHash(str, len); unsigned int bucketnum = h % NUM_BUCKETS; From 6e0defdc695f9b8e18fe6c730f63e5218245728b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Nov 2016 13:48:56 +0100 Subject: [PATCH 20/23] - fixed numeric output precision for a few sliders. --- wadsrc/static/menudef.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 765fe66744..dac933af81 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -667,8 +667,8 @@ OptionMenu "VideoOptions" Slider "$DSPLYMNU_BRIGHTNESS", "Gamma", 0.75, 3.0, 0.05, 2 Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" - Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 1 - Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 1 + Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 2 + Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 2 Option "$DSPLYMNU_COLUMNMETHOD", "r_columnmethod", "ColumnMethods" StaticText " " @@ -700,7 +700,7 @@ OptionMenu "VideoOptions" ColorPicker "$DSPLYMNU_DIMCOLOR", "dimcolor" Slider "$DSPLYMNU_MOVEBOB", "movebob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_STILLBOB", "stillbob", 0, 1.0, 0.05, 2 - Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1, 2 + Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1 } @@ -1242,7 +1242,7 @@ OptionMenu GameplayOptions Title "$GMPLYMNU_TITLE" //Indent 222 Option "$GMPLYMNU_TEAMPLAY", "teamplay", "OnOff" - Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05 + Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05,2 StaticText " " Option "$GMPLYMNU_SMARTAUTOAIM", "sv_smartaim", "SmartAim" StaticText " " @@ -1792,7 +1792,7 @@ OptionMenu NetworkOptions StaticText "$NETMNU_LOCALOPTIONS", 1 Option "$NETMNU_MOVEPREDICTION", "cl_noprediction", "OffOn" Option "$NETMNU_LINESPECIALPREDICTION", "cl_predict_specials", "OnOff" - Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05 + Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05, 2 Slider "$NETMNU_LERPTHRESHOLD", "cl_predict_lerpthreshold", 0.1, 16.0, 0.1 StaticText " " StaticText "$NETMNU_HOSTOPTIONS", 1 From f72ebe67689c6babe991b9b805eef419e3a186ce Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 1 Nov 2016 03:30:59 -0400 Subject: [PATCH 21/23] - Extended map, recordmap, and open commands to accept "dm/coop" as an extra parameter - to open maps in multiplayer mode with the requested ruleset. --- src/doomstat.h | 3 +++ src/g_game.cpp | 1 + src/g_level.cpp | 41 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index bbb323c7e3..70869b5a2c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -71,6 +71,9 @@ extern bool netgame; // Bot game? Like netgame, but doesn't involve network communication. extern bool multiplayer; +// [SP] MPMap implementation - invokes fake multiplayer without bots +extern bool multiplayernext; + // Flag: true only if started as net deathmatch. EXTERN_CVAR (Int, deathmatch) diff --git a/src/g_game.cpp b/src/g_game.cpp index b0c8775fc5..2c827e6391 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -164,6 +164,7 @@ bool viewactive; bool netgame; // only true if packets are broadcast bool multiplayer; +bool multiplayernext = false; // [SP] MPMap implementation player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; diff --git a/src/g_level.cpp b/src/g_level.cpp index d3a8c4015a..65e19d4237 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -90,6 +90,8 @@ #include "g_hub.h" +#include + void STAT_StartNewGame(const char *lev); void STAT_ChangeLevel(const char *newl); @@ -181,6 +183,16 @@ CCMD (map) } else { + if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } G_DeferedInitNew (argv[1]); } } @@ -192,7 +204,7 @@ CCMD (map) } else { - Printf ("Usage: map \n"); + Printf ("Usage: map [coop|dm]\n"); } } @@ -218,6 +230,16 @@ CCMD(recordmap) } else { + if (argv.argc() > 3 && strcmp(argv[3], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 3 && strcmp(argv[3], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } G_DeferedInitNew(argv[2]); gameaction = ga_recordgame; newdemoname = argv[1]; @@ -232,7 +254,7 @@ CCMD(recordmap) } else { - Printf("Usage: recordmap \n"); + Printf("Usage: recordmap [coop|dm]\n"); } } @@ -258,13 +280,23 @@ CCMD (open) } else { + if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } gameaction = ga_newgame2; d_skill = -1; } } else { - Printf ("Usage: open \n"); + Printf ("Usage: open [coop|dm]\n"); } } @@ -293,7 +325,8 @@ void G_NewInit () G_ClearSnapshots (); ST_SetNeedRefresh(); netgame = false; - multiplayer = false; + multiplayer = multiplayernext; + multiplayernext = false; if (demoplayback) { C_RestoreCVars (); From 6755373f464a709041ff77277a24bc808256e2a1 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 1 Nov 2016 09:47:01 -0400 Subject: [PATCH 22/23] - fixed: map commands will now take capslock DM/COOP as arguments --- src/doomstat.h | 2 +- src/g_game.cpp | 2 +- src/g_level.cpp | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 70869b5a2c..22ee4fdb49 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -71,7 +71,7 @@ extern bool netgame; // Bot game? Like netgame, but doesn't involve network communication. extern bool multiplayer; -// [SP] MPMap implementation - invokes fake multiplayer without bots +// [SP] Map dm/coop implementation - invokes fake multiplayer without bots extern bool multiplayernext; // Flag: true only if started as net deathmatch. diff --git a/src/g_game.cpp b/src/g_game.cpp index 2c827e6391..ec79d59e60 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -164,7 +164,7 @@ bool viewactive; bool netgame; // only true if packets are broadcast bool multiplayer; -bool multiplayernext = false; // [SP] MPMap implementation +bool multiplayernext = false; // [SP] Map coop/dm implementation player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; diff --git a/src/g_level.cpp b/src/g_level.cpp index 65e19d4237..9e8448879f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -183,12 +183,12 @@ CCMD (map) } else { - if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0) { deathmatch = false; multiplayernext = true; } - else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0) { deathmatch = true; multiplayernext = true; @@ -230,12 +230,12 @@ CCMD(recordmap) } else { - if (argv.argc() > 3 && strcmp(argv[3], "coop") == 0) + if (argv.argc() > 3 && stricmp(argv[3], "coop") == 0) { deathmatch = false; multiplayernext = true; } - else if (argv.argc() > 3 && strcmp(argv[3], "dm") == 0) + else if (argv.argc() > 3 && stricmp(argv[3], "dm") == 0) { deathmatch = true; multiplayernext = true; @@ -280,12 +280,12 @@ CCMD (open) } else { - if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0) { deathmatch = false; multiplayernext = true; } - else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0) { deathmatch = true; multiplayernext = true; From b420347babeb632497298b9a3e0f0f04e38a6aa9 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Sun, 16 Oct 2016 02:50:21 +0800 Subject: [PATCH 23/23] Added "local" parameters to A_PlaySound and ACS PlaySound --- src/p_acs.cpp | 7 ++++--- src/p_actionfunctions.cpp | 5 +++-- src/s_sound.cpp | 26 ++++++++++++++++++++++++++ src/s_sound.h | 3 +++ wadsrc/static/actors/actor.txt | 2 +- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9281bfad0e..1a60a0c4fb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5350,7 +5350,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_PlaySound: case ACSF_PlayActorSound: - // PlaySound(tid, "SoundName", channel, volume, looping, attenuation) + // PlaySound(tid, "SoundName", channel, volume, looping, attenuation, local) { FSoundID sid; @@ -5371,6 +5371,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) float vol = argCount > 3 ? ACSToFloat(args[3]) : 1.f; INTBOOL looping = argCount > 4 ? args[4] : false; float atten = argCount > 5 ? ACSToFloat(args[5]) : ATTN_NORM; + INTBOOL local = argCount > 6 ? args[6] : false; if (args[0] == 0) { @@ -5387,11 +5388,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { if (!looping) { - S_Sound(spot, chan, sid, vol, atten); + S_PlaySound(spot, chan, sid, vol, atten, local); } else if (!S_IsActorPlayingSomething(spot, chan & 7, sid)) { - S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); + S_PlaySound(spot, chan | CHAN_LOOP, sid, vol, atten, local); } } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c6bc8215b0..73cade49a4 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1032,16 +1032,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) PARAM_FLOAT_OPT (volume) { volume = 1; } PARAM_BOOL_OPT (looping) { looping = false; } PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; } + PARAM_BOOL_OPT (local) { local = false; } if (!looping) { - S_Sound (self, channel, soundid, (float)volume, (float)attenuation); + S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local); } else { if (!S_IsActorPlayingSomething (self, channel&7, soundid)) { - S_Sound (self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation); + S_PlaySound(self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation, local); } } return 0; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 524b121756..a51a7101be 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1301,6 +1301,32 @@ void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, fl S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation); } +//========================================================================== +// +// S_PlaySound - Subfunction used by ACS and DECORATE +// +// Has a local parameter to make the sound audible only to the source +// +//========================================================================== + +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local) +{ + if (a == nullptr) + return; + + if (!local) + { + S_Sound(a, chan, sid, vol, atten); + } + else + { + if (a->CheckLocalView(consoleplayer)) + { + S_Sound(chan, sid, vol, ATTN_NONE); + } + } +} + //========================================================================== // // S_LoadSound diff --git a/src/s_sound.h b/src/s_sound.h index 9b917e25c8..d6d2a5403e 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -241,6 +241,9 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, f void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); void S_Sound(const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation); +// [Nash] Used by ACS and DECORATE +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local); + // sound channels // channel 0 never willingly overrides // other channels (1-7) always override a playing sound on that channel diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index eecc843d39..71e82f613d 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -191,7 +191,7 @@ ACTOR Actor native //: Thinker action native A_ComboAttack(); action native A_BulletAttack(); action native A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", float snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, float runspeed = 160.0, class pufftype = "BulletPuff"); - action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM); + action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM, bool local = false); native void A_PlayWeaponSound(sound whattoplay); action native A_FLoopActiveSound(); action native A_LoopActiveSound();