Merge remote-tracking branch 'refs/remotes/STJr/master' into plus_v2.1.17_main

# Fixed Conflicts:
#	src/r_things.c
This commit is contained in:
yellowtd 2017-01-16 22:09:33 -05:00
commit 7af7b7f494
79 changed files with 3823 additions and 5292 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(SRB2 project(SRB2
VERSION 2.1.14 VERSION 2.1.17
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

3002
SRB2.cbp

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
version: 2.1.16.{branch}-{build} version: 2.1.17.{branch}-{build}
os: MinGW os: MinGW
environment: environment:

3
debian/docs vendored
View file

@ -1,2 +1 @@
readme.txt README.md
readme.txt

View file

@ -391,18 +391,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
endif() endif()
if(${SRB2_CONFIG_USEASM}) if(${SRB2_CONFIG_USEASM})
#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
if(${CMAKE_SYSTEM} MATCHES "Linux")
set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
endif()
if(${SRB2_CONFIG_YASM}) if(${SRB2_CONFIG_YASM})
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas) set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_YASM) enable_language(ASM_YASM)
else() else()
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas) set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_NASM) enable_language(ASM_NASM)
endif() endif()
set(SRB2_USEASM ON) set(SRB2_USEASM ON)
add_definitions(-DUSEASM) add_definitions(-DUSEASM)
else() else()
set(SRB2_USEASM OFF) set(SRB2_USEASM OFF)
add_definitions(-DNOASM -DNONX86) add_definitions(-DNONX86 -DNORUSEASM)
endif() endif()
# Targets # Targets

View file

@ -179,6 +179,9 @@ endif
ifdef LINUX ifdef LINUX
UNIXCOMMON=1 UNIXCOMMON=1
ifndef NOGME
HAVE_LIBGME=1
endif
endif endif
ifdef SOLARIS ifdef SOLARIS
@ -315,6 +318,13 @@ LIBS+=$(PNG_LDFLAGS)
CFLAGS+=$(PNG_CFLAGS) CFLAGS+=$(PNG_CFLAGS)
endif endif
ZLIB_PKGCONFIG?=zlib
ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
LIBS+=$(ZLIB_LDFLAGS)
CFLAGS+=$(ZLIB_CFLAGS)
ifdef HAVE_LIBGME ifdef HAVE_LIBGME
OPTS+=-DHAVE_LIBGME OPTS+=-DHAVE_LIBGME
@ -366,6 +376,14 @@ endif
OPTS:=-fno-exceptions $(OPTS) OPTS:=-fno-exceptions $(OPTS)
ifdef MOBJCONSISTANCY
OPTS+=-DMOBJCONSISTANCY
endif
ifdef PACKETDROP
OPTS+=-DPACKETDROP
endif
ifdef DEBUGMODE ifdef DEBUGMODE
# build with debugging information # build with debugging information
@ -375,7 +393,7 @@ ifdef GCC48
else else
CFLAGS+=-O0 CFLAGS+=-O0
endif endif
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
else else

View file

@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable)
return -1; return -1;
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
char *I_ClipboardPaste(void)
{
return NULL;
}
void I_RegisterSysCommands(void) {} void I_RegisterSysCommands(void) {}
#include "../sdl/dosstr.c" #include "../sdl/dosstr.c"

View file

@ -84,19 +84,23 @@ UINT32 con_scalefactor; // text size scale factor
// hold 32 last lines of input for history // hold 32 last lines of input for history
#define CON_MAXPROMPTCHARS 256 #define CON_MAXPROMPTCHARS 256
#define CON_PROMPTCHAR '>' #define CON_PROMPTCHAR '$'
static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines
static INT32 inputline; // current input line number static INT32 inputline; // current input line number
static INT32 inputhist; // line number of history input line to restore static INT32 inputhist; // line number of history input line to restore
static size_t input_cx; // position in current input line static size_t input_cur; // position of cursor in line
static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected")
static size_t input_len; // length of current line, used to bound cursor and such
// notice: input does NOT include the "$" at the start of the line. - 11/3/16
// protos. // protos.
static void CON_InputInit(void); static void CON_InputInit(void);
static void CON_RecalcSize(void); static void CON_RecalcSize(void);
static void CONS_hudlines_Change(void); static void CONS_hudlines_Change(void);
static void CONS_backcolor_Change(void);
static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth); static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth);
//static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth); //static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth);
@ -129,10 +133,11 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}
// whether to use console background picture, or translucent mode // whether to use console background picture, or translucent mode
static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"}, static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"},
{2, "Blue"}, {3, "Green"}, {4, "Gray"}, {3, "Red"}, {4, "Orange"}, {5, "Yellow"},
{5, "Red"}, {0, NULL}}; {6, "Green"}, {7, "Blue"}, {8, "Cyan"},
consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; {0, NULL}};
consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL};
static void CON_Print(char *msg); static void CON_Print(char *msg);
@ -219,8 +224,9 @@ static void CONS_Bind_f(void)
// CONSOLE SETUP // CONSOLE SETUP
//====================================================================== //======================================================================
// Prepare a colormap for GREEN ONLY translucency over background // Font colormap colors
// // TODO: This could probably be improved somehow...
// These colormaps are 99% identical, with just a few changed bytes
UINT8 *yellowmap; UINT8 *yellowmap;
UINT8 *purplemap; UINT8 *purplemap;
UINT8 *lgreenmap; UINT8 *lgreenmap;
@ -229,44 +235,49 @@ UINT8 *graymap;
UINT8 *redmap; UINT8 *redmap;
UINT8 *orangemap; UINT8 *orangemap;
// Console BG colors // Console BG color
UINT8 *cwhitemap; UINT8 *consolebgmap = NULL;
UINT8 *corangemap;
UINT8 *cbluemap;
UINT8 *cgreenmap;
UINT8 *cgraymap;
UINT8 *credmap;
void CON_ReSetupBackColormap(UINT16 num) void CON_SetupBackColormap(void)
{ {
UINT16 i, j; UINT16 i, palsum;
UINT8 k; UINT8 j, palindex;
UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE); UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
// setup the green translucent background colormaps if (!consolebgmap)
for (i = 0, k = 0; i < 768; i += 3, k++) consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
switch (cons_backcolor.value)
{ {
j = pal[i] + pal[i+1] + pal[i+2]; case 0: palindex = 15; break; // White
cwhitemap[k] = (UINT8)(15 - (j>>6)); case 1: palindex = 31; break; // Gray
corangemap[k] = (UINT8)(95 - (j>>6)); case 2: palindex = 63; break; // Brown
cbluemap[k] = (UINT8)(239 - (j>>6)); case 3: palindex = 143; break; // Red
cgreenmap[k] = (UINT8)(175 - (j>>6)); case 4: palindex = 95; break; // Orange
cgraymap[k] = (UINT8)(31 - (j>>6)); case 5: palindex = 111; break; // Yellow
credmap[k] = (UINT8)(143 - (j>>6)); case 6: palindex = 175; break; // Green
case 7: palindex = 239; break; // Blue
case 8: palindex = 219; break; // Cyan
// Default green
default: palindex = 175; break;
}
// setup background colormap
for (i = 0, j = 0; i < 768; i += 3, j++)
{
palsum = (pal[i] + pal[i+1] + pal[i+2]) >> 6;
consolebgmap[j] = (UINT8)(palindex - palsum);
} }
} }
static void CON_SetupBackColormap(void) static void CONS_backcolor_Change(void)
{ {
INT32 i, j, k; CON_SetupBackColormap();
UINT8 *pal; }
cwhitemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); static void CON_SetupColormaps(void)
corangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); {
cbluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); INT32 i;
cgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
cgraymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
credmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
@ -276,20 +287,6 @@ static void CON_SetupBackColormap(void)
redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
pal = W_CacheLumpName("PLAYPAL", PU_CACHE);
// setup the green translucent background colormaps
for (i = 0, k = 0; i < 768; i += 3, k++)
{
j = pal[i] + pal[i+1] + pal[i+2];
cwhitemap[k] = (UINT8)(15 - (j>>6));
corangemap[k] = (UINT8)(95 - (j>>6));
cbluemap[k] = (UINT8)(239 - (j>>6));
cgreenmap[k] = (UINT8)(175 - (j>>6));
cgraymap[k] = (UINT8)(31 - (j>>6));
credmap[k] = (UINT8)(143 - (j>>6));
}
// setup the other colormaps, for console text // setup the other colormaps, for console text
// these don't need to be aligned, unless you convert the // these don't need to be aligned, unless you convert the
@ -320,6 +317,9 @@ static void CON_SetupBackColormap(void)
redmap[9] = (UINT8)127; redmap[9] = (UINT8)127;
orangemap[3] = (UINT8)85; orangemap[3] = (UINT8)85;
orangemap[9] = (UINT8)90; orangemap[9] = (UINT8)90;
// Init back colormap
CON_SetupBackColormap();
} }
// Setup the console text buffer // Setup the console text buffer
@ -343,7 +343,7 @@ void CON_Init(void)
con_width = 0; con_width = 0;
CON_RecalcSize(); CON_RecalcSize();
CON_SetupBackColormap(); CON_SetupColormaps();
//note: CON_Ticker should always execute at least once before D_Display() //note: CON_Ticker should always execute at least once before D_Display()
con_clipviewtop = -1; // -1 does not clip con_clipviewtop = -1; // -1 does not clip
@ -386,14 +386,10 @@ void CON_Init(void)
// //
static void CON_InputInit(void) static void CON_InputInit(void)
{ {
INT32 i;
// prepare the first prompt line // prepare the first prompt line
memset(inputlines, 0, sizeof (inputlines)); memset(inputlines, 0, sizeof (inputlines));
for (i = 0; i < 32; i++)
inputlines[i][0] = CON_PROMPTCHAR;
inputline = 0; inputline = 0;
input_cx = 1; input_cur = input_sel = input_len = 0;
} }
//====================================================================== //======================================================================
@ -618,13 +614,91 @@ void CON_Ticker(void)
} }
} }
//
// ----
//
// Shortcuts for adding and deleting characters, strings, and sections
// Necessary due to moving cursor
//
static void CON_InputClear(void)
{
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
input_cur = input_sel = input_len = 0;
}
static void CON_InputSetString(const char *c)
{
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
strcpy(inputlines[inputline], c);
input_cur = input_sel = input_len = strlen(c);
}
static void CON_InputAddString(const char *c)
{
size_t csize = strlen(c);
if (input_len + csize > CON_MAXPROMPTCHARS-1)
return;
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
memcpy(&inputlines[inputline][input_cur], c, csize);
input_len += csize;
input_sel = (input_cur += csize);
}
static void CON_InputDelSelection(void)
{
size_t start, end, len;
if (input_cur > input_sel)
{
start = input_sel;
end = input_cur;
}
else
{
start = input_cur;
end = input_sel;
}
len = (end - start);
if (end != input_len)
memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end);
memset(&inputlines[inputline][input_len - len], 0, len);
input_len -= len;
input_sel = input_cur = start;
}
static void CON_InputAddChar(char c)
{
if (input_len >= CON_MAXPROMPTCHARS-1)
return;
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
inputlines[inputline][input_cur++] = c;
inputlines[inputline][++input_len] = 0;
input_sel = input_cur;
}
static void CON_InputDelChar(void)
{
if (!input_cur)
return;
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
inputlines[inputline][--input_len] = 0;
input_sel = --input_cur;
}
//
// ----
//
// Handles console key input // Handles console key input
// //
boolean CON_Responder(event_t *ev) boolean CON_Responder(event_t *ev)
{ {
static boolean consdown; static UINT8 consdown = false; // console is treated differently due to rare usage
static boolean shiftdown;
static boolean ctrldown;
// sequential completions a la 4dos // sequential completions a la 4dos
static char completion[80]; static char completion[80];
@ -639,13 +713,8 @@ boolean CON_Responder(event_t *ev)
// let go keyup events, don't eat them // let go keyup events, don't eat them
if (ev->type != ev_keydown && ev->type != ev_console) if (ev->type != ev_keydown && ev->type != ev_console)
{ {
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT) if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
shiftdown = false;
else if (ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL)
ctrldown = false;
else if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
consdown = false; consdown = false;
return false; return false;
} }
@ -684,94 +753,110 @@ boolean CON_Responder(event_t *ev)
consoletoggle = true; consoletoggle = true;
return true; return true;
} }
} }
// eat shift only if console active // Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas
if (key == KEY_LSHIFT || key == KEY_RSHIFT) if (key == KEY_LSHIFT || key == KEY_RSHIFT
{ || key == KEY_LCTRL || key == KEY_RCTRL
shiftdown = true; || key == KEY_LALT || key == KEY_RALT)
return true; return true;
}
// same for ctrl // ctrl modifier -- changes behavior, adds shortcuts
if (key == KEY_LCTRL || key == KEY_RCTRL) if (ctrldown)
{ {
ctrldown = true; // show all cvars/commands that match what we have inputted
return true; if (key == KEY_TAB)
{
size_t i, len;
if (!completion[0])
{
if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
return true;
strcpy(completion, inputlines[inputline]);
comskips = varskips = 0;
}
len = strlen(completion);
//first check commands
CONS_Printf("\nCommands:\n");
for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i))
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
if (i == 0) CONS_Printf(" (none)\n");
//now we move on to CVARs
CONS_Printf("Variables:\n");
for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i))
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
if (i == 0) CONS_Printf(" (none)\n");
return true;
}
// ---
if (key == KEY_HOME) // oldest text in buffer
{
con_scrollup = (con_totallines-((con_curlines-16)>>3));
return true;
}
else if (key == KEY_END) // most recent text in buffer
{
con_scrollup = 0;
return true;
}
if (key == 'x' || key == 'X')
{
if (input_sel > input_cur)
I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
else
I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
CON_InputDelSelection();
completion[0] = 0;
return true;
}
else if (key == 'c' || key == 'C')
{
if (input_sel > input_cur)
I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
else
I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
return true;
}
else if (key == 'v' || key == 'V')
{
const char *paste = I_ClipboardPaste();
if (input_sel != input_cur)
CON_InputDelSelection();
if (paste != NULL)
CON_InputAddString(paste);
completion[0] = 0;
return true;
}
// Select all
if (key == 'a' || key == 'A')
{
input_sel = 0;
input_cur = input_len;
return true;
}
// don't eat the key
return false;
} }
// command completion forward (tab) and backward (shift-tab) // command completion forward (tab) and backward (shift-tab)
if (key == KEY_TAB) if (key == KEY_TAB)
{ {
// show all cvars/commands that match what we have inputted
if (ctrldown)
{
UINT32 i;
size_t stop = input_cx - 1;
char nameremainder[255];
if (input_cx < 2 || strlen(inputlines[inputline]+1) >= 80)
return true;
strcpy(completion, inputlines[inputline]+1);
// trimming: stop at the first newline
for (i = 0; i < input_cx - 1; ++i)
{
if (completion[i] == ' ')
{
completion[i] = '\0';
stop = i;
break;
}
}
i = 0;
//first check commands
CONS_Printf("\nCommands:\n");
for (cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, i))
{
strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
nameremainder[strlen(cmd)-(stop)] = '\0';
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder);
++i;
}
if (i == 0)
CONS_Printf(" (none)\n");
i = 0;
//now we move on to CVARs
CONS_Printf("Variables:\n");
for (cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, i))
{
strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
nameremainder[strlen(cmd)-(stop)] = '\0';
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder);
++i;
}
if (i == 0)
CONS_Printf(" (none)\n");
return true;
}
// sequential command completion forward and backward // sequential command completion forward and backward
// remember typing for several completions (a-la-4dos) // remember typing for several completions (a-la-4dos)
if (inputlines[inputline][input_cx-1] != ' ') if (!completion[0])
{ {
if (strlen(inputlines[inputline]+1) < 80) if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
strcpy(completion, inputlines[inputline]+1); return true;
else strcpy(completion, inputlines[inputline]);
completion[0] = 0;
comskips = varskips = 0; comskips = varskips = 0;
} }
else else
@ -783,37 +868,26 @@ boolean CON_Responder(event_t *ev)
if (--varskips < 0) if (--varskips < 0)
comskips = -comskips - 2; comskips = -comskips - 2;
} }
else if (comskips > 0) else if (comskips > 0) comskips--;
comskips--;
} }
else else
{ {
if (comskips < 0) if (comskips < 0) varskips++;
varskips++; else comskips++;
else
comskips++;
} }
} }
if (comskips >= 0) if (comskips >= 0)
{ {
cmd = COM_CompleteCommand(completion, comskips); cmd = COM_CompleteCommand(completion, comskips);
if (!cmd) if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
// dirty: make sure if comskips is zero, to have a neg value
comskips = -comskips - 1; comskips = -comskips - 1;
} }
if (comskips < 0) if (comskips < 0)
cmd = CV_CompleteVar(completion, varskips); cmd = CV_CompleteVar(completion, varskips);
if (cmd) if (cmd)
{ CON_InputSetString(va("%s ", cmd));
memset(inputlines[inputline]+1, 0, CON_MAXPROMPTCHARS-1);
strcpy(inputlines[inputline]+1, cmd);
input_cx = strlen(cmd) + 1;
inputlines[inputline][input_cx] = ' ';
input_cx++;
inputlines[inputline][input_cx] = 0;
}
else else
{ {
if (comskips > 0) if (comskips > 0)
@ -839,47 +913,80 @@ boolean CON_Responder(event_t *ev)
return true; return true;
} }
if (key == KEY_HOME) // oldest text in buffer if (key == KEY_LEFTARROW)
{ {
con_scrollup = (con_totallines-((con_curlines-16)>>3)); if (input_cur != 0)
--input_cur;
if (!shiftdown)
input_sel = input_cur;
return true; return true;
} }
else if (key == KEY_END) // most recent text in buffer else if (key == KEY_RIGHTARROW)
{ {
con_scrollup = 0; if (input_cur < input_len)
++input_cur;
if (!shiftdown)
input_sel = input_cur;
return true; return true;
} }
else if (key == KEY_HOME)
{
input_cur = 0;
if (!shiftdown)
input_sel = input_cur;
return true;
}
else if (key == KEY_END)
{
input_cur = input_len;
if (!shiftdown)
input_sel = input_cur;
return true;
}
// At this point we're messing with input
// Clear completion
completion[0] = 0;
// command enter // command enter
if (key == KEY_ENTER) if (key == KEY_ENTER)
{ {
if (input_cx < 2) if (!input_len)
return true; return true;
// push the command // push the command
COM_BufAddText(inputlines[inputline]+1); COM_BufAddText(inputlines[inputline]);
COM_BufAddText("\n"); COM_BufAddText("\n");
CONS_Printf("%s\n", inputlines[inputline]); CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]);
inputline = (inputline+1) & 31; inputline = (inputline+1) & 31;
inputhist = inputline; inputhist = inputline;
CON_InputClear();
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
inputlines[inputline][0] = CON_PROMPTCHAR;
input_cx = 1;
return true; return true;
} }
// backspace command prompt // backspace and delete command prompt
if (key == KEY_BACKSPACE) if (input_sel != input_cur)
{ {
if (input_cx > 1) if (key == KEY_BACKSPACE || key == KEY_DEL)
{ {
input_cx--; CON_InputDelSelection();
inputlines[inputline][input_cx] = 0; return true;
} }
}
else if (key == KEY_BACKSPACE)
{
CON_InputDelChar();
return true;
}
else if (key == KEY_DEL)
{
if (input_cur == input_len)
return true;
++input_cur;
CON_InputDelChar();
return true; return true;
} }
@ -888,18 +995,15 @@ boolean CON_Responder(event_t *ev)
{ {
// copy one of the previous inputlines to the current // copy one of the previous inputlines to the current
do do
{
inputhist = (inputhist - 1) & 31; // cycle back inputhist = (inputhist - 1) & 31; // cycle back
} while (inputhist != inputline && !inputlines[inputhist][1]); while (inputhist != inputline && !inputlines[inputhist][0]);
// stop at the last history input line, which is the // stop at the last history input line, which is the
// current line + 1 because we cycle through the 32 input lines // current line + 1 because we cycle through the 32 input lines
if (inputhist == inputline) if (inputhist == inputline)
inputhist = (inputline + 1) & 31; inputhist = (inputline + 1) & 31;
M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS); CON_InputSetString(inputlines[inputhist]);
input_cx = strlen(inputlines[inputline]);
return true; return true;
} }
@ -909,23 +1013,14 @@ boolean CON_Responder(event_t *ev)
if (inputhist == inputline) if (inputhist == inputline)
return true; return true;
do do
{
inputhist = (inputhist + 1) & 31; inputhist = (inputhist + 1) & 31;
} while (inputhist != inputline && !inputlines[inputhist][1]); while (inputhist != inputline && !inputlines[inputhist][0]);
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
// back to currentline // back to currentline
if (inputhist == inputline) if (inputhist == inputline)
{ CON_InputClear();
inputlines[inputline][0] = CON_PROMPTCHAR;
input_cx = 1;
}
else else
{ CON_InputSetString(inputlines[inputhist]);
strcpy(inputlines[inputline], inputlines[inputhist]);
input_cx = strlen(inputlines[inputline]);
}
return true; return true;
} }
@ -950,15 +1045,12 @@ boolean CON_Responder(event_t *ev)
return false; return false;
// add key to cmd line here // add key to cmd line here
if (input_cx < CON_MAXPROMPTCHARS) if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
{ key = key + 'a' - 'A';
if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
key = key + 'a' - 'A';
inputlines[inputline][input_cx] = (char)key; if (input_sel != input_cur)
inputlines[inputline][input_cx + 1] = 0; CON_InputDelSelection();
input_cx++; CON_InputAddChar(key);
}
return true; return true;
} }
@ -1242,26 +1334,89 @@ void CONS_Error(const char *msg)
// //
static void CON_DrawInput(void) static void CON_DrawInput(void)
{ {
char *p;
size_t c;
INT32 x, y;
INT32 charwidth = (INT32)con_scalefactor << 3; INT32 charwidth = (INT32)con_scalefactor << 3;
const char *p = inputlines[inputline];
// input line scrolls left if it gets too long size_t c, clen, cend;
p = inputlines[inputline]; UINT8 lellip = 0, rellip = 0;
if (input_cx >= con_width-11) INT32 x, y, i;
p += input_cx - (con_width-11) + 1;
y = con_curlines - 12 * con_scalefactor; y = con_curlines - 12 * con_scalefactor;
x = charwidth*2;
for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth) clen = con_width-13;
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
// draw the blinking cursor if (input_len <= clen)
// {
x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth); c = 0;
if (con_tick < 4) clen = input_len;
V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); }
else // input line scrolls left if it gets too long
{
clen -= 2; // There will always be some extra truncation -- but where is what we'll find out
if (input_cur <= clen/2)
{
// Close enough to right edge to show all
c = 0;
// Always will truncate right side from this position, so always draw right ellipsis
rellip = 1;
}
else
{
// Cursor in the middle (or right side) of input
// Move over for the ellipsis
c = input_cur - (clen/2) + 2;
x += charwidth*2;
lellip = 1;
if (c + clen >= input_len)
{
// Cursor in the right side of input
// We were too far over, so move back
c = input_len - clen;
}
else
{
// Cursor in the middle -- ellipses on both sides
clen -= 2;
rellip = 1;
}
}
}
if (lellip)
{
x -= charwidth*3;
if (input_sel < c)
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
for (i = 0; i < 3; ++i, x += charwidth)
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
}
else
V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
for (cend = c + clen; c < cend; ++c, x += charwidth)
{
if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c))
{
V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 107 | V_NOSCALESTART);
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value);
}
else
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
if (c == input_cur && con_tick >= 4)
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
}
if (cend == input_cur && con_tick >= 4)
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
if (rellip)
{
if (input_sel > cend)
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
for (i = 0; i < 3; ++i, x += charwidth)
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
}
} }
// draw the last lines of console text to the top of the screen // draw the last lines of console text to the top of the screen
@ -1417,7 +1572,7 @@ static void CON_DrawConsole(void)
{ {
// inu: no more width (was always 0 and vid.width) // inu: no more width (was always 0 and vid.width)
if (rendermode != render_none) if (rendermode != render_none)
V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background V_DrawFadeConsBack(con_curlines); // translucent background
} }
// draw console text lines from top to bottom // draw console text lines from top to bottom

View file

@ -40,11 +40,10 @@ extern consvar_t cons_backcolor;
extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap; extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap;
// Console bg colors: // Console bg color (auto updated to match)
extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap, extern UINT8 *consolebgmap;
*credmap;
void CON_ReSetupBackColormap(UINT16 num); void CON_SetupBackColormap(void);
void CON_ClearHUD(void); // clear heads up messages void CON_ClearHUD(void); // clear heads up messages
void CON_Ticker(void); void CON_Ticker(void);

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,7 @@ typedef enum
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
// allows HSendPacket(,true,,) to return false. // allows HSendPacket(*, true, *, *) to return false.
// In addition, this packet can't occupy all the available slots. // In addition, this packet can't occupy all the available slots.
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file. PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
@ -76,11 +76,19 @@ typedef enum
NUMPACKETTYPE NUMPACKETTYPE
} packettype_t; } packettype_t;
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
#endif #endif
// client to server packet // Client to server packet
typedef struct typedef struct
{ {
UINT8 client_tic; UINT8 client_tic;
@ -89,7 +97,7 @@ typedef struct
ticcmd_t cmd; ticcmd_t cmd;
} ATTRPACK clientcmd_pak; } ATTRPACK clientcmd_pak;
// splitscreen packet // Splitscreen packet
// WARNING: must have the same format of clientcmd_pak, for more easy use // WARNING: must have the same format of clientcmd_pak, for more easy use
typedef struct typedef struct
{ {
@ -110,16 +118,16 @@ typedef struct
UINT8 starttic; UINT8 starttic;
UINT8 numtics; UINT8 numtics;
UINT8 numslots; // "Slots filled": Highest player number in use plus one. UINT8 numslots; // "Slots filled": Highest player number in use plus one.
ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
} ATTRPACK servertics_pak; } ATTRPACK servertics_pak;
// sent to client when all consistency data // Sent to client when all consistency data
// for players has been restored // for players has been restored
typedef struct typedef struct
{ {
UINT32 randomseed; UINT32 randomseed;
//ctf flag stuff // CTF flag stuff
SINT8 flagplayer[2]; SINT8 flagplayer[2];
INT32 flagloose[2]; INT32 flagloose[2];
INT32 flagflags[2]; INT32 flagflags[2];
@ -127,11 +135,11 @@ typedef struct
fixed_t flagy[2]; fixed_t flagy[2];
fixed_t flagz[2]; fixed_t flagz[2];
UINT32 ingame; // spectator bit for each player UINT32 ingame; // Spectator bit for each player
UINT32 ctfteam; // if not spectator, then which team? INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
// Resynch game scores and the like all at once // Resynch game scores and the like all at once
UINT32 score[MAXPLAYERS]; // Everyone's score. UINT32 score[MAXPLAYERS]; // Everyone's score
INT16 numboxes[MAXPLAYERS]; INT16 numboxes[MAXPLAYERS];
INT16 totalring[MAXPLAYERS]; INT16 totalring[MAXPLAYERS];
tic_t realtime[MAXPLAYERS]; tic_t realtime[MAXPLAYERS];
@ -140,14 +148,14 @@ typedef struct
typedef struct typedef struct
{ {
//player stuff // Player stuff
UINT8 playernum; UINT8 playernum;
// Do not send anything visual related. // Do not send anything visual related.
// Only send data that we need to know for physics. // Only send data that we need to know for physics.
UINT8 playerstate; //playerstate_t UINT8 playerstate; // playerstate_t
UINT32 pflags; //pflags_t UINT32 pflags; // pflags_t
UINT8 panim; //panim_t UINT8 panim; // panim_t
angle_t aiming; angle_t aiming;
INT32 currentweapon; INT32 currentweapon;
@ -174,9 +182,9 @@ typedef struct
UINT8 charability; UINT8 charability;
UINT8 charability2; UINT8 charability2;
UINT32 charflags; UINT32 charflags;
UINT32 thokitem; //mobjtype_t UINT32 thokitem; // mobjtype_t
UINT32 spinitem; //mobjtype_t UINT32 spinitem; // mobjtype_t
UINT32 revitem; //mobjtype_t UINT32 revitem; // mobjtype_t
fixed_t actionspd; fixed_t actionspd;
fixed_t mindash; fixed_t mindash;
fixed_t maxdash; fixed_t maxdash;
@ -230,7 +238,7 @@ typedef struct
INT32 onconveyor; INT32 onconveyor;
//player->mo stuff //player->mo stuff
UINT8 hasmo; //boolean UINT8 hasmo; // Boolean
angle_t angle; angle_t angle;
fixed_t x; fixed_t x;
@ -257,10 +265,10 @@ typedef struct
typedef struct typedef struct
{ {
UINT8 version; // different versions don't work UINT8 version; // Different versions don't work
UINT8 subversion; // contains build version UINT8 subversion; // Contains build version
// server launch stuffs // Server launch stuffs
UINT8 serverplayer; UINT8 serverplayer;
UINT8 totalslotnum; // "Slots": highest player number in use plus one. UINT8 totalslotnum; // "Slots": highest player number in use plus one.
@ -274,18 +282,18 @@ typedef struct
UINT8 gametype; UINT8 gametype;
UINT8 modifiedgame; UINT8 modifiedgame;
SINT8 adminplayer; // needs to be signed SINT8 adminplayer; // Needs to be signed
char server_context[8]; // unique context id, generated at server startup. char server_context[8]; // Unique context id, generated at server startup.
UINT8 varlengthinputs[0]; // playernames and netvars UINT8 varlengthinputs[0]; // Playernames and netvars
} ATTRPACK serverconfig_pak; } ATTRPACK serverconfig_pak;
typedef struct { typedef struct {
UINT8 fileid; UINT8 fileid;
UINT32 position; UINT32 position;
UINT16 size; UINT16 size;
UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
} ATTRPACK filetx_pak; } ATTRPACK filetx_pak;
#ifdef _MSC_VER #ifdef _MSC_VER
@ -294,14 +302,14 @@ typedef struct {
typedef struct typedef struct
{ {
UINT8 version; // different versions don't work UINT8 version; // Different versions don't work
UINT8 subversion; // contains build version UINT8 subversion; // Contains build version
UINT8 localplayers; UINT8 localplayers;
UINT8 mode; UINT8 mode;
} ATTRPACK clientconfig_pak; } ATTRPACK clientconfig_pak;
#define MAXSERVERNAME 32 #define MAXSERVERNAME 32
// this packet is too large // This packet is too large
typedef struct typedef struct
{ {
UINT8 version; UINT8 version;
@ -367,45 +375,45 @@ typedef struct
} ATTRPACK plrconfig; } ATTRPACK plrconfig;
// //
// Network packet data. // Network packet data
// //
typedef struct typedef struct
{ {
UINT32 checksum; UINT32 checksum;
UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
UINT8 ackreturn; // the return of the ack number UINT8 ackreturn; // The return of the ack number
UINT8 packettype; UINT8 packettype;
UINT8 reserved; // padding UINT8 reserved; // Padding
union union
{ {
clientcmd_pak clientpak; // 144 bytes clientcmd_pak clientpak; // 144 bytes
client2cmd_pak client2pak; // 200 bytes client2cmd_pak client2pak; // 200 bytes
servertics_pak serverpak; // 132495 bytes servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes serverconfig_pak servercfg; // 773 bytes
resynchend_pak resynchend; // resynchend_pak resynchend; //
resynch_pak resynchpak; // resynch_pak resynchpak; //
UINT8 resynchgot; // UINT8 resynchgot; //
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes filetx_pak filetxpak; // 139 bytes
clientconfig_pak clientcfg; // 136 bytes clientconfig_pak clientcfg; // 136 bytes
serverinfo_pak serverinfo; // 1024 bytes serverinfo_pak serverinfo; // 1024 bytes
serverrefuse_pak serverrefuse; // 65025 bytes serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes askinfo_pak askinfo; // 61 bytes
msaskinfo_pak msaskinfo; // 22 bytes msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
#ifdef NEWPING #ifdef NEWPING
UINT32 pingtable[MAXPLAYERS]; // 128 bytes UINT32 pingtable[MAXPLAYERS]; // 128 bytes
#endif #endif
} u; // this is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t; } ATTRPACK doomdata_t;
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack() #pragma pack()
#endif #endif
#define MAXSERVERLIST 64 // depends only on the display #define MAXSERVERLIST 64 // Depends only on the display
typedef struct typedef struct
{ {
SINT8 node; SINT8 node;
@ -416,7 +424,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount; extern UINT32 serverlistcount;
extern INT32 mapchangepending; extern INT32 mapchangepending;
// points inside doomcom // Points inside doomcom
extern doomdata_t *netbuffer; extern doomdata_t *netbuffer;
extern consvar_t cv_playbackspeed; extern consvar_t cv_playbackspeed;
@ -437,26 +445,28 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
extern boolean server; extern boolean server;
extern boolean dedicated; // for dedicated server #define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH; extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode; extern boolean acceptnewnode;
extern SINT8 servernode; extern SINT8 servernode;
void Command_Ping_f(void); void Command_Ping_f(void);
extern tic_t connectiontimeout; extern tic_t connectiontimeout;
extern tic_t jointimeout;
#ifdef NEWPING #ifdef NEWPING
extern UINT16 pingmeasurecount; extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
#endif #endif
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend; extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
// used in d_net, the only dependence // Used in d_net, the only dependence
tic_t ExpandTics(INT32 low); tic_t ExpandTics(INT32 low);
void D_ClientServerInit(void); void D_ClientServerInit(void);
// initialise the other field // Initialise the other field
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
@ -474,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void); void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum); void CL_ClearPlayer(INT32 playernum);
void CL_UpdateServerList(boolean internetsearch, INT32 room); void CL_UpdateServerList(boolean internetsearch, INT32 room);
// is there a game running // Is there a game running
boolean Playing(void); boolean Playing(void);
// Broadcasts special packets to other players // Broadcasts special packets to other players
// to notify of game exit // to notify of game exit
void D_QuitNetGame(void); void D_QuitNetGame(void);
//? how many ticks to run? //? How many ticks to run?
void TryRunTics(tic_t realtic); void TryRunTics(tic_t realtic);
// extra data for lmps // extra data for lmps

View file

@ -73,6 +73,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#include "dehacked.h" // Dehacked list test #include "dehacked.h" // Dehacked list test
#include "m_cond.h" // condition initialization #include "m_cond.h" // condition initialization
#include "fastcmp.h" #include "fastcmp.h"
#include "keys.h"
#ifdef CMAKECONFIG #ifdef CMAKECONFIG
#include "config.h" #include "config.h"
@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev)
void D_PostEvent_end(void) {}; void D_PostEvent_end(void) {};
#endif #endif
// modifier keys
UINT8 shiftdown = 0; // 0x1 left, 0x2 right
UINT8 ctrldown = 0; // 0x1 left, 0x2 right
UINT8 altdown = 0; // 0x1 left, 0x2 right
//
// D_ModifierKeyResponder
// Sets global shift/ctrl/alt variables, never actually eats events
//
static inline void D_ModifierKeyResponder(event_t *ev)
{
if (ev->type == ev_keydown) switch (ev->data1)
{
case KEY_LSHIFT: shiftdown |= 0x1; return;
case KEY_RSHIFT: shiftdown |= 0x2; return;
case KEY_LCTRL: ctrldown |= 0x1; return;
case KEY_RCTRL: ctrldown |= 0x2; return;
case KEY_LALT: altdown |= 0x1; return;
case KEY_RALT: altdown |= 0x2; return;
default: return;
}
else if (ev->type == ev_keyup) switch (ev->data1)
{
case KEY_LSHIFT: shiftdown &= ~0x1; return;
case KEY_RSHIFT: shiftdown &= ~0x2; return;
case KEY_LCTRL: ctrldown &= ~0x1; return;
case KEY_RCTRL: ctrldown &= ~0x2; return;
case KEY_LALT: altdown &= ~0x1; return;
case KEY_RALT: altdown &= ~0x2; return;
default: return;
}
}
// //
// D_ProcessEvents // D_ProcessEvents
// Send all the events of the given timestamp down the responder chain // Send all the events of the given timestamp down the responder chain
@ -188,6 +221,9 @@ void D_ProcessEvents(void)
{ {
ev = &events[eventtail]; ev = &events[eventtail];
// Set global shift/ctrl/alt down variables
D_ModifierKeyResponder(ev); // never eats events
// Screenshots over everything so that they can be taken anywhere. // Screenshots over everything so that they can be taken anywhere.
if (M_ScreenshotResponder(ev)) if (M_ScreenshotResponder(ev))
continue; // ate the event continue; // ate the event

View file

@ -31,18 +31,18 @@
// //
// NETWORKING // NETWORKING
// //
// gametic is the tic about to be (or currently being) run // gametic is the tic about to (or currently being) run
// server: // Server:
// maketic is the tic that hasn't had control made for it yet // maketic is the tic that hasn't had control made for it yet
// nettics: is the tic for each node // nettics is the tic for each node
// firsttictosend: is the lowest value of nettics // firstticstosend is the lowest value of nettics
// client: // Client:
// neededtic: is the tic needed by the client to run the game // neededtic is the tic needed by the client to run the game
// firsttictosend: is used to optimize a condition // firstticstosend is used to optimize a condition
// normally maketic >= gametic > 0 // Normally maketic >= gametic > 0
#define FORCECLOSE 0x8000 #define FORCECLOSE 0x8000
tic_t connectiontimeout = (15*TICRATE); tic_t connectiontimeout = (10*TICRATE);
/// \brief network packet /// \brief network packet
doomcom_t *doomcom = NULL; doomcom_t *doomcom = NULL;
@ -62,7 +62,7 @@ INT32 net_bandwidth;
/// \brief max length per packet /// \brief max length per packet
INT16 hardware_MAXPACKETLENGTH; INT16 hardware_MAXPACKETLENGTH;
void (*I_NetGet)(void) = NULL; boolean (*I_NetGet)(void) = NULL;
void (*I_NetSend)(void) = NULL; void (*I_NetSend)(void) = NULL;
boolean (*I_NetCanSend)(void) = NULL; boolean (*I_NetCanSend)(void) = NULL;
boolean (*I_NetCanGet)(void) = NULL; boolean (*I_NetCanGet)(void) = NULL;
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// Some structs and functions for acknowledgement of packets // Some structs and functions for acknowledgement of packets
// ----------------------------------------------------------------- // -----------------------------------------------------------------
#define MAXACKPACKETS 96 // minimum number of nodes #define MAXACKPACKETS 96 // Minimum number of nodes (wat)
#define MAXACKTOSEND 96 #define MAXACKTOSEND 96
#define URGENTFREESLOTENUM 10 #define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11) #define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET #ifndef NONET
@ -139,10 +139,10 @@ typedef struct
{ {
UINT8 acknum; UINT8 acknum;
UINT8 nextacknum; UINT8 nextacknum;
UINT8 destinationnode; UINT8 destinationnode; // The node to send the ack to
tic_t senttime; tic_t senttime; // The time when the ack was sent
UINT16 length; UINT16 length; // The packet size
UINT16 resentnum; UINT16 resentnum; // The number of times the ack has been resent
union { union {
SINT8 raw[MAXPACKETLENGTH]; SINT8 raw[MAXPACKETLENGTH];
doomdata_t data; doomdata_t data;
@ -152,11 +152,12 @@ typedef struct
typedef enum typedef enum
{ {
CLOSE = 1, // flag is set when connection is closing NF_CLOSE = 1, // Flag is set when connection is closing
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t; } node_flags_t;
#ifndef NONET #ifndef NONET
// table of packet that was not acknowleged can be resend (the sender window) // Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS]; static ackpak_t ackpak[MAXACKPACKETS];
#endif #endif
@ -212,11 +213,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
return d; return d;
} }
// return a free acknum and copy netbuffer in the ackpak table /** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
*
* \param freeack The address to store the free acknum at
* \param lowtimer ???
* \return True if a free acknum was found
*/
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{ {
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
INT32 i, numfreeslote = 0; INT32 i, numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{ {
@ -227,10 +233,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
for (i = 0; i < MAXACKPACKETS; i++) for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum) if (!ackpak[i].acknum)
{ {
// for low priority packet, make sure let freeslotes so urgents packets can be sent // For low priority packets, make sure to let freeslots so urgent packets can be sent
numfreeslote++; if (netbuffer->packettype >= PT_CANFAIL)
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM) {
continue; numfreeslot++;
if (numfreeslot <= URGENTFREESLOTNUM)
continue;
}
ackpak[i].acknum = node->nextacknum; ackpak[i].acknum = node->nextacknum;
ackpak[i].nextacknum = node->nextacknum; ackpak[i].nextacknum = node->nextacknum;
@ -241,7 +250,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
ackpak[i].length = doomcom->datalength; ackpak[i].length = doomcom->datalength;
if (lowtimer) if (lowtimer)
{ {
// lowtime mean can't be sent now so try it soon as possible // Lowtime means can't be sent now so try it as soon as possible
ackpak[i].senttime = 0; ackpak[i].senttime = 0;
ackpak[i].resentnum = 1; ackpak[i].resentnum = 1;
} }
@ -254,7 +263,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
*freeack = ackpak[i].acknum; *freeack = ackpak[i].acknum;
sendackpacket++; // for stat sendackpacket++; // For stat
return true; return true;
} }
@ -266,14 +275,46 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false; return false;
} }
// Get a ack to send in the queu of this node /** Counts how many acks are free
*
* \param urgent True if the type of the packet meant to
* use an ack is lower than PT_CANFAIL
* If for some reason you don't want use it
* for any packet type in particular,
* just set to false
* \return The number of free acks
*
*/
INT32 Net_GetFreeAcks(boolean urgent)
{
INT32 i, numfreeslot = 0;
INT32 n = 0; // Number of free acks found
for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum)
{
// For low priority packets, make sure to let freeslots so urgent packets can be sent
if (!urgent)
{
numfreeslot++;
if (numfreeslot <= URGENTFREESLOTNUM)
continue;
}
n++;
}
return n;
}
// Get a ack to send in the queue of this node
static UINT8 GetAcktosend(INT32 node) static UINT8 GetAcktosend(INT32 node)
{ {
nodes[node].lasttimeacktosend_sent = I_GetTime(); nodes[node].lasttimeacktosend_sent = I_GetTime();
return nodes[node].firstacktosend; return nodes[node].firstacktosend;
} }
static void Removeack(INT32 i) static void RemoveAck(INT32 i)
{ {
INT32 node = ackpak[i].destinationnode; INT32 node = ackpak[i].destinationnode;
#ifndef NEWPING #ifndef NEWPING
@ -290,31 +331,31 @@ static void Removeack(INT32 i)
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum)); DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
#endif #endif
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
if (nodes[node].flags & CLOSE) if (nodes[node].flags & NF_CLOSE)
Net_CloseConnection(node); Net_CloseConnection(node);
} }
// we have got a packet proceed the ack request and ack return // We have got a packet, proceed the ack request and ack return
static boolean Processackpak(void) static boolean Processackpak(void)
{ {
INT32 i; INT32 i;
boolean goodpacket = true; boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
// received an ack return, so remove the ack in the list // Received an ack return, so remove the ack in the list
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0) if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
{ {
node->remotefirstack = netbuffer->ackreturn; node->remotefirstack = netbuffer->ackreturn;
// search the ackbuffer and free it // Search the ackbuffer and free it
for (i = 0; i < MAXACKPACKETS; i++) for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{ {
Removeack(i); RemoveAck(i);
} }
} }
// received a packet with ack, queue it to send the ack back // Received a packet with ack, queue it to send the ack back
if (netbuffer->ack) if (netbuffer->ack)
{ {
UINT8 ack = netbuffer->ack; UINT8 ack = netbuffer->ack;
@ -323,23 +364,23 @@ static boolean Processackpak(void)
{ {
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack)); DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
duppacket++; duppacket++;
goodpacket = false; // discard packet (duplicate) goodpacket = false; // Discard packet (duplicate)
} }
else else
{ {
// check if it is not already in the queue // Check if it is not already in the queue
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
if (node->acktosend[i] == ack) if (node->acktosend[i] == ack)
{ {
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
duppacket++; duppacket++;
goodpacket = false; // discard packet (duplicate) goodpacket = false; // Discard packet (duplicate)
break; break;
} }
if (goodpacket) if (goodpacket)
{ {
// is a good packet so increment the acknowledge number, // Is a good packet so increment the acknowledge number,
// then search for a "hole" in the queue // Then search for a "hole" in the queue
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1); UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
if (!nextfirstack) if (!nextfirstack)
nextfirstack = 1; nextfirstack = 1;
@ -383,10 +424,10 @@ static boolean Processackpak(void)
} }
} }
} }
else // out of order packet else // Out of order packet
{ {
// don't increment firsacktosend, put it in asktosend queue // Don't increment firsacktosend, put it in asktosend queue
// will be incremented when the nextfirstack comes (code above) // Will be incremented when the nextfirstack comes (code above)
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND); UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack)); DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
if (newhead != node->acktosend_tail) if (newhead != node->acktosend_tail)
@ -394,8 +435,8 @@ static boolean Processackpak(void)
node->acktosend[node->acktosend_head] = ack; node->acktosend[node->acktosend_head] = ack;
node->acktosend_head = newhead; node->acktosend_head = newhead;
} }
else // buffer full discard packet, sender will resend it else // Buffer full discard packet, sender will resend it
{ // we can admit the packet but we will not detect the duplication after :( { // We can admit the packet but we will not detect the duplication after :(
DEBFILE("no more freeackret\n"); DEBFILE("no more freeackret\n");
goodpacket = false; goodpacket = false;
} }
@ -430,25 +471,29 @@ static void GotAcks(void)
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
{ {
if (ackpak[i].acknum == netbuffer->u.textcmd[j]) if (ackpak[i].acknum == netbuffer->u.textcmd[j])
Removeack(i); RemoveAck(i);
else // nextacknum is first equal to acknum, then when receiving bigger ack
// nextacknum is first equal to acknum, then when receiving bigger ack // there is big chance the packet is lost
// there is big chance the packet is lost // When resent, nextacknum = nodes[node].nextacknum
// when resent, nextacknum = nodes[node].nextacknum // will redo the same but with different value
// will redo the same but with different value else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0 && ackpak[i].senttime > 0)
&& ackpak[i].senttime > 0) {
{ ackpak[i].senttime--; // hurry up
ackpak[i].senttime--; // hurry up }
}
} }
} }
#endif #endif
static inline void Net_ConnectionTimeout(INT32 node) void Net_ConnectionTimeout(INT32 node)
{ {
// send a very special packet to self (hack the reboundstore queue) // Don't timeout several times
// main code will handle it if (nodes[node].flags & NF_TIMEOUT)
return;
nodes[node].flags |= NF_TIMEOUT;
// Send a very special packet to self (hack the reboundstore queue)
// Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT; reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
reboundstore[rebound_head].ack = 0; reboundstore[rebound_head].ack = 0;
reboundstore[rebound_head].ackreturn = 0; reboundstore[rebound_head].ackreturn = 0;
@ -456,12 +501,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1); reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
rebound_head = (rebound_head+1) % MAXREBOUND; rebound_head = (rebound_head+1) % MAXREBOUND;
// do not redo it quickly (if we do not close connection it is // Do not redo it quickly (if we do not close connection it is
// for a good reason!) // for a good reason!)
nodes[node].lasttimepacketreceived = I_GetTime(); nodes[node].lasttimepacketreceived = I_GetTime();
} }
// resend the data if needed // Resend the data if needed
void Net_AckTicker(void) void Net_AckTicker(void)
{ {
#ifndef NONET #ifndef NONET
@ -477,7 +522,7 @@ void Net_AckTicker(void)
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime()) if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
#endif #endif
{ {
if (ackpak[i].resentnum > 10 && (node->flags & CLOSE)) if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
{ {
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n", DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
i, nodei)); i, nodei));
@ -497,7 +542,7 @@ void Net_AckTicker(void)
ackpak[i].senttime = I_GetTime(); ackpak[i].senttime = I_GetTime();
ackpak[i].resentnum++; ackpak[i].resentnum++;
ackpak[i].nextacknum = node->nextacknum; ackpak[i].nextacknum = node->nextacknum;
retransmit++; // for stat retransmit++; // For stat
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum, HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
(size_t)(ackpak[i].length - BASEPACKETSIZE)); (size_t)(ackpak[i].length - BASEPACKETSIZE));
} }
@ -505,15 +550,15 @@ void Net_AckTicker(void)
for (i = 1; i < MAXNETNODES; i++) for (i = 1; i < MAXNETNODES; i++)
{ {
// this is something like node open flag // This is something like node open flag
if (nodes[i].firstacktosend) if (nodes[i].firstacktosend)
{ {
// we haven't sent a packet for a long time // We haven't sent a packet for a long time
// acknowledge packet if needed // Acknowledge packet if needed
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime()) if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
Net_SendAcks(i); Net_SendAcks(i);
if (!(nodes[i].flags & CLOSE) if (!(nodes[i].flags & NF_CLOSE)
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime()) && nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
{ {
Net_ConnectionTimeout(i); Net_ConnectionTimeout(i);
@ -523,9 +568,9 @@ void Net_AckTicker(void)
#endif #endif
} }
// remove last packet received ack before resending the ackret // Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....) // (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgPacket(INT32 node) void Net_UnAcknowledgePacket(INT32 node)
{ {
#ifdef NONET #ifdef NONET
(void)node; (void)node;
@ -564,20 +609,29 @@ void Net_UnAcknowledgPacket(INT32 node)
#endif #endif
} }
boolean Net_AllAckReceived(void)
{
#ifndef NONET #ifndef NONET
/** Checks if all acks have been received
*
* \return True if all acks have been received
*
*/
static boolean Net_AllAcksReceived(void)
{
INT32 i; INT32 i;
for (i = 0; i < MAXACKPACKETS; i++) for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum) if (ackpak[i].acknum)
return false; return false;
#endif
return true; return true;
} }
#endif
// wait for all ackreturns with timeout in seconds /** Waits for all ackreturns
*
* \param timeout Timeout in seconds
*
*/
void Net_WaitAllAckReceived(UINT32 timeout) void Net_WaitAllAckReceived(UINT32 timeout)
{ {
#ifdef NONET #ifdef NONET
@ -587,7 +641,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
timeout = tictac + timeout*NEWTICRATE; timeout = tictac + timeout*NEWTICRATE;
HGetPacket(); HGetPacket();
while (timeout > I_GetTime() && !Net_AllAckReceived()) while (timeout > I_GetTime() && !Net_AllAcksReceived())
{ {
while (tictac == I_GetTime()) while (tictac == I_GetTime())
I_Sleep(); I_Sleep();
@ -598,18 +652,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
#endif #endif
} }
static void InitNode(INT32 node) static void InitNode(node_t *node)
{ {
nodes[node].acktosend_head = nodes[node].acktosend_tail = 0; node->acktosend_head = node->acktosend_tail = 0;
#ifndef NEWPING #ifndef NEWPING
nodes[node].ping = PINGDEFAULT; node->ping = PINGDEFAULT;
nodes[node].varping = VARPINGDEFAULT; node->varping = VARPINGDEFAULT;
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping); node->timeout = TIMEOUT(node->ping, node->varping);
#endif #endif
nodes[node].firstacktosend = 0; node->firstacktosend = 0;
nodes[node].nextacknum = 1; node->nextacknum = 1;
nodes[node].remotefirstack = 0; node->remotefirstack = 0;
nodes[node].flags = 0; node->flags = 0;
} }
static void InitAck(void) static void InitAck(void)
@ -622,9 +676,14 @@ static void InitAck(void)
#endif #endif
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
InitNode(i); InitNode(&nodes[i]);
} }
/** Removes all acks of a given packet type
*
* \param packettype The packet type to forget
*
*/
void Net_AbortPacketType(UINT8 packettype) void Net_AbortPacketType(UINT8 packettype)
{ {
#ifdef NONET #ifdef NONET
@ -657,7 +716,7 @@ void Net_CloseConnection(INT32 node)
if (!node) if (!node)
return; return;
nodes[node].flags |= CLOSE; nodes[node].flags |= NF_CLOSE;
// try to Send ack back (two army problem) // try to Send ack back (two army problem)
if (GetAcktosend(node)) if (GetAcktosend(node))
@ -676,8 +735,8 @@ void Net_CloseConnection(INT32 node)
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
} }
InitNode(node); InitNode(&nodes[node]);
AbortSendFiles(node); SV_AbortSendFiles(node);
I_NetFreeNodenum(node); I_NetFreeNodenum(node);
#endif #endif
} }
@ -729,9 +788,15 @@ static void fprintfstring(char *s, size_t len)
} }
if (mode) if (mode)
fprintf(debugfile, "]"); fprintf(debugfile, "]");
}
static void fprintfstringnewline(char *s, size_t len)
{
fprintfstring(s, len);
fprintf(debugfile, "\n"); fprintf(debugfile, "\n");
} }
/// \warning Keep this up-to-date if you add/remove/rename packet types
static const char *packettypename[NUMPACKETTYPE] = static const char *packettypename[NUMPACKETTYPE] =
{ {
"NOTHING", "NOTHING",
@ -749,15 +814,22 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKINFO", "ASKINFO",
"SERVERINFO", "SERVERINFO",
"PLAYERINFO",
"REQUESTFILE", "REQUESTFILE",
"ASKINFOVIAMS", "ASKINFOVIAMS",
"PLAYERCONFIGS", "RESYNCHEND",
"RESYNCHGET",
"FILEFRAGMENT", "FILEFRAGMENT",
"TEXTCMD", "TEXTCMD",
"TEXTCMD2", "TEXTCMD2",
"CLIENTJOIN", "CLIENTJOIN",
"NODETIMEOUT", "NODETIMEOUT",
"RESYNCHING",
#ifdef NEWPING
"PING"
#endif
}; };
static void DebugPrintpacket(const char *header) static void DebugPrintpacket(const char *header)
@ -770,20 +842,31 @@ static void DebugPrintpacket(const char *header)
{ {
case PT_ASKINFO: case PT_ASKINFO:
case PT_ASKINFOVIAMS: case PT_ASKINFOVIAMS:
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) ); fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
break; break;
case PT_CLIENTJOIN: case PT_CLIENTJOIN:
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers, fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
netbuffer->u.clientcfg.mode); netbuffer->u.clientcfg.mode);
break; break;
case PT_SERVERTICS: case PT_SERVERTICS:
{
servertics_pak *serverpak = &netbuffer->u.serverpak;
UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ", fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots, (UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
netbuffer->u.serverpak.numtics, /// \todo Display more readable information about net commands
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]))); fprintfstringnewline((char *)cmd, ntxtcmd);
fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)( /*fprintfstring((char *)cmd, 3);
&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])); if (ntxtcmd > 4)
{
fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
}
fprintf(debugfile, "\n");*/
break; break;
}
case PT_CLIENTCMD: case PT_CLIENTCMD:
case PT_CLIENT2CMD: case PT_CLIENT2CMD:
case PT_CLIENTMIS: case PT_CLIENTMIS:
@ -797,7 +880,8 @@ static void DebugPrintpacket(const char *header)
case PT_TEXTCMD: case PT_TEXTCMD:
case PT_TEXTCMD2: case PT_TEXTCMD2:
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]); fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
break; break;
case PT_SERVERCFG: case PT_SERVERCFG:
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d " fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
@ -813,7 +897,7 @@ static void DebugPrintpacket(const char *header)
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname, netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
netbuffer->u.serverinfo.fileneedednum, netbuffer->u.serverinfo.fileneedednum,
(UINT32)LONG(netbuffer->u.serverinfo.time)); (UINT32)LONG(netbuffer->u.serverinfo.time));
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded, fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength (UINT8)((UINT8 *)netbuffer + doomcom->datalength
- (UINT8 *)netbuffer->u.serverinfo.fileneeded)); - (UINT8 *)netbuffer->u.serverinfo.fileneeded));
break; break;
@ -827,20 +911,100 @@ static void DebugPrintpacket(const char *header)
break; break;
case PT_REQUESTFILE: case PT_REQUESTFILE:
default: // write as a raw packet default: // write as a raw packet
fprintfstring((char *)netbuffer->u.textcmd, fprintfstringnewline((char *)netbuffer->u.textcmd,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd)); (UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
break; break;
} }
} }
#endif #endif
#ifdef PACKETDROP
static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
static INT32 packetdroprate = 0;
void Command_Drop(void)
{
INT32 packetquantity;
const char *packetname;
size_t i;
if (COM_Argc() < 2)
{
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
"drop reset: cancel all packet drops\n");
return;
}
if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
{
memset(packetdropquantity, 0, sizeof(packetdropquantity));
return;
}
if (COM_Argc() >= 3)
{
packetquantity = atoi(COM_Argv(2));
if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
{
CONS_Printf("Invalid quantity\n");
return;
}
}
else
packetquantity = -1;
packetname = COM_Argv(1);
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
for (i = 0; i < NUMPACKETTYPE; i++)
packetdropquantity[i] = packetquantity;
else
{
for (i = 0; i < NUMPACKETTYPE; i++)
if (!stricmp(packetname, packettypename[i]))
{
packetdropquantity[i] = packetquantity;
return;
}
CONS_Printf("Unknown packet name\n");
}
}
void Command_Droprate(void)
{
INT32 droprate;
if (COM_Argc() < 2)
{
CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
return;
}
droprate = atoi(COM_Argv(1));
if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
{
CONS_Printf("Packet drop rate must be between 0 and 100!\n");
return;
}
packetdroprate = droprate;
}
static boolean ShouldDropPacket(void)
{
return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
}
#endif
// //
// HSendPacket // HSendPacket
// //
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength) boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
{ {
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE); doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
if (node == 0) // packet is to go back to us if (node == 0) // Packet is to go back to us
{ {
if ((rebound_head+1) % MAXREBOUND == rebound_tail) if ((rebound_head+1) % MAXREBOUND == rebound_tail)
{ {
@ -871,7 +1035,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
(void)reliable; (void)reliable;
(void)acknum; (void)acknum;
#else #else
// do this before GetFreeAcknum because this function backup // do this before GetFreeAcknum because this function backups
// the current packet // the current packet
doomcom->remotenode = (INT16)node; doomcom->remotenode = (INT16)node;
if (doomcom->datalength <= 0) if (doomcom->datalength <= 0)
@ -884,7 +1048,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
return false; return false;
} }
if (node < MAXNETNODES) // can be a broadcast if (node < MAXNETNODES) // Can be a broadcast
netbuffer->ackreturn = GetAcktosend(node); netbuffer->ackreturn = GetAcktosend(node);
else else
netbuffer->ackreturn = 0; netbuffer->ackreturn = 0;
@ -905,20 +1069,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
netbuffer->ack = acknum; netbuffer->ack = acknum;
netbuffer->checksum = NetbufferChecksum(); netbuffer->checksum = NetbufferChecksum();
sendbytes += packetheaderlength + doomcom->datalength; // for stat sendbytes += packetheaderlength + doomcom->datalength; // For stat
// simulate internet :) #ifdef PACKETDROP
if (true || rand()<(INT32)RAND_MAX/5) // Simulate internet :)
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
if (!ShouldDropPacket())
{ {
#endif
#ifdef DEBUGFILE #ifdef DEBUGFILE
if (debugfile) if (debugfile)
DebugPrintpacket("SEND"); DebugPrintpacket("SENT");
#endif #endif
I_NetSend(); I_NetSend();
#ifdef PACKETDROP
} }
else
{
if (packetdropquantity[netbuffer->packettype] > 0)
packetdropquantity[netbuffer->packettype]--;
#ifdef DEBUGFILE #ifdef DEBUGFILE
else if (debugfile) if (debugfile)
DebugPrintpacket("NOTSEND"); DebugPrintpacket("NOT SENT");
#endif
}
#endif #endif
#endif // ndef NONET #endif // ndef NONET
@ -933,7 +1107,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
// //
boolean HGetPacket(void) boolean HGetPacket(void)
{ {
// get a packet from self //boolean nodejustjoined;
// Get a packet from self
if (rebound_tail != rebound_head) if (rebound_tail != rebound_head)
{ {
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
@ -958,16 +1134,17 @@ boolean HGetPacket(void)
while(true) while(true)
{ {
//nodejustjoined = I_NetGet();
I_NetGet(); I_NetGet();
if (doomcom->remotenode == -1) if (doomcom->remotenode == -1) // No packet received
return false; return false;
getbytes += packetheaderlength + doomcom->datalength; // for stat getbytes += packetheaderlength + doomcom->datalength; // For stat
if (doomcom->remotenode >= MAXNETNODES) if (doomcom->remotenode >= MAXNETNODES)
{ {
DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode)); DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
continue; continue;
} }
@ -976,6 +1153,7 @@ boolean HGetPacket(void)
if (netbuffer->checksum != NetbufferChecksum()) if (netbuffer->checksum != NetbufferChecksum())
{ {
DEBFILE("Bad packet checksum\n"); DEBFILE("Bad packet checksum\n");
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
Net_CloseConnection(doomcom->remotenode); Net_CloseConnection(doomcom->remotenode);
continue; continue;
} }
@ -985,11 +1163,26 @@ boolean HGetPacket(void)
DebugPrintpacket("GET"); DebugPrintpacket("GET");
#endif #endif
// proceed the ack and ackreturn field /*// If a new node sends an unexpected packet, just ignore it
if (nodejustjoined && server
&& !(netbuffer->packettype == PT_ASKINFO
|| netbuffer->packettype == PT_SERVERINFO
|| netbuffer->packettype == PT_PLAYERINFO
|| netbuffer->packettype == PT_REQUESTFILE
|| netbuffer->packettype == PT_ASKINFOVIAMS
|| netbuffer->packettype == PT_CLIENTJOIN))
{
DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
continue;
}*/
// Proceed the ack and ackreturn field
if (!Processackpak()) if (!Processackpak())
continue; // discarded (duplicated) continue; // discarded (duplicated)
// a packet with just ackreturn // A packet with just ackreturn
if (netbuffer->packettype == PT_NOTHING) if (netbuffer->packettype == PT_NOTHING)
{ {
GotAcks(); GotAcks();
@ -1002,9 +1195,10 @@ boolean HGetPacket(void)
return true; return true;
} }
static void Internal_Get(void) static boolean Internal_Get(void)
{ {
doomcom->remotenode = -1; doomcom->remotenode = -1;
return false;
} }
FUNCNORETURN static ATTRNORETURN void Internal_Send(void) FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
@ -1089,7 +1283,7 @@ boolean D_CheckNetGame(void)
if (netgame) if (netgame)
ret = true; ret = true;
if (!server && netgame) if (client && netgame)
netgame = false; netgame = false;
server = true; // WTF? server always true??? server = true; // WTF? server always true???
// no! The deault mode is server. Client is set elsewhere // no! The deault mode is server. Client is set elsewhere
@ -1230,4 +1424,6 @@ void D_CloseConnection(void)
netgame = false; netgame = false;
addedtogame = false; addedtogame = false;
} }
D_ResetTiccmds();
} }

View file

@ -18,10 +18,10 @@
#ifndef __D_NET__ #ifndef __D_NET__
#define __D_NET__ #define __D_NET__
// Max computers in a game. // Max computers in a game
#define MAXNETNODES 32 #define MAXNETNODES 32
#define BROADCASTADDR MAXNETNODES #define BROADCASTADDR MAXNETNODES
#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer #define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
#define STATLENGTH (TICRATE*2) #define STATLENGTH (TICRATE*2)
@ -32,17 +32,17 @@ extern float lostpercent, duppercent, gamelostpercent;
extern INT32 packetheaderlength; extern INT32 packetheaderlength;
boolean Net_GetNetStat(void); boolean Net_GetNetStat(void);
extern INT32 getbytes; extern INT32 getbytes;
extern INT64 sendbytes; // realtime updated extern INT64 sendbytes; // Realtime updated
extern SINT8 nodetoplayer[MAXNETNODES]; extern SINT8 nodetoplayer[MAXNETNODES];
extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
INT32 Net_GetFreeAcks(boolean urgent);
void Net_AckTicker(void); void Net_AckTicker(void);
boolean Net_AllAckReceived(void);
// if reliable return true if packet sent, 0 else // If reliable return true if packet sent, 0 else
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
size_t packetlength); size_t packetlength);
boolean HGetPacket(void); boolean HGetPacket(void);
@ -52,9 +52,11 @@ void D_SaveBan(void);
#endif #endif
boolean D_CheckNetGame(void); boolean D_CheckNetGame(void);
void D_CloseConnection(void); void D_CloseConnection(void);
void Net_UnAcknowledgPacket(INT32 node); void Net_UnAcknowledgePacket(INT32 node);
void Net_CloseConnection(INT32 node); void Net_CloseConnection(INT32 node);
void Net_ConnectionTimeout(INT32 node);
void Net_AbortPacketType(UINT8 packettype); void Net_AbortPacketType(UINT8 packettype);
void Net_SendAcks(INT32 node); void Net_SendAcks(INT32 node);
void Net_WaitAllAckReceived(UINT32 timeout); void Net_WaitAllAckReceived(UINT32 timeout);
#endif #endif

View file

@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
static void TeamScramble_OnChange(void); static void TeamScramble_OnChange(void);
static void NetTimeout_OnChange(void); static void NetTimeout_OnChange(void);
static void JoinTimeout_OnChange(void);
static void Ringslinger_OnChange(void); static void Ringslinger_OnChange(void);
static void Gravity_OnChange(void); static void Gravity_OnChange(void);
@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef NEWPING #ifdef NEWPING
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
@ -365,6 +368,35 @@ boolean splitscreen = false;
boolean circuitmap = false; boolean circuitmap = false;
INT32 adminplayer = -1; INT32 adminplayer = -1;
/// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] =
{
"NAMEANDCOLOR",
"WEAPONPREF",
"KICK",
"NETVAR",
"SAY",
"MAP",
"EXITLEVEL",
"ADDFILE",
"PAUSE",
"ADDPLAYER",
"TEAMCHANGE",
"CLEARSCORES",
"LOGIN",
"VERIFIED",
"RANDOMSEED",
"RUNSOC",
"REQADDFILE",
"DELFILE",
"SETMOTD",
"SUICIDE",
#ifdef HAVE_BLUA
"LUACMD",
"LUAVAR"
#endif
};
// ========================================================================= // =========================================================================
// SERVER STARTUP // SERVER STARTUP
// ========================================================================= // =========================================================================
@ -517,9 +549,12 @@ void D_RegisterServerCommands(void)
// d_clisrv // d_clisrv
CV_RegisterVar(&cv_maxplayers); CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed);
COM_AddCommand("ping", Command_Ping_f); COM_AddCommand("ping", Command_Ping_f);
CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_nettimeout);
CV_RegisterVar(&cv_jointimeout);
CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep); CV_RegisterVar(&cv_sleep);
@ -976,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true; return true;
// Force skin in effect. // Force skin in effect.
if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1)) if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
return false; return false;
// Can change skin in intermission and whatnot. // Can change skin in intermission and whatnot.
@ -1587,7 +1622,7 @@ static void Command_Map_f(void)
return; return;
} }
if (!server && !(adminplayer == consoleplayer)) if (client && !(adminplayer == consoleplayer))
{ {
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return; return;
@ -1914,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
// You can't suicide someone else. Nice try, there. // You can't suicide someone else. Nice try, there.
if (suicideplayer != playernum || (!G_PlatformGametype())) if (suicideplayer != playernum || (!G_PlatformGametype()))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
if (server) if (server)
{ {
XBOXSTATIC UINT8 buf[2]; XBOXSTATIC UINT8 buf[2];
@ -2629,7 +2664,7 @@ static void Command_Changepassword_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security. // If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else #else
if (!server) // cannot change remotely if (client) // cannot change remotely
{ {
CONS_Printf(M_GetText("Only the server can use this.\n")); CONS_Printf(M_GetText("Only the server can use this.\n"));
return; return;
@ -2688,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
READMEM(*cp, sentmd5, 16); READMEM(*cp, sentmd5, 16);
if (!server) if (client)
return; return;
// Do the final pass to compare with the sent md5 // Do the final pass to compare with the sent md5
@ -2710,7 +2745,7 @@ static void Command_Verify_f(void)
char *temp; char *temp;
INT32 playernum; INT32 playernum;
if (!server) if (client)
{ {
CONS_Printf(M_GetText("Only the server can use this.\n")); CONS_Printf(M_GetText("Only the server can use this.\n"));
return; return;
@ -2794,7 +2829,7 @@ static void Command_MotD_f(void)
return; return;
} }
if ((netgame || multiplayer) && !server) if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd)); SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
else else
{ {
@ -3051,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
READMEM(*cp, md5sum, 16); READMEM(*cp, md5sum, 16);
// Only the server processes this message. // Only the server processes this message.
if (!server) if (client)
return; return;
// Disallow non-printing characters and semicolons. // Disallow non-printing characters and semicolons.
@ -3318,6 +3353,11 @@ static void NetTimeout_OnChange(void)
connectiontimeout = (tic_t)cv_nettimeout.value; connectiontimeout = (tic_t)cv_nettimeout.value;
} }
static void JoinTimeout_OnChange(void)
{
jointimeout = (tic_t)cv_jointimeout.value;
}
UINT32 timelimitintics = 0; UINT32 timelimitintics = 0;
/** Deals with a timelimit change by printing the change to the console. /** Deals with a timelimit change by printing the change to the console.
@ -3962,7 +4002,7 @@ static void Command_Archivetest_f(void)
} }
// assign mobjnum // assign mobjnum
i = 0; i = 1;
for (th = thinkercap.next; th != &thinkercap; th = th->next) for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker) if (th->function.acp1 == (actionf_p1)P_MobjThinker)
((mobj_t *)th)->mobjnum = i++; ((mobj_t *)th)->mobjnum = i++;
@ -4064,8 +4104,7 @@ static void Skin_OnChange(void)
if (!Playing()) if (!Playing())
return; // do whatever you want return; // do whatever you want
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player. if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return; return;

View file

@ -162,6 +162,8 @@ typedef enum
MAXNETXCMD MAXNETXCMD
} netxcmd_t; } netxcmd_t;
extern const char *netxcmdnames[MAXNETXCMD - 1];
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
#endif #endif

View file

@ -62,44 +62,48 @@
#include <errno.h> #include <errno.h>
static void SendFile(INT32 node, const char *filename, UINT8 fileid); static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
// sender structure // Sender structure
typedef struct filetx_s typedef struct filetx_s
{ {
INT32 ram; INT32 ram;
char *filename; // name of the file or ptr of the data in ram union {
UINT32 size; char *filename; // Name of the file
char *ram; // Pointer to the data in RAM
} id;
UINT32 size; // Size of the file
UINT8 fileid; UINT8 fileid;
INT32 node; // destination INT32 node; // Destination
struct filetx_s *next; // a queue struct filetx_s *next; // Next file in the list
} filetx_t; } filetx_t;
// current transfers (one for each node) // Current transfers (one for each node)
typedef struct filetran_s typedef struct filetran_s
{ {
filetx_t *txlist; filetx_t *txlist; // Linked list of all files for the node
UINT32 position; UINT32 position; // The current position in the file
FILE *currentfile; FILE *currentfile; // The file currently being sent/received
} filetran_t; } filetran_t;
static filetran_t transfer[MAXNETNODES]; static filetran_t transfer[MAXNETNODES];
// read time of file: stat _stmtime // Read time of file: stat _stmtime
// write time of file: utime // Write time of file: utime
// receiver structure // Receiver structure
INT32 fileneedednum; INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t fileneeded[MAX_WADFILES]; fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
char downloaddir[256] = "DOWNLOAD"; char downloaddir[256] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
// for cl loading screen // for cl loading screen
INT32 lastfilenum = 0; INT32 lastfilenum = -1;
#endif #endif
/** Fills a serverinfo packet with information about wad files loaded. /** Fills a serverinfo packet with information about wad files loaded.
* *
* \todo Give this function a better name since it is in global scope. * \todo Give this function a better name since it is in global scope.
*
*/ */
UINT8 *PutFileNeeded(void) UINT8 *PutFileNeeded(void)
{ {
@ -111,19 +115,19 @@ UINT8 *PutFileNeeded(void)
for (i = 0; i < numwadfiles; i++) for (i = 0; i < numwadfiles; i++)
{ {
// if it has only music/sound lumps, mark it as unimportant // If it has only music/sound lumps, mark it as unimportant
if (W_VerifyNMUSlumps(wadfiles[i]->filename)) if (W_VerifyNMUSlumps(wadfiles[i]->filename))
filestatus = 0; filestatus = 0;
else else
filestatus = 1; // important filestatus = 1; // Important
// Store in the upper four bits // Store in the upper four bits
if (!cv_downloading.value) if (!cv_downloading.value)
filestatus += (2 << 4); // won't send filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)) else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
filestatus += (0 << 4); // won't send filestatus += (0 << 4); // Won't send
else else
filestatus += (1 << 4); // will send if requested filestatus += (1 << 4); // Will send if requested
bytesused += (nameonlylength(wadfilename) + 22); bytesused += (nameonlylength(wadfilename) + 22);
@ -144,7 +148,12 @@ UINT8 *PutFileNeeded(void)
return p; return p;
} }
// parse the serverinfo packet and fill fileneeded table on client /** Parses the serverinfo packet and fills the fileneeded table on client
*
* \param fileneedednum_parm The number of files needed to join the server
* \param fileneededstr The memory block containing the list of needed files
*
*/
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
{ {
INT32 i; INT32 i;
@ -155,14 +164,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
p = (UINT8 *)fileneededstr; p = (UINT8 *)fileneededstr;
for (i = 0; i < fileneedednum; i++) for (i = 0; i < fileneedednum; i++)
{ {
fileneeded[i].status = FS_NOTFOUND; fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
filestatus = READUINT8(p); filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].important = (UINT8)(filestatus & 3); fileneeded[i].important = (UINT8)(filestatus & 3);
fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p); fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].phandle = NULL; fileneeded[i].file = NULL; // The file isn't open yet
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
READMEM(p, fileneeded[i].md5sum, 16); READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
} }
} }
@ -171,13 +180,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
fileneedednum = 1; fileneedednum = 1;
fileneeded[0].status = FS_REQUESTED; fileneeded[0].status = FS_REQUESTED;
fileneeded[0].totalsize = UINT32_MAX; fileneeded[0].totalsize = UINT32_MAX;
fileneeded[0].phandle = NULL; fileneeded[0].file = NULL;
memset(fileneeded[0].md5sum, 0, 16); memset(fileneeded[0].md5sum, 0, 16);
strcpy(fileneeded[0].filename, tmpsave); strcpy(fileneeded[0].filename, tmpsave);
} }
/** Checks the server to see if we CAN download all the files, /** Checks the server to see if we CAN download all the files,
* before starting to create them and requesting. * before starting to create them and requesting.
*
* \return True if we can download all the files
*
*/ */
boolean CL_CheckDownloadable(void) boolean CL_CheckDownloadable(void)
{ {
@ -239,8 +251,12 @@ boolean CL_CheckDownloadable(void)
return false; return false;
} }
/** Send requests for files in the ::fileneeded table with a status of /** Sends requests for files in the ::fileneeded table with a status of
* ::FS_NOTFOUND. * ::FS_NOTFOUND.
*
* \return True if the packet was successfully sent
* \note Sends a PT_REQUESTFILE packet
*
*/ */
boolean CL_SendRequestFile(void) boolean CL_SendRequestFile(void)
{ {
@ -298,11 +314,17 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF) if (id == 0xFF)
break; break;
READSTRINGN(p, wad, MAX_WADPATH); READSTRINGN(p, wad, MAX_WADPATH);
SendFile(node, wad, id); SV_SendFile(node, wad, id);
} }
} }
// client check if the fileneeded aren't already loaded or on the disk /** Checks if the files needed aren't already loaded or on the disk
*
* \return 0 if some files are missing
* 1 if all files exist
* 2 if some already loaded files are not requested or are in a different order
*
*/
INT32 CL_CheckFiles(void) INT32 CL_CheckFiles(void)
{ {
INT32 i, j; INT32 i, j;
@ -333,7 +355,7 @@ INT32 CL_CheckFiles(void)
} }
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename)) if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
{ {
// unimportant on our side. still don't care. // Unimportant on our side. still don't care.
++j; ++j;
continue; continue;
} }
@ -343,11 +365,11 @@ INT32 CL_CheckFiles(void)
if (i >= fileneedednum || j >= numwadfiles) if (i >= fileneedednum || j >= numwadfiles)
return 2; return 2;
// for the sake of speed, only bother with a md5 check // For the sake of speed, only bother with a md5 check
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16)) if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
return 2; return 2;
// it's accounted for! let's keep going. // It's accounted for! let's keep going.
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
fileneeded[i].status = FS_OPEN; fileneeded[i].status = FS_OPEN;
++i; ++i;
@ -360,7 +382,7 @@ INT32 CL_CheckFiles(void)
{ {
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// check in allready loaded files // Check in already loaded files
for (j = 1; wadfiles[j]; j++) for (j = 1; wadfiles[j]; j++)
{ {
nameonly(strcpy(wadfilename, wadfiles[j]->filename)); nameonly(strcpy(wadfilename, wadfiles[j]->filename));
@ -383,7 +405,7 @@ INT32 CL_CheckFiles(void)
return ret; return ret;
} }
// load it now // Load it now
void CL_LoadServerFiles(void) void CL_LoadServerFiles(void)
{ {
INT32 i; INT32 i;
@ -394,7 +416,7 @@ void CL_LoadServerFiles(void)
for (i = 1; i < fileneedednum; i++) for (i = 1; i < fileneedednum; i++)
{ {
if (fileneeded[i].status == FS_OPEN) if (fileneeded[i].status == FS_OPEN)
continue; // already loaded continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND) else if (fileneeded[i].status == FS_FOUND)
{ {
P_AddWadFile(fileneeded[i].filename, NULL); P_AddWadFile(fileneeded[i].filename, NULL);
@ -423,172 +445,269 @@ void CL_LoadServerFiles(void)
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename)); DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
} }
else if (fileneeded[i].important) else if (fileneeded[i].important)
I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename, {
fileneeded[i].status); const char *s;
switch(fileneeded[i].status)
{
case FS_NOTFOUND:
s = "FS_NOTFOUND";
break;
case FS_REQUESTED:
s = "FS_REQUESTED";
break;
case FS_DOWNLOADING:
s = "FS_DOWNLOADING";
break;
default:
s = "unknown";
break;
}
I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
fileneeded[i].status, s);
}
} }
} }
// little optimization to test if there is a file in the queue // Number of files to send
static INT32 filetosend = 0; // Little optimization to quickly test if there is a file in the queue
static INT32 filestosend = 0;
static void SendFile(INT32 node, const char *filename, UINT8 fileid) /** Adds a file to the file list for a node
*
* \param node The node to send the file to
* \param filename The file to send
* \param fileid ???
* \sa SV_SendRam
*
*/
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
{ {
filetx_t **q; filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; filetx_t *p; // The new file request
INT32 i; INT32 i;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node);
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist; q = &transfer[node].txlist;
while (*q) while (*q)
q = &((*q)->next); q = &((*q)->next);
// Allocate a file request and append it to the file list
p = *q = (filetx_t *)malloc(sizeof (filetx_t)); p = *q = (filetx_t *)malloc(sizeof (filetx_t));
if (p) if (!p)
memset(p, 0, sizeof (filetx_t)); I_Error("SV_SendFile: No more memory\n");
else
I_Error("SendFile: No more ram\n");
p->filename = (char *)malloc(MAX_WADPATH);
if (!p->filename)
I_Error("SendFile: No more ram\n");
// a minimum of security, can get only file in srb2 direcory // Initialise with zeros
strlcpy(p->filename, filename, MAX_WADPATH); memset(p, 0, sizeof (filetx_t));
nameonly(p->filename);
// check first in wads loaded the majority of case // Allocate the file name
p->id.filename = (char *)malloc(MAX_WADPATH);
if (!p->id.filename)
I_Error("SV_SendFile: No more memory\n");
// Set the file name and get rid of the path
strlcpy(p->id.filename, filename, MAX_WADPATH);
nameonly(p->id.filename);
// Look for the requested file through all loaded files
for (i = 0; wadfiles[i]; i++) for (i = 0; wadfiles[i]; i++)
{ {
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH); strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
nameonly(wadfilename); nameonly(wadfilename);
if (!stricmp(wadfilename, p->filename)) if (!stricmp(wadfilename, p->id.filename))
{ {
// copy filename with full path // Copy file name with full path
strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH); strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
break; break;
} }
} }
// Handle non-loaded file requests
if (!wadfiles[i]) if (!wadfiles[i])
{ {
DEBFILE(va("%s not found in wadfiles\n", filename)); DEBFILE(va("%s not found in wadfiles\n", filename));
// this formerly checked if (!findfile(p->filename, NULL, true)) // This formerly checked if (!findfile(p->id.filename, NULL, true))
// not found // Not found
// don't inform client (probably hacker) // Don't inform client (probably someone who thought they could leak 2.2 ACZ)
DEBFILE(va("Client %d request %s: not found\n", node, filename)); DEBFILE(va("Client %d request %s: not found\n", node, filename));
free(p->filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return;
} }
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024) if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{ {
// too big // Too big
// don't inform client (client sucks, man) // Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename)); DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
free(p->filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return;
} }
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node)); DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
p->ram = SF_FILE; p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
p->fileid = fileid; p->fileid = fileid;
p->next = NULL; // end of list p->next = NULL; // End of list
filetosend++; filestosend++;
} }
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid) /** Adds a memory block to the file list for a node
*
* \param node The node to send the memory block to
* \param data The memory block to send
* \param size The size of the block in bytes
* \param freemethod How to free the block after it has been sent
* \param fileid ???
* \sa SV_SendFile
*
*/
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
{ {
filetx_t **q; filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; filetx_t *p; // The new file request
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist; q = &transfer[node].txlist;
while (*q) while (*q)
q = &((*q)->next); q = &((*q)->next);
// Allocate a file request and append it to the file list
p = *q = (filetx_t *)malloc(sizeof (filetx_t)); p = *q = (filetx_t *)malloc(sizeof (filetx_t));
if (p) if (!p)
memset(p, 0, sizeof (filetx_t)); I_Error("SV_SendRam: No more memory\n");
else
I_Error("SendRam: No more ram\n"); // Initialise with zeros
p->ram = freemethod; memset(p, 0, sizeof (filetx_t));
p->filename = data;
p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
p->id.ram = data;
p->size = (UINT32)size; p->size = (UINT32)size;
p->fileid = fileid; p->fileid = fileid;
p->next = NULL; // end of list p->next = NULL; // End of list
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid)); DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
filetosend++; filestosend++;
} }
static void EndSend(INT32 node) /** Stops sending a file for a node, and removes the file request from the list,
* either because the file has been fully sent or because the node was disconnected
*
* \param node The destination
*
*/
static void SV_EndFileSend(INT32 node)
{ {
filetx_t *p = transfer[node].txlist; filetx_t *p = transfer[node].txlist;
// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
switch (p->ram) switch (p->ram)
{ {
case SF_FILE: case SF_FILE: // It's a file, close it and free its filename
if (cv_noticedownload.value)
CONS_Printf("Ending file transfer for node %d\n", node);
if (transfer[node].currentfile) if (transfer[node].currentfile)
fclose(transfer[node].currentfile); fclose(transfer[node].currentfile);
free(p->filename); free(p->id.filename);
break; break;
case SF_Z_RAM: case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
Z_Free(p->filename); Z_Free(p->id.ram);
break; break;
case SF_RAM: case SF_RAM: // It's a memory block allocated with malloc, use free
free(p->filename); free(p->id.ram);
case SF_NOFREERAM: case SF_NOFREERAM: // Nothing to free
break; break;
} }
// Remove the file request from the list
transfer[node].txlist = p->next; transfer[node].txlist = p->next;
transfer[node].currentfile = NULL;
free(p); free(p);
filetosend--;
// Indicate that the transmission is over
transfer[node].currentfile = NULL;
filestosend--;
} }
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH) #define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
void FiletxTicker(void) /** Handles file transmission
*
* \todo Use an acknowledging method more adapted to file transmission
* The current download speed suffers from lack of ack packets,
* especially when the one downloading has high latency
*
*/
void SV_FileSendTicker(void)
{ {
static INT32 currentnode = 0; static INT32 currentnode = 0;
filetx_pak *p; filetx_pak *p;
size_t size; size_t size;
filetx_t *f; filetx_t *f;
INT32 packetsent = PACKETPERTIC, ram, i; INT32 packetsent, ram, i, j;
INT32 maxpacketsent;
if (!filetosend) if (!filestosend) // No file to send
return; return;
if (!packetsent)
packetsent++; if (cv_downloadspeed.value) // New (and experimental) behavior
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while (packetsent-- && filetosend != 0)
{ {
for (i = currentnode, ram = 0; ram < MAXNETNODES; packetsent = cv_downloadspeed.value;
i = (i+1) % MAXNETNODES, ram++) // Don't send more packets than we have free acks
#ifndef NONET
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
#else
maxpacketsent = 1;
#endif
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
packetsent = maxpacketsent;
}
else // Old behavior
{
packetsent = PACKETPERTIC;
if (!packetsent)
packetsent = 1;
}
netbuffer->packettype = PT_FILEFRAGMENT;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while (packetsent-- && filestosend != 0)
{
for (i = currentnode, j = 0; j < MAXNETNODES;
i = (i+1) % MAXNETNODES, j++)
{ {
if (transfer[i].txlist) if (transfer[i].txlist)
goto found; goto found;
} }
// no transfer to do // no transfer to do
I_Error("filetosend=%d but no filetosend found\n", filetosend); I_Error("filestosend=%d but no file to send found\n", filestosend);
found: found:
currentnode = (i+1) % MAXNETNODES; currentnode = (i+1) % MAXNETNODES;
f = transfer[i].txlist; f = transfer[i].txlist;
ram = f->ram; ram = f->ram;
if (!transfer[i].currentfile) // file not already open // Open the file if it isn't open yet, or
if (!transfer[i].currentfile)
{ {
if (!ram) if (!ram) // Sending a file
{ {
long filesize; long filesize;
transfer[i].currentfile = transfer[i].currentfile =
fopen(f->filename, "rb"); fopen(f->id.filename, "rb");
if (!transfer[i].currentfile) if (!transfer[i].currentfile)
I_Error("File %s does not exist", I_Error("File %s does not exist",
f->filename); f->id.filename);
fseek(transfer[i].currentfile, 0, SEEK_END); fseek(transfer[i].currentfile, 0, SEEK_END);
filesize = ftell(transfer[i].currentfile); filesize = ftell(transfer[i].currentfile);
@ -596,45 +715,47 @@ void FiletxTicker(void)
// Nobody wants to transfer a file bigger // Nobody wants to transfer a file bigger
// than 4GB! // than 4GB!
if (filesize >= LONG_MAX) if (filesize >= LONG_MAX)
I_Error("filesize of %s is too large", f->filename); I_Error("filesize of %s is too large", f->id.filename);
if (-1 == filesize) if (filesize == -1)
I_Error("Error getting filesize of %s", f->filename); I_Error("Error getting filesize of %s", f->id.filename);
f->size = (UINT32)filesize; f->size = (UINT32)filesize;
fseek(transfer[i].currentfile, 0, SEEK_SET); fseek(transfer[i].currentfile, 0, SEEK_SET);
} }
else else // Sending RAM
transfer[i].currentfile = (FILE *)1; transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
transfer[i].position = 0; transfer[i].position = 0;
} }
// Build a packet containing a file fragment
p = &netbuffer->u.filetxpak; p = &netbuffer->u.filetxpak;
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE); size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
if (f->size-transfer[i].position < size) if (f->size-transfer[i].position < size)
size = f->size-transfer[i].position; size = f->size-transfer[i].position;
if (ram) if (ram)
M_Memcpy(p->data, &f->filename[transfer[i].position], size); M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size) else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile))); I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
p->position = LONG(transfer[i].position); p->position = LONG(transfer[i].position);
// put flag so receiver know the totalsize // Put flag so receiver knows the total size
if (transfer[i].position + size == f->size) if (transfer[i].position + size == f->size)
p->position |= LONG(0x80000000); p->position |= LONG(0x80000000);
p->fileid = f->fileid; p->fileid = f->fileid;
p->size = SHORT((UINT16)size); p->size = SHORT((UINT16)size);
netbuffer->packettype = PT_FILEFRAGMENT;
if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND // Send the packet
{ // not sent for some odd reason, retry at next call if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
if (!ram) { // Success
fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET); transfer[i].position = (UINT32)(transfer[i].position + size);
// exit the while (can't send this one so why should i send the next?) if (transfer[i].position == f->size) // Finish?
break; SV_EndFileSend(i);
} }
else // success else
{ { // Not sent for some odd reason, retry at next call
transfer[i].position = (UINT32)(size+transfer[i].position); if (!ram)
if (transfer[i].position == f->size) // finish ? fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
EndSend(i); // Exit the while (can't send this one so why should i send the next?)
break;
} }
} }
} }
@ -642,55 +763,90 @@ void FiletxTicker(void)
void Got_Filetxpak(void) void Got_Filetxpak(void)
{ {
INT32 filenum = netbuffer->u.filetxpak.fileid; INT32 filenum = netbuffer->u.filetxpak.fileid;
fileneeded_t *file = &fileneeded[filenum];
char *filename = file->filename;
static INT32 filetime = 0; static INT32 filetime = 0;
if (!(strcmp(filename, "srb2.srb")
&& strcmp(filename, "srb2.wad")
&& strcmp(filename, "zones.dta")
&& strcmp(filename, "player.dta")
&& strcmp(filename, "rings.dta")
&& strcmp(filename, "patch.dta")
&& strcmp(filename, "music.dta")
))
I_Error("Tried to download \"%s\"", filename);
if (filenum >= fileneedednum) if (filenum >= fileneedednum)
{ {
DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum)); DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
return; return;
} }
if (fileneeded[filenum].status == FS_REQUESTED) if (file->status == FS_REQUESTED)
{ {
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n"); if (file->file)
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb"); I_Error("Got_Filetxpak: already open file\n");
if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno)); file->file = fopen(filename, "wb");
CONS_Printf("\r%s...\n",fileneeded[filenum].filename); if (!file->file)
fileneeded[filenum].currentsize = 0; I_Error("Can't create file %s: %s", filename, strerror(errno));
fileneeded[filenum].status = FS_DOWNLOADING; CONS_Printf("\r%s...\n",filename);
file->currentsize = 0;
file->status = FS_DOWNLOADING;
} }
if (fileneeded[filenum].status == FS_DOWNLOADING) if (file->status == FS_DOWNLOADING)
{ {
UINT32 pos = LONG(netbuffer->u.filetxpak.position); UINT32 pos = LONG(netbuffer->u.filetxpak.position);
UINT16 size = SHORT(netbuffer->u.filetxpak.size); UINT16 size = SHORT(netbuffer->u.filetxpak.size);
// use a special tric to know when file is finished (not allways used) // Use a special trick to know when the file is complete (not always used)
// WARNING: filepak can arrive out of order so don't stop now ! // WARNING: file fragments can arrive out of order so don't stop yet!
if (pos & 0x80000000) if (pos & 0x80000000)
{ {
pos &= ~0x80000000; pos &= ~0x80000000;
fileneeded[filenum].totalsize = pos + size; file->totalsize = pos + size;
} }
// we can receive packet in the wrong order, anyway all os support gaped file // We can receive packet in the wrong order, anyway all os support gaped file
fseek(fileneeded[filenum].phandle,pos,SEEK_SET); fseek(file->file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1) if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle))); I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
fileneeded[filenum].currentsize += size; file->currentsize += size;
// finished? // Finished?
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize) if (file->currentsize == file->totalsize)
{ {
fclose(fileneeded[filenum].phandle); fclose(file->file);
fileneeded[filenum].phandle = NULL; file->file = NULL;
fileneeded[filenum].status = FS_FOUND; file->status = FS_FOUND;
CONS_Printf(M_GetText("Downloading %s...(done)\n"), CONS_Printf(M_GetText("Downloading %s...(done)\n"),
fileneeded[filenum].filename); filename);
} }
} }
else else
I_Error("Received a file not requested\n"); {
// send ack back quickly const char *s;
switch(file->status)
{
case FS_NOTFOUND:
s = "FS_NOTFOUND";
break;
case FS_FOUND:
s = "FS_FOUND";
break;
case FS_OPEN:
s = "FS_OPEN";
break;
case FS_MD5SUMBAD:
s = "FS_MD5SUMBAD";
break;
default:
s = "unknown";
break;
}
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
}
// Send ack back quickly
if (++filetime == 3) if (++filetime == 3)
{ {
Net_SendAcks(servernode); Net_SendAcks(servernode);
@ -702,33 +858,50 @@ void Got_Filetxpak(void)
#endif #endif
} }
void AbortSendFiles(INT32 node) /** \brief Checks if a node is downloading a file
*
* \param node The node to check for
* \return True if the node is downloading a file
*
*/
boolean SV_SendingFile(INT32 node)
{
return transfer[node].txlist != NULL;
}
/** Cancels all file requests for a node
*
* \param node The destination
* \sa SV_EndFileSend
*
*/
void SV_AbortSendFiles(INT32 node)
{ {
while (transfer[node].txlist) while (transfer[node].txlist)
EndSend(node); SV_EndFileSend(node);
} }
void CloseNetFile(void) void CloseNetFile(void)
{ {
INT32 i; INT32 i;
// is sending? // Is sending?
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
AbortSendFiles(i); SV_AbortSendFiles(i);
// receiving a file? // Receiving a file?
for (i = 0; i < MAX_WADFILES; i++) for (i = 0; i < MAX_WADFILES; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{ {
fclose(fileneeded[i].phandle); fclose(fileneeded[i].file);
// file is not complete delete it // File is not complete delete it
remove(fileneeded[i].filename); remove(fileneeded[i].filename);
} }
// remove FILEFRAGMENT from acknledge list // Remove PT_FILEFRAGMENT from acknowledge list
Net_AbortPacketType(PT_FILEFRAGMENT); Net_AbortPacketType(PT_FILEFRAGMENT);
} }
// functions cut and pasted from doomatic :) // Functions cut and pasted from Doomatic :)
void nameonly(char *s) void nameonly(char *s)
{ {

View file

@ -29,21 +29,21 @@ typedef enum
FS_FOUND, FS_FOUND,
FS_REQUESTED, FS_REQUESTED,
FS_DOWNLOADING, FS_DOWNLOADING,
FS_OPEN, // is opened and used in w_wad FS_OPEN, // Is opened and used in w_wad
FS_MD5SUMBAD FS_MD5SUMBAD
} filestatus_t; } filestatus_t;
typedef struct typedef struct
{ {
UINT8 important; UINT8 important;
UINT8 willsend; // is the server willing to send it? UINT8 willsend; // Is the server willing to send it?
char filename[MAX_WADPATH]; char filename[MAX_WADPATH];
UINT8 md5sum[16]; UINT8 md5sum[16];
// used only for download // Used only for download
FILE *phandle; FILE *file;
UINT32 currentsize; UINT32 currentsize;
UINT32 totalsize; UINT32 totalsize;
filestatus_t status; // the value returned by recsearch filestatus_t status; // The value returned by recsearch
} fileneeded_t; } fileneeded_t;
extern INT32 fileneedednum; extern INT32 fileneedednum;
@ -58,28 +58,25 @@ UINT8 *PutFileNeeded(void);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr); void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
void CL_PrepareDownloadSaveGame(const char *tmpsave); void CL_PrepareDownloadSaveGame(const char *tmpsave);
// check file list in wadfiles return 0 when a file is not found
// 1 if all file are found
// 2 if you cannot connect (different wad version or
// no enought space to download files)
INT32 CL_CheckFiles(void); INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void); void CL_LoadServerFiles(void);
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid); UINT8 fileid);
void FiletxTicker(void); void SV_FileSendTicker(void);
void Got_Filetxpak(void); void Got_Filetxpak(void);
boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void); boolean CL_SendRequestFile(void);
void Got_RequestFilePak(INT32 node); void Got_RequestFilePak(INT32 node);
void AbortSendFiles(INT32 node); void SV_AbortSendFiles(INT32 node);
void CloseNetFile(void); void CloseNetFile(void);
boolean fileexist(char *filename, time_t ptime); boolean fileexist(char *filename, time_t ptime);
// search a file in the wadpath, return FS_FOUND when found // Search a file in the wadpath, return FS_FOUND when found
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
boolean completepath); boolean completepath);
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum); filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);

View file

@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *variable)
return putenv(variable); return putenv(variable);
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
char *I_ClipboardPaste(void)
{
return NULL;
}
const CPUInfoFlags *I_CPUInfo(void) const CPUInfoFlags *I_CPUInfo(void)
{ {
static CPUInfoFlags DOS_CPUInfo; static CPUInfoFlags DOS_CPUInfo;

View file

@ -150,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
#else #else
#define VERSION 201 // Game version #define VERSION 201 // Game version
#define SUBVERSION 16 // more precise version number #define SUBVERSION 17 // more precise version number
#define VERSIONSTRING "v2.1.16" #define VERSIONSTRING "v2.1.17"
#define VERSIONSTRINGW L"v2.1.16" #define VERSIONSTRINGW L"v2.1.17"
// Hey! If you change this, add 1 to the MODVERSION below! // Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates! // Otherwise we can't force updates!
#endif #endif
@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update. // it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously. // Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 21 #define MODVERSION 22
// ========================================================================= // =========================================================================
@ -394,6 +394,9 @@ extern INT32 cv_debug;
// Misc stuff for later... // Misc stuff for later...
// ======================= // =======================
// Modifier key variables, accessible anywhere
extern UINT8 shiftdown, ctrldown, altdown;
// if we ever make our alloc stuff... // if we ever make our alloc stuff...
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL) #define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)

View file

@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable)
return -1; return -1;
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
char *I_ClipboardPaste(void)
{
return NULL;
}
void I_RegisterSysCommands(void) {} void I_RegisterSysCommands(void) {}
#include "../sdl/dosstr.c" #include "../sdl/dosstr.c"

View file

@ -974,7 +974,7 @@ static const char *credits[] = {
"Scott \"Graue\" Feeney", "Scott \"Graue\" Feeney",
"Nathan \"Jazz\" Giroux", "Nathan \"Jazz\" Giroux",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"\"Monster\" Iestyn Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port "Ronald \"Furyhunter\" Kinard", // The SDL2 port
"John \"JTE\" Muniz", "John \"JTE\" Muniz",
"Ehab \"Wolfy\" Saeed", "Ehab \"Wolfy\" Saeed",
@ -986,6 +986,7 @@ static const char *credits[] = {
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom) "\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
"Andrew \"orospakr\" Clunis", "Andrew \"orospakr\" Clunis",
"Gregor \"Oogaland\" Dick", "Gregor \"Oogaland\" Dick",
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
"Vivian \"toaster\" Grannell", "Vivian \"toaster\" Grannell",
"Julio \"Chaos Zero 64\" Guir", "Julio \"Chaos Zero 64\" Guir",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
@ -1020,7 +1021,7 @@ static const char *credits[] = {
"Paul \"Boinciel\" Clempson", "Paul \"Boinciel\" Clempson",
"Cyan Helkaraxe", "Cyan Helkaraxe",
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"\"Monster\" Iestyn Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"Jarel \"Arrow\" Jones", "Jarel \"Arrow\" Jones",
"Stefan \"Stuf\" Rimalia", "Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton", "Shane Mychal Sexton",

View file

@ -5588,7 +5588,7 @@ boolean G_CheckDemoStatus(void)
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file.
#endif #endif
saved = FIL_WriteFile(demoname, demobuffer, demo_p - demobuffer); // finally output the file. saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file.
free(demobuffer); free(demobuffer);
demorecording = false; demorecording = false;

View file

@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
{ {
FOutVector v[4]; FOutVector v[4];
FSurfaceInfo Surf; FSurfaceInfo Surf;
float sdupx, sdupy;
if (w < 0 || h < 0) if (w < 0 || h < 0)
return; // consistency w/ software return; // consistency w/ software
@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
// | /| // | /|
// |/ | // |/ |
// 0--1 // 0--1
v[0].x = v[3].x = (x - 160.0f)/160.0f; sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f; sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
v[0].y = v[1].y = -(y - 100.0f)/100.0f;
v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f; if (color & V_NOSCALESTART)
sdupx = sdupy = 2.0f;
v[0].x = v[3].x = (x*sdupx)/vid.width - 1;
v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1;
v[0].y = v[1].y = 1-(y*sdupy)/vid.height;
v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height;
//Hurdler: do we still use this argb color? if not, we should remove it //Hurdler: do we still use this argb color? if not, we should remove it
v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;

View file

@ -45,7 +45,7 @@
#include "hw_md2.h" #include "hw_md2.h"
#define R_FAKEFLOORS #define R_FAKEFLOORS
//#define HWPRECIP #define HWPRECIP
#define SORTING #define SORTING
//#define POLYSKY //#define POLYSKY
@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (gr_backsector) if (gr_backsector)
{ {
INT32 gr_toptexture, gr_bottomtexture;
// two sided line // two sided line
if (gr_backsector->heightsec != -1) if (gr_backsector->heightsec != -1)
{ {
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif #endif
} }
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
// check TOP TEXTURE // check TOP TEXTURE
if (( if ((
#ifdef ESLOPE #ifdef ESLOPE
worldhighslope < worldtopslope || worldhighslope < worldtopslope ||
#endif #endif
worldhigh < worldtop worldhigh < worldtop
) && texturetranslation[gr_sidedef->toptexture]) ) && gr_toptexture)
{ {
if (drawtextured) if (drawtextured)
{ {
fixed_t texturevpegtop; // top fixed_t texturevpegtop; // top
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]); grTex = HWR_GetTexture(gr_toptexture);
// PEGGING // PEGGING
if (gr_linedef->flags & ML_DONTPEGTOP) if (gr_linedef->flags & ML_DONTPEGTOP)
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegtop += gr_sidedef->rowoffset; texturevpegtop += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS; texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
@ -1683,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif #endif
if (gr_frontsector->numlights) if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS); HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT) else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap); HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
else else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap); HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
} }
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#ifdef ESLOPE #ifdef ESLOPE
worldlowslope > worldbottomslope || worldlowslope > worldbottomslope ||
#endif #endif
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!! worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
{ {
if (drawtextured) if (drawtextured)
{ {
fixed_t texturevpegbottom = 0; // bottom fixed_t texturevpegbottom = 0; // bottom
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]); grTex = HWR_GetTexture(gr_bottomtexture);
// PEGGING // PEGGING
#ifdef ESLOPE #ifdef ESLOPE
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegbottom += gr_sidedef->rowoffset; texturevpegbottom += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS; texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
@ -1766,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif #endif
if (gr_frontsector->numlights) if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS); HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT) else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap); HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
else else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap); HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
} }
gr_midtexture = texturetranslation[gr_sidedef->midtexture]; gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture) if (gr_midtexture)
{ {
FBITFIELD blendmode; FBITFIELD blendmode;
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
else else
{ {
// Single sided line... Deal only with the middletexture (if one exists) // Single sided line... Deal only with the middletexture (if one exists)
gr_midtexture = texturetranslation[gr_sidedef->midtexture]; gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture) if (gr_midtexture)
{ {
if (drawtextured) if (drawtextured)
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut) if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue; continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE) if (rover->master->flags & ML_TFERLINE)
{ {
size_t linenum = gr_curline->linedef-gr_backsector->lines[0]; size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum; newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
} }
#ifdef ESLOPE #ifdef ESLOPE
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut) if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue; continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE) if (rover->master->flags & ML_TFERLINE)
{ {
size_t linenum = gr_curline->linedef-gr_backsector->lines[0]; size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum; newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
} }
#ifdef ESLOPE //backsides #ifdef ESLOPE //backsides
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight; h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
@ -4401,7 +4405,6 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
FOutVector *wv; FOutVector *wv;
GLPatch_t *gpatch; // sprite patch converted to hardware GLPatch_t *gpatch; // sprite patch converted to hardware
FSurfaceInfo Surf; FSurfaceInfo Surf;
sector_t *sector;
if (!spr->mobj) if (!spr->mobj)
return; return;
@ -4455,19 +4458,38 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap); HWR_GetMappedPatch(gpatch, spr->colormap);
sector = spr->mobj->subsector->sector; // colormap test
if (sector->ffloors)
{ {
ffloor_t *caster = sector->lightlist[R_GetPlaneLight(sector, spr->mobj->z, false)].caster; sector_t *sector = spr->mobj->subsector->sector;
sector = caster ? &sectors[caster->secnum] : sector; UINT8 lightlevel = 255;
} extracolormap_t *colormap = sector->extra_colormap;
// sprite lighting by modulating the RGB components if (sector->numlights)
if (sector->extra_colormap) {
Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,sector->extra_colormap->rgba,sector->extra_colormap->fadergba, false, false); INT32 light;
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *sector->lightlist[light].lightlevel;
if (sector->lightlist[light].extra_colormap)
colormap = sector->lightlist[light].extra_colormap;
}
else else
Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,NORMALFOG,FADEFOG, false, false); {
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (colormap)
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
else
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
}
if (spr->mobj->flags2 & MF2_SHADOW) if (spr->mobj->flags2 & MF2_SHADOW)
{ {
@ -4501,8 +4523,8 @@ static void HWR_SortVisSprites(void)
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst; gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
gr_vissprite_t *best = NULL; gr_vissprite_t *best = NULL;
gr_vissprite_t unsorted; gr_vissprite_t unsorted;
float bestdist; float bestdist = 0.0f;
INT32 bestdispoffset; INT32 bestdispoffset = 0;
if (!gr_visspritecount) if (!gr_visspritecount)
return; return;
@ -5297,6 +5319,11 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// //
vis = HWR_NewVisSprite(); vis = HWR_NewVisSprite();
vis->x1 = x1; vis->x1 = x1;
#if 0
vis->x2 = x2;
#else
(void)x2;
#endif
vis->x2 = tx; vis->x2 = tx;
vis->tz = tz; vis->tz = tz;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
@ -5309,7 +5336,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// set top/bottom coords // set top/bottom coords
vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz; vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz;
vis->sectorlight = 0xff;
vis->precip = true; vis->precip = true;
} }
#endif #endif

View file

@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename)
model->header.numSkins = 1; model->header.numSkins = 1;
#define MD2LIMITCHECK(field, max, msgname) \
if (field > max) \
{ \
CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \
md2_freeModel (model); \
return 0; \
}
// Uncomment if these are actually needed
// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins")
// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates")
MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles")
MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames")
MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices")
#undef MD2LIMITCHECK
// read skins // read skins
fseek(file, model->header.offsetSkins, SEEK_SET); fseek(file, model->header.offsetSkins, SEEK_SET);
if (model->header.numSkins > 0) if (model->header.numSkins > 0)
@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename)
md2_freeModel (model); md2_freeModel (model);
return 0; return 0;
} }
;
} }
// read texture coordinates // read texture coordinates
@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename)
md2_freeModel (model); md2_freeModel (model);
return 0; return 0;
} }
} }
// read triangles // read triangles
@ -769,6 +782,7 @@ void HWR_InitMD2(void)
md2_playermodels[s].grpatch = NULL; md2_playermodels[s].grpatch = NULL;
md2_playermodels[s].skin = -1; md2_playermodels[s].skin = -1;
md2_playermodels[s].notfound = true; md2_playermodels[s].notfound = true;
md2_playermodels[s].error = false;
} }
for (i = 0; i < NUMSPRITES; i++) for (i = 0; i < NUMSPRITES; i++)
{ {
@ -777,6 +791,7 @@ void HWR_InitMD2(void)
md2_models[i].grpatch = NULL; md2_models[i].grpatch = NULL;
md2_models[i].skin = -1; md2_models[i].skin = -1;
md2_models[i].notfound = true; md2_models[i].notfound = true;
md2_models[i].error = false;
} }
// read the md2.dat file // read the md2.dat file
@ -1269,6 +1284,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
else else
md2 = &md2_models[spr->mobj->sprite]; md2 = &md2_models[spr->mobj->sprite];
if (md2->error)
return; // we already failed loading this before :(
if (!md2->model) if (!md2->model)
{ {
//CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]); //CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]);
@ -1282,6 +1299,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
else else
{ {
//CONS_Debug(DBG_RENDER, " FAILED\n"); //CONS_Debug(DBG_RENDER, " FAILED\n");
md2->error = true; // prevent endless fail
return; return;
} }
} }

View file

@ -123,6 +123,7 @@ typedef struct
void *blendgrpatch; void *blendgrpatch;
boolean notfound; boolean notfound;
INT32 skin; INT32 skin;
boolean error;
} md2_t; } md2_t;
extern md2_t md2_models[NUMSPRITES]; extern md2_t md2_models[NUMSPRITES];

View file

@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
boolean action = false; boolean action = false;
char *ptr; char *ptr;
CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]); CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
target = READSINT8(*p); target = READSINT8(*p);
flags = READUINT8(*p); flags = READUINT8(*p);
@ -757,15 +757,8 @@ void HU_clearChatChars(void)
// //
boolean HU_Responder(event_t *ev) boolean HU_Responder(event_t *ev)
{ {
static boolean shiftdown = false;
UINT8 c; UINT8 c;
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
{
shiftdown = (ev->type == ev_keydown);
return chat_on;
}
if (ev->type != ev_keydown) if (ev->type != ev_keydown)
return false; return false;
@ -797,6 +790,14 @@ boolean HU_Responder(event_t *ev)
} }
else // if chat_on else // if chat_on
{ {
// Ignore modifier keys
// Note that we do this here so users can still set
// their chat keys to one of these, if they so desire.
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
return true;
c = (UINT8)ev->data1; c = (UINT8)ev->data1;
// use console translations // use console translations
@ -1101,7 +1102,19 @@ void HU_Drawer(void)
// draw desynch text // draw desynch text
if (hu_resynching) if (hu_resynching)
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching..."); {
static UINT32 resynch_ticker = 0;
char resynch_text[14];
UINT32 i;
// Animate the dots
resynch_ticker++;
strcpy(resynch_text, "Resynching");
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
strcat(resynch_text, ".");
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
}
} }
//====================================================================== //======================================================================

View file

@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
/** \brief return packet in doomcom struct /** \brief return packet in doomcom struct
*/ */
extern void (*I_NetGet)(void); extern boolean (*I_NetGet)(void);
/** \brief ask to driver if there is data waiting /** \brief ask to driver if there is data waiting
*/ */

View file

@ -296,6 +296,14 @@ char *I_GetEnv(const char *name);
INT32 I_PutEnv(char *variable); INT32 I_PutEnv(char *variable);
/** \brief Put data in system clipboard
*/
INT32 I_ClipboardCopy(const char *data, size_t size);
/** \brief Retrieve data from system clipboard
*/
const char *I_ClipboardPaste(void);
void I_RegisterSysCommands(void); void I_RegisterSysCommands(void);
#endif #endif

View file

@ -179,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
#include "i_system.h" #include "i_system.h"
#include "i_net.h" #include "i_net.h"
#include "d_net.h" #include "d_net.h"
#include "d_netfil.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "m_argv.h" #include "m_argv.h"
@ -482,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
return false; return false;
} }
static SINT8 getfreenode(void)
{
SINT8 j;
for (j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
return j;
}
return -1;
}
// This is a hack. For some reason, nodes aren't being freed properly. // This is a hack. For some reason, nodes aren't being freed properly.
// This goes through and cleans up what nodes were supposed to be freed. // This goes through and cleans up what nodes were supposed to be freed.
/** \warning This function causes the file downloading to stop if someone joins.
* How? Because it removes nodes that are connected but not in game,
* which is exactly what clients downloading a file are.
*/
static void cleanupnodes(void) static void cleanupnodes(void)
{ {
SINT8 j; SINT8 j;
@ -506,13 +498,81 @@ static void cleanupnodes(void)
// Why can't I start at zero? // Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++) for (j = 1; j < MAXNETNODES; j++)
//if (!(nodeingame[j] || SV_SendingFile(j)))
if (!nodeingame[j]) if (!nodeingame[j])
nodeconnected[j] = false; nodeconnected[j] = false;
} }
static SINT8 getfreenode(void)
{
SINT8 j;
cleanupnodes();
for (j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
return j;
}
/** \warning No free node? Just in case a node might not have been freed properly,
* look if there are connected nodes that aren't in game, and forget them.
* It's dirty, and might result in a poor guy having to restart
* downloading a needed wad, but it's better than not letting anyone join...
*/
/*I_Error("No more free nodes!!1!11!11!!1111\n");
for (j = 1; j < MAXNETNODES; j++)
if (!nodeingame[j])
return j;*/
return -1;
}
#ifdef _DEBUG
void Command_Numnodes(void)
{
INT32 connected = 0;
INT32 ingame = 0;
INT32 i;
for (i = 1; i < MAXNETNODES; i++)
{
if (!(nodeconnected[i] || nodeingame[i]))
continue;
if (nodeconnected[i])
connected++;
if (nodeingame[i])
ingame++;
CONS_Printf("%2d - ", i);
if (nodetoplayer[i] != -1)
CONS_Printf("player %.2d", nodetoplayer[i]);
else
CONS_Printf(" ");
if (nodeconnected[i])
CONS_Printf(" - connected");
else
CONS_Printf(" - ");
if (nodeingame[i])
CONS_Printf(" - ingame");
else
CONS_Printf(" - ");
CONS_Printf(" - %s\n", I_GetNodeAddress(i));
}
CONS_Printf("\n"
"Connected: %d\n"
"Ingame: %d\n",
connected, ingame);
}
#endif
#endif #endif
#ifndef NONET #ifndef NONET
static void SOCK_Get(void) // Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void)
{ {
size_t i, n; size_t i, n;
int j; int j;
@ -535,13 +595,12 @@ static void SOCK_Get(void)
doomcom->remotenode = (INT16)j; // good packet from a game player doomcom->remotenode = (INT16)j; // good packet from a game player
doomcom->datalength = (INT16)c; doomcom->datalength = (INT16)c;
nodesocket[j] = mysockets[n]; nodesocket[j] = mysockets[n];
return; return false;
} }
} }
// not found // not found
// find a free slot // find a free slot
cleanupnodes();
j = getfreenode(); j = getfreenode();
if (j > 0) if (j > 0)
{ {
@ -564,14 +623,15 @@ static void SOCK_Get(void)
} }
if (i == numbans) if (i == numbans)
SOCK_bannednode[j] = false; SOCK_bannednode[j] = false;
return; return true;
} }
else else
DEBFILE("New node detected: No more free slots\n"); DEBFILE("New node detected: No more free slots\n");
} }
} }
doomcom->remotenode = -1; // no packet doomcom->remotenode = -1; // no packet
return false;
} }
#endif #endif
@ -1256,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
gaie = I_getaddrinfo(address, port, &hints, &ai); gaie = I_getaddrinfo(address, port, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
cleanupnodes();
newnode = getfreenode(); newnode = getfreenode();
} }
if (newnode == -1) if (newnode == -1)

View file

@ -60,7 +60,7 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type #define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
#define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
#define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type boolean LUAh_MobjThinker(mobj_t *mo); // Hook for P_MobjThinker or P_SceneryThinker by mobj type
#define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type #define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type
UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Should mobj take damage?) UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Should mobj take damage?)
boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)

View file

@ -74,12 +74,30 @@ typedef struct hook_s* hook_p;
#define FMT_HOOKID "hook_%d" #define FMT_HOOKID "hook_%d"
// For each mobj type, a linked list to its thinker and collision hooks.
// That way, we don't have to iterate through all the hooks.
// We could do that with all other mobj hooks, but it would probably just be
// a waste of memory since they are only called occasionally. Probably...
static hook_p mobjthinkerhooks[NUMMOBJTYPES];
static hook_p mobjcollidehooks[NUMMOBJTYPES];
// For each mobj type, a linked list for other mobj hooks
static hook_p mobjhooks[NUMMOBJTYPES];
// A linked list for player hooks
static hook_p playerhooks;
// A linked list for linedef executor hooks
static hook_p linedefexecutorhooks;
// For other hooks, a unique linked list
hook_p roothook; hook_p roothook;
// Takes hook, function, and additional arguments (mobj type to act on, etc.) // Takes hook, function, and additional arguments (mobj type to act on, etc.)
static int lib_addHook(lua_State *L) static int lib_addHook(lua_State *L)
{ {
static struct hook_s hook = {NULL, 0, 0, {0}, false}; static struct hook_s hook = {NULL, 0, 0, {0}, false};
static UINT32 nextid;
hook_p hookp, *lastp; hook_p hookp, *lastp;
hook.type = luaL_checkoption(L, 1, NULL, hookNames); hook.type = luaL_checkoption(L, 1, NULL, hookNames);
@ -109,6 +127,7 @@ static int lib_addHook(lua_State *L)
hook.s.mt = MT_NULL; hook.s.mt = MT_NULL;
if (lua_isnumber(L, 2)) if (lua_isnumber(L, 2))
hook.s.mt = lua_tonumber(L, 2); hook.s.mt = lua_tonumber(L, 2);
luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t");
break; break;
case hook_BotAI: case hook_BotAI:
hook.s.skinname = NULL; hook.s.skinname = NULL;
@ -141,18 +160,49 @@ static int lib_addHook(lua_State *L)
hooksAvailable[hook.type/8] |= 1<<(hook.type%8); hooksAvailable[hook.type/8] |= 1<<(hook.type%8);
// iterate the hook metadata structs
// set hook.id to the highest id + 1 // set hook.id to the highest id + 1
// set lastp to the last hook struct's "next" pointer. hook.id = nextid++;
lastp = &roothook;
hook.id = 0; // Special cases for some hook types (see the comments above mobjthinkerhooks declaration)
for (hookp = roothook; hookp; hookp = hookp->next) switch(hook.type)
{ {
if (hookp->id >= hook.id) case hook_MobjThinker:
hook.id = hookp->id+1; lastp = &mobjthinkerhooks[hook.s.mt];
lastp = &hookp->next; break;
case hook_MobjCollide:
case hook_MobjMoveCollide:
lastp = &mobjcollidehooks[hook.s.mt];
break;
case hook_MobjSpawn:
case hook_TouchSpecial:
case hook_MobjFuse:
case hook_BossThinker:
case hook_ShouldDamage:
case hook_MobjDamage:
case hook_MobjDeath:
case hook_BossDeath:
case hook_MobjRemoved:
lastp = &mobjhooks[hook.s.mt];
break;
case hook_JumpSpecial:
case hook_AbilitySpecial:
case hook_SpinSpecial:
case hook_JumpSpinSpecial:
case hook_PlayerSpawn:
lastp = &playerhooks;
break;
case hook_LinedefExecute:
lastp = &linedefexecutorhooks;
break;
default:
lastp = &roothook;
break;
} }
// iterate the hook metadata structs
// set lastp to the last hook struct's "next" pointer.
for (hookp = *lastp; hookp; hookp = hookp->next)
lastp = &hookp->next;
// allocate a permanent memory struct to stuff hook. // allocate a permanent memory struct to stuff hook.
hookp = ZZ_Alloc(sizeof(struct hook_s)); hookp = ZZ_Alloc(sizeof(struct hook_s));
memcpy(hookp, &hook, sizeof(struct hook_s)); memcpy(hookp, &hook, sizeof(struct hook_s));
@ -183,9 +233,29 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) // Look for all generic mobj hooks
if (hookp->type == which for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
&& (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type)) if (hookp->type == which)
{
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ);
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2);
if (lua_pcall(gL, 1, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
if (hookp->type == which)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, mo, META_MOBJ);
@ -217,7 +287,7 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) for (hookp = playerhooks; hookp; hookp = hookp->next)
if (hookp->type == which) if (hookp->type == which)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
@ -338,9 +408,38 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) // Look for all generic mobj collision hooks
if (hookp->type == which for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
&& (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type)) if (hookp->type == which)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, thing1, META_MOBJ);
LUA_PushUserdata(gL, thing2, META_MOBJ);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{ // if nil, leave shouldCollide = 0.
if (lua_toboolean(gL, -1))
shouldCollide = 1; // Force yes
else
shouldCollide = 2; // Force no
}
lua_pop(gL, 1);
}
for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next)
if (hookp->type == which)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
{ {
@ -372,6 +471,59 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
return shouldCollide; return shouldCollide;
} }
// Hook for mobj thinkers
boolean LUAh_MobjThinker(mobj_t *mo)
{
hook_p hookp;
boolean hooked = false;
if (!gL || !(hooksAvailable[hook_MobjThinker/8] & (1<<(hook_MobjThinker%8))))
return false;
lua_settop(gL, 0);
// Look for all generic mobj thinker hooks
for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next)
{
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ);
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2);
if (lua_pcall(gL, 1, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next)
{
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ);
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2);
if (lua_pcall(gL, 1, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return hooked;
}
// Hook for P_TouchSpecialThing by mobj type // Hook for P_TouchSpecialThing by mobj type
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
{ {
@ -382,9 +534,33 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) // Look for all generic touch special hooks
if (hookp->type == hook_TouchSpecial for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
&& (hookp->s.mt == MT_NULL || hookp->s.mt == special->type)) if (hookp->type == hook_TouchSpecial)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, special, META_MOBJ);
LUA_PushUserdata(gL, toucher, META_MOBJ);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_TouchSpecial)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
{ {
@ -421,9 +597,42 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) // Look for all generic should damage hooks
if (hookp->type == hook_ShouldDamage for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) if (hookp->type == hook_ShouldDamage)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
lua_pushinteger(gL, damage);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
if (lua_pcall(gL, 4, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{
if (lua_toboolean(gL, -1))
shouldDamage = 1; // Force yes
else
shouldDamage = 2; // Force no
}
lua_pop(gL, 1);
}
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_ShouldDamage)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
{ {
@ -469,9 +678,37 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) // Look for all generic mobj damage hooks
if (hookp->type == hook_MobjDamage for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) if (hookp->type == hook_MobjDamage)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
lua_pushinteger(gL, damage);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
if (lua_pcall(gL, 4, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MobjDamage)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
{ {
@ -512,9 +749,35 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) // Look for all generic mobj death hooks
if (hookp->type == hook_MobjDeath for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) if (hookp->type == hook_MobjDeath)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
if (lua_pcall(gL, 3, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MobjDeath)
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
{ {
@ -652,9 +915,8 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
lua_settop(gL, 0); lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next) for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next)
if (hookp->type == hook_LinedefExecute if (!strcmp(hookp->s.funcname, line->text))
&& !strcmp(hookp->s.funcname, line->text))
{ {
if (lua_gettop(gL) == 0) if (lua_gettop(gL) == 0)
{ {

View file

@ -369,6 +369,8 @@ static int libd_drawScaled(lua_State *L)
x = luaL_checkinteger(L, 1); x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2); y = luaL_checkinteger(L, 2);
scale = luaL_checkinteger(L, 3); scale = luaL_checkinteger(L, 3);
if (scale < 0)
return luaL_error(L, "negative scale");
patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH)); patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH));
flags = luaL_optinteger(L, 5, 0); flags = luaL_optinteger(L, 5, 0);
if (!lua_isnoneornil(L, 6)) if (!lua_isnoneornil(L, 6))

View file

@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
case sector_ceilingheight: case sector_ceilingheight:
lua_pushfixed(L, sector->ceilingheight); lua_pushfixed(L, sector->ceilingheight);
return 1; return 1;
case sector_floorpic: { // floorpic case sector_floorpic: // floorpic
levelflat_t *levelflat; lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
INT16 i;
for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
;
lua_pushlstring(L, levelflat->name, 8);
return 1; return 1;
} case sector_ceilingpic: // ceilingpic
case sector_ceilingpic: { // ceilingpic lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
levelflat_t *levelflat;
INT16 i;
for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
;
lua_pushlstring(L, levelflat->name, 8);
return 1; return 1;
}
case sector_lightlevel: case sector_lightlevel:
lua_pushinteger(L, sector->lightlevel); lua_pushinteger(L, sector->lightlevel);
return 1; return 1;
@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
return 0; return 0;
} }
// help function for P_LoadSectors, find a flat in the active wad files,
// allocate an id for it, and set the levelflat (to speedup search)
//
static INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
static int sector_set(lua_State *L) static int sector_set(lua_State *L)
{ {
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));

View file

@ -28,4 +28,4 @@ void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
void *M_AATreeGet(aatree_t *aatree, INT32 key); void *M_AATreeGet(aatree_t *aatree, INT32 key);
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback); void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
#endif #endif

View file

@ -452,7 +452,7 @@ void Command_RTeleport_f(void)
else else
inty = 0; inty = 0;
ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{ {
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));

View file

@ -46,41 +46,6 @@ typedef INT32 fixed_t;
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT)) #define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
/** \brief The TMulScale16 function
\param a a parameter of type fixed_t
\param b a parameter of type fixed_t
\param c a parameter of type fixed_t
\param d a parameter of type fixed_t
\param e a parameter of type fixed_t
\param f a parameter of type fixed_t
\return fixed_t
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
{ \
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
+ ((INT64)e * (INT64)f)) >> 16); \
}
/** \brief The DMulScale16 function
\param a a parameter of type fixed_t
\param b a parameter of type fixed_t
\param c a parameter of type fixed_t
\param d a parameter of type fixed_t
\return fixed_t
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
{ \
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
}
#if defined (__WATCOMC__) && FRACBITS == 16 #if defined (__WATCOMC__) && FRACBITS == 16
#pragma aux FixedMul = \ #pragma aux FixedMul = \
"imul ebx", \ "imul ebx", \
@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x != INT32_MIN) if (x != INT32_MIN)
return x-f; // return largest integral value not greater than argument { // return rounded down to nearest whole number
if (x > 0)
return x-f;
else
return x-(FRACUNIT-f);
}
return INT32_MIN; return INT32_MIN;
} }
@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (x != INT32_MIN) if (x != INT32_MIN)
{ // return rounded to nearest whole number, towards zero { // return rounded to nearest whole number, towards zero
if (x > 0) if (x > 0)
@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x == INT32_MIN) if (x == INT32_MIN)
return INT32_MIN; return INT32_MIN;
else if (x < FixedFloor(INT32_MAX)) else if (x < FixedFloor(INT32_MAX))
return x+(FRACUNIT-f); // return smallest integral value not less than argument { // return rounded up to nearest whole number
if (x > 0)
return x+(FRACUNIT-f);
else
return x+f;
}
return INT32_MAX; return INT32_MAX;
} }
@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x == INT32_MIN) if (x == INT32_MIN)
return INT32_MIN; return INT32_MIN;
else if (x < FixedFloor(INT32_MAX)) else if (x < FixedFloor(INT32_MAX))

View file

@ -182,9 +182,6 @@ static INT32 vidm_selected = 0;
static INT32 vidm_nummodes; static INT32 vidm_nummodes;
static INT32 vidm_column_size; static INT32 vidm_column_size;
// what a headache.
static boolean shiftdown = false;
// //
// PROTOTYPES // PROTOTYPES
// //
@ -2079,11 +2076,6 @@ boolean M_Responder(event_t *ev)
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
return false; return false;
if (ev->type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT))
{
shiftdown = false;
return false;
}
if (noFurtherInput) if (noFurtherInput)
{ {
// Ignore input after enter/escape/other buttons // Ignore input after enter/escape/other buttons
@ -2097,10 +2089,6 @@ boolean M_Responder(event_t *ev)
// added 5-2-98 remap virtual keys (mouse & joystick buttons) // added 5-2-98 remap virtual keys (mouse & joystick buttons)
switch (ch) switch (ch)
{ {
case KEY_LSHIFT:
case KEY_RSHIFT:
shiftdown = true;
break; //return false;
case KEY_MOUSE1: case KEY_MOUSE1:
case KEY_JOY1: case KEY_JOY1:
case KEY_JOY1 + 2: case KEY_JOY1 + 2:

View file

@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString)
|| stringToUse[startPos] == '\r' || stringToUse[startPos] == '\r'
|| stringToUse[startPos] == '\n' || stringToUse[startPos] == '\n'
|| stringToUse[startPos] == '\0' || stringToUse[startPos] == '\0'
|| stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
|| inComment != 0) || inComment != 0)
&& startPos < stringLength) && startPos < stringLength)
{ {
@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString)
&& stringToUse[endPos] != ',' && stringToUse[endPos] != ','
&& stringToUse[endPos] != '{' && stringToUse[endPos] != '{'
&& stringToUse[endPos] != '}' && stringToUse[endPos] != '}'
&& stringToUse[endPos] != '"' // see above
&& inComment == 0) && inComment == 0)
&& endPos < stringLength) && endPos < stringLength)
{ {

View file

@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable)
return -1; return -1;
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
char *I_ClipboardPaste(void)
{
return NULL;
}
void I_RegisterSysCommands(void) {} void I_RegisterSysCommands(void) {}
#include "../sdl/dosstr.c" #include "../sdl/dosstr.c"

View file

@ -7644,7 +7644,7 @@ void A_SetObjectFlags(mobj_t *actor)
else if (locvar2 == 1) else if (locvar2 == 1)
locvar1 = actor->flags & ~locvar1; locvar1 = actor->flags & ~locvar1;
if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
unlinkthings = true; unlinkthings = true;
if (unlinkthings) { if (unlinkthings) {

View file

@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
return; return;
//Tagmode round end but only on the tic before the //Tagmode round end but only on the tic before the
//XD_EXITLEVEL packet is recieved by all players. //XD_EXITLEVEL packet is received by all players.
if (G_TagGametype()) if (G_TagGametype())
{ {
if (leveltime == (timelimitintics + 1)) if (leveltime == (timelimitintics + 1))
@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT)) || (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
continue; continue;
CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]); CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
P_AddPlayerScore(&players[i], players[i].score); P_AddPlayerScore(&players[i], players[i].score);
} }
} }

View file

@ -1052,18 +1052,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
topz = thing->z - FixedMul(FRACUNIT, thing->scale); topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// if not in air, let P_TryMove() decide if it's not too high // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z + tmthing->height > topz if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz) && tmthing->z + tmthing->height < tmthing->ceilingz)
return false; // block while in air {
tmfloorz = tmceilingz = topz; // block while in air
if (thing->flags & MF_SPRING) #ifdef ESLOPE
tmceilingslope = NULL;
#endif
tmfloorthing = thing; // needed for side collision
}
else if (thing->flags & MF_SPRING)
; ;
else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height) else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
{ {
tmceilingz = topz; tmceilingz = topz;
#ifdef ESLOPE #ifdef ESLOPE
@ -1089,17 +1095,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
topz = thing->z + thing->height + FixedMul(FRACUNIT, thing->scale); topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// if not in air, let P_TryMove() decide if it's not too high // since return false doesn't handle momentum properly,
if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz) // we lie to P_TryMove() so it's always too high
return false; // block while in air if (tmthing->player && tmthing->z < topz
&& tmthing->z > tmthing->floorz)
if (thing->flags & MF_SPRING) {
tmfloorz = tmceilingz = topz; // block while in air
#ifdef ESLOPE
tmfloorslope = NULL;
#endif
tmfloorthing = thing; // needed for side collision
}
else if (thing->flags & MF_SPRING)
; ;
else if (topz > tmfloorz && tmthing->z >= thing->z) else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
{ {
tmfloorz = topz; tmfloorz = topz;
#ifdef ESLOPE #ifdef ESLOPE

View file

@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
side_t *side = &sides[linedef->sidenum[0]]; side_t *side = &sides[linedef->sidenum[0]];
fixed_t textop, texbottom, texheight; fixed_t textop, texbottom, texheight;
fixed_t texmid, delta1, delta2; fixed_t texmid, delta1, delta2;
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
// Get the midtexture's height if (texnum) {
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS; // Get the midtexture's height
texheight = textures[texnum]->height << FRACBITS;
// Set texbottom and textop to the Z coordinates of the texture's boundaries // Set texbottom and textop to the Z coordinates of the texture's boundaries
#if 0 // #ifdef POLYOBJECTS #if 0 // #ifdef POLYOBJECTS
// don't remove this code unless solid midtextures // don't remove this code unless solid midtextures
// on non-solid polyobjects should NEVER happen in the future // on non-solid polyobjects should NEVER happen in the future
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) { if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = back->floorheight + side->rowoffset; texbottom = back->floorheight + side->rowoffset;
textop = back->ceilingheight + side->rowoffset; textop = back->ceilingheight + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = back->floorheight + side->rowoffset; texbottom = back->floorheight + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1); textop = texbottom + texheight*(side->repeatcnt+1);
} else { } else {
textop = back->ceilingheight + side->rowoffset; textop = back->ceilingheight + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1); texbottom = textop - texheight*(side->repeatcnt+1);
} }
} else } else
#endif #endif
{ {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = openbottom + side->rowoffset; texbottom = openbottom + side->rowoffset;
textop = opentop + side->rowoffset; textop = opentop + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = openbottom + side->rowoffset; texbottom = openbottom + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1); textop = texbottom + texheight*(side->repeatcnt+1);
} else { } else {
textop = opentop + side->rowoffset; textop = opentop + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1); texbottom = textop - texheight*(side->repeatcnt+1);
}
} }
}
texmid = texbottom+(textop-texbottom)/2; texmid = texbottom+(textop-texbottom)/2;
delta1 = abs(mobj->z - texmid); delta1 = abs(mobj->z - texmid);
delta2 = abs(thingtop - texmid); delta2 = abs(thingtop - texmid);
if (delta1 > delta2) { // Below if (delta1 > delta2) { // Below
if (opentop > texbottom) if (opentop > texbottom)
opentop = texbottom; opentop = texbottom;
} else { // Above } else { // Above
if (openbottom < textop) if (openbottom < textop)
openbottom = textop; openbottom = textop;
}
} }
} }

View file

@ -4489,7 +4489,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
{ {
INT32 s; INT32 s;
mobj_t *base = mobj, *seg; mobj_t *base = mobj, *seg;
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS; fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
while ((base = base->tracer)) while ((base = base->tracer))
{ {
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s) for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
@ -4503,7 +4503,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
{ {
INT32 s; INT32 s;
mobj_t *base = mobj, *seg; mobj_t *base = mobj, *seg;
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS; fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
while ((base = base->tracer)) while ((base = base->tracer))
{ {
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s) for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
@ -4619,7 +4619,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
INT32 i, arm; INT32 i, arm;
mobj_t *seg, *base = mobj; mobj_t *seg, *base = mobj;
// First frame init, spawn all the things. // First frame init, spawn all the things.
mobj->spawnpoint->z = mobj->z>>FRACBITS; mobj->watertop = mobj->z;
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2; z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
for (arm = 0; arm <3 ; arm++) for (arm = 0; arm <3 ; arm++)
{ {
@ -4675,7 +4675,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
case 3: case 3:
{ {
fixed_t z; fixed_t z;
if (mobj->z < (mobj->spawnpoint->z+512)<<FRACBITS) if (mobj->z < mobj->watertop+(512<<FRACBITS))
mobj->momz = 8*FRACUNIT; mobj->momz = 8*FRACUNIT;
else else
{ {
@ -4684,7 +4684,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
} }
mobj->movecount += 400<<(FRACBITS>>1); mobj->movecount += 400<<(FRACBITS>>1);
mobj->movecount %= 360*FRACUNIT; mobj->movecount %= 360*FRACUNIT;
z = mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2; z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet. P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
else else
@ -4694,13 +4694,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
// Pinch phase! // Pinch phase!
case 4: case 4:
{ {
if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<<FRACBITS) if (mobj->z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<<FRACBITS)))
mobj->momz = 8*FRACUNIT; mobj->momz = 8*FRACUNIT;
else else
mobj->momz = 0; mobj->momz = 0;
mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1); mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
mobj->movecount %= 360*FRACUNIT; mobj->movecount %= 360*FRACUNIT;
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2); P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
if (!mobj->target || !mobj->target->health) if (!mobj->target || !mobj->target->health)
P_SupermanLook4Players(mobj); P_SupermanLook4Players(mobj);
@ -6101,6 +6101,8 @@ void P_RunOverlays(void)
P_UnsetThingPosition(mo); P_UnsetThingPosition(mo);
mo->x = destx; mo->x = destx;
mo->y = desty; mo->y = desty;
mo->radius = mo->target->radius;
mo->height = mo->target->height;
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs; mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs;
else else
@ -7732,6 +7734,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
if (mobj->type == MT_UNIDUS) if (mobj->type == MT_UNIDUS)
mobj->z -= FixedMul(mobj->info->mass, mobj->scale); mobj->z -= FixedMul(mobj->info->mass, mobj->scale);
// defaults onground
if (mobj->z + mobj->height == mobj->ceilingz)
mobj->eflags |= MFE_ONGROUND;
} }
else else
mobj->z = z; mobj->z = z;

View file

@ -460,6 +460,7 @@ static void P_NetUnArchivePlayers(void)
#define SD_TAG 0x10 #define SD_TAG 0x10
#define SD_FLOORANG 0x20 #define SD_FLOORANG 0x20
#define SD_CEILANG 0x40 #define SD_CEILANG 0x40
#define SD_TAGLIST 0x80
#define LD_FLAG 0x01 #define LD_FLAG 0x01
#define LD_SPECIAL 0x02 #define LD_SPECIAL 0x02
@ -509,10 +510,9 @@ static void P_NetArchiveWorld(void)
// //
// flats // flats
// //
// P_AddLevelFlat should not add but just return the number if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
diff |= SD_FLOORPIC; diff |= SD_FLOORPIC;
if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats)) if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
diff |= SD_CEILPIC; diff |= SD_CEILPIC;
if (ss->lightlevel != SHORT(ms->lightlevel)) if (ss->lightlevel != SHORT(ms->lightlevel))
@ -535,6 +535,8 @@ static void P_NetArchiveWorld(void)
if (ss->tag != SHORT(ms->tag)) if (ss->tag != SHORT(ms->tag))
diff2 |= SD_TAG; diff2 |= SD_TAG;
if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
diff2 |= SD_TAGLIST;
// Check if any of the sector's FOFs differ from how they spawned // Check if any of the sector's FOFs differ from how they spawned
if (ss->ffloors) if (ss->ffloors)
@ -582,16 +584,17 @@ static void P_NetArchiveWorld(void)
WRITEFIXED(put, ss->ceiling_xoffs); WRITEFIXED(put, ss->ceiling_xoffs);
if (diff2 & SD_CYOFFS) if (diff2 & SD_CYOFFS)
WRITEFIXED(put, ss->ceiling_yoffs); WRITEFIXED(put, ss->ceiling_yoffs);
if (diff2 & SD_TAG) if (diff2 & SD_TAG) // save only the tag
{
WRITEINT16(put, ss->tag); WRITEINT16(put, ss->tag);
WRITEINT32(put, ss->firsttag);
WRITEINT32(put, ss->nexttag);
}
if (diff2 & SD_FLOORANG) if (diff2 & SD_FLOORANG)
WRITEANGLE(put, ss->floorpic_angle); WRITEANGLE(put, ss->floorpic_angle);
if (diff2 & SD_CEILANG) if (diff2 & SD_CEILANG)
WRITEANGLE(put, ss->ceilingpic_angle); WRITEANGLE(put, ss->ceilingpic_angle);
if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
{ // either of these could be changed even if tag isn't
WRITEINT32(put, ss->firsttag);
WRITEINT32(put, ss->nexttag);
}
// Special case: save the stats of all modified ffloors along with their ffloor "number"s // Special case: save the stats of all modified ffloors along with their ffloor "number"s
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@ -752,12 +755,12 @@ static void P_NetUnArchiveWorld(void)
sectors[i].ceilingheight = READFIXED(get); sectors[i].ceilingheight = READFIXED(get);
if (diff & SD_FLOORPIC) if (diff & SD_FLOORPIC)
{ {
sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats); sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
get += 8; get += 8;
} }
if (diff & SD_CEILPIC) if (diff & SD_CEILPIC)
{ {
sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats); sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
get += 8; get += 8;
} }
if (diff & SD_LIGHT) if (diff & SD_LIGHT)
@ -774,12 +777,11 @@ static void P_NetUnArchiveWorld(void)
if (diff2 & SD_CYOFFS) if (diff2 & SD_CYOFFS)
sectors[i].ceiling_yoffs = READFIXED(get); sectors[i].ceiling_yoffs = READFIXED(get);
if (diff2 & SD_TAG) if (diff2 & SD_TAG)
sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
if (diff2 & SD_TAGLIST)
{ {
INT16 tag;
tag = READINT16(get);
sectors[i].firsttag = READINT32(get); sectors[i].firsttag = READINT32(get);
sectors[i].nexttag = READINT32(get); sectors[i].nexttag = READINT32(get);
P_ChangeSectorTag(i, tag);
} }
if (diff2 & SD_FLOORANG) if (diff2 & SD_FLOORANG)
sectors[i].floorpic_angle = READANGLE(get); sectors[i].floorpic_angle = READANGLE(get);
@ -2607,6 +2609,7 @@ static void P_NetUnArchiveThinkers(void)
thinker_t *next; thinker_t *next;
UINT8 tclass; UINT8 tclass;
UINT8 restoreNum = false; UINT8 restoreNum = false;
UINT32 i;
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS) if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
I_Error("Bad $$$.sav at archive block Thinkers"); I_Error("Bad $$$.sav at archive block Thinkers");
@ -2627,6 +2630,12 @@ static void P_NetUnArchiveThinkers(void)
iquetail = iquehead = 0; iquetail = iquehead = 0;
P_InitThinkers(); P_InitThinkers();
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
for (i = 0; i < numsectors; i++)
{
sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
}
// read in saved thinkers // read in saved thinkers
for (;;) for (;;)
{ {
@ -3285,7 +3294,7 @@ void P_SaveNetGame(void)
{ {
thinker_t *th; thinker_t *th;
mobj_t *mobj; mobj_t *mobj;
INT32 i = 0; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
CV_SaveNetVars(&save_p); CV_SaveNetVars(&save_p);
P_NetArchiveMisc(); P_NetArchiveMisc();

View file

@ -583,6 +583,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
return (INT32)i; return (INT32)i;
} }
// help function for Lua and $$$.sav reading
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
//
INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
// help function for $$$.sav checking
// this simply returns the flat # for the name given
//
INT32 P_CheckLevelFlat(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
if (i == numlevelflats)
return 0; // ??? flat was not found, this should not happen!
// level flat id
return (INT32)i;
}
static void P_LoadSectors(lumpnum_t lumpnum) static void P_LoadSectors(lumpnum_t lumpnum)
{ {
UINT8 *data; UINT8 *data;
@ -623,6 +686,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
ss->special = SHORT(ms->special); ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag); ss->tag = SHORT(ms->tag);
ss->nexttag = ss->firsttag = -1; ss->nexttag = ss->firsttag = -1;
ss->spawn_nexttag = ss->spawn_firsttag = -1;
memset(&ss->soundorg, 0, sizeof(ss->soundorg)); memset(&ss->soundorg, 0, sizeof(ss->soundorg));
ss->validcount = 0; ss->validcount = 0;
@ -2613,11 +2677,7 @@ boolean P_SetupLevel(boolean skipprecip)
lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap)); lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette); CON_SetupBackColormap();
// now part of level loading since in future each level may have
// its own anim texture sequences, switches etc.
P_InitPicAnims();
// SRB2 determines the sky texture to be used depending on the map header. // SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
@ -3029,6 +3089,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
else else
R_FlushTextureCache(); // just reload it from file R_FlushTextureCache(); // just reload it from file
// Reload ANIMATED / ANIMDEFS
P_InitPicAnims();
// Flush and reload HUD graphics // Flush and reload HUD graphics
ST_UnloadGraphics(); ST_UnloadGraphics();
HU_LoadGraphics(); HU_LoadGraphics();

View file

@ -47,6 +47,8 @@ typedef struct
extern size_t numlevelflats; extern size_t numlevelflats;
extern levelflat_t *levelflats; extern levelflat_t *levelflats;
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat); INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
INT32 P_AddLevelFlatRuntime(const char *flatname);
INT32 P_CheckLevelFlat(const char *flatname);
extern size_t nummapthings; extern size_t nummapthings;
extern mapthing_t *mapthings; extern mapthing_t *mapthings;

View file

@ -221,8 +221,8 @@ static animdef_t harddefs[] =
static animdef_t *animdefs = NULL; static animdef_t *animdefs = NULL;
// A prototype; here instead of p_spec.h, so they're "private" // A prototype; here instead of p_spec.h, so they're "private"
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i); void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum);
void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i); void P_ParseAnimationDefintion(SINT8 istexture);
/** Sets up texture and flat animations. /** Sets up texture and flat animations.
* *
@ -232,24 +232,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
* Issues an error if any animation cycles are invalid. * Issues an error if any animation cycles are invalid.
* *
* \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims * \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims
* \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs) * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_)
*/ */
void P_InitPicAnims(void) void P_InitPicAnims(void)
{ {
// Init animation // Init animation
INT32 i; // Position in the animdefs array
INT32 w; // WAD INT32 w; // WAD
UINT8 *wadAnimdefs; // not to be confused with animdefs, the combined total of every ANIMATED lump in every WAD, or ANIMDEFS, the ZDoom lump I intend to implement later UINT8 *animatedLump;
UINT8 *currentPos; UINT8 *currentPos;
size_t i;
I_Assert(animdefs == NULL);
if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR) if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR)
{ {
if (animdefs) for (w = numwadfiles-1, maxanims = 0; w >= 0; w--)
{
Z_Free(animdefs);
animdefs = NULL;
}
for (w = 0, i = 0, maxanims = 0; w < numwadfiles; w++)
{ {
UINT16 animatedLumpNum; UINT16 animatedLumpNum;
UINT16 animdefsLumpNum; UINT16 animdefsLumpNum;
@ -258,20 +255,20 @@ void P_InitPicAnims(void)
animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0); animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0);
if (animatedLumpNum != INT16_MAX) if (animatedLumpNum != INT16_MAX)
{ {
wadAnimdefs = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC); animatedLump = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
// Get the number of animations in the file // Get the number of animations in the file
for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; maxanims++, currentPos+=23); i = maxanims;
for (currentPos = animatedLump; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
// Resize animdefs (or if it hasn't been created, create it) // Resize animdefs (or if it hasn't been created, create it)
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
// Sanity check it // Sanity check it
if (!animdefs) { if (!animdefs)
I_Error("Not enough free memory for ANIMATED data"); I_Error("Not enough free memory for ANIMATED data");
}
// Populate the new array // Populate the new array
for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; i++, currentPos+=23) for (currentPos = animatedLump; *currentPos != UINT8_MAX; i++, currentPos+=23)
{ {
M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte
M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes
@ -279,15 +276,13 @@ void P_InitPicAnims(void)
M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes
} }
Z_Free(wadAnimdefs); Z_Free(animatedLump);
} }
// Now find ANIMDEFS // Now find ANIMDEFS
animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0); animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0);
if (animdefsLumpNum != INT16_MAX) if (animdefsLumpNum != INT16_MAX)
{ P_ParseANIMDEFSLump(w, animdefsLumpNum);
P_ParseANIMDEFSLump(w, animdefsLumpNum, &i);
}
} }
// Define the last one // Define the last one
animdefs[maxanims].istexture = -1; animdefs[maxanims].istexture = -1;
@ -347,16 +342,20 @@ void P_InitPicAnims(void)
lastanim->istexture = -1; lastanim->istexture = -1;
R_ClearTextureNumCache(false); R_ClearTextureNumCache(false);
// Clear animdefs now that we're done with it.
// We'll only be using anims from now on.
if (animdefs != harddefs) if (animdefs != harddefs)
Z_ChangeTag(animdefs, PU_CACHE); Z_Free(animdefs);
animdefs = NULL;
} }
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i) void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum)
{ {
char *animdefsLump; char *animdefsLump;
size_t animdefsLumpLength; size_t animdefsLumpLength;
char *animdefsText; char *animdefsText;
char *animdefsToken; char *animdefsToken;
char *p;
// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
// need to make a space of memory where I can ensure that it will terminate // need to make a space of memory where I can ensure that it will terminate
@ -376,18 +375,19 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
Z_Free(animdefsLump); Z_Free(animdefsLump);
// Now, let's start parsing this thing // Now, let's start parsing this thing
animdefsToken = M_GetToken(animdefsText); p = animdefsText;
animdefsToken = M_GetToken(p);
while (animdefsToken != NULL) while (animdefsToken != NULL)
{ {
if (stricmp(animdefsToken, "TEXTURE") == 0) if (stricmp(animdefsToken, "TEXTURE") == 0)
{ {
Z_Free(animdefsToken); Z_Free(animdefsToken);
P_ParseAnimationDefintion(1, i); P_ParseAnimationDefintion(1);
} }
else if (stricmp(animdefsToken, "FLAT") == 0) else if (stricmp(animdefsToken, "FLAT") == 0)
{ {
Z_Free(animdefsToken); Z_Free(animdefsToken);
P_ParseAnimationDefintion(0, i); P_ParseAnimationDefintion(0);
} }
else if (stricmp(animdefsToken, "OSCILLATE") == 0) else if (stricmp(animdefsToken, "OSCILLATE") == 0)
{ {
@ -398,23 +398,22 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
{ {
I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken);
} }
animdefsToken = M_GetToken(NULL); // parse next line
while (*p != '\0' && *p != '\n') ++p;
if (*p == '\n') ++p;
animdefsToken = M_GetToken(p);
} }
Z_Free(animdefsToken); Z_Free(animdefsToken);
Z_Free((void *)animdefsText); Z_Free((void *)animdefsText);
} }
void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) void P_ParseAnimationDefintion(SINT8 istexture)
{ {
char *animdefsToken; char *animdefsToken;
size_t animdefsTokenLength; size_t animdefsTokenLength;
char *endPos; char *endPos;
INT32 animSpeed; INT32 animSpeed;
size_t i;
// Increase the size to make room for the new animation definition
maxanims++;
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
animdefs[*i].istexture = istexture;
// Startname // Startname
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
@ -448,14 +447,39 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
{ {
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
} }
strncpy(animdefs[*i].startname, animdefsToken, 9);
// Search for existing animdef
for (i = 0; i < maxanims; i++)
if (stricmp(animdefsToken, animdefs[i].startname) == 0)
{
//CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
// If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found.
// Instead, we're just going to skip parsing the rest of this line entirely.
Z_Free(animdefsToken);
return;
}
// Not found
if (i == maxanims)
{
// Increase the size to make room for the new animation definition
maxanims++;
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
strncpy(animdefs[i].startname, animdefsToken, 9);
}
// animdefs[i].startname is now set to animdefsToken either way.
Z_Free(animdefsToken); Z_Free(animdefsToken);
// set texture type
animdefs[i].istexture = istexture;
// "RANGE" // "RANGE"
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname);
} }
if (stricmp(animdefsToken, "ALLOWDECALS") == 0) if (stricmp(animdefsToken, "ALLOWDECALS") == 0)
{ {
@ -470,7 +494,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
} }
if (stricmp(animdefsToken, "RANGE") != 0) if (stricmp(animdefsToken, "RANGE") != 0)
{ {
I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken);
} }
Z_Free(animdefsToken); Z_Free(animdefsToken);
@ -478,21 +502,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname);
} }
animdefsTokenLength = strlen(animdefsToken); animdefsTokenLength = strlen(animdefsToken);
if (animdefsTokenLength>8) if (animdefsTokenLength>8)
{ {
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
} }
strncpy(animdefs[*i].endname, animdefsToken, 9); strncpy(animdefs[i].endname, animdefsToken, 9);
Z_Free(animdefsToken); Z_Free(animdefsToken);
// "TICS" // "TICS"
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname);
} }
if (stricmp(animdefsToken, "RAND") == 0) if (stricmp(animdefsToken, "RAND") == 0)
{ {
@ -501,7 +525,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
} }
if (stricmp(animdefsToken, "TICS") != 0) if (stricmp(animdefsToken, "TICS") != 0)
{ {
I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken);
} }
Z_Free(animdefsToken); Z_Free(animdefsToken);
@ -509,7 +533,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname);
} }
endPos = NULL; endPos = NULL;
#ifndef AVOID_ERRNO #ifndef AVOID_ERRNO
@ -523,13 +547,10 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
#endif #endif
|| animSpeed < 0) // Number is not positive || animSpeed < 0) // Number is not positive
{ {
I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken);
} }
animdefs[*i].speed = animSpeed; animdefs[i].speed = animSpeed;
Z_Free(animdefsToken); Z_Free(animdefsToken);
// Increment i before we go, so this doesn't cause issues later
(*i)++;
} }
@ -1498,6 +1519,8 @@ static inline void P_InitTagLists(void)
size_t j = (unsigned)sectors[i].tag % numsectors; size_t j = (unsigned)sectors[i].tag % numsectors;
sectors[i].nexttag = sectors[j].firsttag; sectors[i].nexttag = sectors[j].firsttag;
sectors[j].firsttag = (INT32)i; sectors[j].firsttag = (INT32)i;
sectors[i].spawn_nexttag = sectors[i].nexttag;
sectors[j].spawn_firsttag = sectors[j].firsttag;
} }
for (i = numlines - 1; i != (size_t)-1; i--) for (i = numlines - 1; i != (size_t)-1; i--)
@ -5321,6 +5344,10 @@ void T_LaserFlash(laserthink_t *flash)
&& thing->flags & MF_BOSS) && thing->flags & MF_BOSS)
continue; // Don't hurt bosses continue; // Don't hurt bosses
// Don't endlessly kill egg guard shields (or anything else for that matter)
if (thing->health <= 0)
continue;
top = P_GetSpecialTopZ(thing, sourcesec, sector); top = P_GetSpecialTopZ(thing, sourcesec, sector);
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector); bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
@ -7428,7 +7455,7 @@ void T_Pusher(pusher_t *p)
} }
else else
{ {
if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1))) if (top < thing->z || bottom > (thing->z + (thing->height >> 1)))
continue; continue;
if (thing->z + thing->height > top) if (thing->z + thing->height > top)
touching = true; touching = true;

View file

@ -2280,14 +2280,13 @@ static void P_DoClimbing(player_t *player)
fixed_t platy; fixed_t platy;
subsector_t *glidesector; subsector_t *glidesector;
boolean climb = true; boolean climb = true;
boolean onesided = ((player->lastsidehit != -1 && player->lastlinehit != -1) && !(lines[player->lastlinehit].backsector));
platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy);
if (onesided || glidesector->sector != player->mo->subsector->sector) if (!glidesector || glidesector->sector != player->mo->subsector->sector)
{ {
boolean floorclimb = false; boolean floorclimb = false;
boolean thrust = false; boolean thrust = false;
@ -2295,7 +2294,7 @@ static void P_DoClimbing(player_t *player)
boolean skyclimber = false; boolean skyclimber = false;
fixed_t floorheight, ceilingheight; // ESLOPE fixed_t floorheight, ceilingheight; // ESLOPE
if (onesided) if (!glidesector)
floorclimb = true; floorclimb = true;
else else
{ {
@ -7058,7 +7057,6 @@ static void P_DoZoomTube(player_t *player)
mobj_t *waypoint = NULL; mobj_t *waypoint = NULL;
fixed_t dist; fixed_t dist;
boolean reverse; boolean reverse;
fixed_t speedx,speedy,speedz;
player->mo->height = P_GetPlayerSpinHeight(player); player->mo->height = P_GetPlayerSpinHeight(player);
@ -7079,17 +7077,17 @@ static void P_DoZoomTube(player_t *player)
if (dist < 1) if (dist < 1)
dist = 1; dist = 1;
speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
speedz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
// Calculate the distance between the player and the waypoint // Calculate the distance between the player and the waypoint
// 'dist' already equals this. // 'dist' already equals this.
// Will the player be FURTHER away if the momx/momy/momz is added to // Will the player go past the waypoint?
// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors) if (speed > dist)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - player->mo->z - speedz)>>FRACBITS)
{ {
speed -= dist;
// If further away, set XYZ of player to waypoint location // If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo); P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x; player->mo->x = player->mo->tracer->x;
@ -7129,14 +7127,9 @@ static void P_DoZoomTube(player_t *player)
{ {
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health); CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
// calculate MOMX/MOMY/MOMZ for next waypoint P_SetTarget(&player->mo->tracer, waypoint);
// change angle
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y);
if (player == &players[consoleplayer]) // calculate MOMX/MOMY/MOMZ for next waypoint
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
// change slope // change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z); dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z);
@ -7147,22 +7140,14 @@ static void P_DoZoomTube(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
P_SetTarget(&player->mo->tracer, waypoint);
} }
else else
{ {
P_SetTarget(&player->mo->tracer, NULL); // Else, we just let him fly. P_SetTarget(&player->mo->tracer, NULL); // Else, we just let them fly.
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n"); CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n");
} }
} }
else
{
player->mo->momx = speedx;
player->mo->momy = speedy;
player->mo->momz = speedz;
}
// change angle // change angle
if (player->mo->tracer) if (player->mo->tracer)
@ -7190,24 +7175,10 @@ static void P_DoRopeHang(player_t *player)
mobj_t *mo2; mobj_t *mo2;
mobj_t *waypoint = NULL; mobj_t *waypoint = NULL;
fixed_t dist; fixed_t dist;
fixed_t speedx,speedy,speedz;
fixed_t playerz; fixed_t playerz;
player->mo->height = P_GetPlayerHeight(player); player->mo->height = P_GetPlayerHeight(player);
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_ROPEHANG;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
return;
}
// Play the 'clink' sound only if the player is moving. // Play the 'clink' sound only if the player is moving.
if (!(leveltime & 7) && player->speed) if (!(leveltime & 7) && player->speed)
S_StartSound(player->mo, sfx_s3k55); S_StartSound(player->mo, sfx_s3k55);
@ -7224,9 +7195,22 @@ static void P_DoRopeHang(player_t *player)
if (dist < 1) if (dist < 1)
dist = 1; dist = 1;
speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
speedz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_ROPEHANG;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
return;
}
// If not allowed to move, we're done here. // If not allowed to move, we're done here.
if (!speed) if (!speed)
@ -7235,15 +7219,16 @@ static void P_DoRopeHang(player_t *player)
// Calculate the distance between the player and the waypoint // Calculate the distance between the player and the waypoint
// 'dist' already equals this. // 'dist' already equals this.
// Will the player be FURTHER away if the momx/momy/momz is added to // Will the player go past the waypoint?
// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors) if (speed > dist)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - playerz - speedz)>>FRACBITS)
{ {
speed -= dist;
// If further away, set XYZ of player to waypoint location // If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo); P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x; player->mo->x = player->mo->tracer->x;
player->mo->y = player->mo->tracer->y; player->mo->y = player->mo->tracer->y;
player->mo->z = player->mo->tracer->z - player->mo->height; player->mo->z = player->mo->tracer->z - player->mo->height;
playerz = player->mo->tracer->z;
P_SetThingPosition(player->mo); P_SetThingPosition(player->mo);
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n"); CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
@ -7299,6 +7284,8 @@ static void P_DoRopeHang(player_t *player)
{ {
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health); CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
P_SetTarget(&player->mo->tracer, waypoint);
// calculate MOMX/MOMY/MOMZ for next waypoint // calculate MOMX/MOMY/MOMZ for next waypoint
// change slope // change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz); dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz);
@ -7309,8 +7296,6 @@ static void P_DoRopeHang(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
P_SetTarget(&player->mo->tracer, waypoint);
} }
else else
{ {
@ -7329,12 +7314,6 @@ static void P_DoRopeHang(player_t *player)
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n"); CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n");
} }
} }
else
{
player->mo->momx = speedx;
player->mo->momy = speedy;
player->mo->momz = speedz;
}
} }
#if 0 #if 0

View file

@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
static sector_t tempsec; // Deep water hack static sector_t tempsec; // Deep water hack
extracolormap_t *floorcolormap; extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap; extracolormap_t *ceilingcolormap;
fixed_t floorcenterz, ceilingcenterz;
#ifdef RANGECHECK #ifdef RANGECHECK
if (num >= numsubsectors) if (num >= numsubsectors)
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
floorcolormap = ceilingcolormap = frontsector->extra_colormap; floorcolormap = ceilingcolormap = frontsector->extra_colormap;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps. // Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
if (frontsector->ffloors) if (frontsector->ffloors)
{ {
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
sub->sector->moved = frontsector->moved = false; sub->sector->moved = frontsector->moved = false;
} }
light = R_GetPlaneLight(frontsector, light = R_GetPlaneLight(frontsector, floorcenterz, false);
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight, false);
if (frontsector->floorlightsec == -1) if (frontsector->floorlightsec == -1)
floorlightlevel = *frontsector->lightlist[light].lightlevel; floorlightlevel = *frontsector->lightlist[light].lightlevel;
floorcolormap = frontsector->lightlist[light].extra_colormap; floorcolormap = frontsector->lightlist[light].extra_colormap;
light = R_GetPlaneLight(frontsector, light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight, false);
if (frontsector->ceilinglightsec == -1) if (frontsector->ceilinglightsec == -1)
ceilinglightlevel = *frontsector->lightlist[light].lightlevel; ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
ceilingcolormap = frontsector->lightlist[light].extra_colormap; ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
{ {
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel, floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, frontsector->f_slope , frontsector->f_slope
#endif #endif
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle, ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingcolormap, NULL ceilingcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, frontsector->c_slope , frontsector->c_slope
#endif #endif
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
if (frontsector->ffloors) if (frontsector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz; fixed_t heightcheck, planecenterz;
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next) for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
{ {
@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
ffloor[numffloors].polyobj = NULL; ffloor[numffloors].polyobj = NULL;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
heightcheck = heightcheck =
#ifdef ESLOPE #ifdef ESLOPE
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic, ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, *frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover *rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, *rover->b_slope , *rover->b_slope
#endif #endif
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic, ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle, *frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
frontsector->lightlist[light].extra_colormap, rover frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, *rover->t_slope , *rover->t_slope
#endif #endif
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
polysec = po->lines[0]->backsector; polysec = po->lines[0]->backsector;
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
if (polysec->floorheight <= frontsector->ceilingheight if (polysec->floorheight <= ceilingcenterz
&& polysec->floorheight >= frontsector->floorheight && polysec->floorheight >= floorcenterz
&& (viewz < polysec->floorheight)) && (viewz < polysec->floorheight))
{ {
fixed_t xoff, yoff; fixed_t xoff, yoff;
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
polysec->floorpic_angle-po->angle, polysec->floorpic_angle-po->angle,
NULL, NULL,
NULL NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE #ifdef ESLOPE
, NULL // will ffloors be slopable eventually? , NULL // will ffloors be slopable eventually?
#endif #endif
); );
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po; ffloor[numffloors].polyobj = po;
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
if (polysec->ceilingheight >= frontsector->floorheight if (polysec->ceilingheight >= floorcenterz
&& polysec->ceilingheight <= frontsector->ceilingheight && polysec->ceilingheight <= ceilingcenterz
&& (viewz > polysec->ceilingheight)) && (viewz > polysec->ceilingheight))
{ {
fixed_t xoff, yoff; fixed_t xoff, yoff;
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle, polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
NULL, NULL NULL, NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE #ifdef ESLOPE
, NULL // will ffloors be slopable eventually? , NULL // will ffloors be slopable eventually?
#endif #endif
); );
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].polyobj = po; ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight; ffloor[numffloors].height = polysec->ceilingheight;

View file

@ -303,6 +303,32 @@ done:
return blocktex; return blocktex;
} }
//
// R_GetTextureNum
//
// Returns the actual texture id that we should use.
// This can either be texnum, the current frame for texnum's anim (if animated),
// or 0 if not valid.
//
INT32 R_GetTextureNum(INT32 texnum)
{
if (texnum < 0 || texnum >= numtextures)
return 0;
return texturetranslation[texnum];
}
//
// R_CheckTextureCache
//
// Use this if you need to make sure the texture is cached before R_GetColumn calls
// e.g.: midtextures and FOF walls
//
void R_CheckTextureCache(INT32 tex)
{
if (!texturecache[tex])
R_GenerateTexture(tex);
}
// //
// R_GetColumn // R_GetColumn
// //
@ -1499,6 +1525,9 @@ void R_InitData(void)
CONS_Printf("R_LoadTextures()...\n"); CONS_Printf("R_LoadTextures()...\n");
R_LoadTextures(); R_LoadTextures();
CONS_Printf("P_InitPicAnims()...\n");
P_InitPicAnims();
CONS_Printf("R_InitSprites()...\n"); CONS_Printf("R_InitSprites()...\n");
R_InitSpriteLumps(); R_InitSpriteLumps();
R_InitSprites(); R_InitSprites();

View file

@ -65,6 +65,9 @@ extern CV_PossibleValue_t Color_cons_t[];
void R_LoadTextures(void); void R_LoadTextures(void);
void R_FlushTextureCache(void); void R_FlushTextureCache(void);
INT32 R_GetTextureNum(INT32 texnum);
void R_CheckTextureCache(INT32 tex);
// Retrieve column data for span blitting. // Retrieve column data for span blitting.
UINT8 *R_GetColumn(fixed_t tex, INT32 col); UINT8 *R_GetColumn(fixed_t tex, INT32 col);

View file

@ -203,6 +203,7 @@ typedef struct r_lightlist_s
fixed_t heightstep; fixed_t heightstep;
fixed_t botheight; fixed_t botheight;
fixed_t botheightstep; fixed_t botheightstep;
fixed_t startheight; // for repeating midtextures
INT16 lightlevel; INT16 lightlevel;
extracolormap_t *extra_colormap; extracolormap_t *extra_colormap;
lighttable_t *rcolormap; lighttable_t *rcolormap;
@ -224,15 +225,6 @@ typedef struct linechain_s
// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
typedef struct secplane_t
{
// the plane is defined as a*x + b*y + c*z + d = 0
// ic is 1/c, for faster Z calculations
fixed_t a, b, c, d, ic;
} secplane_t;
// Slopes // Slopes
#ifdef ESLOPE #ifdef ESLOPE
typedef enum { typedef enum {
@ -392,6 +384,7 @@ typedef struct sector_s
#endif #endif
// these are saved for netgames, so do not let Lua touch these! // these are saved for netgames, so do not let Lua touch these!
INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
// offsets sector spawned with (via linedef type 7) // offsets sector spawned with (via linedef type 7)
fixed_t spawn_flr_xoffs, spawn_flr_yoffs; fixed_t spawn_flr_xoffs, spawn_flr_yoffs;

View file

@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
return R_PointToDist2(viewx, viewy, x, y); return R_PointToDist2(viewx, viewy, x, y);
} }
/***************************************
*** Zdoom C++ to Legacy C conversion ***
****************************************/
// Utility to find the Z height at an XY location in a sector (for slopes)
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
{
return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
}
// Returns the value of z at (x,y) if d is equal to dist
fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
{
return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
}
// Flips the plane's vertical orientiation, so that if it pointed up,
// it will point down, and vice versa.
void R_SecplaneFlipVert(secplane_t *secplane)
{
secplane->a = -secplane->a;
secplane->b = -secplane->b;
secplane->c = -secplane->c;
secplane->d = -secplane->d;
secplane->ic = -secplane->ic;
}
// Returns true if 2 planes are the same
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
{
return original->a == other->a && original->b == other->b
&& original->c == other->c && original->d == other->d;
}
// Returns true if 2 planes are different
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
{
return original->a != other->a || original->b != other->b
|| original->c != other->c || original->d != other->d;
}
// Moves a plane up/down by hdiff units
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
{
secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
}
// Returns how much this plane's height would change if d were set to oldd
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
{
return FixedMul(oldd - secplane->d, secplane->ic);
}
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
}
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
}
// //
// R_ScaleFromGlobalAngle // R_ScaleFromGlobalAngle
// Returns the texture mapping scale for the current line (horizontal span) // Returns the texture mapping scale for the current line (horizontal span)
@ -771,7 +708,7 @@ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
} }
// //
// R_IsPointInSubsector, same as above but returns 0 if not in subsector - this does not work in opengl because of polyvertex_t // R_IsPointInSubsector, same as above but returns 0 if not in subsector
// //
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
{ {
@ -795,7 +732,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
ret = &subsectors[nodenum & ~NF_SUBSECTOR]; ret = &subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0; i < ret->numlines; i++) for (i = 0; i < ret->numlines; i++)
if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) //if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers
if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side)
return 0; return 0;
return ret; return ret;

View file

@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
fixed_t R_PointToDist(fixed_t x, fixed_t y); fixed_t R_PointToDist(fixed_t x, fixed_t y);
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
// ZDoom C++ to Legacy C conversion Tails 04-29-2002
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
fixed_t dist);
void R_SecplaneFlipVert(secplane_t *secplane);
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other);
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other);
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
fixed_t R_ScaleFromGlobalAngle(angle_t visangle); fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y); subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);

View file

@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
ffloor_t *pfloor ffloor_t *pfloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE #ifdef ESLOPE
, pslope_t *slope , pslope_t *slope
#endif #endif
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
#ifdef POLYOBJECTS_PLANES #ifdef POLYOBJECTS_PLANES
if (check->polyobj && pfloor) if (check->polyobj && pfloor)
continue; continue;
if (polyobj != check->polyobj)
continue;
#endif #endif
if (height == check->height && picnum == check->picnum if (height == check->height && picnum == check->picnum
&& lightlevel == check->lightlevel && lightlevel == check->lightlevel
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
check->viewangle = viewangle; check->viewangle = viewangle;
check->plangle = plangle; check->plangle = plangle;
#ifdef POLYOBJECTS_PLANES #ifdef POLYOBJECTS_PLANES
check->polyobj = NULL; check->polyobj = polyobj;
#endif #endif
#ifdef ESLOPE #ifdef ESLOPE
check->slope = slope; check->slope = slope;
@ -719,7 +724,11 @@ void R_DrawPlanes(void)
continue; continue;
} }
if (pl->ffloor != NULL) if (pl->ffloor != NULL
#ifdef POLYOBJECTS_PLANES
|| pl->polyobj != NULL
#endif
)
continue; continue;
R_DrawSinglePlane(pl); R_DrawSinglePlane(pl);

View file

@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
void R_DrawPlanes(void); void R_DrawPlanes(void);
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
extracolormap_t *planecolormap, ffloor_t *ffloor extracolormap_t *planecolormap, ffloor_t *ffloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE #ifdef ESLOPE
, pslope_t *slope , pslope_t *slope
#endif #endif

View file

@ -300,7 +300,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
curline = ds->curline; curline = ds->curline;
frontsector = curline->frontsector; frontsector = curline->frontsector;
backsector = curline->backsector; backsector = curline->backsector;
texnum = texturetranslation[curline->sidedef->midtexture]; texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX; windowbottom = windowtop = sprbotscreen = INT32_MAX;
// hack translucent linedef types (900-909 for transtables 1-9) // hack translucent linedef types (900-909 for transtables 1-9)
@ -344,6 +344,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rw_scalestep = ds->scalestep; rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2 // are not stored per-column with post info in SRB2
if (textures[texnum]->holes) if (textures[texnum]->holes)
@ -391,6 +394,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale); rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz)); rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
#endif #endif
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel; rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = light->extra_colormap; rlight->extra_colormap = light->extra_colormap;
rlight->flags = light->flags; rlight->flags = light->flags;
@ -484,6 +488,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{ {
rw_scalestep = ds->scalestep; rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
if (dc_numlights)
{ // reset all lights to their starting heights
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height = rlight->startheight;
}
}
} }
#ifndef ESLOPE #ifndef ESLOPE
@ -740,7 +752,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
curline = ds->curline; curline = ds->curline;
backsector = pfloor->target; backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector; frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
colfunc = wallcolfunc; colfunc = wallcolfunc;
@ -748,7 +760,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{ {
size_t linenum = curline->linedef-backsector->lines[0]; size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum; newline = pfloor->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
} }
if (pfloor->flags & FF_TRANSLUCENT) if (pfloor->flags & FF_TRANSLUCENT)
@ -968,6 +980,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_texturemid += offsetvalue; dc_texturemid += offsetvalue;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures //faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy // are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes) if (textures[texnum]->holes)
@ -1878,14 +1893,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (!backsector) if (!backsector)
{ {
fixed_t texheight;
// single sided line // single sided line
midtexture = texturetranslation[sidedef->midtexture]; midtexture = R_GetTextureNum(sidedef->midtexture);
texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends // a single sided line is terminal, so it must mark ends
markfloor = markceiling = true; markfloor = markceiling = true;
#ifdef ESLOPE #ifdef ESLOPE
if (linedef->flags & ML_EFFECT2) { if (linedef->flags & ML_EFFECT2) {
if (linedef->flags & ML_DONTPEGBOTTOM) if (linedef->flags & ML_DONTPEGBOTTOM)
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz; rw_midtexturemid = frontsector->floorheight + texheight - viewz;
else else
rw_midtexturemid = frontsector->ceilingheight - viewz; rw_midtexturemid = frontsector->ceilingheight - viewz;
} }
@ -1894,10 +1911,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (linedef->flags & ML_DONTPEGBOTTOM) if (linedef->flags & ML_DONTPEGBOTTOM)
{ {
#ifdef ESLOPE #ifdef ESLOPE
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture]; rw_midtexturemid = worldbottom + texheight;
rw_midtextureslide = floorfrontslide; rw_midtextureslide = floorfrontslide;
#else #else
vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; vtop = frontsector->floorheight + texheight;
// bottom of texture at bottom // bottom of texture at bottom
rw_midtexturemid = vtop - viewz; rw_midtexturemid = vtop - viewz;
#endif #endif
@ -2129,76 +2146,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#endif #endif
) )
{ {
fixed_t texheight;
// top texture // top texture
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM)) if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
&& linedef->sidenum[1] != 0xffff) && linedef->sidenum[1] != 0xffff)
{ {
// Special case... use offsets from 2nd side but only if it has a texture. // Special case... use offsets from 2nd side but only if it has a texture.
side_t *def = &sides[linedef->sidenum[1]]; side_t *def = &sides[linedef->sidenum[1]];
toptexture = texturetranslation[def->toptexture]; toptexture = R_GetTextureNum(def->toptexture);
if (!toptexture) //Second side has no texture, use the first side's instead. if (!toptexture) //Second side has no texture, use the first side's instead.
toptexture = texturetranslation[sidedef->toptexture]; toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + textureheight[def->toptexture];
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + textureheight[def->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
} }
else else
{ {
toptexture = texturetranslation[sidedef->toptexture]; toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
#ifdef ESLOPE #ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP) if (linedef->flags & ML_DONTPEGTOP)
{ rw_toptexturemid = frontsector->ceilingheight - viewz;
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else else
{ rw_toptexturemid = backsector->ceilingheight - viewz;
#ifdef ESLOPE } else
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture]; #endif
rw_toptextureslide = ceilingbackslide; if (linedef->flags & ML_DONTPEGTOP)
#else {
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; // top of texture at top
// bottom of texture rw_toptexturemid = worldtop;
rw_toptexturemid = vtop - viewz; #ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + texheight;
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + texheight;
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif #endif
}
} }
} }
// check BOTTOM TEXTURE // check BOTTOM TEXTURE
@ -2209,7 +2200,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
) //seulement si VISIBLE!!! ) //seulement si VISIBLE!!!
{ {
// bottom texture // bottom texture
bottomtexture = texturetranslation[sidedef->bottomtexture]; bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
#ifdef ESLOPE #ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@ -2494,7 +2485,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->numthicksides = numthicksides = i; ds_p->numthicksides = numthicksides = i;
} }
if (sidedef->midtexture) if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
{ {
// masked midtexture // masked midtexture
if (!ds_p->thicksidecol) if (!ds_p->thicksidecol)
@ -3101,12 +3092,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
{ {
ds_p->silhouette |= SIL_TOP; ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX; ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
} }
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
{ {
ds_p->silhouette |= SIL_BOTTOM; ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN; ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
} }
ds_p++; ds_p++;
} }

View file

@ -1831,21 +1831,25 @@ static void R_CreateDrawNodes(void)
entry->ffloor = ds->thicksides[i]; entry->ffloor = ds->thicksides[i];
} }
} }
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
plane = ds->curline->polyseg->visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
;
else {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
entry->seg = ds;
}
ds->curline->polyseg->visplane = NULL;
}
#endif
if (ds->maskedtexturecol) if (ds->maskedtexturecol)
{ {
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = ds->curline->polyseg->visplane;
entry->seg = ds;
ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
ds->curline->polyseg->visplane = NULL;
}
#endif
entry = R_CreateDrawNode(&nodehead); entry = R_CreateDrawNode(&nodehead);
entry->seg = ds; entry->seg = ds;
} }
@ -1888,6 +1892,29 @@ static void R_CreateDrawNodes(void)
} }
} }
#ifdef POLYOBJECTS_PLANES
// find all the remaining polyobject planes and add them on the end of the list
// probably this is a terrible idea if we wanted them to be sorted properly
// but it works getting them in for now
for (i = 0; i < numPolyObjects; i++)
{
if (!PolyObjects[i].visplane)
continue;
plane = PolyObjects[i].visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
{
PolyObjects[i].visplane = NULL;
continue;
}
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
// note: no seg is set, for what should be obvious reasons
PolyObjects[i].visplane = NULL;
}
#endif
if (visspritecount == 0) if (visspritecount == 0)
return; return;
@ -1944,13 +1971,16 @@ static void R_CreateDrawNodes(void)
if (x1 < r2->plane->minx) x1 = r2->plane->minx; if (x1 < r2->plane->minx) x1 = r2->plane->minx;
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx; if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
for (i = x1; i <= x2; i++) if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
{ {
if (r2->seg->frontscale[i] > rover->sortscale) for (i = x1; i <= x2; i++)
break; {
if (r2->seg->frontscale[i] > rover->scale)
break;
}
if (i > x2)
continue;
} }
if (i > x2)
continue;
entry = R_CreateDrawNode(NULL); entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry; (entry->prev = r2->prev)->next = entry;

View file

@ -30,7 +30,7 @@
#include "f_finale.h" #include "f_finale.h"
#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) #if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself #define RUSEASM //MSC.NET can't patch itself
#endif #endif

View file

@ -2647,6 +2647,47 @@ INT32 I_PutEnv(char *variable)
#endif #endif
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
char storage[256];
if (size > 255)
size = 255;
memcpy(storage, data, size);
storage[size] = 0;
if (SDL_SetClipboardText(storage))
return 0;
return -1;
}
const char *I_ClipboardPaste(void)
{
static char clipboard_modified[256];
char *clipboard_contents, *i = clipboard_modified;
if (!SDL_HasClipboardText())
return NULL;
clipboard_contents = SDL_GetClipboardText();
memcpy(clipboard_modified, clipboard_contents, 255);
SDL_free(clipboard_contents);
clipboard_modified[255] = 0;
while (*i)
{
if (*i == '\n' || *i == '\r')
{ // End on newline
*i = 0;
break;
}
else if (*i == '\t')
*i = ' '; // Tabs become spaces
else if (*i < 32 || (unsigned)*i > 127)
*i = '?'; // Nonprintable chars become question marks
++i;
}
return (const char *)&clipboard_modified;
}
/** \brief The isWadPathOk function /** \brief The isWadPathOk function
\param path string path to check \param path string path to check

View file

@ -33,14 +33,6 @@
#pragma warning(default : 4214 4244) #pragma warning(default : 4214 4244)
#endif #endif
#if SDL_VERSION_ATLEAST(1,3,0)
#define SDLK_EQUALS SDLK_KP_EQUALSAS400
#define SDLK_LMETA SDLK_LGUI
#define SDLK_RMETA SDLK_RGUI
#else
#define HAVE_SDLMETAKEYS
#endif
#ifdef HAVE_TTF #ifdef HAVE_TTF
#include "i_ttf.h" #include "i_ttf.h"
#endif #endif
@ -189,14 +181,14 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
wasfullscreen = SDL_TRUE; wasfullscreen = SDL_TRUE;
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
} }
else if (!fullscreen && wasfullscreen) else if (wasfullscreen)
{ {
wasfullscreen = SDL_FALSE; wasfullscreen = SDL_FALSE;
SDL_SetWindowFullscreen(window, 0); SDL_SetWindowFullscreen(window, 0);
SDL_SetWindowSize(window, width, height); SDL_SetWindowSize(window, width, height);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1)); SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
} }
else if (!wasfullscreen) else
{ {
// Reposition window only in windowed mode // Reposition window only in windowed mode
SDL_SetWindowSize(window, width, height); SDL_SetWindowSize(window, width, height);
@ -282,129 +274,70 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
} }
switch (code) switch (code)
{ {
case SDL_SCANCODE_F11: // F11 and F12 are // F11 and F12 are separated from the rest of the function keys
return KEY_F11; // separated from the case SDL_SCANCODE_F11: return KEY_F11;
case SDL_SCANCODE_F12: // rest of the function case SDL_SCANCODE_F12: return KEY_F12;
return KEY_F12; // keys
case SDL_SCANCODE_KP_0: case SDL_SCANCODE_KP_0: return KEY_KEYPAD0;
return KEY_KEYPAD0; case SDL_SCANCODE_KP_1: return KEY_KEYPAD1;
case SDL_SCANCODE_KP_1: case SDL_SCANCODE_KP_2: return KEY_KEYPAD2;
return KEY_KEYPAD1; case SDL_SCANCODE_KP_3: return KEY_KEYPAD3;
case SDL_SCANCODE_KP_2: case SDL_SCANCODE_KP_4: return KEY_KEYPAD4;
return KEY_KEYPAD2; case SDL_SCANCODE_KP_5: return KEY_KEYPAD5;
case SDL_SCANCODE_KP_3: case SDL_SCANCODE_KP_6: return KEY_KEYPAD6;
return KEY_KEYPAD3; case SDL_SCANCODE_KP_7: return KEY_KEYPAD7;
case SDL_SCANCODE_KP_4: case SDL_SCANCODE_KP_8: return KEY_KEYPAD8;
return KEY_KEYPAD4; case SDL_SCANCODE_KP_9: return KEY_KEYPAD9;
case SDL_SCANCODE_KP_5:
return KEY_KEYPAD5;
case SDL_SCANCODE_KP_6:
return KEY_KEYPAD6;
case SDL_SCANCODE_KP_7:
return KEY_KEYPAD7;
case SDL_SCANCODE_KP_8:
return KEY_KEYPAD8;
case SDL_SCANCODE_KP_9:
return KEY_KEYPAD9;
case SDL_SCANCODE_RETURN: case SDL_SCANCODE_RETURN: return KEY_ENTER;
return KEY_ENTER; case SDL_SCANCODE_ESCAPE: return KEY_ESCAPE;
case SDL_SCANCODE_ESCAPE: case SDL_SCANCODE_BACKSPACE: return KEY_BACKSPACE;
return KEY_ESCAPE; case SDL_SCANCODE_TAB: return KEY_TAB;
case SDL_SCANCODE_BACKSPACE: case SDL_SCANCODE_SPACE: return KEY_SPACE;
return KEY_BACKSPACE; case SDL_SCANCODE_MINUS: return KEY_MINUS;
case SDL_SCANCODE_TAB: case SDL_SCANCODE_EQUALS: return KEY_EQUALS;
return KEY_TAB; case SDL_SCANCODE_LEFTBRACKET: return '[';
case SDL_SCANCODE_SPACE: case SDL_SCANCODE_RIGHTBRACKET: return ']';
return KEY_SPACE; case SDL_SCANCODE_BACKSLASH: return '\\';
case SDL_SCANCODE_MINUS: case SDL_SCANCODE_NONUSHASH: return '#';
return KEY_MINUS; case SDL_SCANCODE_SEMICOLON: return ';';
case SDL_SCANCODE_EQUALS: case SDL_SCANCODE_APOSTROPHE: return '\'';
return KEY_EQUALS; case SDL_SCANCODE_GRAVE: return '`';
case SDL_SCANCODE_LEFTBRACKET: case SDL_SCANCODE_COMMA: return ',';
return '['; case SDL_SCANCODE_PERIOD: return '.';
case SDL_SCANCODE_RIGHTBRACKET: case SDL_SCANCODE_SLASH: return '/';
return ']'; case SDL_SCANCODE_CAPSLOCK: return KEY_CAPSLOCK;
case SDL_SCANCODE_BACKSLASH: case SDL_SCANCODE_PRINTSCREEN: return 0; // undefined?
return '\\'; case SDL_SCANCODE_SCROLLLOCK: return KEY_SCROLLLOCK;
case SDL_SCANCODE_NONUSHASH: case SDL_SCANCODE_PAUSE: return KEY_PAUSE;
return '#'; case SDL_SCANCODE_INSERT: return KEY_INS;
case SDL_SCANCODE_SEMICOLON: case SDL_SCANCODE_HOME: return KEY_HOME;
return ';'; case SDL_SCANCODE_PAGEUP: return KEY_PGUP;
case SDL_SCANCODE_APOSTROPHE: case SDL_SCANCODE_DELETE: return KEY_DEL;
return '\''; case SDL_SCANCODE_END: return KEY_END;
case SDL_SCANCODE_GRAVE: case SDL_SCANCODE_PAGEDOWN: return KEY_PGDN;
return '`'; case SDL_SCANCODE_RIGHT: return KEY_RIGHTARROW;
case SDL_SCANCODE_COMMA: case SDL_SCANCODE_LEFT: return KEY_LEFTARROW;
return ','; case SDL_SCANCODE_DOWN: return KEY_DOWNARROW;
case SDL_SCANCODE_PERIOD: case SDL_SCANCODE_UP: return KEY_UPARROW;
return '.'; case SDL_SCANCODE_NUMLOCKCLEAR: return KEY_NUMLOCK;
case SDL_SCANCODE_SLASH: case SDL_SCANCODE_KP_DIVIDE: return KEY_KPADSLASH;
return '/'; case SDL_SCANCODE_KP_MULTIPLY: return '*'; // undefined?
case SDL_SCANCODE_CAPSLOCK: case SDL_SCANCODE_KP_MINUS: return KEY_MINUSPAD;
return KEY_CAPSLOCK; case SDL_SCANCODE_KP_PLUS: return KEY_PLUSPAD;
case SDL_SCANCODE_PRINTSCREEN: case SDL_SCANCODE_KP_ENTER: return KEY_ENTER;
return 0; // undefined? case SDL_SCANCODE_KP_PERIOD: return KEY_KPADDEL;
case SDL_SCANCODE_SCROLLLOCK: case SDL_SCANCODE_NONUSBACKSLASH: return '\\';
return KEY_SCROLLLOCK;
case SDL_SCANCODE_PAUSE:
return KEY_PAUSE;
case SDL_SCANCODE_INSERT:
return KEY_INS;
case SDL_SCANCODE_HOME:
return KEY_HOME;
case SDL_SCANCODE_PAGEUP:
return KEY_PGUP;
case SDL_SCANCODE_DELETE:
return KEY_DEL;
case SDL_SCANCODE_END:
return KEY_END;
case SDL_SCANCODE_PAGEDOWN:
return KEY_PGDN;
case SDL_SCANCODE_RIGHT:
return KEY_RIGHTARROW;
case SDL_SCANCODE_LEFT:
return KEY_LEFTARROW;
case SDL_SCANCODE_DOWN:
return KEY_DOWNARROW;
case SDL_SCANCODE_UP:
return KEY_UPARROW;
case SDL_SCANCODE_NUMLOCKCLEAR:
return KEY_NUMLOCK;
case SDL_SCANCODE_KP_DIVIDE:
return KEY_KPADSLASH;
case SDL_SCANCODE_KP_MULTIPLY:
return '*'; // undefined?
case SDL_SCANCODE_KP_MINUS:
return KEY_MINUSPAD;
case SDL_SCANCODE_KP_PLUS:
return KEY_PLUSPAD;
case SDL_SCANCODE_KP_ENTER:
return KEY_ENTER;
case SDL_SCANCODE_KP_PERIOD:
return KEY_KPADDEL;
case SDL_SCANCODE_NONUSBACKSLASH:
return '\\';
case SDL_SCANCODE_LSHIFT: case SDL_SCANCODE_LSHIFT: return KEY_LSHIFT;
return KEY_LSHIFT; case SDL_SCANCODE_RSHIFT: return KEY_RSHIFT;
case SDL_SCANCODE_RSHIFT: case SDL_SCANCODE_LCTRL: return KEY_LCTRL;
return KEY_RSHIFT; case SDL_SCANCODE_RCTRL: return KEY_RCTRL;
case SDL_SCANCODE_LCTRL: case SDL_SCANCODE_LALT: return KEY_LALT;
return KEY_LCTRL; case SDL_SCANCODE_RALT: return KEY_RALT;
case SDL_SCANCODE_RCTRL: case SDL_SCANCODE_LGUI: return KEY_LEFTWIN;
return KEY_RCTRL; case SDL_SCANCODE_RGUI: return KEY_RIGHTWIN;
case SDL_SCANCODE_LALT: default: break;
return KEY_LALT;
case SDL_SCANCODE_RALT:
return KEY_RALT;
case SDL_SCANCODE_LGUI:
return KEY_LEFTWIN;
case SDL_SCANCODE_RGUI:
return KEY_RIGHTWIN;
default:
break;
} }
#ifdef HWRENDER #ifdef HWRENDER
DBG_Printf("Unknown incoming scancode: %d, represented %c\n", DBG_Printf("Unknown incoming scancode: %d, represented %c\n",
@ -432,15 +365,10 @@ static void VID_Command_NumModes_f (void)
CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes()); CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes());
} }
// SDL2 doesn't have SDL_GetVideoSurface or a lot of the SDL_Surface flags that SDL 1.2 had
static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText) static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
{ {
#if 1
(void)infoSurface;
(void)SurfaceText;
SDL2STUB();
#else
INT32 vfBPP; INT32 vfBPP;
const SDL_Surface *VidSur = SDL_GetVideoSurface();
if (!infoSurface) if (!infoSurface)
return; return;
@ -453,49 +381,12 @@ static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
CONS_Printf("\x82" "%s\n", SurfaceText); CONS_Printf("\x82" "%s\n", SurfaceText);
CONS_Printf(M_GetText(" %ix%i at %i bit color\n"), infoSurface->w, infoSurface->h, vfBPP); CONS_Printf(M_GetText(" %ix%i at %i bit color\n"), infoSurface->w, infoSurface->h, vfBPP);
if (infoSurface->flags&SDL_HWSURFACE) if (infoSurface->flags&SDL_PREALLOC)
CONS_Printf("%s", M_GetText(" Stored in video memory\n"));
else if (infoSurface->flags&SDL_OPENGL)
CONS_Printf("%s", M_GetText(" Stored in an OpenGL context\n"));
else if (infoSurface->flags&SDL_PREALLOC)
CONS_Printf("%s", M_GetText(" Uses preallocated memory\n")); CONS_Printf("%s", M_GetText(" Uses preallocated memory\n"));
else else
CONS_Printf("%s", M_GetText(" Stored in system memory\n")); CONS_Printf("%s", M_GetText(" Stored in system memory\n"));
if (infoSurface->flags&SDL_ASYNCBLIT)
CONS_Printf("%s", M_GetText(" Uses asynchronous blits if possible\n"));
else
CONS_Printf("%s", M_GetText(" Uses synchronous blits if possible\n"));
if (infoSurface->flags&SDL_ANYFORMAT)
CONS_Printf("%s", M_GetText(" Allows any pixel-format\n"));
if (infoSurface->flags&SDL_HWPALETTE)
CONS_Printf("%s", M_GetText(" Has exclusive palette access\n"));
else if (VidSur == infoSurface)
CONS_Printf("%s", M_GetText(" Has nonexclusive palette access\n"));
if (infoSurface->flags&SDL_DOUBLEBUF)
CONS_Printf("%s", M_GetText(" Double buffered\n"));
else if (VidSur == infoSurface)
CONS_Printf("%s", M_GetText(" No hardware flipping\n"));
if (infoSurface->flags&SDL_FULLSCREEN)
CONS_Printf("%s", M_GetText(" Full screen\n"));
else if (infoSurface->flags&SDL_RESIZABLE)
CONS_Printf("%s", M_GetText(" Resizable window\n"));
else if (VidSur == infoSurface)
CONS_Printf("%s", M_GetText(" Nonresizable window\n"));
if (infoSurface->flags&SDL_HWACCEL)
CONS_Printf("%s", M_GetText(" Uses hardware acceleration blit\n"));
if (infoSurface->flags&SDL_SRCCOLORKEY)
CONS_Printf("%s", M_GetText(" Use colorkey blitting\n"));
if (infoSurface->flags&SDL_RLEACCEL) if (infoSurface->flags&SDL_RLEACCEL)
CONS_Printf("%s", M_GetText(" Colorkey RLE acceleration blit\n")); CONS_Printf("%s", M_GetText(" Colorkey RLE acceleration blit\n"));
if (infoSurface->flags&SDL_SRCALPHA)
CONS_Printf("%s", M_GetText(" Use alpha blending acceleration blit\n"));
#endif
} }
static void VID_Command_Info_f (void) static void VID_Command_Info_f (void)
@ -579,23 +470,6 @@ static void VID_Command_Mode_f (void)
setmodeneeded = modenum+1; // request vid mode change setmodeneeded = modenum+1; // request vid mode change
} }
#if 0
#if defined(RPC_NO_WINDOWS_H)
static VOID MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(hWnd);
UNREFERENCED_PARAMETER(message);
UNREFERENCED_PARAMETER(wParam);
switch (message)
{
case WM_SETTEXT:
COM_BufAddText((LPCSTR)lParam);
break;
}
}
#endif
#endif
static inline void SDLJoyRemap(event_t *event) static inline void SDLJoyRemap(event_t *event)
{ {
(void)event; (void)event;
@ -954,218 +828,6 @@ void I_GetEvent(void)
// In order to make wheels act like buttons, we have to set their state to Up. // In order to make wheels act like buttons, we have to set their state to Up.
// This is because wheel messages don't have an up/down state. // This is because wheel messages don't have an up/down state.
gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0; gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0;
#if 0
SDL_Event inputEvent;
static SDL_bool sdlquit = SDL_FALSE; //Alam: once, just once
event_t event;
if (!graphics_started)
return;
memset(&inputEvent, 0x00, sizeof(inputEvent));
while (SDL_PollEvent(&inputEvent))
{
memset(&event,0x00,sizeof (event_t));
switch (inputEvent.type)
{
case SDL_ACTIVEEVENT:
if (inputEvent.active.state & (SDL_APPACTIVE|SDL_APPINPUTFOCUS))
{
// pause music when alt-tab
if (inputEvent.active.gain /*&& !paused */)
{
static SDL_bool firsttimeonmouse = SDL_TRUE;
if (!firsttimeonmouse)
{
if (cv_usemouse.value) I_StartupMouse();
}
else firsttimeonmouse = SDL_FALSE;
//if (!netgame && !con_destlines) paused = false;
if (gamestate == GS_LEVEL)
if (!paused) I_ResumeSong(0); //resume it
}
else /*if (!paused)*/
{
if (!disable_mouse)
SDLforceUngrabMouse();
if (!netgame && gamestate == GS_LEVEL) paused = true;
memset(gamekeydown, 0, NUMKEYS);
//S_PauseSound();
if (gamestate == GS_LEVEL)
I_PauseSong(0); //pause it
}
}
if (MOUSE_MENU)
{
SDLdoUngrabMouse();
break;
}
if ((SDL_APPMOUSEFOCUS&inputEvent.active.state) && USE_MOUSEINPUT && inputEvent.active.gain)
HalfWarpMouse(realwidth, realheight);
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
/// \todo inputEvent.key.which?
if (inputEvent.type == SDL_KEYUP)
event.type = ev_keyup;
else if (inputEvent.type == SDL_KEYDOWN)
event.type = ev_keydown;
else break;
event.data1 = SDLatekey(inputEvent.key.keysym.sym);
if (event.data1) D_PostEvent(&event);
break;
case SDL_MOUSEMOTION:
/// \todo inputEvent.motion.which
if (MOUSE_MENU)
{
SDLdoUngrabMouse();
break;
}
//if (USE_MOUSEINPUT) TODO SDL2 stub
{
// If the event is from warping the pointer back to middle
// of the screen then ignore it.
if ((inputEvent.motion.x == realwidth/2) &&
(inputEvent.motion.y == realheight/2))
{
break;
}
else
{
event.data2 = +inputEvent.motion.xrel;
event.data3 = -inputEvent.motion.yrel;
}
event.type = ev_mouse;
D_PostEvent(&event);
// Warp the pointer back to the middle of the window
// or we cannot move any further if it's at a border.
if ((inputEvent.motion.x < (realwidth/2 )-(realwidth/4 )) ||
(inputEvent.motion.y < (realheight/2)-(realheight/4)) ||
(inputEvent.motion.x > (realwidth/2 )+(realwidth/4 )) ||
(inputEvent.motion.y > (realheight/2)+(realheight/4) ) )
{
//if (SDL_GRAB_ON == SDL_WM_GrabInput(SDL_GRAB_QUERY) || !mousegrabok)
HalfWarpMouse(realwidth, realheight);
}
}
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
/// \todo inputEvent.button.which
if (USE_MOUSEINPUT)
{
if (inputEvent.type == SDL_MOUSEBUTTONUP)
event.type = ev_keyup;
else if (inputEvent.type == SDL_MOUSEBUTTONDOWN)
event.type = ev_keydown;
else break;
if (inputEvent.button.button==SDL_BUTTON_WHEELUP || inputEvent.button.button==SDL_BUTTON_WHEELDOWN)
{
if (inputEvent.type == SDL_MOUSEBUTTONUP)
event.data1 = 0; //Alam: dumb! this could be a real button with some mice
else
event.data1 = KEY_MOUSEWHEELUP + inputEvent.button.button - SDL_BUTTON_WHEELUP;
}
else if (inputEvent.button.button == SDL_BUTTON_MIDDLE)
event.data1 = KEY_MOUSE1+2;
else if (inputEvent.button.button == SDL_BUTTON_RIGHT)
event.data1 = KEY_MOUSE1+1;
else if (inputEvent.button.button <= MOUSEBUTTONS)
event.data1 = KEY_MOUSE1 + inputEvent.button.button - SDL_BUTTON_LEFT;
if (event.data1) D_PostEvent(&event);
}
break;
case SDL_JOYAXISMOTION:
inputEvent.jaxis.which++;
inputEvent.jaxis.axis++;
event.data1 = event.data2 = event.data3 = INT32_MAX;
if (cv_usejoystick.value == inputEvent.jaxis.which)
{
event.type = ev_joystick;
}
else if (cv_usejoystick.value == inputEvent.jaxis.which)
{
event.type = ev_joystick2;
}
else break;
//axis
if (inputEvent.jaxis.axis > JOYAXISSET*2)
break;
//vaule
if (inputEvent.jaxis.axis%2)
{
event.data1 = inputEvent.jaxis.axis / 2;
event.data2 = SDLJoyAxis(inputEvent.jaxis.value, event.type);
}
else
{
inputEvent.jaxis.axis--;
event.data1 = inputEvent.jaxis.axis / 2;
event.data3 = SDLJoyAxis(inputEvent.jaxis.value, event.type);
}
D_PostEvent(&event);
break;
case SDL_JOYBALLMOTION:
case SDL_JOYHATMOTION:
break; //NONE
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
inputEvent.jbutton.which++;
if (cv_usejoystick.value == inputEvent.jbutton.which)
event.data1 = KEY_JOY1;
else if (cv_usejoystick.value == inputEvent.jbutton.which)
event.data1 = KEY_2JOY1;
else break;
if (inputEvent.type == SDL_JOYBUTTONUP)
event.type = ev_keyup;
else if (inputEvent.type == SDL_JOYBUTTONDOWN)
event.type = ev_keydown;
else break;
if (inputEvent.jbutton.button < JOYBUTTONS)
event.data1 += inputEvent.jbutton.button;
else
break;
SDLJoyRemap(&event);
if (event.type != ev_console) D_PostEvent(&event);
break;
case SDL_QUIT:
if (!sdlquit)
{
sdlquit = SDL_TRUE;
M_QuitResponse('y');
}
break;
#if defined(RPC_NO_WINDOWS_H)
case SDL_SYSWMEVENT:
MainWndproc(inputEvent.syswm.msg->hwnd,
inputEvent.syswm.msg->msg,
inputEvent.syswm.msg->wParam,
inputEvent.syswm.msg->lParam);
break;
#endif
case SDL_VIDEORESIZE:
if (gamestate == GS_LEVEL || gamestate == GS_TITLESCREEN || gamestate == GS_EVALUATION)
setmodeneeded = VID_GetModeForSize(inputEvent.resize.w,inputEvent.resize.h)+1;
if (render_soft == rendermode)
{
SDLSetMode(realwidth, realheight, vid.bpp*8, surfaceFlagsW);
if (vidSurface) SDL_SetColors(vidSurface, localPalette, 0, 256);
}
else
SDLSetMode(realwidth, realheight, vid.bpp*8, surfaceFlagsW);
if (!vidSurface)
I_Error("Could not reset vidmode: %s\n",SDL_GetError());
break;
case SDL_VIDEOEXPOSE:
exposevideo = SDL_TRUE;
break;
default:
break;
}
}
//reset wheel like in win32, I don't understand it but works
#endif
} }
void I_StartupMouse(void) void I_StartupMouse(void)
@ -1494,11 +1156,6 @@ void VID_PrepareModeList(void)
#endif #endif
} }
static inline void SDLESSet(void)
{
SDL2STUB();
}
INT32 VID_SetMode(INT32 modeNum) INT32 VID_SetMode(INT32 modeNum)
{ {
SDLdoUngrabMouse(); SDLdoUngrabMouse();
@ -1550,6 +1207,12 @@ INT32 VID_SetMode(INT32 modeNum)
static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
{ {
int flags = 0; int flags = 0;
if (rendermode == render_none) // dedicated
{
return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh
}
if (window != NULL) if (window != NULL)
{ {
return SDL_FALSE; return SDL_FALSE;
@ -1568,38 +1231,43 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode == render_opengl) if (rendermode == render_opengl)
{ {
window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, flags |= SDL_WINDOW_OPENGL;
realwidth, realheight, flags | SDL_WINDOW_OPENGL);
if (window != NULL)
{
sdlglcontext = SDL_GL_CreateContext(window);
if (sdlglcontext == NULL)
{
SDL_DestroyWindow(window);
I_Error("Failed to create a GL context: %s\n", SDL_GetError());
}
else
{
SDL_GL_MakeCurrent(window, sdlglcontext);
}
}
else return SDL_FALSE;
} }
#endif #endif
// Create a window
window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
realwidth, realheight, flags);
if (window == NULL)
{
CONS_Printf(M_GetText("Couldn't create window: %s\n"), SDL_GetError());
return SDL_FALSE;
}
// Renderer-specific stuff
#ifdef HWRENDER
if (rendermode == render_opengl)
{
sdlglcontext = SDL_GL_CreateContext(window);
if (sdlglcontext == NULL)
{
SDL_DestroyWindow(window);
I_Error("Failed to create a GL context: %s\n", SDL_GetError());
}
SDL_GL_MakeCurrent(window, sdlglcontext);
}
else
#endif
if (rendermode == render_soft) if (rendermode == render_soft)
{ {
window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0));
realwidth, realheight, flags); if (renderer == NULL)
if (window != NULL)
{ {
renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0)); CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError());
if (renderer != NULL) return SDL_FALSE;
{
SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
}
else return SDL_FALSE;
} }
else return SDL_FALSE; SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
} }
return SDL_TRUE; return SDL_TRUE;
@ -1620,7 +1288,7 @@ static void Impl_SetWindowIcon(void)
{ {
return; return;
} }
SDL2STUB(); //SDL2STUB(); // Monster Iestyn: why is this stubbed?
SDL_SetWindowIcon(window, icoSurface); SDL_SetWindowIcon(window, icoSurface);
} }
@ -1718,7 +1386,6 @@ void I_StartupGraphics(void)
borderlesswindow = M_CheckParm("-borderless"); borderlesswindow = M_CheckParm("-borderless");
//SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2); //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2);
SDLESSet();
VID_Command_ModeList_f(); VID_Command_ModeList_f();
#ifdef HWRENDER #ifdef HWRENDER
if (M_CheckParm("-opengl") || rendermode == render_opengl) if (M_CheckParm("-opengl") || rendermode == render_opengl)

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -231,7 +231,7 @@ static Mix_Chunk *ds2chunk(void *stream)
break; break;
default: // convert arbitrary hz to 44100. default: // convert arbitrary hz to 44100.
step = 0; step = 0;
frac = ((UINT32)freq << FRACBITS) / 44100; frac = ((UINT32)freq << FRACBITS) / 44100 + 1; //Add 1 to counter truncation.
while (i < samples) while (i < samples)
{ {
o = (INT16)(*s+0x80)<<8; // changed signedness and shift up to 16 bits o = (INT16)(*s+0x80)<<8; // changed signedness and shift up to 16 bits

View file

@ -24,7 +24,6 @@ boolean OglSdlSurface(INT32 w, INT32 h);
void OglSdlFinishUpdate(boolean vidwait); void OglSdlFinishUpdate(boolean vidwait);
extern SDL_Window *window;
extern SDL_Renderer *renderer; extern SDL_Renderer *renderer;
extern SDL_GLContext sdlglcontext; extern SDL_GLContext sdlglcontext;
extern Uint16 realwidth; extern Uint16 realwidth;

View file

@ -71,4 +71,7 @@ void I_GetConsoleEvents(void);
void SDLforceUngrabMouse(void); void SDLforceUngrabMouse(void);
// Needed for some WIN32 functions
extern SDL_Window *window;
#endif #endif

View file

@ -2666,6 +2666,18 @@ INT32 I_PutEnv(char *variable)
#endif #endif
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
char *I_ClipboardPaste(void)
{
return NULL;
}
/** \brief The isWadPathOk function /** \brief The isWadPathOk function
\param path string path to check \param path string path to check

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -267,7 +267,7 @@ static void CV_Gammaxxx_ONChange(void)
#endif #endif
#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) #if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes, void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
size_t destrowbytes); size_t destrowbytes);
#define HAVE_VIDCOPY #define HAVE_VIDCOPY
@ -774,43 +774,51 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
if (!screens[0]) if (!screens[0])
return; return;
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) if (c & V_NOSCALESTART)
{ // Clear the entire screen, from dest to deststop. Yes, this really works.
memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
return;
}
dest = screens[0] + y*dupy*vid.width + x*dupx;
deststop = screens[0] + vid.rowbytes * vid.height;
if (w == BASEVIDWIDTH)
w = vid.width;
else
w *= dupx;
if (h == BASEVIDHEIGHT)
h = vid.height;
else
h *= dupy;
if (x && y && x + w < vid.width && y + h < vid.height)
{ {
// Center it if necessary dest = screens[0] + y*vid.width + x;
if (vid.width != BASEVIDWIDTH * dupx) deststop = screens[0] + vid.rowbytes * vid.height;
{ }
// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, else
// so center this imaginary screen {
if (c & V_SNAPTORIGHT) if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
dest += (vid.width - (BASEVIDWIDTH * dupx)); { // Clear the entire screen, from dest to deststop. Yes, this really works.
else if (!(c & V_SNAPTOLEFT)) memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2; return;
} }
if (vid.height != BASEVIDHEIGHT * dupy)
dest = screens[0] + y*dupy*vid.width + x*dupx;
deststop = screens[0] + vid.rowbytes * vid.height;
if (w == BASEVIDWIDTH)
w = vid.width;
else
w *= dupx;
if (h == BASEVIDHEIGHT)
h = vid.height;
else
h *= dupy;
if (x && y && x + w < vid.width && y + h < vid.height)
{ {
// same thing here // Center it if necessary
if (c & V_SNAPTOBOTTOM) if (vid.width != BASEVIDWIDTH * dupx)
dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; {
else if (!(c & V_SNAPTOTOP)) // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; // so center this imaginary screen
if (c & V_SNAPTORIGHT)
dest += (vid.width - (BASEVIDWIDTH * dupx));
else if (!(c & V_SNAPTOLEFT))
dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
}
if (vid.height != BASEVIDHEIGHT * dupy)
{
// same thing here
if (c & V_SNAPTOBOTTOM)
dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
else if (!(c & V_SNAPTOTOP))
dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
}
} }
} }
@ -968,45 +976,38 @@ void V_DrawFadeScreen(void)
} }
// Simple translucency with one color, over a set number of lines starting from the top. // Simple translucency with one color, over a set number of lines starting from the top.
void V_DrawFadeConsBack(INT32 plines, INT32 pcolor) void V_DrawFadeConsBack(INT32 plines)
{ {
UINT8 *deststop, *colormap, *buf; UINT8 *deststop, *buf;
#ifdef HWRENDER // not win32 only 19990829 by Kin #ifdef HWRENDER // not win32 only 19990829 by Kin
if (rendermode != render_soft && rendermode != render_none) if (rendermode != render_soft && rendermode != render_none)
{ {
UINT32 hwcolor; UINT32 hwcolor;
switch (pcolor) switch (cons_backcolor.value)
{ {
case 0: hwcolor = 0xffffff00; break; //white case 0: hwcolor = 0xffffff00; break; // White
case 1: hwcolor = 0xff800000; break; //orange case 1: hwcolor = 0x80808000; break; // Gray
case 2: hwcolor = 0x0000ff00; break; //blue case 2: hwcolor = 0x40201000; break; // Brown
case 3: hwcolor = 0x00800000; break; //green case 3: hwcolor = 0xff000000; break; // Red
case 4: hwcolor = 0x80808000; break; //gray case 4: hwcolor = 0xff800000; break; // Orange
case 5: hwcolor = 0xff000000; break; //red case 5: hwcolor = 0x80800000; break; // Yellow
default: hwcolor = 0x00800000; break; //green case 6: hwcolor = 0x00800000; break; // Green
case 7: hwcolor = 0x0000ff00; break; // Blue
case 8: hwcolor = 0x4080ff00; break; // Cyan
// Default green
default: hwcolor = 0x00800000; break;
} }
HWR_DrawConsoleBack(hwcolor, plines); HWR_DrawConsoleBack(hwcolor, plines);
return; return;
} }
#endif #endif
switch (pcolor)
{
case 0: colormap = cwhitemap; break;
case 1: colormap = corangemap; break;
case 2: colormap = cbluemap; break;
case 3: colormap = cgreenmap; break;
case 4: colormap = cgraymap; break;
case 5: colormap = credmap; break;
default: colormap = cgreenmap; break;
}
// heavily simplified -- we don't need to know x or y position, // heavily simplified -- we don't need to know x or y position,
// just the stop position // just the stop position
deststop = screens[0] + vid.rowbytes * min(plines, vid.height); deststop = screens[0] + vid.rowbytes * min(plines, vid.height);
for (buf = screens[0]; buf < deststop; ++buf) for (buf = screens[0]; buf < deststop; ++buf)
*buf = colormap[*buf]; *buf = consolebgmap[*buf];
} }
// Gets string colormap, used for 0x80 color codes // Gets string colormap, used for 0x80 color codes

View file

@ -145,7 +145,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum);
// fade down the screen buffer before drawing the menu over // fade down the screen buffer before drawing the menu over
void V_DrawFadeScreen(void); void V_DrawFadeScreen(void);
void V_DrawFadeConsBack(INT32 plines, INT32 pcolor); void V_DrawFadeConsBack(INT32 plines);
// draw a single character // draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);

View file

@ -1238,6 +1238,7 @@ int W_VerifyNMUSlumps(const char *filename)
{"COLORMAP", 8}, {"COLORMAP", 8},
{"PAL", 3}, {"PAL", 3},
{"CLM", 3}, {"CLM", 3},
{"TRANS", 5},
{NULL, 0}, {NULL, 0},
}; };
return W_VerifyFile(filename, NMUSlist, false); return W_VerifyFile(filename, NMUSlist, false);

View file

@ -85,13 +85,21 @@ endif
OBJS=$(OBJDIR)/dx_error.o $(OBJDIR)/fabdxlib.o $(OBJDIR)/win_vid.o $(OBJDIR)/win_dll.o OBJS=$(OBJDIR)/dx_error.o $(OBJDIR)/fabdxlib.o $(OBJDIR)/win_vid.o $(OBJDIR)/win_dll.o
endif endif
ZLIB_CFLAGS?=-I../libs/zlib
ifdef MINGW64
ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz64
else
ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz32
endif
ifndef NOPNG ifndef NOPNG
ifndef PNG_CONFIG ifndef PNG_CONFIG
PNG_CFLAGS?=-I../libs/libpng-src -I../libs/zlib PNG_CFLAGS?=-I../libs/libpng-src
ifdef MINGW64 ifdef MINGW64
PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64 -L../libs/zlib/win32 -lz64 PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64
else else
PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32 -L../libs/zlib/win32 -lz32 PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32
endif #MINGW64 endif #MINGW64
endif #PNG_CONFIG endif #PNG_CONFIG
endif #NOPNG endif #NOPNG

View file

@ -20,7 +20,9 @@
#include <tchar.h> #include <tchar.h>
#ifndef HAVE_SDL
#include "win_main.h" #include "win_main.h"
#endif
#include "../doomdef.h" //just for VERSION #include "../doomdef.h" //just for VERSION
#include "win_dbg.h" #include "win_dbg.h"
#include "../m_argv.h" //print the parameter in the log #include "../m_argv.h" //print the parameter in the log

View file

@ -69,7 +69,7 @@ static HCURSOR windowCursor = NULL; // main window cursor
static LPCSTR wClassName = "SRB2WC"; static LPCSTR wClassName = "SRB2WC";
boolean appActive = false; // app window is active INT appActive = false; // app window is active
#ifdef LOGMESSAGES #ifdef LOGMESSAGES
FILE *logstream; FILE *logstream;

View file

@ -23,7 +23,7 @@
extern HWND hWndMain; extern HWND hWndMain;
extern boolean appActive; extern INT appActive;
VOID I_GetSysMouseEvents(INT mouse_state); VOID I_GetSysMouseEvents(INT mouse_state);
extern UINT MSHWheelMessage; extern UINT MSHWheelMessage;

View file

@ -3598,6 +3598,18 @@ INT32 I_PutEnv(char *variable)
return putenv(variable); return putenv(variable);
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
const char *I_ClipboardPaste(void)
{
return NULL;
}
typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD); typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD);
const CPUInfoFlags *I_CPUInfo(void) const CPUInfoFlags *I_CPUInfo(void)

View file

@ -3470,6 +3470,18 @@ INT32 I_PutEnv(char *variable)
return putenv(variable); return putenv(variable);
} }
INT32 I_ClipboardCopy(const char *data, size_t size)
{
(void)data;
(void)size;
return -1;
}
char *I_ClipboardPaste(void)
{
return NULL;
}
typedef BOOL (WINAPI *MyFunc3) (DWORD); typedef BOOL (WINAPI *MyFunc3) (DWORD);
const CPUInfoFlags *I_CPUInfo(void) const CPUInfoFlags *I_CPUInfo(void)