diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e72e4375..c20a86ba7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -845,6 +845,7 @@ add_executable( zdoom WIN32 c_bind.cpp c_cmds.cpp c_console.cpp + c_consolebuffer.cpp c_cvars.cpp c_dispatch.cpp c_expr.cpp diff --git a/src/c_console.cpp b/src/c_console.cpp index 396b2dfce..4dabdb9e1 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -65,22 +65,29 @@ #include "g_level.h" #include "d_event.h" #include "d_player.h" +#include "c_consolebuffer.h" #include "gi.h" -#define CONSOLESIZE 16384 // Number of characters to store in console -#define CONSOLELINES 256 // Max number of lines of console text -#define LINEMASK (CONSOLELINES-1) - #define LEFTMARGIN 8 #define RIGHTMARGIN 8 #define BOTTOMARGIN 12 + +CUSTOM_CVAR(Int, con_buffersize, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + // ensure a minimum size + if (self >= 0 && self < 128) self = 128; +} + +FConsoleBuffer *conbuffer; + static void C_TabComplete (bool goForward); static bool C_TabCompleteList (); static bool TabbedLast; // True if last key pressed was tab static bool TabbedList; // True if tab list was shown -CVAR (Bool, con_notablist, false, CVAR_ARCHIVE) +CVAR(Bool, con_notablist, false, CVAR_ARCHIVE) + static FTextureID conback; static DWORD conshade; @@ -94,18 +101,15 @@ extern FBaseCVar *CVars; extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; int ConCols, PhysRows; +int ConWidth; bool vidactive = false; bool cursoron = false; int ConBottom, ConScroll, RowAdjust; int CursorTicker; constate_e ConsoleState = c_up; -static char ConsoleBuffer[CONSOLESIZE]; -static char *Lines[CONSOLELINES]; -static bool LineJoins[CONSOLELINES]; static int TopLine, InsertLine; -static char *BufferRover = ConsoleBuffer; static void ClearConsole (); static void C_PasteText(FString clip, BYTE *buffer, int len); @@ -182,7 +186,6 @@ static struct NotifyText static int NotifyTop, NotifyTopGoal; -#define PRINTLEVELS 5 int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_GREEN, CR_GOLD }; static void setmsgcolor (int index, int color); @@ -328,78 +331,11 @@ void C_InitConsole (int width, int height, bool ingame) { cwidth = cheight = 8; } - ConCols = (width - LEFTMARGIN - RIGHTMARGIN) / cwidth; + ConWidth = (width - LEFTMARGIN - RIGHTMARGIN); + ConCols = ConWidth / cwidth; PhysRows = height / cheight; - // If there is some text in the console buffer, reformat it - // for the new resolution. - if (TopLine != InsertLine) - { - // Note: Don't use new here, because we attach a handler to new in - // i_main.cpp that calls I_FatalError if the allocation fails, - // but we can gracefully handle such a condition here by just - // clearing the console buffer. (OTOH, what are the chances that - // any other memory allocations would succeed if we can't get - // these mallocs here?) - - char *fmtBuff = (char *)malloc (CONSOLESIZE); - char **fmtLines = (char **)malloc (CONSOLELINES*sizeof(char*)*4); - int out = 0; - - if (fmtBuff && fmtLines) - { - int in; - char *fmtpos; - bool newline = true; - - fmtpos = fmtBuff; - memset (fmtBuff, 0, CONSOLESIZE); - - for (in = TopLine; in != InsertLine; in = (in + 1) & LINEMASK) - { - size_t len = strlen (Lines[in]); - - if (fmtpos + len + 2 - fmtBuff > CONSOLESIZE) - { - break; - } - if (newline) - { - newline = false; - fmtLines[out++] = fmtpos; - } - strcpy (fmtpos, Lines[in]); - fmtpos += len; - if (!LineJoins[in]) - { - *fmtpos++ = '\n'; - fmtpos++; - if (out == CONSOLELINES*4) - { - break; - } - newline = true; - } - } - } - - ClearConsole (); - - if (fmtBuff && fmtLines) - { - int i; - - for (i = 0; i < out; i++) - { - AddToConsole (-1, fmtLines[i]); - } - } - - if (fmtBuff) - free (fmtBuff); - if (fmtLines) - free (fmtLines); - } + if (conbuffer == NULL) conbuffer = new FConsoleBuffer; } //========================================================================== @@ -507,16 +443,21 @@ void C_DeinitConsole () work = NULL; worklen = 0; } + + if (conbuffer != NULL) + { + delete conbuffer; + conbuffer = NULL; + } } static void ClearConsole () { - RowAdjust = 0; + if (conbuffer != NULL) + { + conbuffer->Clear(); + } TopLine = InsertLine = 0; - BufferRover = ConsoleBuffer; - memset (ConsoleBuffer, 0, CONSOLESIZE); - memset (Lines, 0, sizeof(Lines)); - memset (LineJoins, 0, sizeof(LineJoins)); } static void setmsgcolor (int index, int color) @@ -596,223 +537,9 @@ void C_AddNotifyString (int printlevel, const char *source) NotifyTopGoal = 0; } -static int FlushLines (const char *start, const char *stop) -{ - int i; - - for (i = TopLine; i != InsertLine; i = (i + 1) & LINEMASK) - { - if (Lines[i] < stop && Lines[i] + strlen (Lines[i]) > start) - { - Lines[i] = NULL; - } - else - { - break; - } - } - return i; -} - -static void AddLine (const char *text, bool more, size_t len) -{ - if (BufferRover + len + 1 - ConsoleBuffer > CONSOLESIZE) - { - TopLine = FlushLines (BufferRover, ConsoleBuffer + CONSOLESIZE); - BufferRover = ConsoleBuffer; - } - if (len >= CONSOLESIZE - 1) - { - text = text + len - CONSOLESIZE + 1; - len = CONSOLESIZE - 1; - } - TopLine = FlushLines (BufferRover, BufferRover + len + 1); - memcpy (BufferRover, text, len); - BufferRover[len] = 0; - Lines[InsertLine] = BufferRover; - BufferRover += len + 1; - LineJoins[InsertLine] = more; - InsertLine = (InsertLine + 1) & LINEMASK; - if (InsertLine == TopLine) - { - TopLine = (TopLine + 1) & LINEMASK; - } -} - void AddToConsole (int printlevel, const char *text) { - static enum - { - NEWLINE, - APPENDLINE, - REPLACELINE - } addtype = NEWLINE; - - char *work_p; - char *linestart; - FString cc('A' + char(CR_TAN)); - int size, len; - int x; - int maxwidth; - - if (ConsoleDrawing) - { - EnqueueConsoleText (false, printlevel, text); - return; - } - - len = (int)strlen (text); - size = len + 20; - - if (addtype != NEWLINE) - { - InsertLine = (InsertLine - 1) & LINEMASK; - if (Lines[InsertLine] == NULL) - { - InsertLine = (InsertLine + 1) & LINEMASK; - addtype = NEWLINE; - } - else - { - BufferRover = Lines[InsertLine]; - } - } - if (addtype == APPENDLINE) - { - size += (int)strlen (Lines[InsertLine]); - } - if (size > worklen) - { - work = (char *)M_Realloc (work, size); - worklen = size; - } - if (work == NULL) - { - static char oom[] = TEXTCOLOR_RED "*** OUT OF MEMORY ***"; - work = oom; - worklen = 0; - } - else - { - if (addtype == APPENDLINE) - { - strcpy (work, Lines[InsertLine]); - strcat (work, text); - } - else if (printlevel >= 0) - { - work[0] = TEXTCOLOR_ESCAPE; - work[1] = 'A' + (printlevel == PRINT_HIGH ? CR_TAN : - printlevel == 200 ? CR_GREEN : - printlevel < PRINTLEVELS ? PrintColors[printlevel] : - CR_TAN); - cc = work[1]; - strcpy (work + 2, text); - } - else - { - strcpy (work, text); - } - } - - work_p = linestart = work; - - if (ConFont != NULL && screen != NULL) - { - x = 0; - maxwidth = screen->GetWidth() - LEFTMARGIN - RIGHTMARGIN; - - while (*work_p) - { - if (*work_p == TEXTCOLOR_ESCAPE) - { - work_p++; - if (*work_p == '[') - { - char *start = work_p; - while (*work_p != ']' && *work_p != '\0') - { - work_p++; - } - if (*work_p != '\0') - { - work_p++; - } - cc = FString(start, work_p - start); - } - else if (*work_p != '\0') - { - cc = *work_p++; - } - continue; - } - int w = ConFont->GetCharWidth (*work_p); - if (*work_p == '\n' || x + w > maxwidth) - { - AddLine (linestart, *work_p != '\n', work_p - linestart); - if (*work_p == '\n') - { - x = 0; - work_p++; - } - else - { - x = w; - } - if (*work_p) - { - linestart = work_p - 1 - cc.Len(); - if (linestart < work) - { - // The line start is outside the buffer. - // Make space for the newly inserted stuff. - size_t movesize = work-linestart; - memmove(work + movesize, work, strlen(work)+1); - work_p += movesize; - linestart = work; - } - linestart[0] = TEXTCOLOR_ESCAPE; - strncpy (linestart + 1, cc, cc.Len()); - } - else - { - linestart = work_p; - } - } - else - { - x += w; - work_p++; - } - } - - if (*linestart) - { - AddLine (linestart, true, work_p - linestart); - } - } - else - { - while (*work_p) - { - if (*work_p++ == '\n') - { - AddLine (linestart, false, work_p - linestart - 1); - linestart = work_p; - } - } - if (*linestart) - { - AddLine (linestart, true, work_p - linestart); - } - } - - switch (text[len-1]) - { - case '\r': addtype = REPLACELINE; break; - case '\n': addtype = NEWLINE; break; - default: addtype = APPENDLINE; break; - } + conbuffer->AddText(printlevel, text, Logfile); } /* Adds a string to the console and also to the notify buffer */ @@ -823,34 +550,6 @@ int PrintString (int printlevel, const char *outline) return 0; } - if (Logfile) - { - // Strip out any color escape sequences before writing to the log file - char * copy = new char[strlen(outline)+1]; - const char * srcp = outline; - char * dstp = copy; - - while (*srcp != 0) - { - if (*srcp!=0x1c) - { - *dstp++=*srcp++; - } - else - { - if (srcp[1]!=0) srcp+=2; - else break; - } - } - *dstp=0; - - fputs (copy, Logfile); - delete [] copy; -//#ifdef _DEBUG - fflush (Logfile); -//#endif - } - if (printlevel != PRINT_LOG) { I_PrintStr (outline); @@ -949,6 +648,11 @@ void C_Ticker () if (lasttic == 0) lasttic = gametic - 1; + if (con_buffersize > 0) + { + conbuffer->ResizeBuffer(con_buffersize); + } + if (ConsoleState != c_up) { if (ConsoleState == c_falling) @@ -1236,38 +940,22 @@ void C_DrawConsole (bool hw2d) if (lines > 0) { + // No more enqueuing because adding new text to the console won't touch the actual print data. + conbuffer->FormatText(ConFont, ConWidth); + unsigned int consolelines = conbuffer->GetFormattedLineCount(); + FBrokenLines **blines = conbuffer->GetLines(); + FBrokenLines **printline = blines + consolelines - 1 - RowAdjust; + int bottomline = ConBottom - ConFont->GetHeight()*2 - 4; - int pos = (InsertLine - 1) & LINEMASK; - int i; ConsoleDrawing = true; - for (i = RowAdjust; i; i--) + for(FBrokenLines **p = printline; p >= blines && lines > 0; p--, lines--) { - if (pos == TopLine) - { - RowAdjust = RowAdjust - i; - break; - } - else - { - pos = (pos - 1) & LINEMASK; - } + screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, TAG_DONE); } - pos++; - do - { - pos = (pos - 1) & LINEMASK; - if (Lines[pos] != NULL) - { - screen->DrawText (ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), - Lines[pos], TAG_DONE); - } - lines--; - } while (pos != TopLine && lines > 0); ConsoleDrawing = false; - DequeueConsoleText (); if (ConBottom >= 20) { @@ -1293,7 +981,7 @@ void C_DrawConsole (bool hw2d) { // Indicate that the view has been scrolled up (10) // and if we can scroll no further (12) - screen->DrawChar (ConFont, CR_GREEN, 0, bottomline, pos == TopLine ? 12 : 10, TAG_DONE); + screen->DrawChar (ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE); } } } @@ -1445,7 +1133,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) RowAdjust += (SCREENHEIGHT-4) / ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? ConFont->GetHeight() : ConFont->GetHeight()*2) - 3; } - else if (RowAdjust < CONSOLELINES) + else if (RowAdjust < conbuffer->GetFormattedLineCount()) { // Scroll console buffer up if (ev->subtype == EV_GUI_WheelUp) { @@ -1455,6 +1143,10 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) { RowAdjust++; } + if (RowAdjust > conbuffer->GetFormattedLineCount()) + { + RowAdjust = conbuffer->GetFormattedLineCount(); + } } break; @@ -1488,7 +1180,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) case GK_HOME: if (ev->data3 & GKM_CTRL) { // Move to top of console buffer - RowAdjust = CONSOLELINES; + RowAdjust = conbuffer->GetFormattedLineCount(); } else { // Move cursor to start of line diff --git a/src/c_console.h b/src/c_console.h index 8560d6779..2c2e553f9 100644 --- a/src/c_console.h +++ b/src/c_console.h @@ -47,6 +47,9 @@ typedef enum cstate_t } constate_e; +#define PRINTLEVELS 5 +extern int PrintColors[PRINTLEVELS + 2]; + extern constate_e ConsoleState; extern int ConBottom; diff --git a/src/c_consolebuffer.cpp b/src/c_consolebuffer.cpp new file mode 100644 index 000000000..3f64f34e4 --- /dev/null +++ b/src/c_consolebuffer.cpp @@ -0,0 +1,317 @@ +/* +** consolebuffer.cpp +** +** manages the text for the console +** +**--------------------------------------------------------------------------- +** Copyright 2014 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_console.h" +#include "c_consolebuffer.h" + + +//========================================================================== +// +// +// +//========================================================================== + +FConsoleBuffer::FConsoleBuffer() +{ + mLogFile = NULL; + mAddType = NEWLINE; + mLastFont = NULL; + mLastDisplayWidth = -1; + mLastLineNeedsUpdate = false; + mTextLines = 0; + mBufferWasCleared = true; + mBrokenStart.Push(0); +} + +//========================================================================== +// +// +// +//========================================================================== + +FConsoleBuffer::~FConsoleBuffer() +{ + FreeBrokenText(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FConsoleBuffer::FreeBrokenText(unsigned start, unsigned end) +{ + if (end > mBrokenConsoleText.Size()) end = mBrokenConsoleText.Size(); + for (unsigned i = start; i < end; i++) + { + if (mBrokenConsoleText[i] != NULL) V_FreeBrokenLines(mBrokenConsoleText[i]); + mBrokenConsoleText[i] = NULL; + } +} + +//========================================================================== +// +// Adds a new line of text to the console +// This is kept as simple as possible. This function does not: +// - remove old text if the buffer gets larger than the specified size +// - format the text for the current screen layout +// +// These tasks will only be be performed once per frame because they are +// relatively expensive. The old console did them each time text was added +// resulting in extremely bad performance with a high output rate. +// +//========================================================================== + +void FConsoleBuffer::AddText(int printlevel, const char *text, FILE *logfile) +{ + FString build = TEXTCOLOR_TAN; + + if (mAddType == REPLACELINE) + { + // Just wondering: Do we actually need this case? If so, it may need some work. + mConsoleText.Pop(); // remove the line to be replaced + mLastLineNeedsUpdate = true; + } + else if (mAddType == APPENDLINE) + { + mConsoleText.Pop(build); + printlevel = -1; + mLastLineNeedsUpdate = true; + } + + if (printlevel >= 0 && printlevel != PRINT_HIGH) + { + if (printlevel == 200) build = TEXTCOLOR_GREEN; + else if (printlevel < PRINTLEVELS) build.Format("%c%c", TEXTCOLOR_ESCAPE, PrintColors[printlevel]); + } + + size_t textsize = strlen(text); + + if (text[textsize-1] == '\r') + { + textsize--; + mAddType = REPLACELINE; + } + else if (text[textsize-1] == '\n') + { + textsize--; + mAddType = NEWLINE; + } + else + { + mAddType = APPENDLINE; + } + + // don't bother about linefeeds etc. inside the text, we'll let the formatter sort this out later. + build.AppendCStrPart(text, textsize); + mConsoleText.Push(build); + if (logfile != NULL) WriteLineToLog(logfile, text); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FConsoleBuffer::WriteLineToLog(FILE *LogFile, const char *outline) +{ + // Strip out any color escape sequences before writing to the log file + char * copy = new char[strlen(outline)+1]; + const char * srcp = outline; + char * dstp = copy; + + while (*srcp != 0) + { + + if (*srcp != TEXTCOLOR_ESCAPE) + { + switch (*srcp) + { + case '\35': + *dstp++ = '<'; + break; + + case '\36': + *dstp++ = '-'; + break; + + case '\37': + *dstp++ = '>'; + break; + + default: + *dstp++=*srcp; + break; + } + srcp++; + } + else if (srcp[1] == '[') + { + srcp+=2; + while (*srcp != ']' && *srcp != 0) srcp++; + if (*srcp == ']') srcp++; + } + else + { + if (srcp[1]!=0) srcp+=2; + else break; + } + } + *dstp=0; + + fputs (copy, LogFile); + delete [] copy; + fflush (LogFile); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FConsoleBuffer::WriteContentToLog(FILE *LogFile) +{ + if (LogFile != NULL) + { + for (unsigned i = 0; i < mConsoleText.Size(); i++) + { + WriteLineToLog(LogFile, mConsoleText[i]); + } + } +} + +//========================================================================== +// +// ensures that the following text is not appended to the current line. +// +//========================================================================== + +void FConsoleBuffer::Linefeed(FILE *Logfile) +{ + if (mAddType != NEWLINE && Logfile != NULL) fputc('\n', Logfile); + mAddType = NEWLINE; +} + +//========================================================================== +// +// +// +//========================================================================== + +static const char bar1[] = TEXTCOLOR_RED "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36" + "\36\36\36\36\36\36\36\36\36\36\36\36\37" TEXTCOLOR_TAN "\n"; +static const char bar2[] = TEXTCOLOR_RED "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36" + "\36\36\36\36\36\36\36\36\36\36\36\36\37" TEXTCOLOR_GREEN "\n"; +static const char bar3[] = TEXTCOLOR_RED "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36" + "\36\36\36\36\36\36\36\36\36\36\36\36\37" TEXTCOLOR_NORMAL "\n"; +static const char logbar[] = "\n<------------------------------->\n"; + +void FConsoleBuffer::AddMidText(const char *string, bool bold, FILE *Logfile) +{ + Linefeed(Logfile); + AddText (-1, bold? bar2 : bar1, Logfile); + AddText (-1, string, Logfile); + Linefeed(Logfile); + AddText(-1, bar3, Logfile); +} + +//========================================================================== +// +// Format the text for output +// +//========================================================================== + +void FConsoleBuffer::FormatText(FFont *formatfont, int displaywidth) +{ + if (formatfont != mLastFont || displaywidth != mLastDisplayWidth || mBufferWasCleared) + { + FreeBrokenText(); + mBrokenConsoleText.Clear(); + mBrokenStart.Clear(); + mBrokenStart.Push(0); + mBrokenLines.Clear(); + mLastFont = formatfont; + mLastDisplayWidth = displaywidth; + mBufferWasCleared = false; + } + unsigned brokensize = mBrokenConsoleText.Size(); + if (brokensize == mConsoleText.Size()) + { + // The last line got text appended. We have to wait until here to format it because + // it is possible that during display new text will be added from the NetUpdate calls in the software version of DrawTextureV. + if (mLastLineNeedsUpdate) + { + brokensize--; + V_FreeBrokenLines(mBrokenConsoleText[brokensize]); + mBrokenConsoleText.Resize(brokensize); + } + } + mBrokenLines.Resize(mBrokenStart[brokensize]); + mBrokenStart.Resize(brokensize); + for (unsigned i = brokensize; i < mConsoleText.Size(); i++) + { + FBrokenLines *bl = V_BreakLines(formatfont, displaywidth, mConsoleText[i], true); + mBrokenConsoleText.Push(bl); + mBrokenStart.Push(mBrokenLines.Size()); + while (bl->Width != -1) + { + mBrokenLines.Push(bl); + bl++; + } + } + mTextLines = mBrokenLines.Size(); + mBrokenStart.Push(mTextLines); + mLastLineNeedsUpdate = false; +} + +//========================================================================== +// +// Delete old content if number of lines gets too large +// +//========================================================================== + +void FConsoleBuffer::ResizeBuffer(unsigned newsize) +{ + if (mConsoleText.Size() > newsize) + { + unsigned todelete = mConsoleText.Size() - newsize; + mConsoleText.Delete(0, todelete); + mBufferWasCleared = true; + } +} + diff --git a/src/c_consolebuffer.h b/src/c_consolebuffer.h new file mode 100644 index 000000000..710423012 --- /dev/null +++ b/src/c_consolebuffer.h @@ -0,0 +1,85 @@ +/* +** consolebuffer.h +** +** manages the text for the console +** +**--------------------------------------------------------------------------- +** Copyright 2014 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include "zstring.h" +#include "tarray.h" +#include "v_text.h" + +enum EAddType +{ + NEWLINE, + APPENDLINE, + REPLACELINE +}; + +class FConsoleBuffer +{ + TArray mConsoleText; + TArray mBrokenConsoleText; // This holds the structures returned by V_BreakLines and is used for memory management. + TArray mBrokenStart; + TArray mBrokenLines; // This holds the single lines, indexed by mBrokenStart and is used for printing. + FILE * mLogFile; + EAddType mAddType; + int mTextLines; + bool mBufferWasCleared; + + FFont *mLastFont; + int mLastDisplayWidth; + bool mLastLineNeedsUpdate; + + void WriteLineToLog(FILE *LogFile, const char *outline); + void FreeBrokenText(unsigned int start = 0, unsigned int end = INT_MAX); + + void Linefeed(FILE *Logfile); + +public: + FConsoleBuffer(); + ~FConsoleBuffer(); + void AddText(int printlevel, const char *string, FILE *logfile = NULL); + void AddMidText(const char *string, bool bold, FILE *logfile); + void FormatText(FFont *formatfont, int displaywidth); + void ResizeBuffer(unsigned newsize); + void WriteContentToLog(FILE *logfile); + void Clear() + { + mBufferWasCleared = true; + mConsoleText.Clear(); + } + int GetFormattedLineCount() { return mTextLines; } + FBrokenLines **GetLines() { return &mBrokenLines[0]; } +}; + diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index e7f1b286b..67d0ffb10 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -19,12 +19,29 @@ struct OneKey bool check(AActor * owner) { - // P_GetMapColorForKey() checks the key directly - if (owner->IsKindOf (RUNTIME_CLASS(AKey))) + if (owner->IsKindOf(RUNTIME_CLASS(AKey))) + { + // P_GetMapColorForKey() checks the key directly return owner->IsA(key); - // Other calls check an actor that may have a key in its inventory. - else - return !!owner->FindInventory(key); + } + else + { + // Other calls check an actor that may have a key in its inventory. + AInventory *item; + + for (item = owner->Inventory; item != NULL; item = item->Inventory) + { + if (item->IsA(key)) + { + return true; + } + else if (item->GetSpecies() == key->TypeName) + { + return true; + } + } + return false; + } } }; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index cc559ea94..f14e7f4c7 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1018,7 +1018,7 @@ void AInventory::Touch (AActor *toucher) if (flags5 & MF5_COUNTSECRET) { - P_GiveSecret(toucher, true, true); + P_GiveSecret(toucher, true, true, -1); } //Added by MC: Check if item taken was the roam destination of any bot diff --git a/src/g_shared/a_secrettrigger.cpp b/src/g_shared/a_secrettrigger.cpp index 4484340db..24c6f0db4 100644 --- a/src/g_shared/a_secrettrigger.cpp +++ b/src/g_shared/a_secrettrigger.cpp @@ -42,8 +42,6 @@ #include "v_font.h" #include "p_spec.h" -EXTERN_CVAR(String, secretmessage) - class ASecretTrigger : public AActor { DECLARE_CLASS (ASecretTrigger, AActor) @@ -62,7 +60,7 @@ void ASecretTrigger::PostBeginPlay () void ASecretTrigger::Activate (AActor *activator) { - P_GiveSecret(activator, args[0] <= 1, (args[0] == 0 || args[0] == 2)); + P_GiveSecret(activator, args[0] <= 1, (args[0] == 0 || args[0] == 2), -1); Destroy (); } diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index f3ceec17d..210f0f3de 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -125,12 +125,10 @@ void FNodeBuilder::BuildTree () { fixed_t bbox[4]; - C_InitTicker ("Building BSP", FRACUNIT); HackSeg = DWORD_MAX; HackMate = DWORD_MAX; CreateNode (0, Segs.Size(), bbox); CreateSubsectorsForReal (); - C_InitTicker (NULL, 0); } int FNodeBuilder::CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]) @@ -199,10 +197,6 @@ int FNodeBuilder::CreateSubsector (DWORD set, fixed_t bbox[4]) } SegsStuffed += count; - if ((SegsStuffed & ~127) != ((SegsStuffed - count) & ~127)) - { - C_SetTicker (MulScale16 (SegsStuffed, (SDWORD)Segs.Size())); - } D(Printf (PRINT_LOG, "bbox (%d,%d)-(%d,%d)\n", bbox[BOXLEFT]>>16, bbox[BOXBOTTOM]>>16, bbox[BOXRIGHT]>>16, bbox[BOXTOP]>>16)); diff --git a/src/p_doors.cpp b/src/p_doors.cpp index b530f688d..7c6952d7f 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -297,7 +297,7 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const continue; FTexture *tex = TexMan[line->sidedef[0]->GetTexture(side_t::top)]; - texname = tex? tex->Name : NULL; + texname = tex ? tex->Name.GetChars() : NULL; if (texname != NULL && texname[0] == 'D' && texname[1] == 'O' && texname[2] == 'R') { switch (texname[3]) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 63f7c1c89..e66dc2ab4 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -61,6 +61,7 @@ #include "a_sharedglobal.h" #include "farchive.h" #include "a_keys.h" +#include "c_dispatch.h" // State. #include "r_state.h" @@ -73,9 +74,6 @@ static FRandom pr_playerinspecialsector ("PlayerInSpecialSector"); void P_SetupPortals(); -// [GrafZahl] Make this message changable by the user! ;) -CVAR(String, secretmessage, "A Secret is revealed!", CVAR_ARCHIVE) - IMPLEMENT_POINTY_CLASS (DScroller) DECLARE_POINTER (m_Interpolations[0]) DECLARE_POINTER (m_Interpolations[1]) @@ -581,7 +579,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) if (sector->special & SECRET_MASK) { sector->special &= ~SECRET_MASK; - P_GiveSecret(player->mo, true, true); + P_GiveSecret(player->mo, true, true, int(sector - sectors)); } } @@ -672,7 +670,9 @@ void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, // //============================================================================ -void P_GiveSecret(AActor *actor, bool printmessage, bool playsound) +CVAR(Bool, showsecretsector, false, 0) + +void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum) { if (actor != NULL) { @@ -682,7 +682,16 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound) } if (actor->CheckLocalView (consoleplayer)) { - if (printmessage) C_MidPrint (SmallFont, secretmessage); + if (printmessage) + { + if (!showsecretsector || sectornum < 0) C_MidPrint(SmallFont, GStrings["SECRETMESSAGE"]); + else + { + FString s = GStrings["SECRETMESSAGE"]; + s.AppendFormat(" (Sector %d)", sectornum); + C_MidPrint(SmallFont, s); + } + } if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM); } } diff --git a/src/p_spec.h b/src/p_spec.h index f8dad701b..245c699d7 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -172,7 +172,7 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType); void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, int flags); void P_SetSectorFriction (int tag, int amount, bool alterFlag); -void P_GiveSecret(AActor *actor, bool printmessage, bool playsound); +void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum); // // getSide() diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 012abb2f6..c1e59c415 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -63,7 +63,7 @@ static bool R_InstallSpriteLump (FTextureID lump, unsigned frame, char rot, bool if (frame >= MAX_SPRITE_FRAMES || rotation > 16) { - Printf (TEXTCOLOR_RED"R_InstallSpriteLump: Bad frame characters in lump %s\n", TexMan[lump]->Name); + Printf (TEXTCOLOR_RED"R_InstallSpriteLump: Bad frame characters in lump %s\n", TexMan[lump]->Name.GetChars()); return false; } @@ -249,6 +249,8 @@ static void R_InstallSprite (int num) // letter/number appended. // The rotation character can be 0 to signify no rotations. // +#define TEX_DWNAME(tex) MAKE_ID(tex->Name[0], tex->Name[1], tex->Name[2], tex->Name[3]) + void R_InitSpriteDefs () { struct Hasher @@ -272,7 +274,7 @@ void R_InitSpriteDefs () FTexture *tex = TexMan.ByIndex(i); if (tex->UseType == FTexture::TEX_Sprite && strlen(tex->Name) >= 6) { - size_t bucket = tex->dwName % smax; + size_t bucket = TEX_DWNAME(tex) % smax; hashes[i].Next = hashes[bucket].Head; hashes[bucket].Head = i; } @@ -352,7 +354,7 @@ void R_InitSpriteDefs () while (hash != -1) { FTexture *tex = TexMan[hash]; - if (tex->dwName == intname) + if (TEX_DWNAME(tex) == intname) { bool res = R_InstallSpriteLump (FTextureID(hash), tex->Name[4] - 'A', tex->Name[5], false); @@ -996,4 +998,4 @@ void R_DeinitSpriteData() delete[] skins; skins = NULL; } -} \ No newline at end of file +} diff --git a/src/r_utility.cpp b/src/r_utility.cpp index e11631700..5bf38ad26 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -972,7 +972,7 @@ void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, int fov) texture = static_cast(TexMan[picnum]); if (!texture->bHasCanvas) { - Printf ("%s is not a valid target for a camera\n", texture->Name); + Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars()); return; } diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index 3601646a0..58ef7a5ca 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -231,8 +231,8 @@ void FTextureManager::InitAnimated (void) if (debuganimated) { Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n", - tex1->Name, pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()), - tex2->Name, pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); + tex1->Name.GetChars(), pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()), + tex2->Name.GetChars(), pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); } if (pic1 == pic2) diff --git a/src/textures/buildtexture.cpp b/src/textures/buildtexture.cpp index e534ca9c8..ee5f66fab 100644 --- a/src/textures/buildtexture.cpp +++ b/src/textures/buildtexture.cpp @@ -78,7 +78,7 @@ FBuildTexture::FBuildTexture (int tilenum, const BYTE *pixels, int width, int he LeftOffset = left; TopOffset = top; CalcBitSize (); - mysnprintf (Name, countof(Name), "BTIL%04d", tilenum); + Name.Format("BTIL%04d", tilenum); UseType = TEX_Build; } diff --git a/src/textures/canvastexture.cpp b/src/textures/canvastexture.cpp index a6e1918df..8bfd1946b 100644 --- a/src/textures/canvastexture.cpp +++ b/src/textures/canvastexture.cpp @@ -41,8 +41,7 @@ FCanvasTexture::FCanvasTexture (const char *name, int width, int height) { - strncpy (Name, name, 8); - Name[8] = 0; + Name = name; Width = width; Height = height; LeftOffset = TopOffset = 0; diff --git a/src/textures/imgztexture.cpp b/src/textures/imgztexture.cpp index 36f954b95..153880d67 100644 --- a/src/textures/imgztexture.cpp +++ b/src/textures/imgztexture.cpp @@ -106,7 +106,6 @@ FIMGZTexture::FIMGZTexture (int lumpnum, WORD w, WORD h, SWORD l, SWORD t) : FTexture(NULL, lumpnum), Pixels(0), Spans(0) { Wads.GetLumpName (Name, lumpnum); - Name[8] = 0; Width = w; Height = h; LeftOffset = l; diff --git a/src/textures/jpegtexture.cpp b/src/textures/jpegtexture.cpp index 3a87f70af..849cec645 100644 --- a/src/textures/jpegtexture.cpp +++ b/src/textures/jpegtexture.cpp @@ -448,7 +448,7 @@ void FJPEGTexture::MakeTexture () } catch (int) { - Printf (TEXTCOLOR_ORANGE " in texture %s\n", Name); + Printf (TEXTCOLOR_ORANGE " in texture %s\n", Name.GetChars()); jpeg_destroy_decompress(&cinfo); } if (buff != NULL) @@ -532,7 +532,7 @@ int FJPEGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FC } catch(int) { - Printf (TEXTCOLOR_ORANGE " in JPEG texture %s\n", Name); + Printf (TEXTCOLOR_ORANGE " in JPEG texture %s\n", Name.GetChars()); } jpeg_destroy_decompress(&cinfo); if (buff != NULL) delete [] buff; diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 124add5db..348ad3a98 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -47,6 +47,7 @@ #include "colormatcher.h" #include "v_palette.h" #include "v_video.h" +#include "v_text.h" #include "m_fixed.h" #include "textures/textures.h" #include "r_data/colormaps.h" @@ -136,7 +137,7 @@ struct strifemaptexture_t struct FPatchLookup { - char Name[9]; + FString Name; FTexture *Texture; }; @@ -242,8 +243,7 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl Parts = NumParts > 0 ? new TexPart[NumParts] : NULL; Width = SAFESHORT(mtexture.d->width); Height = SAFESHORT(mtexture.d->height); - strncpy (Name, (const char *)mtexture.d->name, 8); - Name[8] = 0; + Name = (char *)mtexture.d->name; CalcBitSize (); xScale = mtexture.d->ScaleX ? mtexture.d->ScaleX*(FRACUNIT/8) : FRACUNIT; @@ -268,14 +268,14 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl if (unsigned(LittleShort(mpatch.d->patch)) >= unsigned(maxpatchnum)) { I_FatalError ("Bad PNAMES and/or texture directory:\n\nPNAMES has %d entries, but\n%s wants to use entry %d.", - maxpatchnum, Name, LittleShort(mpatch.d->patch)+1); + maxpatchnum, Name.GetChars(), LittleShort(mpatch.d->patch)+1); } Parts[i].OriginX = LittleShort(mpatch.d->originx); Parts[i].OriginY = LittleShort(mpatch.d->originy); Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture; if (Parts[i].Texture == NULL) { - Printf ("Unknown patch %s in texture %s\n", patchlookup[LittleShort(mpatch.d->patch)].Name, Name); + Printf(TEXTCOLOR_RED "Unknown patch %s in texture %s\n", patchlookup[LittleShort(mpatch.d->patch)].Name.GetChars(), Name.GetChars()); NumParts--; i--; } @@ -290,7 +290,7 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl } if (NumParts == 0) { - Printf ("Texture %s is left without any patches\n", Name); + Printf ("Texture %s is left without any patches\n", Name.GetChars()); } CheckForHacks (); @@ -823,7 +823,7 @@ FMultiPatchTexture::TexPart::TexPart() void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1) { - FPatchLookup *patchlookup; + FPatchLookup *patchlookup = NULL; int i; DWORD numpatches; @@ -856,12 +856,13 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d // Catalog the patches these textures use so we know which // textures they represent. - patchlookup = (FPatchLookup *)alloca (numpatches * sizeof(*patchlookup)); - + patchlookup = new FPatchLookup[numpatches]; for (DWORD i = 0; i < numpatches; ++i) { - pnames.Read (patchlookup[i].Name, 8); - patchlookup[i].Name[8] = 0; + char pname[9]; + pnames.Read(pname, 8); + pname[8] = '\0'; + patchlookup[i].Name = pname; FTextureID j = CheckForTexture (patchlookup[i].Name, FTexture::TEX_WallPatch); if (j.isValid()) { @@ -891,6 +892,7 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d if (maxoff < DWORD(numtextures+1)*4) { Printf ("Texture directory is too short"); + delete[] patchlookup; return; } @@ -901,6 +903,7 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d if (offset > maxoff) { Printf ("Bad texture directory"); + delete[] patchlookup; return; } @@ -936,6 +939,7 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d if (offset > maxoff) { Printf ("Bad texture directory"); + delete[] patchlookup; return; } @@ -959,6 +963,7 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d StartScreen->Progress(); } } + delete[] patchlookup; } @@ -1018,7 +1023,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, i } if (part.Texture == NULL) { - if (!silent) Printf("Unknown patch '%s' in texture '%s'\n", sc.String, Name); + if (!silent) Printf(TEXTCOLOR_RED "Unknown patch '%s' in texture '%s'\n", sc.String, Name.GetChars()); } sc.MustGetStringName(","); sc.MustGetNumber(); @@ -1220,8 +1225,8 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) bSilent = false; } } - uppercopy(Name, !textureName ? sc.String : textureName); - Name[8] = 0; + Name = !textureName ? sc.String : textureName; + Name.ToUpper(); sc.MustGetStringName(","); sc.MustGetNumber(); Width = sc.Number; @@ -1239,13 +1244,13 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) { sc.MustGetFloat(); xScale = FLOAT2FIXED(sc.Float); - if (xScale == 0) sc.ScriptError("Texture %s is defined with null x-scale\n", Name); + if (xScale == 0) sc.ScriptError("Texture %s is defined with null x-scale\n", Name.GetChars()); } else if (sc.Compare("YScale")) { sc.MustGetFloat(); yScale = FLOAT2FIXED(sc.Float); - if (yScale == 0) sc.ScriptError("Texture %s is defined with null y-scale\n", Name); + if (yScale == 0) sc.ScriptError("Texture %s is defined with null y-scale\n", Name.GetChars()); } else if (sc.Compare("WorldPanning")) { @@ -1313,7 +1318,7 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) if (Width <= 0 || Height <= 0) { UseType = FTexture::TEX_Null; - Printf("Texture %s has invalid dimensions (%d, %d)\n", Name, Width, Height); + Printf("Texture %s has invalid dimensions (%d, %d)\n", Name.GetChars(), Width, Height); Width = Height = 1; } CalcBitSize (); diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index f41f1902d..6ee6ccb0a 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -137,7 +137,10 @@ FTexture * FTexture::CreateTexture (int lumpnum, int usetype) FTexture * FTexture::CreateTexture (const char *name, int lumpnum, int usetype) { FTexture *tex = CreateTexture(lumpnum, usetype); - if (tex != NULL && name != NULL) uppercopy(tex->Name, name); + if (tex != NULL && name != NULL) { + tex->Name = name; + tex->Name.ToUpper(); + } return tex; } @@ -152,16 +155,16 @@ FTexture::FTexture (const char *name, int lumpnum) id.SetInvalid(); if (name != NULL) { - uppercopy(Name, name); + Name = name; + Name.ToUpper(); } else if (lumpnum < 0) { - *Name = 0; + Name = FString(); } else { Wads.GetLumpName (Name, lumpnum); - Name[8] = 0; } } @@ -574,7 +577,6 @@ FDummyTexture::FDummyTexture () HeightBits = 6; WidthBits = 6; WidthMask = 63; - Name[0] = 0; UseType = TEX_Null; } diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 6fb963e42..a79769c3d 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -373,7 +373,7 @@ FTextureID FTextureManager::AddTexture (FTexture *texture) // Later textures take precedence over earlier ones // Textures without name can't be looked for - if (texture->Name[0] != 0) + if (texture->Name[0] != '\0') { bucket = int(MakeKey (texture->Name) % HASH_SIZE); hash = HashFirst[bucket]; @@ -429,7 +429,7 @@ void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, b FTexture *oldtexture = Textures[index].Texture; - strcpy (newtexture->Name, oldtexture->Name); + newtexture->Name = oldtexture->Name; newtexture->UseType = oldtexture->UseType; Textures[index].Texture = newtexture; @@ -488,9 +488,7 @@ void FTextureManager::AddGroup(int wadnum, int ns, int usetype) { int firsttx = Wads.GetFirstLump(wadnum); int lasttx = Wads.GetLastLump(wadnum); - char name[9]; - - name[8] = 0; + FString Name; // Go from first to last so that ANIMDEFS work as expected. However, // to avoid duplicates (and to keep earlier entries from overriding @@ -501,9 +499,9 @@ void FTextureManager::AddGroup(int wadnum, int ns, int usetype) { if (Wads.GetLumpNamespace(firsttx) == ns) { - Wads.GetLumpName (name, firsttx); + Wads.GetLumpName (Name, firsttx); - if (Wads.CheckNumForName (name, ns) == firsttx) + if (Wads.CheckNumForName (Name, ns) == firsttx) { CreateTexture (firsttx, usetype); } @@ -511,7 +509,7 @@ void FTextureManager::AddGroup(int wadnum, int ns, int usetype) } else if (ns == ns_flats && Wads.GetLumpFlags(firsttx) & LUMPF_MAYBEFLAT) { - if (Wads.CheckNumForName (name, ns) < firsttx) + if (Wads.CheckNumForName (Name, ns) < firsttx) { CreateTexture (firsttx, usetype); } @@ -531,7 +529,7 @@ void FTextureManager::AddHiresTextures (int wadnum) int firsttx = Wads.GetFirstLump(wadnum); int lasttx = Wads.GetLastLump(wadnum); - char name[9]; + FString Name; TArray tlist; if (firsttx == -1 || lasttx == -1) @@ -539,18 +537,16 @@ void FTextureManager::AddHiresTextures (int wadnum) return; } - name[8] = 0; - for (;firsttx <= lasttx; ++firsttx) { if (Wads.GetLumpNamespace(firsttx) == ns_hires) { - Wads.GetLumpName (name, firsttx); + Wads.GetLumpName (Name, firsttx); - if (Wads.CheckNumForName (name, ns_hires) == firsttx) + if (Wads.CheckNumForName (Name, ns_hires) == firsttx) { tlist.Clear(); - int amount = ListTextures(name, tlist); + int amount = ListTextures(Name, tlist); if (amount == 0) { // A texture with this name does not yet exist @@ -594,14 +590,13 @@ void FTextureManager::AddHiresTextures (int wadnum) void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) { int remapLump, lastLump; - char src[9]; + FString src; bool is32bit; int width, height; int type, mode; TArray tlist; lastLump = 0; - src[8] = '\0'; while ((remapLump = Wads.FindLump(lumpname, &lastLump)) != -1) { @@ -678,7 +673,7 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) FString base = ExtractFileBase(sc.String, false); if (!base.IsEmpty()) { - strncpy(src, base, 8); + src = base.Left(8); int lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_patches); if (lumpnum == -1) lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_graphics); @@ -701,7 +696,7 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) // Replace the entire texture and adjust the scaling and offset factors. newtex->bWorldPanning = true; newtex->SetScaledSize(width, height); - memcpy(newtex->Name, src, sizeof(newtex->Name)); + newtex->Name = src; FTextureID oldtex = TexMan.CheckForTexture(src, FTexture::TEX_MiscPatch); if (oldtex.isValid()) @@ -757,7 +752,7 @@ void FTextureManager::AddPatches (int lumpnum) char name[9]; *file >> numpatches; - name[8] = 0; + name[8] = '\0'; for (i = 0; i < numpatches; ++i) { @@ -839,9 +834,8 @@ void FTextureManager::AddTexturesForWad(int wadnum) for (int i= firsttx; i <= lasttx; i++) { bool skin = false; - char name[9]; - Wads.GetLumpName(name, i); - name[8]=0; + FString Name; + Wads.GetLumpName(Name, i); // Ignore anything not in the global namespace int ns = Wads.GetLumpNamespace(i); @@ -867,20 +861,20 @@ void FTextureManager::AddTexturesForWad(int wadnum) if (Wads.CheckLumpName(i, "BEHAVIOR")) continue; // Don't bother looking at this lump if something later overrides it. - if (Wads.CheckNumForName(name, ns_graphics) != i) continue; + if (Wads.CheckNumForName(Name, ns_graphics) != i) continue; // skip this if it has already been added as a wall patch. - if (CheckForTexture(name, FTexture::TEX_WallPatch, 0).Exists()) continue; + if (CheckForTexture(Name, FTexture::TEX_WallPatch, 0).Exists()) continue; } else if (ns == ns_graphics) { // Don't bother looking this lump if something later overrides it. - if (Wads.CheckNumForName(name, ns_graphics) != i) continue; + if (Wads.CheckNumForName(Name, ns_graphics) != i) continue; } else if (ns >= ns_firstskin) { // Don't bother looking this lump if something later overrides it. - if (Wads.CheckNumForName(name, ns) != i) continue; + if (Wads.CheckNumForName(Name, ns) != i) continue; skin = true; } else continue; @@ -955,7 +949,7 @@ void FTextureManager::SortTexturesByType(int start, int end) { if (newtextures[j] != NULL) { - Printf("Texture %s has unknown type!\n", newtextures[j]->Name); + Printf("Texture %s has unknown type!\n", newtextures[j]->Name.GetChars()); AddTexture(newtextures[j]); } } diff --git a/src/textures/textures.h b/src/textures/textures.h index 3530cf334..ff0e22c0c 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -180,11 +180,7 @@ public: int SourceLump; FTextureID id; - union - { - char Name[9]; - DWORD dwName; // Used with sprites - }; + FString Name; BYTE UseType; // This texture's primary purpose BYTE bNoDecals:1; // Decals should not stick to texture diff --git a/src/textures/tgatexture.cpp b/src/textures/tgatexture.cpp index 374861699..cff89603c 100644 --- a/src/textures/tgatexture.cpp +++ b/src/textures/tgatexture.cpp @@ -145,7 +145,6 @@ FTGATexture::FTGATexture (int lumpnum, TGAHeader * hdr) : FTexture(NULL, lumpnum), Pixels(0), Spans(0) { Wads.GetLumpName (Name, lumpnum); - Name[8] = 0; Width = hdr->width; Height = hdr->height; // Alpha channel is used only for 32 bit RGBA and paletted images with RGBA palettes. diff --git a/src/v_text.cpp b/src/v_text.cpp index c5208be36..64b95c041 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -336,7 +336,7 @@ static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const B line->Width = font->StringWidth (line->Text); } -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string) +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor) { FBrokenLines lines[128]; // Support up to 128 lines (should be plenty) @@ -397,7 +397,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string) space = string - 1; breakit (&lines[i], font, start, space, linecolor); - if (c == '\n') + if (c == '\n' && !preservecolor) { lastcolor = ""; // Why, oh why, did I do it like this? } diff --git a/src/v_text.h b/src/v_text.h index 29dfa627b..f1426b30a 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -75,9 +75,9 @@ struct FBrokenLines #define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_TEAMCHAT "\034!" -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str); +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false); void V_FreeBrokenLines (FBrokenLines *lines); -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str) - { return V_BreakLines (font, maxwidth, (const BYTE *)str); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) + { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor); } #endif //__V_TEXT_H__ diff --git a/src/w_wad.cpp b/src/w_wad.cpp index c351de6f8..9455817db 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -492,7 +492,7 @@ int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int n return -1; } - i = FirstLumpIndex_FullName[MakeKey (name) % NumLumps]; + i = FirstLumpIndex_FullName[MakeKey(name) % NumLumps]; while (i != NULL_INDEX && stricmp(name, LumpInfo[i].lump->FullName)) { @@ -1015,6 +1015,16 @@ void FWadCollection::GetLumpName (char *to, int lump) const uppercopy (to, LumpInfo[lump].lump->Name); } +void FWadCollection::GetLumpName(FString &to, int lump) const +{ + if ((size_t)lump >= NumLumps) + to = FString(); + else { + to = LumpInfo[lump].lump->Name; + to.ToUpper(); + } +} + //========================================================================== // // FWadCollection :: GetLumpFullName diff --git a/src/w_wad.h b/src/w_wad.h index 530182147..4dfe3434d 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -196,6 +196,7 @@ public: int GetLumpOffset (int lump); // [RH] Returns offset of lump in the wadfile int GetLumpFlags (int lump); // Return the flags for this lump void GetLumpName (char *to, int lump) const; // [RH] Copies the lump name to to using uppercopy + void GetLumpName (FString &to, int lump) const; const char *GetLumpFullName (int lump) const; // [RH] Returns the lump's full name FString GetLumpFullPath (int lump) const; // [RH] Returns wad's name + lump's full name int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 5695ad502..76ba7c0d7 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2,6 +2,8 @@ [enu default] +SECRETMESSAGE = "A secret is revealed!"; + D_DEVSTR = "Useless mode ON.\n"; D_CDROM = "CD-ROM Version: zdoom.ini from c:\\zdoomdat\n"; PRESSKEY = "press a key.";