- 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.
This commit is contained in:
Christoph Oelckers 2019-12-04 00:28:28 +01:00
parent c561255018
commit 72857db17b
26 changed files with 418 additions and 596 deletions

View file

@ -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

View file

@ -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

65
source/common/quotemgr.h Normal file
View file

@ -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 &quote);
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;

180
source/common/quotes.cpp Normal file
View file

@ -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 &quote)
{
}
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;

View file

@ -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();
}
//=============================================================================

View file

@ -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);

View file

@ -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

View file

@ -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;
}
}

View file

@ -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<char> 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)

View file

@ -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<char> 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<char> 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):

View file

@ -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;

View file

@ -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;
}

View file

@ -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]);
}
}

View file

@ -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)

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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;
}
}

View file

@ -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<char> 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)

View file

@ -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++;

View file

@ -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;

View file

@ -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]);
}
}

View file

@ -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)

View file

@ -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;

View file

@ -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;
}