From 72857db17bcce93f29e4d2cf7fba7e9038d6ed49 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 4 Dec 2019 00:28:28 +0100 Subject: [PATCH] - refactor of the quote storage. This was consolidated for both EDuke and RedNukem frontends, put into a class with strict access control and the length limit was lifted. The new class will eventually allow better localization control. --- source/CMakeLists.txt | 1 + source/blood/src/controls.cpp | 6 - source/common/quotemgr.h | 65 +++++++++++ source/common/quotes.cpp | 180 ++++++++++++++++++++++++++++++ source/common/savegamehelp.cpp | 3 + source/duke3d/src/cheats.cpp | 6 +- source/duke3d/src/demo.cpp | 8 +- source/duke3d/src/game.cpp | 8 +- source/duke3d/src/gamedef.cpp | 176 ++++------------------------- source/duke3d/src/gameexec.cpp | 185 +++++++++++++------------------ source/duke3d/src/global.h | 1 - source/duke3d/src/network.cpp | 2 +- source/duke3d/src/player.cpp | 10 +- source/duke3d/src/quotes.h | 4 +- source/duke3d/src/savegame.cpp | 79 +------------ source/duke3d/src/screentext.cpp | 20 +--- source/rr/src/cheats.cpp | 6 +- source/rr/src/demo.cpp | 8 +- source/rr/src/game.cpp | 8 +- source/rr/src/gamedef.cpp | 161 ++++----------------------- source/rr/src/gameexec.cpp | 2 +- source/rr/src/global.h | 1 - source/rr/src/player.cpp | 10 +- source/rr/src/quotes.h | 4 +- source/rr/src/savegame.cpp | 41 +------ source/rr/src/screentext.cpp | 19 +--- 26 files changed, 418 insertions(+), 596 deletions(-) create mode 100644 source/common/quotemgr.h create mode 100644 source/common/quotes.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 5d8a8c36f..37806cc21 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -752,6 +752,7 @@ set (PCH_SOURCES common/secrets.cpp common/compositesavegame.cpp common/savegamehelp.cpp + common/quotes.cpp common/2d/v_2ddrawer.cpp common/2d/v_draw.cpp diff --git a/source/blood/src/controls.cpp b/source/blood/src/controls.cpp index 508ece563..8da67bced 100644 --- a/source/blood/src/controls.cpp +++ b/source/blood/src/controls.cpp @@ -384,12 +384,6 @@ void ctrlGetInput(void) strafe = ClipRange(strafe-(info.dx<<5), -2048, 2048); -#if 0 - if (info.dz < 0) - gInput.mlook = ClipRange((info.dz+127)>>7, -127, 127); - else - gInput.mlook = ClipRange(info.dz>>7, -127, 127); -#endif if (g_MyAimMode) gInput.q16mlook = fix16_clamp(fix16_div(fix16_from_int(info.mousey), F16(128)), F16(-127)>>2, F16(127)>>2); else diff --git a/source/common/quotemgr.h b/source/common/quotemgr.h new file mode 100644 index 000000000..3de93401e --- /dev/null +++ b/source/common/quotemgr.h @@ -0,0 +1,65 @@ +#pragma once + +#include "zstring.h" +#include "gstrings.h" +// Reimplementation of the Duke quote string buffer. +// Needed because these strings need a level of abstraction from the engine to allow localization +// and because some of the quotes are really status messages that need to be shared between the different games. +// Also a good opportunity to consolidate the data buffers from Duke and Redneck frontends. + +enum +{ + MAXQUOTES = 16384, +}; + +class Quotes +{ + FString quotes[MAXQUOTES]; + FString exquotes[MAXQUOTES]; + + void MakeStringLabel(FString "e); + +public: + + void InitializeQuote(int num, const char *text, bool fromscript = false); + void InitializeExQuote(int num, const char *text, bool fromscript = false); + + const char *GetQuote(int num) + { + return GStrings.localize(quotes[num]); + } + + const char *GetExQuote(int num) + { + return GStrings.localize(exquotes[num]); + } + + const char *GetRawQuote(int num) + { + return quotes[num]; + } + + const char *GetRawExQuote(int num) + { + return exquotes[num]; + } + + void CopyQuote(int dst, int src) + { + quotes[dst] = quotes[src]; + } + + void CopyExQuote(int dst, int src) + { + quotes[dst] = exquotes[src]; + } + + void AppendQuote(int dst, int src, int len = -1); + void AppendExQuote(int dst, int src, int len = -1); + void FormatQuote(int dst, const char* fmt, ...); + void Substitute(int num, const char* text, const char* replc); + void ReadFromSavegame(); + void WriteToSavegame(); +}; + +extern Quotes quoteMgr; diff --git a/source/common/quotes.cpp b/source/common/quotes.cpp new file mode 100644 index 000000000..4ca7057ce --- /dev/null +++ b/source/common/quotes.cpp @@ -0,0 +1,180 @@ +/* +** +** quotes.cpp +** Duke-Nukem-style quote buffer +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** This is actually a VERY inefficient way to manage strings +** but needs to be preserved because the CON VM depends on it. +*/ + +#include "quotemgr.h" +#include "savegamehelp.h" +#include "sjson.h" + + +void Quotes::MakeStringLabel(FString "e) +{ +} + +void Quotes::InitializeQuote(int num, const char *text, bool fromscript) +{ + quotes[num] = num; + if (fromscript) // means this is the initial setup from the source data. + { + MakeStringLabel(quotes[num]); + } +} + +void Quotes::InitializeExQuote(int num, const char *text, bool fromscript) +{ + exquotes[num] = num; + if (fromscript) // means this is the initial setup from the source data. + { + MakeStringLabel(quotes[num]); + } +} + +void Quotes::AppendQuote(int dst, int src, int len) +{ + // This needs to apply the localization because the combined string is not localizable anymore. + if (quotes[dst][0] == '$') quotes[dst] = GStrings.localize(quotes[dst]); + if (len < 0) quotes[dst] << GStrings.localize(quotes[src]); + else quotes[dst] += FString(GStrings.localize(quotes[src]), len); +} + +void Quotes::AppendExQuote(int dst, int src, int len) +{ + // This needs to apply the localization because the combined string is not localizable anymore. + if (quotes[dst][0] == '$') quotes[dst] = GStrings.localize(quotes[dst]); + if (len < 0) quotes[dst] << GStrings.localize(exquotes[src]); + else quotes[dst] += FString(GStrings.localize(exquotes[src]), len); +} + + +void Quotes::FormatQuote(int dst, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + quotes[dst].VFormat(fmt, ap); +} + +void Quotes::Substitute(int dst, const char* text, const char* replc) +{ + if (quotes[dst][0] == '$') quotes[dst] = GStrings.localize(quotes[dst]); + quotes[dst].Substitute(text, replc); +} + + +void Quotes::ReadFromSavegame() +{ + for (auto& q : quotes) q = ""; + for (auto& q : exquotes) q = ""; + + auto fil = ReadSavegameChunk("quotes.json"); + if (!fil.isOpen()) + { + return; + } + + auto text = fil.ReadPadded(1); + fil.Close(); + + if (text.Size() == 0) + { + return; + } + + sjson_context* ctx = sjson_create_context(0, 0, NULL); + sjson_node* root = sjson_decode(ctx, (const char*)text.Data()); + + auto qs = sjson_find_member(root, "quotes"); + auto xs = sjson_find_member(root, "exquotes"); + + sjson_node* q; + sjson_foreach(q, qs) + { + int index = (int)strtoll(q->key, nullptr, 10); + quotes[index] = q->string_; + } + sjson_foreach(q, xs) + { + int index = (int)strtoll(q->key, nullptr, 10); + exquotes[index] = q->string_; + } + sjson_destroy_context(ctx); +} + +void Quotes::WriteToSavegame() +{ + sjson_context* ctx = sjson_create_context(0, 0, NULL); + if (!ctx) + { + return; + } + sjson_node* root = sjson_mkobject(ctx); + sjson_node* qs = sjson_mkobject(ctx); + sjson_node* xs = sjson_mkobject(ctx); + + for (unsigned i = 0; i < MAXQUOTES; i++) + { + if (quotes[i].IsNotEmpty()) + { + char buff[10]; + snprintf(buff, 10, "%d", i); + sjson_append_member(ctx, qs, buff, sjson_mkstring(ctx, quotes[i])); + } + if (exquotes[i].IsNotEmpty()) + { + char buff[10]; + snprintf(buff, 10, "%d", i); + sjson_append_member(ctx, xs, buff, sjson_mkstring(ctx, exquotes[i])); + } + } + sjson_append_member(ctx, root, "quotes", qs); + sjson_append_member(ctx, root, "exquotes", xs); + + char* encoded = sjson_stringify(ctx, root, " "); + FileWriter* fil = WriteSavegameChunk("quotes.json"); + if (!fil) + { + sjson_destroy_context(ctx); + return; + } + + fil->Write(encoded, strlen(encoded)); + + sjson_free_string(ctx, encoded); + sjson_destroy_context(ctx); + return; + +} + +Quotes quoteMgr; diff --git a/source/common/savegamehelp.cpp b/source/common/savegamehelp.cpp index 7061245ff..59d7968b3 100644 --- a/source/common/savegamehelp.cpp +++ b/source/common/savegamehelp.cpp @@ -44,6 +44,7 @@ #include "statistics.h" #include "secrets.h" #include "s_music.h" +#include "quotemgr.h" static CompositeSavegameWriter savewriter; static FResourceFile *savereader; @@ -79,6 +80,7 @@ bool OpenSaveGameForRead(const char *name) ReadStatistics(); SECRET_Load(); MUS_Restore(); + quoteMgr.ReadFromSavegame(); } return savereader != nullptr; @@ -155,6 +157,7 @@ void G_WriteSaveHeader(const char *name, const char*mapname, const char *maptitl SaveStatistics(); SECRET_Save(); MUS_Save(); + quoteMgr.WriteToSavegame(); } //============================================================================= diff --git a/source/duke3d/src/cheats.cpp b/source/duke3d/src/cheats.cpp index 13feb226d..0559ed960 100644 --- a/source/duke3d/src/cheats.cpp +++ b/source/duke3d/src/cheats.cpp @@ -499,7 +499,7 @@ void G_DoCheats(void) } else { - Bstrcpy(apStrings[QUOTE_RESERVED4], "Come Get Some!"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Come Get Some!"); S_PlaySound(DUKE_GETWEAPON2); P_DoQuote(QUOTE_RESERVED4, pPlayer); @@ -654,7 +654,7 @@ void G_DoCheats(void) case CHEAT_TODD: if (NAM) { - Bstrcpy(apStrings[QUOTE_RESERVED4], CheatDescriptions[CHEAT_TODD]); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, CheatDescriptions[CHEAT_TODD]); P_DoQuote(QUOTE_RESERVED4, pPlayer); } else @@ -690,7 +690,7 @@ void G_DoCheats(void) if (++g_noEnemies == 3) g_noEnemies = 0; - Bsprintf(apStrings[QUOTE_RESERVED4], "Monsters: %s", s[g_noEnemies]); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Monsters: %s", s[g_noEnemies]); P_DoQuote(QUOTE_RESERVED4, pPlayer); end_cheat(pPlayer); diff --git a/source/duke3d/src/demo.cpp b/source/duke3d/src/demo.cpp index 9ac934183..b06aa304b 100644 --- a/source/duke3d/src/demo.cpp +++ b/source/duke3d/src/demo.cpp @@ -143,7 +143,7 @@ void G_OpenDemoWrite(void) if ((g_player[myconnectindex].ps->gm&MODE_GAME) && g_player[myconnectindex].ps->dead_flag) { - Bstrcpy(apStrings[QUOTE_RESERVED4], "CANNOT START DEMO RECORDING WHEN DEAD!"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "CANNOT START DEMO RECORDING WHEN DEAD!"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); ud.recstat = m_recstat = 0; return; @@ -180,7 +180,7 @@ void G_OpenDemoWrite(void) delete g_demo_filePtr; g_demo_filePtr = nullptr; error_wopen_demo: - Bstrcpy(apStrings[QUOTE_RESERVED4], "FAILED STARTING DEMO RECORDING. SEE CONSOLE FOR DETAILS."); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "FAILED STARTING DEMO RECORDING. SEE CONSOLE FOR DETAILS."); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); ud.recstat = m_recstat = 0; return; @@ -190,7 +190,7 @@ error_wopen_demo: demorec_diffs = demorec_diffs_cvar; demorec_difftics = demorec_difftics_cvar; - Bsprintf(apStrings[QUOTE_RESERVED4], "DEMO %d RECORDING STARTED", demonum-1); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "DEMO %d RECORDING STARTED", demonum-1); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); ud.reccnt = 0; @@ -285,7 +285,7 @@ void G_CloseDemoWrite(void) sv_freemem(); - Bstrcpy(apStrings[QUOTE_RESERVED4], "DEMO RECORDING STOPPED"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "DEMO RECORDING STOPPED"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); } #if KRANDDEBUG diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index f5737af6e..a33cbc81e 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -5396,12 +5396,6 @@ static void G_Cleanup(void) G_FreeMapState(i); } - for (i=MAXQUOTES-1; i>=0; i--) - { - Xfree(apStrings[i]); - Xfree(apXStrings[i]); - } - for (i=MAXPLAYERS-1; i>=0; i--) { Xfree(g_player[i].ps); @@ -6347,7 +6341,7 @@ int G_DoMoveThings(void) { if (ldist(&sprite[pPlayer->i], &sprite[hitData.sprite]) < 9216) { - Bsprintf(apStrings[QUOTE_RESERVED3], "%s", &g_player[playerNum].user_name[0]); + quoteMgr.InitializeQuote(QUOTE_RESERVED3, "%s", &g_player[playerNum].user_name[0]); pPlayer->fta = 12, pPlayer->ftq = QUOTE_RESERVED3; } } diff --git a/source/duke3d/src/gamedef.cpp b/source/duke3d/src/gamedef.cpp index ee02f33d3..ff5a202a2 100644 --- a/source/duke3d/src/gamedef.cpp +++ b/source/duke3d/src/gamedef.cpp @@ -2166,129 +2166,31 @@ LUNATIC_EXTERN void C_DefineProjectile(int32_t j, int32_t what, int32_t val) int32_t C_AllocQuote(int32_t qnum) { Bassert((unsigned)qnum < MAXQUOTES); - - if (apStrings[qnum] == NULL) - { - apStrings[qnum] = (char *)Xcalloc(MAXQUOTELEN,sizeof(uint8_t)); - return 1; - } - - return 0; + // No longer needed, quotes are now FStrings. + return 1; } -#ifndef EDUKE32_TOUCH_DEVICES -static void C_ReplaceQuoteSubstring(const size_t q, char const * const query, char const * const replacement) -{ - size_t querylength = Bstrlen(query); - - for (bssize_t i = MAXQUOTELEN - querylength - 2; i >= 0; i--) - if (Bstrncmp(&apStrings[q][i], query, querylength) == 0) - { - Bmemset(tempbuf, 0, sizeof(tempbuf)); - Bstrncpy(tempbuf, apStrings[q], i); - Bstrcat(tempbuf, replacement); - Bstrcat(tempbuf, &apStrings[q][i + querylength]); - Bstrncpy(apStrings[q], tempbuf, MAXQUOTELEN - 1); - i = MAXQUOTELEN - querylength - 2; - } -} -#endif - void C_InitQuotes(void) { - for (int i = 0; i < 128; i++) C_AllocQuote(i); - -#ifdef EDUKE32_TOUCH_DEVICES - apStrings[QUOTE_DEAD] = 0; -#else auto openkeys = Bindings.GetKeysForCommand("+open"); if (openkeys.Size()) { auto OpenGameFunc = C_NameKeys(openkeys.Data(), 1); - C_ReplaceQuoteSubstring(QUOTE_DEAD, "SPACE", OpenGameFunc); - C_ReplaceQuoteSubstring(QUOTE_DEAD, "OPEN", OpenGameFunc); - C_ReplaceQuoteSubstring(QUOTE_DEAD, "USE", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "SPACE", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "OPEN", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "USE", OpenGameFunc); } -#endif - // most of these are based on Blood, obviously - const char *PlayerObituaries[] = - { - "^02%s^02 beat %s^02 like a cur", - "^02%s^02 broke %s", - "^02%s^02 body bagged %s", - "^02%s^02 boned %s^02 like a fish", - "^02%s^02 castrated %s", - "^02%s^02 creamed %s", - "^02%s^02 crushed %s", - "^02%s^02 destroyed %s", - "^02%s^02 diced %s", - "^02%s^02 disemboweled %s", - "^02%s^02 erased %s", - "^02%s^02 eviscerated %s", - "^02%s^02 flailed %s", - "^02%s^02 flattened %s", - "^02%s^02 gave AnAl MaDnEsS to %s", - "^02%s^02 gave %s^02 Anal Justice", - "^02%s^02 hosed %s", - "^02%s^02 hurt %s^02 real bad", - "^02%s^02 killed %s", - "^02%s^02 made dog meat out of %s", - "^02%s^02 made mincemeat out of %s", - "^02%s^02 manhandled %s", - "^02%s^02 massacred %s", - "^02%s^02 mutilated %s", - "^02%s^02 murdered %s", - "^02%s^02 neutered %s", - "^02%s^02 punted %s", - "^02%s^02 reamed %s", - "^02%s^02 ripped %s^02 a new orifice", - "^02%s^02 rocked %s", - "^02%s^02 sent %s^02 to hell", - "^02%s^02 shredded %s", - "^02%s^02 slashed %s", - "^02%s^02 slaughtered %s", - "^02%s^02 sliced %s", - "^02%s^02 smacked %s around", - "^02%s^02 smashed %s", - "^02%s^02 snuffed %s", - "^02%s^02 sodomized %s", - "^02%s^02 splattered %s", - "^02%s^02 sprayed %s", - "^02%s^02 squashed %s", - "^02%s^02 throttled %s", - "^02%s^02 toasted %s", - "^02%s^02 vented %s", - "^02%s^02 ventilated %s", - "^02%s^02 wasted %s", - "^02%s^02 wrecked %s", - }; - - const char *PlayerSelfObituaries[] = - { - "^02%s^02 is excrement", - "^02%s^02 is hamburger", - "^02%s^02 suffered scrotum separation", - "^02%s^02 volunteered for population control", - "^02%s^02 has suicided", - "^02%s^02 bled out", - }; - - EDUKE32_STATIC_ASSERT(OBITQUOTEINDEX + ARRAY_SIZE(PlayerObituaries)-1 < MAXQUOTES); - EDUKE32_STATIC_ASSERT(SUICIDEQUOTEINDEX + ARRAY_SIZE(PlayerSelfObituaries)-1 < MAXQUOTES); - - g_numObituaries = ARRAY_SIZE(PlayerObituaries); + g_numObituaries = 48; for (bssize_t i = g_numObituaries - 1; i >= 0; i--) { - if (C_AllocQuote(i + OBITQUOTEINDEX)) - Bstrcpy(apStrings[i + OBITQUOTEINDEX], PlayerObituaries[i]); + quoteMgr.FormatQuote(i + OBITQUOTEINDEX, "$TXT_OBITUARY%d", i + 1); } - g_numSelfObituaries = ARRAY_SIZE(PlayerSelfObituaries); + g_numSelfObituaries = 6; for (bssize_t i = g_numSelfObituaries - 1; i >= 0; i--) { - if (C_AllocQuote(i + SUICIDEQUOTEINDEX)) - Bstrcpy(apStrings[i + SUICIDEQUOTEINDEX], PlayerSelfObituaries[i]); + quoteMgr.FormatQuote(i + SUICIDEQUOTEINDEX, "$TXT_SELFOBIT%d", i + 1); } } @@ -3167,7 +3069,7 @@ DO_DEFSTATE: case CON_QUOTE: C_GetNextValue(LABEL_DEFINE); - if (EDUKE32_PREDICT_FALSE(((unsigned)g_scriptPtr[-1] >= MAXQUOTES) || apStrings[g_scriptPtr[-1]] == NULL)) + if (EDUKE32_PREDICT_FALSE(((unsigned)g_scriptPtr[-1] >= MAXQUOTES))) { g_errorCnt++; C_ReportError(-1); @@ -5329,6 +5231,7 @@ repeatcase: case CON_DEFINEQUOTE: case CON_REDEFINEQUOTE: + { if (tw == CON_DEFINEQUOTE) { g_scriptPtr--; @@ -5353,53 +5256,27 @@ repeatcase: if (tw == CON_DEFINEQUOTE) g_scriptPtr--; - i = 0; - scriptSkipSpaces(); - if (tw == CON_REDEFINEQUOTE) - { - if (apXStrings[g_numXStrings] == NULL) - apXStrings[g_numXStrings] = (char *)Xcalloc(MAXQUOTELEN,sizeof(uint8_t)); - } - + TArray buffer; while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) { - /* - if (*textptr == '%' && *(textptr+1) == 's') - { - initprintf("%s:%d: error: quote text contains string identifier.\n",g_szScriptFileName,g_lineNumber); - g_numCompilerErrors++; - while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++; - break; - } - */ - if (tw == CON_DEFINEQUOTE) - *(apStrings[k]+i) = *textptr; - else - *(apXStrings[g_numXStrings]+i) = *textptr; - textptr++,i++; - if (EDUKE32_PREDICT_FALSE(i >= MAXQUOTELEN-1)) - { - initprintf("%s:%d: warning: truncating quote text to %d characters.\n",g_scriptFileName,g_lineNumber,MAXQUOTELEN-1); - g_warningCnt++; - scriptSkipLine(); - break; - } + buffer.Push(*textptr); + textptr++; } + buffer.Push(0); + if (tw == CON_DEFINEQUOTE) + quoteMgr.InitializeQuote(k, buffer.Data(), true); + else + quoteMgr.InitializeExQuote(k, buffer.Data(), true); - if (tw == CON_DEFINEQUOTE) + + if (tw != CON_DEFINEQUOTE) { - if ((unsigned)k < MAXQUOTES) - *(apStrings[k]+i) = '\0'; - } - else - { - *(apXStrings[g_numXStrings]+i) = '\0'; scriptWriteValue(g_numXStrings++); } continue; - + } case CON_DEFINECHEATDESCRIPTION: g_scriptPtr--; @@ -5981,14 +5858,7 @@ void C_PrintStats(void) MAXSPRITES * sizeof(spritetype)/(1<<6)), g_gameVarCount, MAXGAMEVARS, g_gameArrayCount, MAXGAMEARRAYS); - int cnt = g_numXStrings; - - for (auto &ptr : apStrings) - if (ptr) - cnt++; - - if (cnt) initprintf("%d strings, ", cnt); - cnt = 0; + int cnt = 0; for (auto & apScriptEvent : apScriptEvents) if (apScriptEvent) diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index 61ae6e792..c457b4223 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "version.h" #include "menu/menu.h" #include "c_dispatch.h" +#include "quotemgr.h" #include "debugbreak.h" extern bool rotatesprite_2doverride; @@ -2772,7 +2773,7 @@ badindex: int const strIndex = *insptr++; int const XstrIndex = *insptr++; - Bstrcpy(apStrings[strIndex], apXStrings[XstrIndex]); + quoteMgr.CopyExQuote(strIndex, XstrIndex); dispatch(); } @@ -3547,9 +3548,9 @@ badindex: int const gameVar = *insptr++; int const quoteNum = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)quoteNum < MAXQUOTES && apStrings[quoteNum], "invalid quote %d\n", quoteNum); + VM_ASSERT((unsigned)quoteNum < MAXQUOTES, "invalid quote %d\n", quoteNum); - Gv_SetVar(gameVar, Bstrlen(apStrings[quoteNum])); + Gv_SetVar(gameVar, strlen(quoteMgr.GetQuote(quoteNum))); dispatch(); } @@ -3572,11 +3573,11 @@ badindex: if (EDUKE32_PREDICT_FALSE(v.tileNum < 0 || v.tileNum + 127 >= MAXTILES)) CON_ERRPRINTF("invalid base tilenum %d\n", v.tileNum); - else if (EDUKE32_PREDICT_FALSE((unsigned)v.quoteNum >= MAXQUOTES || apStrings[v.quoteNum] == NULL)) + else if ((unsigned)v.quoteNum >= MAXQUOTES) CON_ERRPRINTF("invalid quote %d\n", v.quoteNum); else { - vec2_t dim = G_ScreenTextSize(v.tileNum, v.vect.x, v.vect.y, v.vect.z, v.blockAngle, apStrings[v.quoteNum], 2 | v.orientation, + vec2_t dim = G_ScreenTextSize(v.tileNum, v.vect.x, v.vect.y, v.vect.z, v.blockAngle, quoteMgr.GetQuote(v.quoteNum), 2 | v.orientation, v.offset.x, v.offset.y, v.between.x, v.between.y, v.f, v.bound[0].x, v.bound[0].y, v.bound[1].x, v.bound[1].y); @@ -3668,12 +3669,12 @@ badindex: int const quoteIndex = Gv_GetVar(*insptr++); int const gameFunc = Gv_GetVar(*insptr++); int funcPos = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)quoteIndex < MAXQUOTES && apStrings[quoteIndex], "invalid quote %d\n", quoteIndex); + VM_ASSERT((unsigned)quoteIndex < MAXQUOTES, "invalid quote %d\n", quoteIndex); VM_ASSERT((unsigned)gameFunc < NUMGAMEFUNCTIONS, "invalid function %d\n", gameFunc); auto bindings = Bindings.GetKeysForCommand(C_CON_GetButtonFunc(gameFunc)); if ((unsigned)funcPos >= bindings.Size()) funcPos = 0; - Bstrcpy(apStrings[quoteIndex], KB_ScanCodeToString(bindings[funcPos])); + quoteMgr.InitializeQuote(quoteIndex, KB_ScanCodeToString(bindings[funcPos])); dispatch(); } @@ -3683,14 +3684,11 @@ badindex: int const quoteIndex = Gv_GetVar(*insptr++); int const gameFunc = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)quoteIndex < MAXQUOTES && apStrings[quoteIndex], "invalid quote %d\n", quoteIndex); + VM_ASSERT((unsigned)quoteIndex < MAXQUOTES, "invalid quote %d\n", quoteIndex); VM_ASSERT((unsigned)gameFunc < NUMGAMEFUNCTIONS, "invalid function %d\n", gameFunc); - static char const s_KeyboardFormat[] = "[%s]"; - static char const s_JoystickFormat[] = "(%s)"; - auto binding = C_CON_GetBoundKeyForLastInput(gameFunc); - if (binding.Len()) snprintf(apStrings[quoteIndex], MAXQUOTELEN, "(%s)", binding.GetChars()); + if (binding.Len()) quoteMgr.FormatQuote(quoteIndex, "(%s)", binding.GetChars()); dispatch(); } @@ -3703,17 +3701,11 @@ badindex: } v; Gv_FillWithVars(v); - if (EDUKE32_PREDICT_FALSE((unsigned)v.outputQuote >= MAXQUOTES || apStrings[v.outputQuote] == NULL + if (EDUKE32_PREDICT_FALSE((unsigned)v.outputQuote >= MAXQUOTES || (unsigned)v.inputQuote >= MAXQUOTES - || apStrings[v.inputQuote] == NULL)) + )) { - CON_ERRPRINTF("invalid quote %d\n", apStrings[v.outputQuote] ? v.inputQuote : v.outputQuote); - abort_after_error(); - } - - if (EDUKE32_PREDICT_FALSE((unsigned)v.quotePos >= MAXQUOTELEN)) - { - CON_ERRPRINTF("invalid position %d\n", v.quotePos); + CON_ERRPRINTF("invalid quote %d\n", v.inputQuote >= MAXQUOTES ? v.inputQuote : v.outputQuote); abort_after_error(); } @@ -3723,18 +3715,18 @@ badindex: abort_after_error(); } - char * pOutput = apStrings[v.outputQuote]; - char const *pInput = apStrings[v.inputQuote]; + TArray output; + char const *pInput = quoteMgr.GetQuote(v.inputQuote); while (*pInput && v.quotePos--) pInput++; - while ((*pOutput = *pInput) && v.quoteLength--) + while ((*pInput) && v.quoteLength--) { - pOutput++; + output.Push(*pInput); pInput++; } - *pOutput = '\0'; - + output.Push(0); + quoteMgr.InitializeQuote(v.outputQuote, output.Data()); dispatch(); } @@ -3745,13 +3737,7 @@ badindex: int const quote2 = Gv_GetVar(*insptr++); int const gameVar = *insptr++; - if (EDUKE32_PREDICT_FALSE(apStrings[quote1] == NULL || apStrings[quote2] == NULL)) - { - CON_ERRPRINTF("null quote %d\n", apStrings[quote1] ? quote2 : quote1); - abort_after_error(); - } - - Gv_SetVar(gameVar, strcmp(apStrings[quote1], apStrings[quote2])); + Gv_SetVar(gameVar, strcmp(quoteMgr.GetQuote(quote1), quoteMgr.GetQuote(quote2))); dispatch(); } @@ -3775,14 +3761,14 @@ badindex: switch (VM_DECODE_INST(tw)) { case CON_GETPNAME: - VM_ASSERT((unsigned)q < MAXQUOTES && apStrings[q], "invalid quote %d\n", q); - if (g_player[j].user_name[0]) - Bstrcpy(apStrings[q], g_player[j].user_name); - else - Bsprintf(apStrings[q], "%d", j); + VM_ASSERT((unsigned)q < MAXQUOTES, "invalid quote %d\n", q); + if (g_player[j].user_name[0]) + quoteMgr.InitializeQuote(q, g_player[j].user_name); + else + quoteMgr.FormatQuote(q, "%d", j); break; case CON_QGETSYSSTR: - VM_ASSERT((unsigned)q < MAXQUOTES && apStrings[q], "invalid quote %d\n", q); + VM_ASSERT((unsigned)q < MAXQUOTES, "invalid quote %d\n", q); switch (j) { case STR_MAPNAME: @@ -3790,7 +3776,7 @@ badindex: { if (G_HaveUserMap()) { - snprintf(apStrings[q], MAXQUOTELEN, "%s", boardfilename); + quoteMgr.FormatQuote(q, "%s", boardfilename); break; } @@ -3812,22 +3798,22 @@ badindex: abort_after_error(); } - Bstrcpy(apStrings[q], j == STR_MAPNAME ? g_mapInfo[levelNum].name : g_mapInfo[levelNum].filename); + quoteMgr.InitializeQuote(q, j == STR_MAPNAME ? g_mapInfo[levelNum].name : g_mapInfo[levelNum].filename); break; } case STR_PLAYERNAME: VM_ASSERT((unsigned)vm.playerNum < (unsigned)g_mostConcurrentPlayers, "invalid player %d\n", vm.playerNum); - Bstrcpy(apStrings[q], g_player[vm.playerNum].user_name); + quoteMgr.InitializeQuote(q, g_player[vm.playerNum].user_name); break; case STR_VERSION: Bsprintf(tempbuf, HEAD2 " %s", GetGitDescription()); - Bstrcpy(apStrings[q], tempbuf); + quoteMgr.InitializeQuote(q, tempbuf); break; - case STR_GAMETYPE: Bstrcpy(apStrings[q], g_gametypeNames[ud.coop]); break; + case STR_GAMETYPE: quoteMgr.InitializeQuote(q, g_gametypeNames[ud.coop]); break; case STR_VOLUMENAME: if (G_HaveUserMap()) { - apStrings[q][0] = '\0'; + quoteMgr.InitializeQuote(q, ""); break; } @@ -3837,36 +3823,28 @@ badindex: abort_after_error(); } // length is no longer limited so a check is needed. - Bstrncpy(apStrings[q], gVolumeNames[ud.volume_number], MAXQUOTELEN); - apStrings[q][MAXQUOTELEN-1] = 0; + quoteMgr.InitializeQuote(q, gVolumeNames[ud.volume_number]); break; - case STR_YOURTIME: Bstrcpy(apStrings[q], G_PrintYourTime()); break; - case STR_PARTIME: Bstrcpy(apStrings[q], G_PrintParTime()); break; - case STR_DESIGNERTIME: Bstrcpy(apStrings[q], G_PrintDesignerTime()); break; - case STR_BESTTIME: Bstrcpy(apStrings[q], G_PrintBestTime()); break; - case STR_USERMAPFILENAME: snprintf(apStrings[q], MAXQUOTELEN, "%s", boardfilename); break; + case STR_YOURTIME: quoteMgr.InitializeQuote(q, G_PrintYourTime()); break; + case STR_PARTIME: quoteMgr.InitializeQuote(q, G_PrintParTime()); break; + case STR_DESIGNERTIME: quoteMgr.InitializeQuote(q, G_PrintDesignerTime()); break; + case STR_BESTTIME: quoteMgr.InitializeQuote(q, G_PrintBestTime()); break; + case STR_USERMAPFILENAME: quoteMgr.FormatQuote(q, "%s", boardfilename); break; default: CON_ERRPRINTF("invalid string index %d or %d\n", q, j); abort_after_error(); } break; case CON_QSTRCAT: - if (EDUKE32_PREDICT_FALSE(apStrings[q] == NULL || apStrings[j] == NULL)) - goto nullquote; - Bstrncat(apStrings[q], apStrings[j], (MAXQUOTELEN - 1) - Bstrlen(apStrings[q])); + quoteMgr.AppendQuote(q, j); break; case CON_QSTRNCAT: - if (EDUKE32_PREDICT_FALSE(apStrings[q] == NULL || apStrings[j] == NULL)) - goto nullquote; - Bstrncat(apStrings[q], apStrings[j], Gv_GetVar(*insptr++)); + quoteMgr.AppendQuote(q, j, Gv_GetVar(*insptr++)); break; case CON_QSTRCPY: - if (EDUKE32_PREDICT_FALSE(apStrings[q] == NULL || apStrings[j] == NULL)) - goto nullquote; - if (q != j) - Bstrcpy(apStrings[q], apStrings[j]); + if (q != j) + quoteMgr.CopyQuote(q, j); break; default: - nullquote: - CON_ERRPRINTF("invalid quote %d\n", apStrings[q] ? j : q); + CON_ERRPRINTF("invalid quote %d\n", q < MAXQUOTES? j : q); abort_after_error(); } dispatch(); @@ -4188,18 +4166,18 @@ badindex: { int const nQuote = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)nQuote < MAXQUOTES && apStrings[nQuote], "invalid quote %d\n", nQuote); + VM_ASSERT((unsigned)nQuote < MAXQUOTES, "invalid quote %d\n", nQuote); if (VM_DECODE_INST(tw) == CON_IFCUTSCENE) { insptr--; - VM_CONDITIONAL(g_animPtr == Anim_Find(apStrings[nQuote])); + VM_CONDITIONAL(g_animPtr == Anim_Find(quoteMgr.GetQuote(nQuote))); dispatch(); } tw = vm.pPlayer->palette; I_ClearAllInput(); - Anim_Play(apStrings[nQuote]); + Anim_Play(quoteMgr.GetQuote(nQuote)); P_SetGamePalette(vm.pPlayer, tw, 2 + 16); dispatch(); } @@ -4342,9 +4320,9 @@ badindex: abort_after_error(); } - VM_ASSERT((unsigned)v.nQuote < MAXQUOTES && apStrings[v.nQuote], "invalid quote %d\n", v.nQuote); + VM_ASSERT((unsigned)v.nQuote < MAXQUOTES, "invalid quote %d\n", v.nQuote); - G_PrintGameText(v.tilenum, v.pos.x >> 1, v.pos.y, apStrings[v.nQuote], v.shade, v.pal, v.orientation & (ROTATESPRITE_MAX - 1), + G_PrintGameText(v.tilenum, v.pos.x >> 1, v.pos.y, quoteMgr.GetQuote(v.nQuote), v.shade, v.pal, v.orientation & (ROTATESPRITE_MAX - 1), v.bound[0].x, v.bound[0].y, v.bound[1].x, v.bound[1].y, z, 0); dispatch(); } @@ -4386,9 +4364,9 @@ badindex: } v; Gv_FillWithVars(v); - VM_ASSERT((unsigned)v.nQuote < MAXQUOTES && apStrings[v.nQuote], "invalid quote %d\n", v.nQuote); + VM_ASSERT((unsigned)v.nQuote < MAXQUOTES, "invalid quote %d\n", v.nQuote); - minitextshade(v.pos.x, v.pos.y, apStrings[v.nQuote], v.shade, v.pal, 2 + 8 + 16); + minitextshade(v.pos.x, v.pos.y, quoteMgr.GetQuote(v.nQuote), v.shade, v.pal, 2 + 8 + 16); dispatch(); } @@ -4412,9 +4390,9 @@ badindex: abort_after_error(); } - VM_ASSERT((unsigned)v.nQuote < MAXQUOTES && apStrings[v.nQuote], "invalid quote %d\n", v.nQuote); + VM_ASSERT((unsigned)v.nQuote < MAXQUOTES, "invalid quote %d\n", v.nQuote); - G_ScreenText(v.tilenum, v.v.x, v.v.y, v.v.z, v.blockangle, v.charangle, apStrings[v.nQuote], v.shade, v.pal, + G_ScreenText(v.tilenum, v.v.x, v.v.y, v.v.z, v.blockangle, v.charangle, quoteMgr.GetQuote(v.nQuote), v.shade, v.pal, 2 | (v.orientation & (ROTATESPRITE_MAX - 1)), v.alpha, v.spacing.x, v.spacing.y, v.between.x, v.between.y, v.nFlags, v.bound[0].x, v.bound[0].y, v.bound[1].x, v.bound[1].y); dispatch(); @@ -4814,9 +4792,9 @@ badindex: insptr++; int const nQuote = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)nQuote < MAXQUOTES && apStrings[nQuote], "invalid quote %d\n", nQuote); + VM_ASSERT((unsigned)nQuote < MAXQUOTES, "invalid quote %d\n", nQuote); - //communityapiUnlockAchievement(apStrings[nQuote]); + //communityapiUnlockAchievement(quoteMgr.GetQuote(v.nQuote)); dispatch(); } @@ -4826,9 +4804,9 @@ badindex: int const nQuote = Gv_GetVar(*insptr++); int const value = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)nQuote < MAXQUOTES && apStrings[nQuote], "invalid quote %d\n", nQuote); + VM_ASSERT((unsigned)nQuote < MAXQUOTES, "invalid quote %d\n", nQuote); - //communityapiSetStat(apStrings[nQuote], value); + //communityapiSetStat(quoteMgr.GetQuote(nQuote), value); dispatch(); } @@ -5103,16 +5081,10 @@ badindex: int const outputQuote = Gv_GetVar(*insptr++); int const inputQuote = Gv_GetVar(*insptr++); - if (EDUKE32_PREDICT_FALSE(apStrings[inputQuote] == NULL || apStrings[outputQuote] == NULL)) - { - CON_ERRPRINTF("null quote %d\n", apStrings[inputQuote] ? outputQuote : inputQuote); - abort_after_error(); - } - - auto &inBuf = apStrings[inputQuote]; + auto inBuf = quoteMgr.GetQuote(inputQuote); int32_t arg[32]; - char outBuf[MAXQUOTELEN]; + TArray outBuf; int const quoteLen = Bstrlen(inBuf); @@ -5131,8 +5103,8 @@ badindex: do { - while (inputPos < quoteLen && outputPos < MAXQUOTELEN && inBuf[inputPos] != '%') - outBuf[outputPos++] = inBuf[inputPos++]; + while (inputPos < quoteLen && inBuf[inputPos] != '%') + outBuf.Push(inBuf[inputPos++]); if (inBuf[inputPos] == '%') { @@ -5143,8 +5115,8 @@ badindex: if (inBuf[inputPos + 1] != 'd') { // write the % and l - outBuf[outputPos++] = inBuf[inputPos - 1]; - outBuf[outputPos++] = inBuf[inputPos++]; + outBuf.Push(inBuf[inputPos - 1]); + outBuf.Push(inBuf[inputPos++]); break; } inputPos++; @@ -5158,7 +5130,8 @@ badindex: Bsprintf(buf, "%d", arg[argIdx++]); int const bufLen = Bstrlen(buf); - Bmemcpy(&outBuf[outputPos], buf, bufLen); + outputPos = outBuf.Reserve(bufLen); + memcpy(&outBuf[outputPos], buf, bufLen); outputPos += bufLen; inputPos++; } @@ -5169,22 +5142,24 @@ badindex: if (argIdx >= numArgs) goto finish_qsprintf; - int const argLen = Bstrlen(apStrings[arg[argIdx]]); + auto quoteArg = quoteMgr.GetQuote(arg[argIdx]); + int const argLen = (int)strlen(quoteArg); - Bmemcpy(&outBuf[outputPos], apStrings[arg[argIdx]], argLen); + outputPos = outBuf.Reserve(argLen); + memcpy(&outBuf[outputPos], quoteArg, argLen); outputPos += argLen; argIdx++; inputPos++; } break; - default: outBuf[outputPos++] = inBuf[inputPos - 1]; break; + default: outBuf.Push(inBuf[inputPos - 1]); break; } } - } while (inputPos < quoteLen && outputPos < MAXQUOTELEN); + } while (inputPos < quoteLen); finish_qsprintf: - outBuf[outputPos] = '\0'; - Bstrncpyz(apStrings[outputQuote], outBuf, MAXQUOTELEN); + outBuf.Push(0); + quoteMgr.InitializeQuote(outputQuote, outBuf.Data()); dispatch(); } @@ -5600,9 +5575,9 @@ badindex: int const arrayNum = *insptr++; int const quoteFilename = *insptr++; - VM_ASSERT((unsigned)quoteFilename < MAXQUOTES && apStrings[quoteFilename], "invalid quote %d\n", quoteFilename); + VM_ASSERT((unsigned)quoteFilename < MAXQUOTES, "invalid quote %d\n", quoteFilename); FStringf IniSection("%s.UserStrings", LumpFilter.GetChars()); - auto IniKey = apStrings[quoteFilename]; + auto IniKey = quoteMgr.GetQuote(quoteFilename); if (!GameConfig->SetSection(IniSection)) { dispatch(); @@ -5676,12 +5651,12 @@ badindex: int const arrayNum = *insptr++; int const quoteFilename = *insptr++; - VM_ASSERT((unsigned)quoteFilename < MAXQUOTES && apStrings[quoteFilename], "invalid quote %d\n", quoteFilename); + VM_ASSERT((unsigned)quoteFilename < MAXQUOTES, "invalid quote %d\n", quoteFilename); // No, we are not writing stuff to an arbitrary file on the hard drive! This is a first grade exploit for doing serious damage. // Instead, encode the data as BASE64 and write it to the config file, // which doesn't create a wide open door for exploits. FStringf IniSection("%s.UserStrings", LumpFilter.GetChars()); - auto IniKey = apStrings[quoteFilename]; + auto IniKey = quoteMgr.GetQuote(quoteFilename); BufferWriter bw; switch (aGameArrays[arrayNum].flags & GAMEARRAY_SIZE_MASK) @@ -6198,18 +6173,18 @@ badindex: insptr++; tw = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)tw < MAXQUOTES && apStrings[tw], "invalid quote %d\n", (int)tw); + VM_ASSERT((unsigned)tw < MAXQUOTES, "invalid quote %d\n", (int)tw); - G_AddUserQuote(apStrings[tw]); + G_AddUserQuote(quoteMgr.GetQuote(tw)); dispatch(); vInstruction(CON_ECHO): insptr++; tw = Gv_GetVar(*insptr++); - VM_ASSERT((unsigned)tw < MAXQUOTES && apStrings[tw], "invalid quote %d\n", (int)tw); + VM_ASSERT((unsigned)tw < MAXQUOTES, "invalid quote %d\n", (int)tw); - OSD_Printf("%s\n", apStrings[tw]); + OSD_Printf("%s\n", quoteMgr.GetQuote(tw)); dispatch(); vInstruction(CON_RESPAWNHITAG): diff --git a/source/duke3d/src/global.h b/source/duke3d/src/global.h index 9acb60b9f..23657c87b 100644 --- a/source/duke3d/src/global.h +++ b/source/duke3d/src/global.h @@ -67,7 +67,6 @@ G_EXTERN actor_t actor[MAXSPRITES]; // g_tile: tile-specific data THAT DOES NOT CHANGE during the course of a game G_EXTERN tiledata_t g_tile[MAXTILES]; G_EXTERN animwalltype animwall[MAXANIMWALLS]; -G_EXTERN char *apStrings[MAXQUOTES],*apXStrings[MAXQUOTES]; G_EXTERN char *label; G_EXTERN int32_t g_musicIndex; G_EXTERN char g_loadFromGroupOnly; diff --git a/source/duke3d/src/network.cpp b/source/duke3d/src/network.cpp index f0864e9c1..597dc95ba 100644 --- a/source/duke3d/src/network.cpp +++ b/source/duke3d/src/network.cpp @@ -1517,7 +1517,7 @@ static void P_RemovePlayer(int32_t p) voting = -1; } - Bstrcpy(apStrings[QUOTE_RESERVED2],recbuf); + quoteMgr.InitializeQuote(QUOTE_RESERVED2 ,recbuf); g_player[myconnectindex].ps->ftq = QUOTE_RESERVED2; g_player[myconnectindex].ps->fta = 180; } diff --git a/source/duke3d/src/player.cpp b/source/duke3d/src/player.cpp index 5442cb8ed..2771ef572 100644 --- a/source/duke3d/src/player.cpp +++ b/source/duke3d/src/player.cpp @@ -3768,18 +3768,18 @@ void P_FragPlayer(int playerNum) if (playerNum == screenpeek) { - Bsprintf(apStrings[QUOTE_RESERVED], "Killed by %s", &g_player[pPlayer->frag_ps].user_name[0]); + quoteMgr.FormatQuote(QUOTE_RESERVED, "Killed by %s", &g_player[pPlayer->frag_ps].user_name[0]); P_DoQuote(QUOTE_RESERVED, pPlayer); } else { - Bsprintf(apStrings[QUOTE_RESERVED2], "Killed %s", &g_player[playerNum].user_name[0]); + quoteMgr.FormatQuote(QUOTE_RESERVED2, "Killed %s", &g_player[playerNum].user_name[0]); P_DoQuote(QUOTE_RESERVED2, g_player[pPlayer->frag_ps].ps); } if (cl_obituaries) { - Bsprintf(tempbuf, apStrings[OBITQUOTEINDEX + (krand() % g_numObituaries)], + Bsprintf(tempbuf, quoteMgr.GetQuote(OBITQUOTEINDEX + (krand() % g_numObituaries)), &g_player[pPlayer->frag_ps].user_name[0], &g_player[playerNum].user_name[0]); G_AddUserQuote(tempbuf); } @@ -3792,14 +3792,14 @@ void P_FragPlayer(int playerNum) { pPlayer->fraggedself++; if ((unsigned)pPlayer->wackedbyactor < MAXTILES && A_CheckEnemyTile(sprite[pPlayer->wackedbyactor].picnum)) - Bsprintf(tempbuf, apStrings[OBITQUOTEINDEX + (krand() % g_numObituaries)], "A monster", + Bsprintf(tempbuf, quoteMgr.GetQuote(OBITQUOTEINDEX + (krand() % g_numObituaries)), "A monster", &g_player[playerNum].user_name[0]); else if (actor[pPlayer->i].picnum == NUKEBUTTON) Bsprintf(tempbuf, "^02%s^02 tried to leave", &g_player[playerNum].user_name[0]); else { // random suicide death string - Bsprintf(tempbuf, apStrings[SUICIDEQUOTEINDEX + (krand() % g_numSelfObituaries)], + Bsprintf(tempbuf, quoteMgr.GetQuote(SUICIDEQUOTEINDEX + (krand() % g_numSelfObituaries)), &g_player[playerNum].user_name[0]); } } diff --git a/source/duke3d/src/quotes.h b/source/duke3d/src/quotes.h index b75ff9d13..ae5078a16 100644 --- a/source/duke3d/src/quotes.h +++ b/source/duke3d/src/quotes.h @@ -23,8 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef quotes_h_ #define quotes_h_ -#define MAXQUOTES 16384 -#define MAXQUOTELEN 128 +#include "quotemgr.h" + #define OBITQUOTEINDEX (MAXQUOTES-128) #define SUICIDEQUOTEINDEX (MAXQUOTES-32) diff --git a/source/duke3d/src/savegame.cpp b/source/duke3d/src/savegame.cpp index 72d746177..b7d9ee2c1 100644 --- a/source/duke3d/src/savegame.cpp +++ b/source/duke3d/src/savegame.cpp @@ -617,7 +617,7 @@ bool G_SavePlayer(FSaveGameNode *sv) if (!g_netServer && ud.multimode < 2) { OSD_Printf("Saved: %s\n", fn.GetChars()); - strcpy(apStrings[QUOTE_RESERVED4], "Game Saved"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Game Saved"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); } @@ -638,7 +638,7 @@ bool GameInterface::LoadGame(FSaveGameNode *sv) { if (g_netServer || ud.multimode > 1) { - Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Loading Not Yet Supported"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); // g_player[myconnectindex].ps->gm = MODE_GAME; @@ -657,7 +657,7 @@ bool GameInterface::SaveGame(FSaveGameNode* sv) { if (g_netServer || ud.multimode > 1) { - Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Saving Not Yet Supported"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); return false; } @@ -1145,9 +1145,6 @@ static void sv_create_lua_state(void) static void sv_postactordata(); static void sv_preanimateptrsave(); static void sv_postanimateptr(); -static void sv_prequote(); -static void sv_quotesave(); -static void sv_quoteload(); static void sv_prequoteredef(); static void sv_quoteredefsave(); static void sv_quoteredefload(); @@ -1167,9 +1164,6 @@ static int32_t savegame_projectilecnt = 0; ((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \ +sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS) -static uint8_t savegame_quotedef[MAXQUOTES >> 3]; -static char (*savegame_quotes)[MAXQUOTELEN]; -static char (*savegame_quoteredefs)[MAXQUOTELEN]; static uint8_t savegame_restdata[SVARDATALEN]; static char svgm_udnetw_string [] = "blK:udnt"; @@ -1309,20 +1303,6 @@ static const dataspec_t svgm_anmisc[] = { 0, &g_pskyidx, sizeof(g_pskyidx), 1 }, // DS_NOCHK? { 0, &g_earthquakeTime, sizeof(g_earthquakeTime), 1 }, - { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)sv_prequote, 0, 1 }, - { DS_SAVEFN, (void *)&sv_quotesave, 0, 1 }, - { DS_NOCHK, &savegame_quotedef, sizeof(savegame_quotedef), 1 }, // quotes can change during runtime, but new quote numbers cannot be allocated - { DS_DYNAMIC, &savegame_quotes, MAXQUOTELEN, MAXQUOTES }, - { DS_LOADFN, (void *)&sv_quoteload, 0, 1 }, - - { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_prequoteredef, 0, 1 }, - { DS_NOCHK|DS_SAVEFN, (void *)&sv_quoteredefsave, 0, 1 }, // quote redefinitions replace quotes at runtime, but cannot be changed after CON compilation - { DS_NOCHK|DS_DYNAMIC|DS_CNT(g_numXStrings), &savegame_quoteredefs, MAXQUOTELEN, (intptr_t)&g_numXStrings }, - { DS_NOCHK|DS_LOADFN, (void *)&sv_quoteredefload, 0, 1 }, - { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_postquoteredef, 0, 1 }, -#ifdef LUNATIC - { 0, g_playerWeapon, sizeof(weapondata_t), MAXPLAYERS*MAX_WEAPONS }, -#endif { DS_SAVEFN, (void *)&sv_restsave, 0, 1 }, { 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread { DS_LOADFN, (void *)&sv_restload, 0, 1 }, @@ -1798,34 +1778,6 @@ static void sv_postanimateptr() { G_Util_PtrToIdx(g_animatePtr, g_animateCnt, sector, P2I_BACK); } -static void sv_prequote() -{ - if (!savegame_quotes) - { - void *ptr = Xcalloc(MAXQUOTES, MAXQUOTELEN); - savegame_quotes = (char(*)[MAXQUOTELEN])ptr; - } -} -static void sv_quotesave() -{ - Bmemset(savegame_quotedef, 0, sizeof(savegame_quotedef)); - for (int i = 0; i < MAXQUOTES; i++) - if (apStrings[i]) - { - savegame_quotedef[i>>3] |= 1<<(i&7); - Bmemcpy(savegame_quotes[i], apStrings[i], MAXQUOTELEN); - } -} -static void sv_quoteload() -{ - for (int i = 0; i < MAXQUOTES; i++) - if (savegame_quotedef[i>>3] & pow2char[i&7]) - { - C_AllocQuote(i); - Bmemcpy(apStrings[i], savegame_quotes[i], MAXQUOTELEN); - } -} - static void sv_preprojectilesave() { savegame_projectilecnt = 0; @@ -1881,31 +1833,6 @@ static void sv_postprojectileload() DO_FREE_AND_NULL(savegame_projectiledata); } -static void sv_prequoteredef() -{ - // "+1" needed for dfwrite which doesn't handle the src==NULL && cnt==0 case - void *ptr = Xcalloc(g_numXStrings+1, MAXQUOTELEN); - savegame_quoteredefs = (decltype(savegame_quoteredefs))ptr; -} -static void sv_quoteredefsave() -{ - for (int i = 0; i < g_numXStrings; i++) - if (apXStrings[i]) - Bmemcpy(savegame_quoteredefs[i], apXStrings[i], MAXQUOTELEN); -} -static void sv_quoteredefload() -{ - for (int i = 0; i < g_numXStrings; i++) - { - if (!apXStrings[i]) - apXStrings[i] = (char *)Xcalloc(1,MAXQUOTELEN); - Bmemcpy(apXStrings[i], savegame_quoteredefs[i], MAXQUOTELEN); - } -} -static void sv_postquoteredef() -{ - Xfree(savegame_quoteredefs), savegame_quoteredefs=NULL; -} static void sv_restsave() { uint8_t * mem = savegame_restdata; diff --git a/source/duke3d/src/screentext.cpp b/source/duke3d/src/screentext.cpp index bc17bbe12..5af0e37b0 100644 --- a/source/duke3d/src/screentext.cpp +++ b/source/duke3d/src/screentext.cpp @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sbar.h" #include "menus.h" #include "gstrings.h" +#include "quotemgr.h" BEGIN_DUKE_NS @@ -1069,12 +1070,6 @@ void G_PrintGameQuotes(int32_t snum) if (k <= 1) break; - if (EDUKE32_PREDICT_FALSE(apStrings[ps->ftq] == NULL)) - { - OSD_Printf(OSD_ERROR "%s %d null quote %d\n", "screentext:", __LINE__, ps->ftq); - break; - } - int32_t y = ybase; if (reserved_quote) { @@ -1104,7 +1099,7 @@ void G_PrintGameQuotes(int32_t snum) } #endif - height = gametext_(x, y, apStrings[ps->ftq], textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16); + height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16); } while (0); @@ -1143,12 +1138,6 @@ void P_DoQuote(int32_t q, DukePlayer_t *p) q &= ~MAXQUOTES; } - if (EDUKE32_PREDICT_FALSE(apStrings[q] == NULL)) - { - OSD_Printf(OSD_ERROR "%s %d null quote %d\n", "screentext:", __LINE__, q); - return; - } - if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; @@ -1156,8 +1145,9 @@ void P_DoQuote(int32_t q, DukePlayer_t *p) if (p->ftq != q) { - if (p == g_player[screenpeek].ps && apStrings[q][0] != '\0') - OSD_Printf(cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", apStrings[q]); + auto qu = quoteMgr.GetQuote(q); + if (p == g_player[screenpeek].ps && qu[0] != '\0') + OSD_Printf(cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", qu); p->ftq = q; } diff --git a/source/rr/src/cheats.cpp b/source/rr/src/cheats.cpp index d2e315636..a859e34c6 100644 --- a/source/rr/src/cheats.cpp +++ b/source/rr/src/cheats.cpp @@ -490,7 +490,7 @@ void G_DoCheats(void) //} //else //{ - // Bstrcpy(apStrings[QUOTE_RESERVED4], "Come Get Some!"); + // Bstrcpy(pStrings[QUOTE_RESERVED4], "Come Get Some!"); // // S_PlaySound(DUKE_GETWEAPON2); // P_DoQuote(QUOTE_RESERVED4, pPlayer); @@ -661,7 +661,7 @@ void G_DoCheats(void) case CHEAT_TODD: if (NAM) { - Bstrcpy(apStrings[QUOTE_RESERVED4], g_NAMMattCheatQuote); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, g_NAMMattCheatQuote); P_DoQuote(QUOTE_RESERVED4, pPlayer); } else @@ -698,7 +698,7 @@ void G_DoCheats(void) if (++g_noEnemies == 3) g_noEnemies = 0; - Bsprintf(apStrings[QUOTE_RESERVED4], "Monsters: %s", s[g_noEnemies]); + quoteMgr.FormatQuote(QUOTE_RESERVED4, "Monsters: %s", s[g_noEnemies]); P_DoQuote(QUOTE_RESERVED4, pPlayer); end_cheat(pPlayer); diff --git a/source/rr/src/demo.cpp b/source/rr/src/demo.cpp index 4eea7b22b..e459bc519 100644 --- a/source/rr/src/demo.cpp +++ b/source/rr/src/demo.cpp @@ -143,7 +143,7 @@ void G_OpenDemoWrite(void) if ((g_player[myconnectindex].ps->gm&MODE_GAME) && g_player[myconnectindex].ps->dead_flag) { - Bstrcpy(apStrings[QUOTE_RESERVED4], "CANNOT START DEMO RECORDING WHEN DEAD!"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "CANNOT START DEMO RECORDING WHEN DEAD!"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); ud.recstat = m_recstat = 0; return; @@ -180,7 +180,7 @@ void G_OpenDemoWrite(void) delete g_demo_filePtr; g_demo_filePtr = nullptr; error_wopen_demo: - Bstrcpy(apStrings[QUOTE_RESERVED4], "FAILED STARTING DEMO RECORDING. SEE CONSOLE FOR DETAILS."); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "FAILED STARTING DEMO RECORDING. SEE CONSOLE FOR DETAILS."); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); ud.recstat = m_recstat = 0; return; @@ -190,7 +190,7 @@ error_wopen_demo: demorec_diffs = demorec_diffs_cvar; demorec_difftics = demorec_difftics_cvar; - Bsprintf(apStrings[QUOTE_RESERVED4], "DEMO %d RECORDING STARTED", demonum-1); + quoteMgr.FormatQuote(QUOTE_RESERVED4, "DEMO %d RECORDING STARTED", demonum-1); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); ud.reccnt = 0; @@ -285,7 +285,7 @@ void G_CloseDemoWrite(void) sv_freemem(); - Bstrcpy(apStrings[QUOTE_RESERVED4], "DEMO RECORDING STOPPED"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "DEMO RECORDING STOPPED"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); } #if KRANDDEBUG diff --git a/source/rr/src/game.cpp b/source/rr/src/game.cpp index 949f66748..cb800850a 100644 --- a/source/rr/src/game.cpp +++ b/source/rr/src/game.cpp @@ -6805,12 +6805,6 @@ static void G_Cleanup(void) G_FreeMapState(i); } - for (i=MAXQUOTES-1; i>=0; i--) - { - Bfree(apStrings[i]); - Bfree(apXStrings[i]); - } - for (i=MAXPLAYERS-1; i>=0; i--) { Bfree(g_player[i].ps); @@ -7794,7 +7788,7 @@ int G_DoMoveThings(void) { if (ldist(&sprite[pPlayer->i], &sprite[hitData.sprite]) < 9216) { - Bsprintf(apStrings[QUOTE_RESERVED3], "%s", &g_player[playerNum].user_name[0]); + quoteMgr.FormatQuote(QUOTE_RESERVED3, "%s", &g_player[playerNum].user_name[0]); pPlayer->fta = 12, pPlayer->ftq = QUOTE_RESERVED3; } } diff --git a/source/rr/src/gamedef.cpp b/source/rr/src/gamedef.cpp index 226be8da0..a05ba4fae 100644 --- a/source/rr/src/gamedef.cpp +++ b/source/rr/src/gamedef.cpp @@ -902,129 +902,30 @@ void C_DefineVolumeFlags(int32_t vol, int32_t flags) int32_t C_AllocQuote(int32_t qnum) { Bassert((unsigned)qnum < MAXQUOTES); - - if (apStrings[qnum] == NULL) - { - apStrings[qnum] = (char *)Xcalloc(MAXQUOTELEN,sizeof(uint8_t)); - return 1; - } - - return 0; + return 1; } -#ifndef EDUKE32_TOUCH_DEVICES -static void C_ReplaceQuoteSubstring(const size_t q, char const * const query, char const * const replacement) -{ - size_t querylength = Bstrlen(query); - - for (bssize_t i = MAXQUOTELEN - querylength - 2; i >= 0; i--) - if (Bstrncmp(&apStrings[q][i], query, querylength) == 0) - { - Bmemset(tempbuf, 0, sizeof(tempbuf)); - Bstrncpy(tempbuf, apStrings[q], i); - Bstrcat(tempbuf, replacement); - Bstrcat(tempbuf, &apStrings[q][i + querylength]); - Bstrncpy(apStrings[q], tempbuf, MAXQUOTELEN - 1); - i = MAXQUOTELEN - querylength - 2; - } -} -#endif - void C_InitQuotes(void) { - for (bssize_t i = 0; i < 128; i++) C_AllocQuote(i); - -#ifdef EDUKE32_TOUCH_DEVICES - apStrings[QUOTE_DEAD] = 0; -#else auto openkeys = Bindings.GetKeysForCommand("+open"); if (openkeys.Size()) { auto OpenGameFunc = C_NameKeys(openkeys.Data(), 1); - C_ReplaceQuoteSubstring(QUOTE_DEAD, "SPACE", OpenGameFunc); - C_ReplaceQuoteSubstring(QUOTE_DEAD, "OPEN", OpenGameFunc); - C_ReplaceQuoteSubstring(QUOTE_DEAD, "USE", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "SPACE", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "OPEN", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "USE", OpenGameFunc); } -#endif - // most of these are based on Blood, obviously - const char *PlayerObituaries[] = - { - "^02%s^02 beat %s^02 like a cur", - "^02%s^02 broke %s", - "^02%s^02 body bagged %s", - "^02%s^02 boned %s^02 like a fish", - "^02%s^02 castrated %s", - "^02%s^02 creamed %s", - "^02%s^02 crushed %s", - "^02%s^02 destroyed %s", - "^02%s^02 diced %s", - "^02%s^02 disemboweled %s", - "^02%s^02 erased %s", - "^02%s^02 eviscerated %s", - "^02%s^02 flailed %s", - "^02%s^02 flattened %s", - "^02%s^02 gave AnAl MaDnEsS to %s", - "^02%s^02 gave %s^02 Anal Justice", - "^02%s^02 hosed %s", - "^02%s^02 hurt %s^02 real bad", - "^02%s^02 killed %s", - "^02%s^02 made dog meat out of %s", - "^02%s^02 made mincemeat out of %s", - "^02%s^02 manhandled %s", - "^02%s^02 massacred %s", - "^02%s^02 mutilated %s", - "^02%s^02 murdered %s", - "^02%s^02 neutered %s", - "^02%s^02 punted %s", - "^02%s^02 reamed %s", - "^02%s^02 ripped %s^02 a new orifice", - "^02%s^02 rocked %s", - "^02%s^02 sent %s^02 to hell", - "^02%s^02 shredded %s", - "^02%s^02 slashed %s", - "^02%s^02 slaughtered %s", - "^02%s^02 sliced %s", - "^02%s^02 smacked %s around", - "^02%s^02 smashed %s", - "^02%s^02 snuffed %s", - "^02%s^02 sodomized %s", - "^02%s^02 splattered %s", - "^02%s^02 sprayed %s", - "^02%s^02 squashed %s", - "^02%s^02 throttled %s", - "^02%s^02 toasted %s", - "^02%s^02 vented %s", - "^02%s^02 ventilated %s", - "^02%s^02 wasted %s", - "^02%s^02 wrecked %s", - }; - - const char *PlayerSelfObituaries[] = - { - "^02%s^02 is excrement", - "^02%s^02 is hamburger", - "^02%s^02 suffered scrotum separation", - "^02%s^02 volunteered for population control", - "^02%s^02 has suicided", - "^02%s^02 bled out", - }; - - EDUKE32_STATIC_ASSERT(OBITQUOTEINDEX + ARRAY_SIZE(PlayerObituaries)-1 < MAXQUOTES); - EDUKE32_STATIC_ASSERT(SUICIDEQUOTEINDEX + ARRAY_SIZE(PlayerSelfObituaries)-1 < MAXQUOTES); - - g_numObituaries = ARRAY_SIZE(PlayerObituaries); + g_numObituaries = 48; for (bssize_t i = g_numObituaries - 1; i >= 0; i--) { - if (C_AllocQuote(i + OBITQUOTEINDEX)) - Bstrcpy(apStrings[i + OBITQUOTEINDEX], PlayerObituaries[i]); + quoteMgr.FormatQuote(i + OBITQUOTEINDEX, "$TXT_OBITUARY%d", i + 1); } - g_numSelfObituaries = ARRAY_SIZE(PlayerSelfObituaries); + g_numSelfObituaries = 6; for (bssize_t i = g_numSelfObituaries - 1; i >= 0; i--) { - if (C_AllocQuote(i + SUICIDEQUOTEINDEX)) - Bstrcpy(apStrings[i + SUICIDEQUOTEINDEX], PlayerSelfObituaries[i]); + quoteMgr.FormatQuote(i + SUICIDEQUOTEINDEX, "$TXT_SELFOBIT%d", i + 1); } } @@ -2028,6 +1929,7 @@ static int32_t C_ParseCommand(int32_t loop) continue; case CON_DEFINEQUOTE: + { g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); @@ -2050,33 +1952,16 @@ static int32_t C_ParseCommand(int32_t loop) C_SkipSpace(); - while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) - { - /* - if (*textptr == '%' && *(textptr+1) == 's') - { - initprintf("%s:%d: error: quote text contains string identifier.\n",g_szScriptFileName,g_lineNumber); - g_numCompilerErrors++; - while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++; - break; - } - */ - *(apStrings[k]+i) = *textptr; - - textptr++,i++; - if (EDUKE32_PREDICT_FALSE(i >= MAXQUOTELEN-1)) - { - initprintf("%s:%d: warning: truncating quote text to %d characters.\n",g_scriptFileName,g_lineNumber,MAXQUOTELEN-1); - g_warningCnt++; - C_NextLine(); - break; - } - } - - if ((unsigned)k < MAXQUOTES) - *(apStrings[k]+i) = '\0'; - continue; - + TArray buffer; + while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) + { + buffer.Push(*textptr); + textptr++; + } + buffer.Push(0); + quoteMgr.InitializeQuote(k, buffer.Data(), true); + continue; + } case CON_DEFINESOUND: g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); @@ -2313,14 +2198,6 @@ void C_PrintStats(void) int i, j; - for (i=MAXQUOTES-1, j=0; i>=0; i--) - { - if (apStrings[i]) - j++; - } - - if (j) initprintf("%d strings, ", j); - for (i=MAXTILES-1, j=0; i>=0; i--) { if (g_tile[i].execPtr) diff --git a/source/rr/src/gameexec.cpp b/source/rr/src/gameexec.cpp index 49997724e..e6efa911a 100644 --- a/source/rr/src/gameexec.cpp +++ b/source/rr/src/gameexec.cpp @@ -2457,7 +2457,7 @@ GAMEEXEC_STATIC void VM_Execute(native_t loop) case CON_QUOTE: insptr++; - if (EDUKE32_PREDICT_FALSE((unsigned)(*insptr) >= MAXQUOTES) || apStrings[*insptr] == NULL) + if (EDUKE32_PREDICT_FALSE((unsigned)(*insptr) >= MAXQUOTES)) { CON_ERRPRINTF("invalid quote %d\n", (int32_t)(*insptr)); insptr++; diff --git a/source/rr/src/global.h b/source/rr/src/global.h index 217368c60..574f27750 100644 --- a/source/rr/src/global.h +++ b/source/rr/src/global.h @@ -72,7 +72,6 @@ G_EXTERN actor_t actor[MAXSPRITES]; // g_tile: tile-specific data THAT DOES NOT CHANGE during the course of a game G_EXTERN tiledata_t g_tile[MAXTILES]; G_EXTERN animwalltype animwall[MAXANIMWALLS]; -G_EXTERN char *apStrings[MAXQUOTES],*apXStrings[MAXQUOTES]; G_EXTERN char *label; G_EXTERN int32_t g_musicIndex; G_EXTERN char g_loadFromGroupOnly; diff --git a/source/rr/src/player.cpp b/source/rr/src/player.cpp index a9577925d..47756f982 100644 --- a/source/rr/src/player.cpp +++ b/source/rr/src/player.cpp @@ -4478,18 +4478,18 @@ void P_FragPlayer(int playerNum) if (playerNum == screenpeek) { - Bsprintf(apStrings[QUOTE_RESERVED], "Killed by %s", &g_player[pPlayer->frag_ps].user_name[0]); + quoteMgr.InitializeQuote(QUOTE_RESERVED, "Killed by %s", &g_player[pPlayer->frag_ps].user_name[0]); P_DoQuote(QUOTE_RESERVED, pPlayer); } else { - Bsprintf(apStrings[QUOTE_RESERVED2], "Killed %s", &g_player[playerNum].user_name[0]); + quoteMgr.InitializeQuote(QUOTE_RESERVED2, "Killed %s", &g_player[playerNum].user_name[0]); P_DoQuote(QUOTE_RESERVED2, g_player[pPlayer->frag_ps].ps); } if (cl_obituaries) { - Bsprintf(tempbuf, apStrings[OBITQUOTEINDEX + (krand2() % g_numObituaries)], + Bsprintf(tempbuf, quoteMgr.GetQuote(OBITQUOTEINDEX + (krand2() % g_numObituaries)), &g_player[pPlayer->frag_ps].user_name[0], &g_player[playerNum].user_name[0]); G_AddUserQuote(tempbuf); } @@ -4502,14 +4502,14 @@ void P_FragPlayer(int playerNum) { pPlayer->fraggedself++; if ((unsigned)pPlayer->wackedbyactor < MAXTILES && A_CheckEnemyTile(sprite[pPlayer->wackedbyactor].picnum)) - Bsprintf(tempbuf, apStrings[OBITQUOTEINDEX + (krand2() % g_numObituaries)], "A monster", + Bsprintf(tempbuf, quoteMgr.GetQuote(OBITQUOTEINDEX + (krand2() % g_numObituaries)), "A monster", &g_player[playerNum].user_name[0]); else if (actor[pPlayer->i].picnum == NUKEBUTTON) Bsprintf(tempbuf, "^02%s^02 tried to leave", &g_player[playerNum].user_name[0]); else { // random suicide death string - Bsprintf(tempbuf, apStrings[SUICIDEQUOTEINDEX + (krand2() % g_numSelfObituaries)], + Bsprintf(tempbuf, quoteMgr.GetQuote(SUICIDEQUOTEINDEX + (krand2() % g_numSelfObituaries)), &g_player[playerNum].user_name[0]); } } diff --git a/source/rr/src/quotes.h b/source/rr/src/quotes.h index 4ff44df24..46858c821 100644 --- a/source/rr/src/quotes.h +++ b/source/rr/src/quotes.h @@ -23,8 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef quotes_h_ #define quotes_h_ -#define MAXQUOTES 16384 -#define MAXQUOTELEN 128 +#include "quotemgr.h" + #define OBITQUOTEINDEX (MAXQUOTES-128) #define SUICIDEQUOTEINDEX (MAXQUOTES-32) diff --git a/source/rr/src/savegame.cpp b/source/rr/src/savegame.cpp index c5cd7aa4f..d794681fb 100644 --- a/source/rr/src/savegame.cpp +++ b/source/rr/src/savegame.cpp @@ -362,7 +362,7 @@ bool G_SavePlayer(FSaveGameNode *sv) if (!g_netServer && ud.multimode < 2) { OSD_Printf("Saved: %s\n", fn.GetChars()); - Bstrcpy(apStrings[QUOTE_RESERVED4], "Game Saved"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Game Saved"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); } @@ -380,7 +380,7 @@ bool GameInterface::LoadGame(FSaveGameNode* sv) { if (g_netServer || ud.multimode > 1) { - Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Loading Not Yet Supported"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); // g_player[myconnectindex].ps->gm = MODE_GAME; @@ -399,7 +399,7 @@ bool GameInterface::SaveGame(FSaveGameNode* sv) { if (g_netServer || ud.multimode > 1) { - Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported"); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Saving Not Yet Supported"); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); return false; } @@ -881,8 +881,6 @@ static void sv_rrrafog(); ((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \ +sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS) -static uint8_t savegame_quotedef[MAXQUOTES>>3]; -static char (*savegame_quotes)[MAXQUOTELEN]; static uint8_t savegame_restdata[SVARDATALEN]; static char svgm_udnetw_string [] = "blK:udnt"; @@ -1082,12 +1080,6 @@ static const dataspec_t svgm_anmisc[] = { 0, &g_fogType, sizeof(g_fogType), 1 }, { DS_LOADFN, (void *)sv_rrrafog, 0, 1 }, - { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)sv_prequote, 0, 1 }, - { DS_SAVEFN, (void *)&sv_quotesave, 0, 1 }, - { DS_NOCHK, &savegame_quotedef, sizeof(savegame_quotedef), 1 }, // quotes can change during runtime, but new quote numbers cannot be allocated - { DS_DYNAMIC, &savegame_quotes, MAXQUOTELEN, MAXQUOTES }, - { DS_LOADFN, (void *)&sv_quoteload, 0, 1 }, - { DS_SAVEFN, (void *)&sv_restsave, 0, 1 }, { 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread { DS_LOADFN, (void *)&sv_restload, 0, 1 }, @@ -1482,33 +1474,6 @@ static void sv_postanimateptr() { G_Util_PtrToIdx(g_animatePtr, g_animateCnt, sector, P2I_BACK); } -static void sv_prequote() -{ - if (!savegame_quotes) - { - void *ptr = Xcalloc(MAXQUOTES, MAXQUOTELEN); - savegame_quotes = (char(*)[MAXQUOTELEN])ptr; - } -} -static void sv_quotesave() -{ - Bmemset(savegame_quotedef, 0, sizeof(savegame_quotedef)); - for (int i = 0; i < MAXQUOTES; i++) - if (apStrings[i]) - { - savegame_quotedef[i>>3] |= 1<<(i&7); - Bmemcpy(savegame_quotes[i], apStrings[i], MAXQUOTELEN); - } -} -static void sv_quoteload() -{ - for (int i = 0; i < MAXQUOTES; i++) - if (savegame_quotedef[i>>3] & (1<<(i&7))) - { - C_AllocQuote(i); - Bmemcpy(apStrings[i], savegame_quotes[i], MAXQUOTELEN); - } -} static void sv_restsave() { uint8_t * mem = savegame_restdata; diff --git a/source/rr/src/screentext.cpp b/source/rr/src/screentext.cpp index cc0a49ae6..ec66b14c2 100644 --- a/source/rr/src/screentext.cpp +++ b/source/rr/src/screentext.cpp @@ -1071,12 +1071,6 @@ void G_PrintGameQuotes(int32_t snum) if (k <= 1) break; - if (EDUKE32_PREDICT_FALSE(apStrings[ps->ftq] == NULL)) - { - OSD_Printf(OSD_ERROR "%s %d null quote %d\n", __FILE__, __LINE__, ps->ftq); - break; - } - int32_t y = ybase; if (reserved_quote) { @@ -1106,7 +1100,7 @@ void G_PrintGameQuotes(int32_t snum) } #endif - height = gametext_(x, y, apStrings[ps->ftq], textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16); + height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16); } while (0); @@ -1145,12 +1139,6 @@ void P_DoQuote(int32_t q, DukePlayer_t *p) q &= ~MAXQUOTES; } - if (EDUKE32_PREDICT_FALSE(apStrings[q] == NULL)) - { - OSD_Printf(OSD_ERROR "%s %d null quote %d\n", __FILE__, __LINE__, q); - return; - } - if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; @@ -1158,8 +1146,9 @@ void P_DoQuote(int32_t q, DukePlayer_t *p) if (p->ftq != q) { - if (p == g_player[screenpeek].ps && apStrings[q][0] != '\0') - OSD_Printf(cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", apStrings[q]); + auto qu = quoteMgr.GetQuote(q); + if (p == g_player[screenpeek].ps && qu[0] != '\0') + OSD_Printf(cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", qu); p->ftq = q; }