Merge pull request #1 from rheit/master

Sync with zdoom trunk
This commit is contained in:
Shawn 2014-06-21 20:38:05 -07:00
commit 640a6156e5
35 changed files with 883 additions and 611 deletions

View file

@ -74,8 +74,24 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
*c = c2; *c = c2;
*d = d2; *d = d2;
#elif __PIC__
/* GCC or Clang WITH position-independent code generation */
__asm__ __volatile__ (
"xchgl %%ebx, %1\n"
"cpuid\n"
"xchgl %%ebx, %1\n"
: "=a" (*a) ,
"=r" (*b) ,
"=c" (*c) ,
"=d" (*d)
: "0" (function)) ;
#else #else
/* GCC or Clang WITHOUT position-independent code generation */
__asm__ __volatile__ ( __asm__ __volatile__ (
"cpuid" "cpuid"
: "=a" (*a) , : "=a" (*a) ,

View file

@ -789,6 +789,7 @@ add_executable( zdoom WIN32
c_bind.cpp c_bind.cpp
c_cmds.cpp c_cmds.cpp
c_console.cpp c_console.cpp
c_consolebuffer.cpp
c_cvars.cpp c_cvars.cpp
c_dispatch.cpp c_dispatch.cpp
c_expr.cpp c_expr.cpp

View file

@ -65,22 +65,29 @@
#include "g_level.h" #include "g_level.h"
#include "d_event.h" #include "d_event.h"
#include "d_player.h" #include "d_player.h"
#include "c_consolebuffer.h"
#include "gi.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 LEFTMARGIN 8
#define RIGHTMARGIN 8 #define RIGHTMARGIN 8
#define BOTTOMARGIN 12 #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 void C_TabComplete (bool goForward);
static bool C_TabCompleteList (); static bool C_TabCompleteList ();
static bool TabbedLast; // True if last key pressed was tab static bool TabbedLast; // True if last key pressed was tab
static bool TabbedList; // True if tab list was shown 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 FTextureID conback;
static DWORD conshade; static DWORD conshade;
@ -94,18 +101,15 @@ extern FBaseCVar *CVars;
extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE];
int ConCols, PhysRows; int ConCols, PhysRows;
int ConWidth;
bool vidactive = false; bool vidactive = false;
bool cursoron = false; bool cursoron = false;
int ConBottom, ConScroll, RowAdjust; int ConBottom, ConScroll, RowAdjust;
int CursorTicker; int CursorTicker;
constate_e ConsoleState = c_up; constate_e ConsoleState = c_up;
static char ConsoleBuffer[CONSOLESIZE];
static char *Lines[CONSOLELINES];
static bool LineJoins[CONSOLELINES];
static int TopLine, InsertLine; static int TopLine, InsertLine;
static char *BufferRover = ConsoleBuffer;
static void ClearConsole (); static void ClearConsole ();
static void C_PasteText(FString clip, BYTE *buffer, int len); static void C_PasteText(FString clip, BYTE *buffer, int len);
@ -182,7 +186,6 @@ static struct NotifyText
static int NotifyTop, NotifyTopGoal; static int NotifyTop, NotifyTopGoal;
#define PRINTLEVELS 5
int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_GREEN, CR_GOLD }; int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_GREEN, CR_GOLD };
static void setmsgcolor (int index, int color); static void setmsgcolor (int index, int color);
@ -328,78 +331,11 @@ void C_InitConsole (int width, int height, bool ingame)
{ {
cwidth = cheight = 8; cwidth = cheight = 8;
} }
ConCols = (width - LEFTMARGIN - RIGHTMARGIN) / cwidth; ConWidth = (width - LEFTMARGIN - RIGHTMARGIN);
ConCols = ConWidth / cwidth;
PhysRows = height / cheight; PhysRows = height / cheight;
// If there is some text in the console buffer, reformat it if (conbuffer == NULL) conbuffer = new FConsoleBuffer;
// 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);
}
} }
//========================================================================== //==========================================================================
@ -507,16 +443,21 @@ void C_DeinitConsole ()
work = NULL; work = NULL;
worklen = 0; worklen = 0;
} }
if (conbuffer != NULL)
{
delete conbuffer;
conbuffer = NULL;
}
} }
static void ClearConsole () static void ClearConsole ()
{ {
RowAdjust = 0; if (conbuffer != NULL)
{
conbuffer->Clear();
}
TopLine = InsertLine = 0; 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) static void setmsgcolor (int index, int color)
@ -596,223 +537,9 @@ void C_AddNotifyString (int printlevel, const char *source)
NotifyTopGoal = 0; 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) void AddToConsole (int printlevel, const char *text)
{ {
static enum conbuffer->AddText(printlevel, text, Logfile);
{
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;
}
} }
/* Adds a string to the console and also to the notify buffer */ /* 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; 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) if (printlevel != PRINT_LOG)
{ {
I_PrintStr (outline); I_PrintStr (outline);
@ -949,6 +648,11 @@ void C_Ticker ()
if (lasttic == 0) if (lasttic == 0)
lasttic = gametic - 1; lasttic = gametic - 1;
if (con_buffersize > 0)
{
conbuffer->ResizeBuffer(con_buffersize);
}
if (ConsoleState != c_up) if (ConsoleState != c_up)
{ {
if (ConsoleState == c_falling) if (ConsoleState == c_falling)
@ -1236,38 +940,22 @@ void C_DrawConsole (bool hw2d)
if (lines > 0) 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 bottomline = ConBottom - ConFont->GetHeight()*2 - 4;
int pos = (InsertLine - 1) & LINEMASK;
int i;
ConsoleDrawing = true; ConsoleDrawing = true;
for (i = RowAdjust; i; i--) for(FBrokenLines **p = printline; p >= blines && lines > 0; p--, lines--)
{ {
if (pos == TopLine) screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, TAG_DONE);
{
RowAdjust = RowAdjust - i;
break;
}
else
{
pos = (pos - 1) & LINEMASK;
}
} }
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; ConsoleDrawing = false;
DequeueConsoleText ();
if (ConBottom >= 20) if (ConBottom >= 20)
{ {
@ -1293,7 +981,7 @@ void C_DrawConsole (bool hw2d)
{ {
// Indicate that the view has been scrolled up (10) // Indicate that the view has been scrolled up (10)
// and if we can scroll no further (12) // 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) / RowAdjust += (SCREENHEIGHT-4) /
((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? ConFont->GetHeight() : ConFont->GetHeight()*2) - 3; ((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 { // Scroll console buffer up
if (ev->subtype == EV_GUI_WheelUp) if (ev->subtype == EV_GUI_WheelUp)
{ {
@ -1455,6 +1143,10 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len)
{ {
RowAdjust++; RowAdjust++;
} }
if (RowAdjust > conbuffer->GetFormattedLineCount())
{
RowAdjust = conbuffer->GetFormattedLineCount();
}
} }
break; break;
@ -1488,7 +1180,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len)
case GK_HOME: case GK_HOME:
if (ev->data3 & GKM_CTRL) if (ev->data3 & GKM_CTRL)
{ // Move to top of console buffer { // Move to top of console buffer
RowAdjust = CONSOLELINES; RowAdjust = conbuffer->GetFormattedLineCount();
} }
else else
{ // Move cursor to start of line { // Move cursor to start of line

View file

@ -47,6 +47,9 @@ typedef enum cstate_t
} }
constate_e; constate_e;
#define PRINTLEVELS 5
extern int PrintColors[PRINTLEVELS + 2];
extern constate_e ConsoleState; extern constate_e ConsoleState;
extern int ConBottom; extern int ConBottom;

317
src/c_consolebuffer.cpp Normal file
View file

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

85
src/c_consolebuffer.h Normal file
View file

@ -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 <limits.h>
#include <stdio.h>
#include "zstring.h"
#include "tarray.h"
#include "v_text.h"
enum EAddType
{
NEWLINE,
APPENDLINE,
REPLACELINE
};
class FConsoleBuffer
{
TArray<FString> mConsoleText;
TArray<FBrokenLines *> mBrokenConsoleText; // This holds the structures returned by V_BreakLines and is used for memory management.
TArray<unsigned int> mBrokenStart;
TArray<FBrokenLines *> 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]; }
};

View file

@ -1307,7 +1307,7 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags)
} }
// Clears the entire inventory and gives back the defaults for starting a game // Clears the entire inventory and gives back the defaults for starting a game
if (flags & CHANGELEVEL_RESETINVENTORY) if ((flags & CHANGELEVEL_RESETINVENTORY) && p->playerstate != PST_DEAD)
{ {
p->mo->ClearInventory(); p->mo->ClearInventory();
p->mo->GiveDefaultInventory(); p->mo->GiveDefaultInventory();

View file

@ -19,12 +19,29 @@ struct OneKey
bool check(AActor * owner) 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); return owner->IsA(key);
// Other calls check an actor that may have a key in its inventory. }
else else
return !!owner->FindInventory(key); {
// 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;
}
} }
}; };

View file

@ -1018,7 +1018,7 @@ void AInventory::Touch (AActor *toucher)
if (flags5 & MF5_COUNTSECRET) 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 //Added by MC: Check if item taken was the roam destination of any bot

View file

@ -42,8 +42,6 @@
#include "v_font.h" #include "v_font.h"
#include "p_spec.h" #include "p_spec.h"
EXTERN_CVAR(String, secretmessage)
class ASecretTrigger : public AActor class ASecretTrigger : public AActor
{ {
DECLARE_CLASS (ASecretTrigger, AActor) DECLARE_CLASS (ASecretTrigger, AActor)
@ -62,7 +60,7 @@ void ASecretTrigger::PostBeginPlay ()
void ASecretTrigger::Activate (AActor *activator) 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 (); Destroy ();
} }

View file

@ -1143,7 +1143,7 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player)
return weap; return weap;
} }
} }
while ((slot != startslot || index != startindex) && slotschecked < NUM_WEAPON_SLOTS); while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
} }
return player->ReadyWeapon; return player->ReadyWeapon;
} }
@ -1198,7 +1198,7 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player)
return weap; return weap;
} }
} }
while ((slot != startslot || index != startindex) && slotschecked < NUM_WEAPON_SLOTS); while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
} }
return player->ReadyWeapon; return player->ReadyWeapon;
} }

View file

@ -82,9 +82,7 @@ CVAR (Int, sb_deathmatch_otherplayercolor, CR_GREY, CVAR_ARCHIVE)
CVAR (Bool, sb_teamdeathmatch_enable, true, CVAR_ARCHIVE) CVAR (Bool, sb_teamdeathmatch_enable, true, CVAR_ARCHIVE)
CVAR (Int, sb_teamdeathmatch_headingcolor, CR_RED, CVAR_ARCHIVE) CVAR (Int, sb_teamdeathmatch_headingcolor, CR_RED, CVAR_ARCHIVE)
// PRIVATE DATA DEFINITIONS ------------------------------------------------ int STACK_ARGS comparepoints (const void *arg1, const void *arg2)
static int STACK_ARGS comparepoints (const void *arg1, const void *arg2)
{ {
// Compare first be frags/kills, then by name. // Compare first be frags/kills, then by name.
player_t *p1 = *(player_t **)arg1; player_t *p1 = *(player_t **)arg1;
@ -99,7 +97,7 @@ static int STACK_ARGS comparepoints (const void *arg1, const void *arg2)
return diff; return diff;
} }
static int STACK_ARGS compareteams (const void *arg1, const void *arg2) int STACK_ARGS compareteams (const void *arg1, const void *arg2)
{ {
// Compare first by teams, then by frags, then by name. // Compare first by teams, then by frags, then by name.
player_t *p1 = *(player_t **)arg1; player_t *p1 = *(player_t **)arg1;
@ -118,6 +116,8 @@ static int STACK_ARGS compareteams (const void *arg1, const void *arg2)
return diff; return diff;
} }
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
//========================================================================== //==========================================================================
@ -247,7 +247,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
lineheight = MAX(height, maxiconheight * CleanYfac); lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2; ypadding = (lineheight - height + 1) / 2;
bottom = gamestate != GS_INTERMISSION ? ST_Y : SCREENHEIGHT; bottom = ST_Y;
y = MAX(48*CleanYfac, (bottom - MAXPLAYERS * (height + CleanYfac + 1)) / 2); y = MAX(48*CleanYfac, (bottom - MAXPLAYERS * (height + CleanYfac + 1)) / 2);
HU_DrawTimeRemaining (bottom - height); HU_DrawTimeRemaining (bottom - height);
@ -255,10 +255,6 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
if (teamplay && deathmatch) if (teamplay && deathmatch)
{ {
y -= (BigFont->GetHeight() + 8) * CleanYfac; y -= (BigFont->GetHeight() + 8) * CleanYfac;
if (gamestate == GS_INTERMISSION)
{
y = MAX(BigFont->GetHeight() * 4, y);
}
for (i = 0; i < Teams.Size (); i++) for (i = 0; i < Teams.Size (); i++)
{ {

View file

@ -50,4 +50,9 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheigh
void HU_DrawColorBar(int x, int y, int height, int playernum); void HU_DrawColorBar(int x, int y, int height, int playernum);
int HU_GetRowColor(player_t *player, bool hightlight); int HU_GetRowColor(player_t *player, bool hightlight);
// Sorting routines
int comparepoints(const void *arg1, const void *arg2);
int compareteams(const void *arg1, const void *arg2);
#endif #endif

View file

@ -335,7 +335,7 @@ FString M_GetCachePath(bool create)
char pathstr[PATH_MAX]; char pathstr[PATH_MAX];
FSRef folder; FSRef folder;
if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) && if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX))
{ {
path = pathstr; path = pathstr;

View file

@ -125,12 +125,10 @@ void FNodeBuilder::BuildTree ()
{ {
fixed_t bbox[4]; fixed_t bbox[4];
C_InitTicker ("Building BSP", FRACUNIT);
HackSeg = DWORD_MAX; HackSeg = DWORD_MAX;
HackMate = DWORD_MAX; HackMate = DWORD_MAX;
CreateNode (0, Segs.Size(), bbox); CreateNode (0, Segs.Size(), bbox);
CreateSubsectorsForReal (); CreateSubsectorsForReal ();
C_InitTicker (NULL, 0);
} }
int FNodeBuilder::CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]) 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; 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)); D(Printf (PRINT_LOG, "bbox (%d,%d)-(%d,%d)\n", bbox[BOXLEFT]>>16, bbox[BOXBOTTOM]>>16, bbox[BOXRIGHT]>>16, bbox[BOXTOP]>>16));

View file

@ -959,6 +959,7 @@ bool P_LoadGLNodes(MapData * map)
bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime) bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime)
{ {
bool ret = false; bool ret = false;
bool loaded = false;
// If the map loading code has performed a node rebuild we don't need to check for it again. // If the map loading code has performed a node rebuild we don't need to check for it again.
if (!rebuilt && !P_CheckForGLNodes()) if (!rebuilt && !P_CheckForGLNodes())
@ -978,7 +979,8 @@ bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime)
numsegs = 0; numsegs = 0;
// Try to load GL nodes (cached or GWA) // Try to load GL nodes (cached or GWA)
if (!P_LoadGLNodes(map)) loaded = P_LoadGLNodes(map);
if (!loaded)
{ {
// none found - we have to build new ones! // none found - we have to build new ones!
unsigned int startTime, endTime; unsigned int startTime, endTime;
@ -1006,20 +1008,22 @@ bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime)
} }
} }
if (!loaded)
{
#ifdef DEBUG #ifdef DEBUG
// Building nodes in debug is much slower so let's cache them only if cachetime is 0 // Building nodes in debug is much slower so let's cache them only if cachetime is 0
buildtime = 0; buildtime = 0;
#endif #endif
if (gl_cachenodes && buildtime/1000.f >= gl_cachetime) if (gl_cachenodes && buildtime/1000.f >= gl_cachetime)
{ {
DPrintf("Caching nodes\n"); DPrintf("Caching nodes\n");
CreateCachedNodes(map); CreateCachedNodes(map);
}
else
{
DPrintf("Not caching nodes (time = %f)\n", buildtime/1000.f);
}
} }
else
{
DPrintf("Not caching nodes (time = %f)\n", buildtime/1000.f);
}
if (!gamenodes) if (!gamenodes)
{ {
@ -1168,8 +1172,21 @@ static void CreateCachedNodes(MapData *map)
FString path = CreateCacheName(map, true); FString path = CreateCacheName(map, true);
FILE *f = fopen(path, "wb"); FILE *f = fopen(path, "wb");
fwrite(compressed, 1, outlen+offset, f);
fclose(f); if (f != NULL)
{
if (fwrite(compressed, outlen+offset, 1, f) != 1)
{
Printf("Error saving nodes to file %s\n", path.GetChars());
}
fclose(f);
}
else
{
Printf("Cannot open nodes file %s for writing\n", path.GetChars());
}
delete [] compressed; delete [] compressed;
} }

View file

@ -320,6 +320,10 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
message = GStrings("OB_DEFAULT"); message = GStrings("OB_DEFAULT");
} }
// [CK] Don't display empty strings
if (message == NULL || strlen(message) <= 0)
return;
SexMessage (message, gendermessage, gender, SexMessage (message, gendermessage, gender,
self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
Printf (PRINT_MEDIUM, "%s\n", gendermessage); Printf (PRINT_MEDIUM, "%s\n", gendermessage);

View file

@ -500,6 +500,7 @@ void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance,
void P_DelSector_List(); void P_DelSector_List();
void P_DelSeclist(msecnode_t *); // phares 3/16/98 void P_DelSeclist(msecnode_t *); // phares 3/16/98
msecnode_t* P_DelSecnode(msecnode_t *);
void P_CreateSecNodeList(AActor*,fixed_t,fixed_t); // phares 3/14/98 void P_CreateSecNodeList(AActor*,fixed_t,fixed_t); // phares 3/14/98
int P_GetMoveFactor(const AActor *mo, int *frictionp); // phares 3/6/98 int P_GetMoveFactor(const AActor *mo, int *frictionp); // phares 3/6/98
int P_GetFriction(const AActor *mo, int *frictionfactor); int P_GetFriction(const AActor *mo, int *frictionfactor);

View file

@ -61,6 +61,7 @@
#include "a_sharedglobal.h" #include "a_sharedglobal.h"
#include "farchive.h" #include "farchive.h"
#include "a_keys.h" #include "a_keys.h"
#include "c_dispatch.h"
// State. // State.
#include "r_state.h" #include "r_state.h"
@ -73,9 +74,6 @@ static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
void P_SetupPortals(); void P_SetupPortals();
// [GrafZahl] Make this message changable by the user! ;)
CVAR(String, secretmessage, "A Secret is revealed!", CVAR_ARCHIVE)
IMPLEMENT_POINTY_CLASS (DScroller) IMPLEMENT_POINTY_CLASS (DScroller)
DECLARE_POINTER (m_Interpolations[0]) DECLARE_POINTER (m_Interpolations[0])
DECLARE_POINTER (m_Interpolations[1]) DECLARE_POINTER (m_Interpolations[1])
@ -581,7 +579,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
if (sector->special & SECRET_MASK) if (sector->special & SECRET_MASK)
{ {
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) if (actor != NULL)
{ {
@ -682,7 +682,16 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound)
} }
if (actor->CheckLocalView (consoleplayer)) 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); if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM);
} }
} }

View file

@ -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_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, int flags);
void P_SetSectorFriction (int tag, int amount, bool alterFlag); 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() // getSide()

View file

@ -1246,6 +1246,7 @@ public:
int fadecolor = -1; int fadecolor = -1;
int desaturation = -1; int desaturation = -1;
int fplaneflags = 0, cplaneflags = 0; int fplaneflags = 0, cplaneflags = 0;
double fp[4] = { 0 }, cp[4] = { 0 };
memset(sec, 0, sizeof(*sec)); memset(sec, 0, sizeof(*sec));
sec->lightlevel = 160; sec->lightlevel = 160;
@ -1449,44 +1450,42 @@ public:
case NAME_floorplane_a: case NAME_floorplane_a:
fplaneflags |= 1; fplaneflags |= 1;
sec->floorplane.a = CheckFixed(key); fp[0] = CheckFloat(key);
break; break;
case NAME_floorplane_b: case NAME_floorplane_b:
fplaneflags |= 2; fplaneflags |= 2;
sec->floorplane.b = CheckFixed(key); fp[1] = CheckFloat(key);
break; break;
case NAME_floorplane_c: case NAME_floorplane_c:
fplaneflags |= 4; fplaneflags |= 4;
sec->floorplane.c = CheckFixed(key); fp[2] = CheckFloat(key);
sec->floorplane.ic = FixedDiv(FRACUNIT, sec->floorplane.c);
break; break;
case NAME_floorplane_d: case NAME_floorplane_d:
fplaneflags |= 8; fplaneflags |= 8;
sec->floorplane.d = CheckFixed(key); fp[3] = CheckFloat(key);
break; break;
case NAME_ceilingplane_a: case NAME_ceilingplane_a:
cplaneflags |= 1; cplaneflags |= 1;
sec->ceilingplane.a = CheckFixed(key); cp[0] = CheckFloat(key);
break; break;
case NAME_ceilingplane_b: case NAME_ceilingplane_b:
cplaneflags |= 2; cplaneflags |= 2;
sec->ceilingplane.b = CheckFixed(key); cp[1] = CheckFloat(key);
break; break;
case NAME_ceilingplane_c: case NAME_ceilingplane_c:
cplaneflags |= 4; cplaneflags |= 4;
sec->ceilingplane.c = CheckFixed(key); cp[2] = CheckFloat(key);
sec->ceilingplane.ic = FixedDiv(FRACUNIT, sec->ceilingplane.c);
break; break;
case NAME_ceilingplane_d: case NAME_ceilingplane_d:
cplaneflags |= 8; cplaneflags |= 8;
sec->ceilingplane.d = CheckFixed(key); cp[3] = CheckFloat(key);
break; break;
default: default:
@ -1509,6 +1508,17 @@ public:
sec->floorplane.c = FRACUNIT; sec->floorplane.c = FRACUNIT;
sec->floorplane.ic = FRACUNIT; sec->floorplane.ic = FRACUNIT;
} }
else
{
double ulen = TVector3<double>(fp[0], fp[1], fp[2]).Length();
// normalize the vector, it must have a length of 1
sec->floorplane.a = FLOAT2FIXED(fp[0] / ulen);
sec->floorplane.b = FLOAT2FIXED(fp[1] / ulen);
sec->floorplane.c = FLOAT2FIXED(fp[2] / ulen);
sec->floorplane.d = FLOAT2FIXED(fp[3] / ulen);
sec->floorplane.ic = FLOAT2FIXED(ulen / fp[2]);
}
if (cplaneflags != 15) if (cplaneflags != 15)
{ {
sec->ceilingplane.a = sec->ceilingplane.b = 0; sec->ceilingplane.a = sec->ceilingplane.b = 0;
@ -1516,6 +1526,17 @@ public:
sec->ceilingplane.c = -FRACUNIT; sec->ceilingplane.c = -FRACUNIT;
sec->ceilingplane.ic = -FRACUNIT; sec->ceilingplane.ic = -FRACUNIT;
} }
else
{
double ulen = TVector3<double>(cp[0], cp[1], cp[2]).Length();
// normalize the vector, it must have a length of 1
sec->floorplane.a = FLOAT2FIXED(cp[0] / ulen);
sec->floorplane.b = FLOAT2FIXED(cp[1] / ulen);
sec->floorplane.c = FLOAT2FIXED(cp[2] / ulen);
sec->floorplane.d = FLOAT2FIXED(cp[3] / ulen);
sec->floorplane.ic = FLOAT2FIXED(ulen / cp[2]);
}
if (lightcolor == -1 && fadecolor == -1 && desaturation == -1) if (lightcolor == -1 && fadecolor == -1 && desaturation == -1)
{ {

View file

@ -2742,25 +2742,11 @@ void P_UnPredictPlayer ()
act->UnlinkFromWorld(); act->UnlinkFromWorld();
memcpy(&act->x, PredictionActorBackup, sizeof(AActor)-((BYTE *)&act->x - (BYTE *)act)); memcpy(&act->x, PredictionActorBackup, sizeof(AActor)-((BYTE *)&act->x - (BYTE *)act));
// Make the sector_list match the player's touching_sectorlist before it got predicted. // The blockmap ordering needs to remain unchanged, too.
P_DelSeclist(sector_list); // Restore sector links and refrences.
sector_list = NULL; // [ED850] This is somewhat of a duplicate of LinkToWorld(), but we need to keep every thing the same,
for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;) // otherwise we end up fixing bugs in blockmap logic (i.e undefined behaviour with polyobject collisions),
{ // which we really don't want to do here.
sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list);
}
// The blockmap ordering needs to remain unchanged, too. Right now, act has the right
// pointers, so temporarily set its MF_NOBLOCKMAP flag so that LinkToWorld() does not
// mess with them.
{
DWORD keepflags = act->flags;
act->flags |= MF_NOBLOCKMAP;
act->LinkToWorld();
act->flags = keepflags;
}
// Restore sector links.
if (!(act->flags & MF_NOSECTOR)) if (!(act->flags & MF_NOSECTOR))
{ {
sector_t *sec = act->Sector; sector_t *sec = act->Sector;
@ -2781,6 +2767,39 @@ void P_UnPredictPlayer ()
*link = me; *link = me;
} }
// Destroy old refrences
msecnode_t *node = sector_list;
while (node)
{
node->m_thing = NULL;
node = node->m_tnext;
}
// Make the sector_list match the player's touching_sectorlist before it got predicted.
P_DelSeclist(sector_list);
sector_list = NULL;
for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;)
{
sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list);
}
act->touching_sectorlist = sector_list; // Attach to thing
sector_list = NULL; // clear for next time
node = sector_list;
while (node)
{
if (node->m_thing == NULL)
{
if (node == sector_list)
sector_list = node->m_tnext;
node = P_DelSecnode(node);
}
else
{
node = node->m_tnext;
}
}
msecnode_t *snode; msecnode_t *snode;
// Restore sector thinglist order // Restore sector thinglist order

View file

@ -63,7 +63,7 @@ static bool R_InstallSpriteLump (FTextureID lump, unsigned frame, char rot, bool
if (frame >= MAX_SPRITE_FRAMES || rotation > 16) 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; return false;
} }
@ -998,4 +998,4 @@ void R_DeinitSpriteData()
delete[] skins; delete[] skins;
skins = NULL; skins = NULL;
} }
} }

View file

@ -972,7 +972,7 @@ void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, int fov)
texture = static_cast<FCanvasTexture *>(TexMan[picnum]); texture = static_cast<FCanvasTexture *>(TexMan[picnum]);
if (!texture->bHasCanvas) 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; return;
} }

View file

@ -231,8 +231,8 @@ void FTextureManager::InitAnimated (void)
if (debuganimated) if (debuganimated)
{ {
Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n", 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()), tex1->Name.GetChars(), pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()),
tex2->Name, pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); tex2->Name.GetChars(), pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump()));
} }
if (pic1 == pic2) if (pic1 == pic2)

View file

@ -448,7 +448,7 @@ void FJPEGTexture::MakeTexture ()
} }
catch (int) catch (int)
{ {
Printf (TEXTCOLOR_ORANGE " in texture %s\n", Name); Printf (TEXTCOLOR_ORANGE " in texture %s\n", Name.GetChars());
jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
} }
if (buff != NULL) if (buff != NULL)
@ -532,7 +532,7 @@ int FJPEGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FC
} }
catch(int) 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); jpeg_destroy_decompress(&cinfo);
if (buff != NULL) delete [] buff; if (buff != NULL) delete [] buff;

View file

@ -268,14 +268,14 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
if (unsigned(LittleShort(mpatch.d->patch)) >= unsigned(maxpatchnum)) 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.", 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].OriginX = LittleShort(mpatch.d->originx);
Parts[i].OriginY = LittleShort(mpatch.d->originy); Parts[i].OriginY = LittleShort(mpatch.d->originy);
Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture; Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture;
if (Parts[i].Texture == NULL) if (Parts[i].Texture == NULL)
{ {
Printf(TEXTCOLOR_RED "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--; NumParts--;
i--; i--;
} }
@ -290,7 +290,7 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
} }
if (NumParts == 0) 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 (); CheckForHacks ();
@ -1023,7 +1023,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, i
} }
if (part.Texture == NULL) if (part.Texture == NULL)
{ {
if (!silent) Printf(TEXTCOLOR_RED "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.MustGetStringName(",");
sc.MustGetNumber(); sc.MustGetNumber();
@ -1244,13 +1244,13 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
{ {
sc.MustGetFloat(); sc.MustGetFloat();
xScale = FLOAT2FIXED(sc.Float); 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")) else if (sc.Compare("YScale"))
{ {
sc.MustGetFloat(); sc.MustGetFloat();
yScale = FLOAT2FIXED(sc.Float); 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")) else if (sc.Compare("WorldPanning"))
{ {
@ -1318,7 +1318,7 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
if (Width <= 0 || Height <= 0) if (Width <= 0 || Height <= 0)
{ {
UseType = FTexture::TEX_Null; 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; Width = Height = 1;
} }
CalcBitSize (); CalcBitSize ();

View file

@ -949,7 +949,7 @@ void FTextureManager::SortTexturesByType(int start, int end)
{ {
if (newtextures[j] != NULL) 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]); AddTexture(newtextures[j]);
} }
} }

View file

@ -336,7 +336,7 @@ static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const B
line->Width = font->StringWidth (line->Text); 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) 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; space = string - 1;
breakit (&lines[i], font, start, space, linecolor); breakit (&lines[i], font, start, space, linecolor);
if (c == '\n') if (c == '\n' && !preservecolor)
{ {
lastcolor = ""; // Why, oh why, did I do it like this? lastcolor = ""; // Why, oh why, did I do it like this?
} }

View file

@ -75,9 +75,9 @@ struct FBrokenLines
#define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_CHAT "\034*"
#define TEXTCOLOR_TEAMCHAT "\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); void V_FreeBrokenLines (FBrokenLines *lines);
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str) inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false)
{ return V_BreakLines (font, maxwidth, (const BYTE *)str); } { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor); }
#endif //__V_TEXT_H__ #endif //__V_TEXT_H__

View file

@ -196,8 +196,8 @@ public:
int GetLumpOffset (int lump); // [RH] Returns offset of lump in the wadfile int GetLumpOffset (int lump); // [RH] Returns offset of lump in the wadfile
int GetLumpFlags (int lump); // Return the flags for this lump 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 (char *to, int lump) const; // [RH] Copies the lump name to to using uppercopy
void FWadCollection::GetLumpName(FString &to, int lump) const; void GetLumpName (FString &to, int lump) const;
const char *GetLumpFullName(int lump) const; // [RH] Returns the lump's full name 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 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 int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump
int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to

View file

@ -45,6 +45,7 @@
#include "v_text.h" #include "v_text.h"
#include "gi.h" #include "gi.h"
#include "d_player.h" #include "d_player.h"
#include "d_netinf.h"
#include "b_bot.h" #include "b_bot.h"
#include "textures/textures.h" #include "textures/textures.h"
#include "r_data/r_translate.h" #include "r_data/r_translate.h"
@ -63,6 +64,7 @@ typedef enum
CVAR (Bool, wi_percents, true, CVAR_ARCHIVE) CVAR (Bool, wi_percents, true, CVAR_ARCHIVE)
CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE) CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE)
CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE) CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE)
CVAR (Int, wi_autoadvance, 0, CVAR_SERVERINFO)
void WI_loadData (); void WI_loadData ();
@ -190,6 +192,7 @@ static TArray<in_anim_t> anims;
#define SHOWNEXTLOCDELAY 4 // in seconds #define SHOWNEXTLOCDELAY 4 // in seconds
static int acceleratestage; // used to accelerate or skip a stage static int acceleratestage; // used to accelerate or skip a stage
static bool playerready[MAXPLAYERS];
static int me; // wbs->pnum static int me; // wbs->pnum
static stateenum_t state; // specifies current state static stateenum_t state; // specifies current state
static wbstartstruct_t *wbs; // contains information passed into intermission static wbstartstruct_t *wbs; // contains information passed into intermission
@ -199,11 +202,17 @@ static int bcnt; // used for timing of background animation
static int cnt_kills[MAXPLAYERS]; static int cnt_kills[MAXPLAYERS];
static int cnt_items[MAXPLAYERS]; static int cnt_items[MAXPLAYERS];
static int cnt_secret[MAXPLAYERS]; static int cnt_secret[MAXPLAYERS];
static int cnt_frags[MAXPLAYERS];
static int cnt_deaths[MAXPLAYERS];
static int cnt_time; static int cnt_time;
static int cnt_total_time; static int cnt_total_time;
static int cnt_par; static int cnt_par;
static int cnt_pause; static int cnt_pause;
static int total_frags;
static int total_deaths;
static bool noautostartmap; static bool noautostartmap;
static int dofrags;
static int ng_state;
// //
// GRAPHICS // GRAPHICS
@ -1105,6 +1114,7 @@ void WI_updateNoState ()
else else
{ {
bool noauto = noautostartmap; bool noauto = noautostartmap;
bool autoskip = (wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE));
for (int i = 0; !noauto && i < MAXPLAYERS; ++i) for (int i = 0; !noauto && i < MAXPLAYERS; ++i)
{ {
@ -1113,7 +1123,7 @@ void WI_updateNoState ()
noauto |= players[i].userinfo.GetNoAutostartMap(); noauto |= players[i].userinfo.GetNoAutostartMap();
} }
} }
if (!noauto) if (!noauto || autoskip)
{ {
cnt--; cnt--;
} }
@ -1208,128 +1218,134 @@ int WI_fragSum (int playernum)
return frags; return frags;
} }
static int dm_state; static int player_deaths[MAXPLAYERS];
static int dm_frags[MAXPLAYERS][MAXPLAYERS];
static int dm_totals[MAXPLAYERS];
void WI_initDeathmatchStats (void) void WI_initDeathmatchStats (void)
{ {
int i, j; int i, j;
state = StatCount; state = StatCount;
acceleratestage = 0; acceleratestage = 0;
dm_state = 1; memset(playerready, 0, sizeof(playerready));
memset(cnt_frags, 0, sizeof(cnt_frags));
memset(cnt_deaths, 0, sizeof(cnt_frags));
memset(player_deaths, 0, sizeof(player_deaths));
total_frags = 0;
total_deaths = 0;
ng_state = 1;
cnt_pause = TICRATE; cnt_pause = TICRATE;
for (i=0 ; i<MAXPLAYERS ; i++) for (i=0 ; i<MAXPLAYERS ; i++)
{ {
if (playeringame[i]) if (playeringame[i])
{ {
for (j=0 ; j<MAXPLAYERS ; j++) for (j = 0; j < MAXPLAYERS; j++)
if (playeringame[j]) if (playeringame[j])
dm_frags[i][j] = 0; player_deaths[i] += plrs[j].frags[i];
total_deaths += player_deaths[i];
dm_totals[i] = 0; total_frags += plrs[i].fragcount;
} }
} }
} }
void WI_updateDeathmatchStats () void WI_updateDeathmatchStats ()
{ {
/*
int i, j; int i;
bool stillticking; bool stillticking;
*/ bool autoskip = (wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE));
WI_updateAnimatedBack(); WI_updateAnimatedBack();
if (acceleratestage && dm_state != 4) if ((acceleratestage || autoskip) && ng_state != 6)
{ {
/*
acceleratestage = 0; acceleratestage = 0;
for (i=0 ; i<MAXPLAYERS ; i++) for (i = 0; i<MAXPLAYERS; i++)
{ {
if (playeringame[i]) if (!playeringame[i])
{ continue;
for (j=0 ; j<MAXPLAYERS ; j++)
if (playeringame[j]) cnt_frags[i] = plrs[i].fragcount;
dm_frags[i][j] = plrs[i].frags[j]; cnt_deaths[i] = player_deaths[i];
dm_totals[i] = WI_fragSum(i);
}
} }
S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); ng_state = 6;
*/
dm_state = 4;
} }
if (ng_state == 2)
if (dm_state == 2)
{ {
/* if (!(bcnt & 3))
if (!(bcnt&3)) S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
stillticking = false; stillticking = false;
for (i=0 ; i<MAXPLAYERS ; i++) for (i = 0; i<MAXPLAYERS; i++)
{ {
if (playeringame[i]) if (!playeringame[i])
{ continue;
for (j=0 ; j<MAXPLAYERS ; j++)
{
if (playeringame[j]
&& dm_frags[i][j] != plrs[i].frags[j])
{
if (plrs[i].frags[j] < 0)
dm_frags[i][j]--;
else
dm_frags[i][j]++;
if (dm_frags[i][j] > 99) cnt_frags[i] += 2;
dm_frags[i][j] = 99;
if (dm_frags[i][j] < -99) if (cnt_frags[i] > plrs[i].fragcount)
dm_frags[i][j] = -99; cnt_frags[i] = plrs[i].fragcount;
else
stillticking = true; stillticking = true;
} }
}
dm_totals[i] = WI_fragSum(i);
if (dm_totals[i] > 99) if (!stillticking)
dm_totals[i] = 99; {
S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
if (dm_totals[i] < -99) ng_state++;
dm_totals[i] = -99; }
} }
else if (ng_state == 4)
{
if (!(bcnt & 3))
S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
stillticking = false;
for (i = 0; i<MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
cnt_deaths[i] += 2;
if (cnt_deaths[i] > player_deaths[i])
cnt_deaths[i] = player_deaths[i];
else
stillticking = true;
} }
if (!stillticking) if (!stillticking)
{ {
S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
dm_state++; ng_state++;
} }
*/
dm_state = 3;
} }
else if (dm_state == 4) else if (ng_state == 6)
{ {
if (acceleratestage) int i;
for (i = 0; i < MAXPLAYERS; i++)
{ {
S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE); // If the player is in the game and not ready, stop checking
if (playeringame[i] && !players[i].isbot && !playerready[i])
break;
}
// All players are ready; proceed.
if ((i == MAXPLAYERS && acceleratestage) || autoskip)
{
S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE);
WI_initShowNextLoc(); WI_initShowNextLoc();
} }
} }
else if (dm_state & 1) else if (ng_state & 1)
{ {
if (!--cnt_pause) if (!--cnt_pause)
{ {
dm_state++; ng_state++;
cnt_pause = TICRATE; cnt_pause = TICRATE;
} }
} }
@ -1339,97 +1355,126 @@ void WI_updateDeathmatchStats ()
void WI_drawDeathmatchStats () void WI_drawDeathmatchStats ()
{ {
int i, pnum, x, y, ypadding, height, lineheight;
int maxnamewidth, maxscorewidth, maxiconheight;
int pwidth = IntermissionFont->GetCharWidth('%');
int icon_x, name_x, frags_x, deaths_x;
int deaths_len;
float h, s, v, r, g, b;
EColorRange color;
const char *text_deaths, *text_frags;
FTexture *readyico = TexMan.FindTexture("READYICO");
player_t *sortedplayers[MAXPLAYERS];
// draw animated background // draw animated background
WI_drawBackground(); WI_drawBackground();
WI_drawLF();
// [RH] Draw heads-up scores display y = WI_drawLF();
HU_DrawScores (&players[me]);
/* HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
int i; // Use the readyico height if it's bigger.
int j; height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset();
int x; maxiconheight = MAX(height, maxiconheight);
int y; height = SmallFont->GetHeight() * CleanYfac;
int w; lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2;
int lh; // line height y += CleanYfac;
lh = WI_SPACINGY; text_deaths = GStrings("SCORE_DEATHS");
//text_color = GStrings("SCORE_COLOR");
text_frags = GStrings("SCORE_FRAGS");
// draw stat titles (top line) icon_x = 8 * CleanXfac;
V_DrawPatchClean(DM_TOTALSX-LittleShort(total->width)/2, name_x = icon_x + maxscorewidth * CleanXfac;
DM_MATRIXY-WI_SPACINGY+10, frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac;
&FB, deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac;
total);
V_DrawPatchClean(DM_KILLERSX, DM_KILLERSY, &FB, killers);
V_DrawPatchClean(DM_VICTIMSX, DM_VICTIMSY, &FB, victims);
// draw P? x = (SCREENWIDTH - deaths_x) >> 1;
x = DM_MATRIXX + DM_SPACINGX; icon_x += x;
y = DM_MATRIXY; name_x += x;
frags_x += x;
deaths_x += x;
for (i=0 ; i<MAXPLAYERS ; i++) color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE);
y += height + 6 * CleanYfac;
// Sort all players
for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i]) sortedplayers[i] = &players[i];
{
V_DrawPatchClean(x-LittleShort(p[i]->width)/2,
DM_MATRIXY - WI_SPACINGY,
&FB,
p[i]);
V_DrawPatchClean(DM_MATRIXX-LittleShort(p[i]->width)/2,
y,
&FB,
p[i]);
if (i == me)
{
V_DrawPatchClean(x-LittleShort(p[i]->width)/2,
DM_MATRIXY - WI_SPACINGY,
&FB,
bstar);
V_DrawPatchClean(DM_MATRIXX-LittleShort(p[i]->width)/2,
y,
&FB,
star);
}
}
x += DM_SPACINGX;
y += WI_SPACINGY;
} }
// draw stats if (teamplay)
y = DM_MATRIXY+10; qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams);
w = LittleShort(num[0]->width); else
qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints);
for (i=0 ; i<MAXPLAYERS ; i++) // Draw lines for each player
for (i = 0; i < MAXPLAYERS; i++)
{ {
x = DM_MATRIXX + DM_SPACINGX; player_t *player = sortedplayers[i];
pnum = int(player - players);
if (playeringame[i]) if (!playeringame[pnum])
continue;
D_GetPlayerColor(pnum, &h, &s, &v, NULL);
HSVtoRGB(&r, &g, &b, h, s, v);
screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255),
clamp(int(g*255.f), 0, 255),
clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight);
if (playerready[pnum] || player->isbot) // Bots are automatically assumed ready, to prevent confusion
screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE);
color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer);
if (player->mo->ScoreIcon.isValid())
{ {
for (j=0 ; j<MAXPLAYERS ; j++) FTexture *pic = TexMan[player->mo->ScoreIcon];
{ screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE);
if (playeringame[j])
WI_drawNum(x+w, y, dm_frags[i][j], 2);
x += DM_SPACINGX;
}
WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
} }
y += WI_SPACINGY; screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE);
WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color);
if (ng_state >= 2)
{
WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color);
}
y += lineheight + CleanYfac;
} }
*/
// Draw "TOTAL" line
y += height + 3 * CleanYfac;
color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color);
if (ng_state >= 4)
{
WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color);
}
// Draw game time
y += height + CleanYfac;
int seconds = plrs[me].stime / TICRATE;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
seconds = seconds % 60;
FString leveltime = GStrings("SCORE_LVLTIME");
leveltime += ": ";
char timer[sizeof "HH:MM:SS"];
mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds);
leveltime += timer;
screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE);
} }
static int cnt_frags[MAXPLAYERS];
static int dofrags;
static int ng_state;
void WI_initNetgameStats () void WI_initNetgameStats ()
{ {
@ -1437,6 +1482,7 @@ void WI_initNetgameStats ()
state = StatCount; state = StatCount;
acceleratestage = 0; acceleratestage = 0;
memset(playerready, 0, sizeof(playerready));
ng_state = 1; ng_state = 1;
cnt_pause = TICRATE; cnt_pause = TICRATE;
@ -1460,10 +1506,11 @@ void WI_updateNetgameStats ()
int i; int i;
int fsum; int fsum;
bool stillticking; bool stillticking;
bool autoskip = (wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE));
WI_updateAnimatedBack (); WI_updateAnimatedBack ();
if (acceleratestage && ng_state != 10) if ((acceleratestage || autoskip) && ng_state != 10)
{ {
acceleratestage = 0; acceleratestage = 0;
@ -1587,7 +1634,16 @@ void WI_updateNetgameStats ()
} }
else if (ng_state == 10) else if (ng_state == 10)
{ {
if (acceleratestage) int i;
for (i = 0; i < MAXPLAYERS; i++)
{
// If the player is in the game and not ready, stop checking
if (playeringame[i] && !players[i].isbot && !playerready[i])
break;
}
// All players are ready; proceed.
if ((i == MAXPLAYERS && acceleratestage) || autoskip)
{ {
S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE); S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE);
WI_initShowNextLoc(); WI_initShowNextLoc();
@ -1611,8 +1667,10 @@ void WI_drawNetgameStats ()
int icon_x, name_x, kills_x, bonus_x, secret_x; int icon_x, name_x, kills_x, bonus_x, secret_x;
int bonus_len, secret_len; int bonus_len, secret_len;
int missed_kills, missed_items, missed_secrets; int missed_kills, missed_items, missed_secrets;
float h, s, v, r, g, b;
EColorRange color; EColorRange color;
const char *text_bonus, *text_color, *text_secret, *text_kills; const char *text_bonus, *text_secret, *text_kills;
FTexture *readyico = TexMan.FindTexture("READYICO");
// draw animated background // draw animated background
WI_drawBackground(); WI_drawBackground();
@ -1620,17 +1678,22 @@ void WI_drawNetgameStats ()
y = WI_drawLF(); y = WI_drawLF();
HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
// Use the readyico height if it's bigger.
height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset();
if (height > maxiconheight)
{
maxiconheight = height;
}
height = SmallFont->GetHeight() * CleanYfac; height = SmallFont->GetHeight() * CleanYfac;
lineheight = MAX(height, maxiconheight * CleanYfac); lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2; ypadding = (lineheight - height + 1) / 2;
y += 16*CleanYfac; y += CleanYfac;
text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS"); text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS");
text_color = GStrings("SCORE_COLOR");
text_secret = GStrings("SCORE_SECRET"); text_secret = GStrings("SCORE_SECRET");
text_kills = GStrings("SCORE_KILLS"); text_kills = GStrings("SCORE_KILLS");
icon_x = (SmallFont->StringWidth(text_color) + 8) * CleanXfac; icon_x = 8 * CleanXfac;
name_x = icon_x + maxscorewidth * CleanXfac; name_x = icon_x + maxscorewidth * CleanXfac;
kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac; kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac;
bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac; bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac;
@ -1645,7 +1708,6 @@ void WI_drawNetgameStats ()
color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
screen->DrawText(SmallFont, color, x, y, text_color, DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE);
@ -1665,7 +1727,17 @@ void WI_drawNetgameStats ()
continue; continue;
player = &players[i]; player = &players[i];
HU_DrawColorBar(x, y, lineheight, i);
D_GetPlayerColor(i, &h, &s, &v, NULL);
HSVtoRGB(&r, &g, &b, h, s, v);
screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255),
clamp(int(g*255.f), 0, 255),
clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight);
if (playerready[i] || player->isbot) // Bots are automatically assumed ready, to prevent confusion
screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE);
color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); color = (EColorRange)HU_GetRowColor(player, i == consoleplayer);
if (player->mo->ScoreIcon.isValid()) if (player->mo->ScoreIcon.isValid())
{ {
@ -1689,7 +1761,7 @@ void WI_drawNetgameStats ()
} }
// Draw "MISSED" line // Draw "MISSED" line
y += 5 * CleanYfac; y += 3 * CleanYfac;
screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE);
WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY); WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY);
if (ng_state >= 4) if (ng_state >= 4)
@ -1702,7 +1774,7 @@ void WI_drawNetgameStats ()
} }
// Draw "TOTAL" line // Draw "TOTAL" line
y += height + 5 * CleanYfac; y += height + 3 * CleanYfac;
color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color); WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color);
@ -1939,6 +2011,7 @@ void WI_checkForAccelerate(void)
== players[i].oldbuttons) && !player->isbot) == players[i].oldbuttons) && !player->isbot)
{ {
acceleratestage = 1; acceleratestage = 1;
playerready[i] = true;
} }
player->oldbuttons = player->cmd.ucmd.buttons; player->oldbuttons = player->cmd.ucmd.buttons;
} }

View file

@ -332,7 +332,7 @@ F481922F4881F74760F3C0437FD5EDD0 // map03
setactivation 455 16 // SPAC_Push setactivation 455 16 // SPAC_Push
} }
8B2AC8D4DB4A49A5DCCBB067E04434D6 // The Hell Factory Hub One, map04
65A1EB4C87386F290816660A52932FF1 // Master Levels, garrison.wad 65A1EB4C87386F290816660A52932FF1 // Master Levels, garrison.wad
{ {
rebuildnodes rebuildnodes

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

View file

@ -2,6 +2,8 @@
[enu default] [enu default]
SECRETMESSAGE = "A secret is revealed!";
D_DEVSTR = "Useless mode ON.\n"; D_DEVSTR = "Useless mode ON.\n";
D_CDROM = "CD-ROM Version: zdoom.ini from c:\\zdoomdat\n"; D_CDROM = "CD-ROM Version: zdoom.ini from c:\\zdoomdat\n";
PRESSKEY = "press a key."; PRESSKEY = "press a key.";
@ -836,8 +838,10 @@ SCORE_SECRET = "SECRET";
SCORE_NAME = "NAME"; SCORE_NAME = "NAME";
SCORE_KILLS = "KILLS"; SCORE_KILLS = "KILLS";
SCORE_FRAGS = "FRAGS"; SCORE_FRAGS = "FRAGS";
SCORE_DEATHS = "DEATHS";
SCORE_MISSED = "MISSED"; SCORE_MISSED = "MISSED";
SCORE_TOTAL = "TOTAL"; SCORE_TOTAL = "TOTAL";
SCORE_LVLTIME = "LEVEL TIME";
// Item tags: Doom weapons // Item tags: Doom weapons
TAG_FIST = "Brass Knuckles"; TAG_FIST = "Brass Knuckles";