mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-01-30 21:20:54 +00:00
Merge branch 'master' into crumble-FOF
This commit is contained in:
commit
d0861a084a
113 changed files with 10238 additions and 7253 deletions
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project(SRB2
|
||||
VERSION 2.1.14
|
||||
VERSION 2.1.17
|
||||
LANGUAGES C)
|
||||
|
||||
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: 2.1.16.{branch}-{build}
|
||||
version: 2.1.17.{branch}-{build}
|
||||
os: MinGW
|
||||
|
||||
environment:
|
||||
|
|
3
debian/docs
vendored
3
debian/docs
vendored
|
@ -1,2 +1 @@
|
|||
readme.txt
|
||||
readme.txt
|
||||
README.md
|
||||
|
|
|
@ -231,6 +231,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
|
|||
add_definitions(-DHAVE_BLUA)
|
||||
set(SRB2_LUA_SOURCES
|
||||
lua_baselib.c
|
||||
lua_blockmaplib.c
|
||||
lua_consolelib.c
|
||||
lua_hooklib.c
|
||||
lua_hudlib.c
|
||||
|
@ -390,18 +391,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
|
|||
endif()
|
||||
|
||||
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})
|
||||
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)
|
||||
else()
|
||||
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)
|
||||
endif()
|
||||
set(SRB2_USEASM ON)
|
||||
add_definitions(-DUSEASM)
|
||||
else()
|
||||
set(SRB2_USEASM OFF)
|
||||
add_definitions(-DNOASM -DNONX86)
|
||||
add_definitions(-DNONX86 -DNORUSEASM)
|
||||
endif()
|
||||
|
||||
# Targets
|
||||
|
|
20
src/Makefile
20
src/Makefile
|
@ -179,6 +179,9 @@ endif
|
|||
|
||||
ifdef LINUX
|
||||
UNIXCOMMON=1
|
||||
ifndef NOGME
|
||||
HAVE_LIBGME=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOLARIS
|
||||
|
@ -315,6 +318,13 @@ LIBS+=$(PNG_LDFLAGS)
|
|||
CFLAGS+=$(PNG_CFLAGS)
|
||||
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
|
||||
OPTS+=-DHAVE_LIBGME
|
||||
|
||||
|
@ -366,6 +376,14 @@ endif
|
|||
|
||||
OPTS:=-fno-exceptions $(OPTS)
|
||||
|
||||
ifdef MOBJCONSISTANCY
|
||||
OPTS+=-DMOBJCONSISTANCY
|
||||
endif
|
||||
|
||||
ifdef PACKETDROP
|
||||
OPTS+=-DPACKETDROP
|
||||
endif
|
||||
|
||||
ifdef DEBUGMODE
|
||||
|
||||
# build with debugging information
|
||||
|
@ -375,7 +393,7 @@ ifdef GCC48
|
|||
else
|
||||
CFLAGS+=-O0
|
||||
endif
|
||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
|
||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
|
||||
else
|
||||
|
||||
|
||||
|
|
|
@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable)
|
|||
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) {}
|
||||
|
||||
#include "../sdl/dosstr.c"
|
||||
|
|
|
@ -48,4 +48,5 @@ OBJS:=$(OBJS) \
|
|||
$(OBJDIR)/lua_skinlib.o \
|
||||
$(OBJDIR)/lua_thinkerlib.o \
|
||||
$(OBJDIR)/lua_maplib.o \
|
||||
$(OBJDIR)/lua_blockmaplib.o \
|
||||
$(OBJDIR)/lua_hudlib.o
|
||||
|
|
585
src/console.c
585
src/console.c
|
@ -84,19 +84,23 @@ UINT32 con_scalefactor; // text size scale factor
|
|||
|
||||
// hold 32 last lines of input for history
|
||||
#define CON_MAXPROMPTCHARS 256
|
||||
#define CON_PROMPTCHAR '>'
|
||||
#define CON_PROMPTCHAR '$'
|
||||
|
||||
static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines
|
||||
|
||||
static INT32 inputline; // current input line number
|
||||
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.
|
||||
static void CON_InputInit(void);
|
||||
static void CON_RecalcSize(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_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth);
|
||||
|
||||
|
@ -129,10 +133,12 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}
|
|||
// 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 CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"},
|
||||
{2, "Blue"}, {3, "Green"}, {4, "Gray"},
|
||||
{5, "Red"}, {0, NULL}};
|
||||
consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"},
|
||||
{3, "Red"}, {4, "Orange"}, {5, "Yellow"},
|
||||
{6, "Green"}, {7, "Blue"}, {8, "Purple"},
|
||||
{9, "Magenta"}, {10, "Aqua"},
|
||||
{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);
|
||||
|
||||
|
@ -219,8 +225,9 @@ static void CONS_Bind_f(void)
|
|||
// 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 *purplemap;
|
||||
UINT8 *lgreenmap;
|
||||
|
@ -229,44 +236,52 @@ UINT8 *graymap;
|
|||
UINT8 *redmap;
|
||||
UINT8 *orangemap;
|
||||
|
||||
// Console BG colors
|
||||
UINT8 *cwhitemap;
|
||||
UINT8 *corangemap;
|
||||
UINT8 *cbluemap;
|
||||
UINT8 *cgreenmap;
|
||||
UINT8 *cgraymap;
|
||||
UINT8 *credmap;
|
||||
// Console BG color
|
||||
UINT8 *consolebgmap = NULL;
|
||||
|
||||
void CON_ReSetupBackColormap(UINT16 num)
|
||||
void CON_SetupBackColormap(void)
|
||||
{
|
||||
UINT16 i, j;
|
||||
UINT8 k;
|
||||
UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE);
|
||||
UINT16 i, palsum;
|
||||
UINT8 j, palindex, shift;
|
||||
UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
|
||||
|
||||
// setup the green translucent background colormaps
|
||||
for (i = 0, k = 0; i < 768; i += 3, k++)
|
||||
if (!consolebgmap)
|
||||
consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
|
||||
shift = 6; // 12 colors -- shift of 7 means 6 colors
|
||||
switch (cons_backcolor.value)
|
||||
{
|
||||
j = pal[i] + pal[i+1] + pal[i+2];
|
||||
cwhitemap[k] = (UINT8)(15 - (j>>6));
|
||||
corangemap[k] = (UINT8)(63 - (j>>6));
|
||||
cbluemap[k] = (UINT8)(159 - (j>>6));
|
||||
cgreenmap[k] = (UINT8)(111 - (j>>6));
|
||||
cgraymap[k] = (UINT8)(31 - (j>>6));
|
||||
credmap[k] = (UINT8)(47 - (j>>6));
|
||||
case 0: palindex = 15; break; // White
|
||||
case 1: palindex = 31; break; // Gray
|
||||
case 2: palindex = 239; break; // Brown
|
||||
case 3: palindex = 47; break; // Red
|
||||
case 4: palindex = 63; break; // Orange
|
||||
case 5: palindex = 79; shift = 7; break; // Yellow
|
||||
case 6: palindex = 111; break; // Green
|
||||
case 7: palindex = 159; break; // Blue
|
||||
case 8: palindex = 199; shift = 7; break; // Purple
|
||||
case 9: palindex = 187; break; // Magenta
|
||||
case 10: palindex = 139; break; // Aqua
|
||||
// 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]) >> shift;
|
||||
consolebgmap[j] = (UINT8)(palindex - palsum);
|
||||
}
|
||||
}
|
||||
|
||||
static void CON_SetupBackColormap(void)
|
||||
static void CONS_backcolor_Change(void)
|
||||
{
|
||||
INT32 i, j, k;
|
||||
UINT8 *pal;
|
||||
CON_SetupBackColormap();
|
||||
}
|
||||
|
||||
cwhitemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
corangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
cbluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
cgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
cgraymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
credmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
static void CON_SetupColormaps(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
|
@ -276,20 +291,6 @@ static void CON_SetupBackColormap(void)
|
|||
redmap = (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)(63 - (j>>6));
|
||||
cbluemap[k] = (UINT8)(159 - (j>>6));
|
||||
cgreenmap[k] = (UINT8)(111 - (j>>6));
|
||||
cgraymap[k] = (UINT8)(31 - (j>>6));
|
||||
credmap[k] = (UINT8)(47 - (j>>6));
|
||||
}
|
||||
|
||||
// setup the other colormaps, for console text
|
||||
|
||||
// these don't need to be aligned, unless you convert the
|
||||
|
@ -320,6 +321,9 @@ static void CON_SetupBackColormap(void)
|
|||
redmap[9] = (UINT8)32;
|
||||
orangemap[3] = (UINT8)52;
|
||||
orangemap[9] = (UINT8)57;
|
||||
|
||||
// Init back colormap
|
||||
CON_SetupBackColormap();
|
||||
}
|
||||
|
||||
// Setup the console text buffer
|
||||
|
@ -343,7 +347,7 @@ void CON_Init(void)
|
|||
con_width = 0;
|
||||
CON_RecalcSize();
|
||||
|
||||
CON_SetupBackColormap();
|
||||
CON_SetupColormaps();
|
||||
|
||||
//note: CON_Ticker should always execute at least once before D_Display()
|
||||
con_clipviewtop = -1; // -1 does not clip
|
||||
|
@ -386,14 +390,10 @@ void CON_Init(void)
|
|||
//
|
||||
static void CON_InputInit(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
// prepare the first prompt line
|
||||
memset(inputlines, 0, sizeof (inputlines));
|
||||
for (i = 0; i < 32; i++)
|
||||
inputlines[i][0] = CON_PROMPTCHAR;
|
||||
inputline = 0;
|
||||
input_cx = 1;
|
||||
input_cur = input_sel = input_len = 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
@ -618,13 +618,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
|
||||
//
|
||||
boolean CON_Responder(event_t *ev)
|
||||
{
|
||||
static boolean consdown;
|
||||
static boolean shiftdown;
|
||||
static boolean ctrldown;
|
||||
static UINT8 consdown = false; // console is treated differently due to rare usage
|
||||
|
||||
// sequential completions a la 4dos
|
||||
static char completion[80];
|
||||
|
@ -639,13 +717,8 @@ boolean CON_Responder(event_t *ev)
|
|||
// let go keyup events, don't eat them
|
||||
if (ev->type != ev_keydown && ev->type != ev_console)
|
||||
{
|
||||
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
|
||||
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])
|
||||
if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
|
||||
consdown = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -684,94 +757,110 @@ boolean CON_Responder(event_t *ev)
|
|||
consoletoggle = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eat shift only if console active
|
||||
if (key == KEY_LSHIFT || key == KEY_RSHIFT)
|
||||
{
|
||||
shiftdown = true;
|
||||
// Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas
|
||||
if (key == KEY_LSHIFT || key == KEY_RSHIFT
|
||||
|| key == KEY_LCTRL || key == KEY_RCTRL
|
||||
|| key == KEY_LALT || key == KEY_RALT)
|
||||
return true;
|
||||
}
|
||||
|
||||
// same for ctrl
|
||||
if (key == KEY_LCTRL || key == KEY_RCTRL)
|
||||
// ctrl modifier -- changes behavior, adds shortcuts
|
||||
if (ctrldown)
|
||||
{
|
||||
ctrldown = true;
|
||||
return true;
|
||||
// show all cvars/commands that match what we have inputted
|
||||
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)
|
||||
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
|
||||
|
||||
// remember typing for several completions (a-la-4dos)
|
||||
if (inputlines[inputline][input_cx-1] != ' ')
|
||||
if (!completion[0])
|
||||
{
|
||||
if (strlen(inputlines[inputline]+1) < 80)
|
||||
strcpy(completion, inputlines[inputline]+1);
|
||||
else
|
||||
completion[0] = 0;
|
||||
|
||||
if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
|
||||
return true;
|
||||
strcpy(completion, inputlines[inputline]);
|
||||
comskips = varskips = 0;
|
||||
}
|
||||
else
|
||||
|
@ -783,37 +872,26 @@ boolean CON_Responder(event_t *ev)
|
|||
if (--varskips < 0)
|
||||
comskips = -comskips - 2;
|
||||
}
|
||||
else if (comskips > 0)
|
||||
comskips--;
|
||||
else if (comskips > 0) comskips--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (comskips < 0)
|
||||
varskips++;
|
||||
else
|
||||
comskips++;
|
||||
if (comskips < 0) varskips++;
|
||||
else comskips++;
|
||||
}
|
||||
}
|
||||
|
||||
if (comskips >= 0)
|
||||
{
|
||||
cmd = COM_CompleteCommand(completion, comskips);
|
||||
if (!cmd)
|
||||
// dirty: make sure if comskips is zero, to have a neg value
|
||||
if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
|
||||
comskips = -comskips - 1;
|
||||
}
|
||||
if (comskips < 0)
|
||||
cmd = CV_CompleteVar(completion, varskips);
|
||||
|
||||
if (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;
|
||||
}
|
||||
CON_InputSetString(va("%s ", cmd));
|
||||
else
|
||||
{
|
||||
if (comskips > 0)
|
||||
|
@ -839,47 +917,80 @@ boolean CON_Responder(event_t *ev)
|
|||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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
|
||||
if (key == KEY_ENTER)
|
||||
{
|
||||
if (input_cx < 2)
|
||||
if (!input_len)
|
||||
return true;
|
||||
|
||||
// push the command
|
||||
COM_BufAddText(inputlines[inputline]+1);
|
||||
COM_BufAddText(inputlines[inputline]);
|
||||
COM_BufAddText("\n");
|
||||
|
||||
CONS_Printf("%s\n", inputlines[inputline]);
|
||||
CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]);
|
||||
|
||||
inputline = (inputline+1) & 31;
|
||||
inputhist = inputline;
|
||||
|
||||
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
||||
inputlines[inputline][0] = CON_PROMPTCHAR;
|
||||
input_cx = 1;
|
||||
CON_InputClear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// backspace command prompt
|
||||
if (key == KEY_BACKSPACE)
|
||||
// backspace and delete command prompt
|
||||
if (input_sel != input_cur)
|
||||
{
|
||||
if (input_cx > 1)
|
||||
if (key == KEY_BACKSPACE || key == KEY_DEL)
|
||||
{
|
||||
input_cx--;
|
||||
inputlines[inputline][input_cx] = 0;
|
||||
CON_InputDelSelection();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -888,18 +999,15 @@ boolean CON_Responder(event_t *ev)
|
|||
{
|
||||
// copy one of the previous inputlines to the current
|
||||
do
|
||||
{
|
||||
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
|
||||
// current line + 1 because we cycle through the 32 input lines
|
||||
if (inputhist == inputline)
|
||||
inputhist = (inputline + 1) & 31;
|
||||
|
||||
M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS);
|
||||
input_cx = strlen(inputlines[inputline]);
|
||||
|
||||
CON_InputSetString(inputlines[inputhist]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -909,23 +1017,14 @@ boolean CON_Responder(event_t *ev)
|
|||
if (inputhist == inputline)
|
||||
return true;
|
||||
do
|
||||
{
|
||||
inputhist = (inputhist + 1) & 31;
|
||||
} while (inputhist != inputline && !inputlines[inputhist][1]);
|
||||
|
||||
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
||||
while (inputhist != inputline && !inputlines[inputhist][0]);
|
||||
|
||||
// back to currentline
|
||||
if (inputhist == inputline)
|
||||
{
|
||||
inputlines[inputline][0] = CON_PROMPTCHAR;
|
||||
input_cx = 1;
|
||||
}
|
||||
CON_InputClear();
|
||||
else
|
||||
{
|
||||
strcpy(inputlines[inputline], inputlines[inputhist]);
|
||||
input_cx = strlen(inputlines[inputline]);
|
||||
}
|
||||
CON_InputSetString(inputlines[inputhist]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -950,15 +1049,12 @@ boolean CON_Responder(event_t *ev)
|
|||
return false;
|
||||
|
||||
// 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;
|
||||
inputlines[inputline][input_cx + 1] = 0;
|
||||
input_cx++;
|
||||
}
|
||||
if (input_sel != input_cur)
|
||||
CON_InputDelSelection();
|
||||
CON_InputAddChar(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1242,26 +1338,89 @@ void CONS_Error(const char *msg)
|
|||
//
|
||||
static void CON_DrawInput(void)
|
||||
{
|
||||
char *p;
|
||||
size_t c;
|
||||
INT32 x, y;
|
||||
INT32 charwidth = (INT32)con_scalefactor << 3;
|
||||
|
||||
// input line scrolls left if it gets too long
|
||||
p = inputlines[inputline];
|
||||
if (input_cx >= con_width-11)
|
||||
p += input_cx - (con_width-11) + 1;
|
||||
const char *p = inputlines[inputline];
|
||||
size_t c, clen, cend;
|
||||
UINT8 lellip = 0, rellip = 0;
|
||||
INT32 x, y, i;
|
||||
|
||||
y = con_curlines - 12 * con_scalefactor;
|
||||
x = charwidth*2;
|
||||
|
||||
for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth)
|
||||
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
clen = con_width-13;
|
||||
|
||||
// draw the blinking cursor
|
||||
//
|
||||
x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth);
|
||||
if (con_tick < 4)
|
||||
V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
if (input_len <= clen)
|
||||
{
|
||||
c = 0;
|
||||
clen = input_len;
|
||||
}
|
||||
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), 77 | 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), 77 | 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), 77 | 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
|
||||
|
@ -1417,7 +1576,7 @@ static void CON_DrawConsole(void)
|
|||
{
|
||||
// inu: no more width (was always 0 and vid.width)
|
||||
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
|
||||
|
|
|
@ -40,11 +40,10 @@ extern consvar_t cons_backcolor;
|
|||
|
||||
extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap;
|
||||
|
||||
// Console bg colors:
|
||||
extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap,
|
||||
*credmap;
|
||||
// Console bg color (auto updated to match)
|
||||
extern UINT8 *consolebgmap;
|
||||
|
||||
void CON_ReSetupBackColormap(UINT16 num);
|
||||
void CON_SetupBackColormap(void);
|
||||
void CON_ClearHUD(void); // clear heads up messages
|
||||
|
||||
void CON_Ticker(void);
|
||||
|
|
1885
src/d_clisrv.c
1885
src/d_clisrv.c
File diff suppressed because it is too large
Load diff
127
src/d_clisrv.h
127
src/d_clisrv.h
|
@ -59,7 +59,7 @@ typedef enum
|
|||
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
|
||||
|
||||
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.
|
||||
|
||||
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
|
||||
|
@ -76,11 +76,19 @@ typedef enum
|
|||
NUMPACKETTYPE
|
||||
} packettype_t;
|
||||
|
||||
#ifdef PACKETDROP
|
||||
void Command_Drop(void);
|
||||
void Command_Droprate(void);
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
void Command_Numnodes(void);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
// client to server packet
|
||||
// Client to server packet
|
||||
typedef struct
|
||||
{
|
||||
UINT8 client_tic;
|
||||
|
@ -89,7 +97,7 @@ typedef struct
|
|||
ticcmd_t cmd;
|
||||
} ATTRPACK clientcmd_pak;
|
||||
|
||||
// splitscreen packet
|
||||
// Splitscreen packet
|
||||
// WARNING: must have the same format of clientcmd_pak, for more easy use
|
||||
typedef struct
|
||||
{
|
||||
|
@ -110,16 +118,16 @@ typedef struct
|
|||
UINT8 starttic;
|
||||
UINT8 numtics;
|
||||
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;
|
||||
|
||||
// sent to client when all consistency data
|
||||
// Sent to client when all consistency data
|
||||
// for players has been restored
|
||||
typedef struct
|
||||
{
|
||||
UINT32 randomseed;
|
||||
|
||||
//ctf flag stuff
|
||||
// CTF flag stuff
|
||||
SINT8 flagplayer[2];
|
||||
INT32 flagloose[2];
|
||||
INT32 flagflags[2];
|
||||
|
@ -127,11 +135,11 @@ typedef struct
|
|||
fixed_t flagy[2];
|
||||
fixed_t flagz[2];
|
||||
|
||||
UINT32 ingame; // spectator bit for each player
|
||||
UINT32 ctfteam; // if not spectator, then which team?
|
||||
UINT32 ingame; // Spectator bit for each player
|
||||
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
|
||||
UINT32 score[MAXPLAYERS]; // Everyone's score.
|
||||
UINT32 score[MAXPLAYERS]; // Everyone's score
|
||||
INT16 numboxes[MAXPLAYERS];
|
||||
INT16 totalring[MAXPLAYERS];
|
||||
tic_t realtime[MAXPLAYERS];
|
||||
|
@ -140,14 +148,14 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
//player stuff
|
||||
// Player stuff
|
||||
UINT8 playernum;
|
||||
|
||||
// Do not send anything visual related.
|
||||
// Only send data that we need to know for physics.
|
||||
UINT8 playerstate; //playerstate_t
|
||||
UINT32 pflags; //pflags_t
|
||||
UINT8 panim; //panim_t
|
||||
UINT8 playerstate; // playerstate_t
|
||||
UINT32 pflags; // pflags_t
|
||||
UINT8 panim; // panim_t
|
||||
|
||||
angle_t aiming;
|
||||
INT32 currentweapon;
|
||||
|
@ -155,7 +163,7 @@ typedef struct
|
|||
UINT16 powers[NUMPOWERS];
|
||||
|
||||
// Score is resynched in the confirm resync packet
|
||||
INT32 health;
|
||||
INT32 rings;
|
||||
SINT8 lives;
|
||||
SINT8 continues;
|
||||
UINT8 scoreadd;
|
||||
|
@ -176,9 +184,9 @@ typedef struct
|
|||
UINT8 charability;
|
||||
UINT8 charability2;
|
||||
UINT32 charflags;
|
||||
UINT32 thokitem; //mobjtype_t
|
||||
UINT32 spinitem; //mobjtype_t
|
||||
UINT32 revitem; //mobjtype_t
|
||||
UINT32 thokitem; // mobjtype_t
|
||||
UINT32 spinitem; // mobjtype_t
|
||||
UINT32 revitem; // mobjtype_t
|
||||
fixed_t actionspd;
|
||||
fixed_t mindash;
|
||||
fixed_t maxdash;
|
||||
|
@ -234,8 +242,9 @@ typedef struct
|
|||
INT32 onconveyor;
|
||||
|
||||
//player->mo stuff
|
||||
UINT8 hasmo; //boolean
|
||||
UINT8 hasmo; // Boolean
|
||||
|
||||
INT32 health;
|
||||
angle_t angle;
|
||||
fixed_t x;
|
||||
fixed_t y;
|
||||
|
@ -261,10 +270,10 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version; // different versions don't work
|
||||
UINT8 subversion; // contains build version
|
||||
UINT8 version; // Different versions don't work
|
||||
UINT8 subversion; // Contains build version
|
||||
|
||||
// server launch stuffs
|
||||
// Server launch stuffs
|
||||
UINT8 serverplayer;
|
||||
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
|
||||
|
||||
|
@ -278,18 +287,18 @@ typedef struct
|
|||
|
||||
UINT8 gametype;
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
UINT8 fileid;
|
||||
UINT32 position;
|
||||
UINT16 size;
|
||||
UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
|
||||
UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
|
||||
} ATTRPACK filetx_pak;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -298,14 +307,14 @@ typedef struct {
|
|||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version; // different versions don't work
|
||||
UINT8 subversion; // contains build version
|
||||
UINT8 version; // Different versions don't work
|
||||
UINT8 subversion; // Contains build version
|
||||
UINT8 localplayers;
|
||||
UINT8 mode;
|
||||
} ATTRPACK clientconfig_pak;
|
||||
|
||||
#define MAXSERVERNAME 32
|
||||
// this packet is too large
|
||||
// This packet is too large
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version;
|
||||
|
@ -371,45 +380,45 @@ typedef struct
|
|||
} ATTRPACK plrconfig;
|
||||
|
||||
//
|
||||
// Network packet data.
|
||||
// Network packet data
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
UINT32 checksum;
|
||||
UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
|
||||
UINT8 ackreturn; // the return of the ack number
|
||||
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 packettype;
|
||||
UINT8 reserved; // padding
|
||||
UINT8 reserved; // Padding
|
||||
union
|
||||
{
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
resynchend_pak resynchend; //
|
||||
resynch_pak resynchpak; //
|
||||
UINT8 resynchgot; //
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
resynchend_pak resynchend; //
|
||||
resynch_pak resynchpak; //
|
||||
UINT8 resynchgot; //
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
|
||||
#ifdef NEWPING
|
||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||
#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;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#define MAXSERVERLIST 64 // depends only on the display
|
||||
#define MAXSERVERLIST 64 // Depends only on the display
|
||||
typedef struct
|
||||
{
|
||||
SINT8 node;
|
||||
|
@ -420,7 +429,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
|
|||
extern UINT32 serverlistcount;
|
||||
extern INT32 mapchangepending;
|
||||
|
||||
// points inside doomcom
|
||||
// Points inside doomcom
|
||||
extern doomdata_t *netbuffer;
|
||||
|
||||
extern consvar_t cv_playbackspeed;
|
||||
|
@ -441,26 +450,28 @@ extern consvar_t cv_playbackspeed;
|
|||
#define KICK_MSG_CUSTOM_BAN 8
|
||||
|
||||
extern boolean server;
|
||||
extern boolean dedicated; // for dedicated server
|
||||
#define client (!server)
|
||||
extern boolean dedicated; // For dedicated server
|
||||
extern UINT16 software_MAXPACKETLENGTH;
|
||||
extern boolean acceptnewnode;
|
||||
extern SINT8 servernode;
|
||||
|
||||
void Command_Ping_f(void);
|
||||
extern tic_t connectiontimeout;
|
||||
extern tic_t jointimeout;
|
||||
#ifdef NEWPING
|
||||
extern UINT16 pingmeasurecount;
|
||||
extern UINT32 realpingtable[MAXPLAYERS];
|
||||
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||
#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);
|
||||
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 SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
|
||||
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
|
||||
|
@ -478,14 +489,14 @@ void CL_RemoveSplitscreenPlayer(void);
|
|||
void CL_Reset(void);
|
||||
void CL_ClearPlayer(INT32 playernum);
|
||||
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
||||
// is there a game running
|
||||
// Is there a game running
|
||||
boolean Playing(void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame(void);
|
||||
|
||||
//? how many ticks to run?
|
||||
//? How many ticks to run?
|
||||
void TryRunTics(tic_t realtic);
|
||||
|
||||
// extra data for lmps
|
||||
|
|
36
src/d_main.c
36
src/d_main.c
|
@ -73,6 +73,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
|
|||
#include "dehacked.h" // Dehacked list test
|
||||
#include "m_cond.h" // condition initialization
|
||||
#include "fastcmp.h"
|
||||
#include "keys.h"
|
||||
|
||||
#ifdef CMAKECONFIG
|
||||
#include "config.h"
|
||||
|
@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev)
|
|||
void D_PostEvent_end(void) {};
|
||||
#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
|
||||
// Send all the events of the given timestamp down the responder chain
|
||||
|
@ -188,6 +221,9 @@ void D_ProcessEvents(void)
|
|||
{
|
||||
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.
|
||||
if (M_ScreenshotResponder(ev))
|
||||
continue; // ate the event
|
||||
|
|
422
src/d_net.c
422
src/d_net.c
|
@ -31,18 +31,18 @@
|
|||
//
|
||||
// NETWORKING
|
||||
//
|
||||
// gametic is the tic about to be (or currently being) run
|
||||
// server:
|
||||
// gametic is the tic about to (or currently being) run
|
||||
// Server:
|
||||
// maketic is the tic that hasn't had control made for it yet
|
||||
// nettics: is the tic for each node
|
||||
// firsttictosend: is the lowest value of nettics
|
||||
// client:
|
||||
// neededtic: is the tic needed by the client to run the game
|
||||
// firsttictosend: is used to optimize a condition
|
||||
// normally maketic >= gametic > 0
|
||||
// nettics is the tic for each node
|
||||
// firstticstosend is the lowest value of nettics
|
||||
// Client:
|
||||
// neededtic is the tic needed by the client to run the game
|
||||
// firstticstosend is used to optimize a condition
|
||||
// Normally maketic >= gametic > 0
|
||||
|
||||
#define FORCECLOSE 0x8000
|
||||
tic_t connectiontimeout = (15*TICRATE);
|
||||
tic_t connectiontimeout = (10*TICRATE);
|
||||
|
||||
/// \brief network packet
|
||||
doomcom_t *doomcom = NULL;
|
||||
|
@ -62,7 +62,7 @@ INT32 net_bandwidth;
|
|||
/// \brief max length per packet
|
||||
INT16 hardware_MAXPACKETLENGTH;
|
||||
|
||||
void (*I_NetGet)(void) = NULL;
|
||||
boolean (*I_NetGet)(void) = NULL;
|
||||
void (*I_NetSend)(void) = NULL;
|
||||
boolean (*I_NetCanSend)(void) = NULL;
|
||||
boolean (*I_NetCanGet)(void) = NULL;
|
||||
|
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
|
|||
// -----------------------------------------------------------------
|
||||
// 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 URGENTFREESLOTENUM 10
|
||||
#define URGENTFREESLOTNUM 10
|
||||
#define ACKTOSENDTIMEOUT (TICRATE/11)
|
||||
|
||||
#ifndef NONET
|
||||
|
@ -139,10 +139,10 @@ typedef struct
|
|||
{
|
||||
UINT8 acknum;
|
||||
UINT8 nextacknum;
|
||||
UINT8 destinationnode;
|
||||
tic_t senttime;
|
||||
UINT16 length;
|
||||
UINT16 resentnum;
|
||||
UINT8 destinationnode; // The node to send the ack to
|
||||
tic_t senttime; // The time when the ack was sent
|
||||
UINT16 length; // The packet size
|
||||
UINT16 resentnum; // The number of times the ack has been resent
|
||||
union {
|
||||
SINT8 raw[MAXPACKETLENGTH];
|
||||
doomdata_t data;
|
||||
|
@ -152,11 +152,12 @@ typedef struct
|
|||
|
||||
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;
|
||||
|
||||
#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];
|
||||
#endif
|
||||
|
||||
|
@ -212,11 +213,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
|
|||
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)
|
||||
{
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
INT32 i, numfreeslote = 0;
|
||||
INT32 i, numfreeslot = 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++)
|
||||
if (!ackpak[i].acknum)
|
||||
{
|
||||
// for low priority packet, make sure let freeslotes so urgents packets can be sent
|
||||
numfreeslote++;
|
||||
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
|
||||
continue;
|
||||
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||
if (netbuffer->packettype >= PT_CANFAIL)
|
||||
{
|
||||
numfreeslot++;
|
||||
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||
continue;
|
||||
}
|
||||
|
||||
ackpak[i].acknum = node->nextacknum;
|
||||
ackpak[i].nextacknum = node->nextacknum;
|
||||
|
@ -241,7 +250,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
ackpak[i].length = doomcom->datalength;
|
||||
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].resentnum = 1;
|
||||
}
|
||||
|
@ -254,7 +263,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
|
||||
*freeack = ackpak[i].acknum;
|
||||
|
||||
sendackpacket++; // for stat
|
||||
sendackpacket++; // For stat
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -266,14 +275,46 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
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)
|
||||
{
|
||||
nodes[node].lasttimeacktosend_sent = I_GetTime();
|
||||
return nodes[node].firstacktosend;
|
||||
}
|
||||
|
||||
static void Removeack(INT32 i)
|
||||
static void RemoveAck(INT32 i)
|
||||
{
|
||||
INT32 node = ackpak[i].destinationnode;
|
||||
#ifndef NEWPING
|
||||
|
@ -290,31 +331,31 @@ static void Removeack(INT32 i)
|
|||
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
|
||||
#endif
|
||||
ackpak[i].acknum = 0;
|
||||
if (nodes[node].flags & CLOSE)
|
||||
if (nodes[node].flags & NF_CLOSE)
|
||||
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)
|
||||
{
|
||||
INT32 i;
|
||||
boolean goodpacket = true;
|
||||
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)
|
||||
{
|
||||
node->remotefirstack = netbuffer->ackreturn;
|
||||
// search the ackbuffer and free it
|
||||
// Search the ackbuffer and free it
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
|
||||
&& 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)
|
||||
{
|
||||
UINT8 ack = netbuffer->ack;
|
||||
|
@ -323,23 +364,23 @@ static boolean Processackpak(void)
|
|||
{
|
||||
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
|
||||
duppacket++;
|
||||
goodpacket = false; // discard packet (duplicate)
|
||||
goodpacket = false; // Discard packet (duplicate)
|
||||
}
|
||||
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)
|
||||
if (node->acktosend[i] == ack)
|
||||
{
|
||||
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
|
||||
duppacket++;
|
||||
goodpacket = false; // discard packet (duplicate)
|
||||
goodpacket = false; // Discard packet (duplicate)
|
||||
break;
|
||||
}
|
||||
if (goodpacket)
|
||||
{
|
||||
// is a good packet so increment the acknowledge number,
|
||||
// then search for a "hole" in the queue
|
||||
// Is a good packet so increment the acknowledge number,
|
||||
// Then search for a "hole" in the queue
|
||||
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
|
||||
if (!nextfirstack)
|
||||
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
|
||||
// will be incremented when the nextfirstack comes (code above)
|
||||
// Don't increment firsacktosend, put it in asktosend queue
|
||||
// Will be incremented when the nextfirstack comes (code above)
|
||||
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
|
||||
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
|
||||
if (newhead != node->acktosend_tail)
|
||||
|
@ -394,8 +435,8 @@ static boolean Processackpak(void)
|
|||
node->acktosend[node->acktosend_head] = ack;
|
||||
node->acktosend_head = newhead;
|
||||
}
|
||||
else // buffer full discard packet, sender will resend it
|
||||
{ // we can admit the packet but we will not detect the duplication after :(
|
||||
else // Buffer full discard packet, sender will resend it
|
||||
{ // We can admit the packet but we will not detect the duplication after :(
|
||||
DEBFILE("no more freeackret\n");
|
||||
goodpacket = false;
|
||||
}
|
||||
|
@ -430,25 +471,29 @@ static void GotAcks(void)
|
|||
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
|
||||
{
|
||||
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
|
||||
Removeack(i);
|
||||
else
|
||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||
// there is big chance the packet is lost
|
||||
// when resent, nextacknum = nodes[node].nextacknum
|
||||
// will redo the same but with different value
|
||||
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||
&& ackpak[i].senttime > 0)
|
||||
{
|
||||
ackpak[i].senttime--; // hurry up
|
||||
}
|
||||
RemoveAck(i);
|
||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||
// there is big chance the packet is lost
|
||||
// When resent, nextacknum = nodes[node].nextacknum
|
||||
// will redo the same but with different value
|
||||
else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||
&& ackpak[i].senttime > 0)
|
||||
{
|
||||
ackpak[i].senttime--; // hurry up
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void Net_ConnectionTimeout(INT32 node)
|
||||
void Net_ConnectionTimeout(INT32 node)
|
||||
{
|
||||
// send a very special packet to self (hack the reboundstore queue)
|
||||
// main code will handle it
|
||||
// Don't timeout several times
|
||||
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].ack = 0;
|
||||
reboundstore[rebound_head].ackreturn = 0;
|
||||
|
@ -456,12 +501,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
|
|||
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
|
||||
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!)
|
||||
nodes[node].lasttimepacketreceived = I_GetTime();
|
||||
}
|
||||
|
||||
// resend the data if needed
|
||||
// Resend the data if needed
|
||||
void Net_AckTicker(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
|
@ -477,7 +522,7 @@ void Net_AckTicker(void)
|
|||
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
|
||||
#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",
|
||||
i, nodei));
|
||||
|
@ -497,7 +542,7 @@ void Net_AckTicker(void)
|
|||
ackpak[i].senttime = I_GetTime();
|
||||
ackpak[i].resentnum++;
|
||||
ackpak[i].nextacknum = node->nextacknum;
|
||||
retransmit++; // for stat
|
||||
retransmit++; // For stat
|
||||
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
|
||||
(size_t)(ackpak[i].length - BASEPACKETSIZE));
|
||||
}
|
||||
|
@ -505,15 +550,15 @@ void Net_AckTicker(void)
|
|||
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
{
|
||||
// this is something like node open flag
|
||||
// This is something like node open flag
|
||||
if (nodes[i].firstacktosend)
|
||||
{
|
||||
// we haven't sent a packet for a long time
|
||||
// acknowledge packet if needed
|
||||
// We haven't sent a packet for a long time
|
||||
// Acknowledge packet if needed
|
||||
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
||||
Net_SendAcks(i);
|
||||
|
||||
if (!(nodes[i].flags & CLOSE)
|
||||
if (!(nodes[i].flags & NF_CLOSE)
|
||||
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
|
||||
{
|
||||
Net_ConnectionTimeout(i);
|
||||
|
@ -523,9 +568,9 @@ void Net_AckTicker(void)
|
|||
#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 ....)
|
||||
void Net_UnAcknowledgPacket(INT32 node)
|
||||
void Net_UnAcknowledgePacket(INT32 node)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
|
@ -564,20 +609,29 @@ void Net_UnAcknowledgPacket(INT32 node)
|
|||
#endif
|
||||
}
|
||||
|
||||
boolean Net_AllAckReceived(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
/** Checks if all acks have been received
|
||||
*
|
||||
* \return True if all acks have been received
|
||||
*
|
||||
*/
|
||||
static boolean Net_AllAcksReceived(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef NONET
|
||||
|
@ -587,7 +641,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
timeout = tictac + timeout*NEWTICRATE;
|
||||
|
||||
HGetPacket();
|
||||
while (timeout > I_GetTime() && !Net_AllAckReceived())
|
||||
while (timeout > I_GetTime() && !Net_AllAcksReceived())
|
||||
{
|
||||
while (tictac == I_GetTime())
|
||||
I_Sleep();
|
||||
|
@ -598,18 +652,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
#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
|
||||
nodes[node].ping = PINGDEFAULT;
|
||||
nodes[node].varping = VARPINGDEFAULT;
|
||||
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
|
||||
node->ping = PINGDEFAULT;
|
||||
node->varping = VARPINGDEFAULT;
|
||||
node->timeout = TIMEOUT(node->ping, node->varping);
|
||||
#endif
|
||||
nodes[node].firstacktosend = 0;
|
||||
nodes[node].nextacknum = 1;
|
||||
nodes[node].remotefirstack = 0;
|
||||
nodes[node].flags = 0;
|
||||
node->firstacktosend = 0;
|
||||
node->nextacknum = 1;
|
||||
node->remotefirstack = 0;
|
||||
node->flags = 0;
|
||||
}
|
||||
|
||||
static void InitAck(void)
|
||||
|
@ -622,9 +676,14 @@ static void InitAck(void)
|
|||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef NONET
|
||||
|
@ -657,7 +716,7 @@ void Net_CloseConnection(INT32 node)
|
|||
if (!node)
|
||||
return;
|
||||
|
||||
nodes[node].flags |= CLOSE;
|
||||
nodes[node].flags |= NF_CLOSE;
|
||||
|
||||
// try to Send ack back (two army problem)
|
||||
if (GetAcktosend(node))
|
||||
|
@ -676,8 +735,8 @@ void Net_CloseConnection(INT32 node)
|
|||
ackpak[i].acknum = 0;
|
||||
}
|
||||
|
||||
InitNode(node);
|
||||
AbortSendFiles(node);
|
||||
InitNode(&nodes[node]);
|
||||
SV_AbortSendFiles(node);
|
||||
I_NetFreeNodenum(node);
|
||||
#endif
|
||||
}
|
||||
|
@ -729,9 +788,15 @@ static void fprintfstring(char *s, size_t len)
|
|||
}
|
||||
if (mode)
|
||||
fprintf(debugfile, "]");
|
||||
}
|
||||
|
||||
static void fprintfstringnewline(char *s, size_t len)
|
||||
{
|
||||
fprintfstring(s, len);
|
||||
fprintf(debugfile, "\n");
|
||||
}
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename packet types
|
||||
static const char *packettypename[NUMPACKETTYPE] =
|
||||
{
|
||||
"NOTHING",
|
||||
|
@ -749,15 +814,22 @@ static const char *packettypename[NUMPACKETTYPE] =
|
|||
|
||||
"ASKINFO",
|
||||
"SERVERINFO",
|
||||
"PLAYERINFO",
|
||||
"REQUESTFILE",
|
||||
"ASKINFOVIAMS",
|
||||
|
||||
"PLAYERCONFIGS",
|
||||
"RESYNCHEND",
|
||||
"RESYNCHGET",
|
||||
|
||||
"FILEFRAGMENT",
|
||||
"TEXTCMD",
|
||||
"TEXTCMD2",
|
||||
"CLIENTJOIN",
|
||||
"NODETIMEOUT",
|
||||
"RESYNCHING",
|
||||
#ifdef NEWPING
|
||||
"PING"
|
||||
#endif
|
||||
};
|
||||
|
||||
static void DebugPrintpacket(const char *header)
|
||||
|
@ -770,20 +842,31 @@ static void DebugPrintpacket(const char *header)
|
|||
{
|
||||
case PT_ASKINFO:
|
||||
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;
|
||||
case PT_CLIENTJOIN:
|
||||
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
|
||||
netbuffer->u.clientcfg.mode);
|
||||
break;
|
||||
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 ",
|
||||
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
|
||||
netbuffer->u.serverpak.numtics,
|
||||
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
|
||||
fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
|
||||
&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
|
||||
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
|
||||
/// \todo Display more readable information about net commands
|
||||
fprintfstringnewline((char *)cmd, ntxtcmd);
|
||||
/*fprintfstring((char *)cmd, 3);
|
||||
if (ntxtcmd > 4)
|
||||
{
|
||||
fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
|
||||
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
|
||||
}
|
||||
fprintf(debugfile, "\n");*/
|
||||
break;
|
||||
}
|
||||
case PT_CLIENTCMD:
|
||||
case PT_CLIENT2CMD:
|
||||
case PT_CLIENTMIS:
|
||||
|
@ -797,7 +880,8 @@ static void DebugPrintpacket(const char *header)
|
|||
case PT_TEXTCMD:
|
||||
case PT_TEXTCMD2:
|
||||
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;
|
||||
case PT_SERVERCFG:
|
||||
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.fileneedednum,
|
||||
(UINT32)LONG(netbuffer->u.serverinfo.time));
|
||||
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
|
||||
fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
|
||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
|
||||
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
|
||||
break;
|
||||
|
@ -827,20 +911,100 @@ static void DebugPrintpacket(const char *header)
|
|||
break;
|
||||
case PT_REQUESTFILE:
|
||||
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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#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
|
||||
//
|
||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -871,7 +1035,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
(void)reliable;
|
||||
(void)acknum;
|
||||
#else
|
||||
// do this before GetFreeAcknum because this function backup
|
||||
// do this before GetFreeAcknum because this function backups
|
||||
// the current packet
|
||||
doomcom->remotenode = (INT16)node;
|
||||
if (doomcom->datalength <= 0)
|
||||
|
@ -884,7 +1048,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
return false;
|
||||
}
|
||||
|
||||
if (node < MAXNETNODES) // can be a broadcast
|
||||
if (node < MAXNETNODES) // Can be a broadcast
|
||||
netbuffer->ackreturn = GetAcktosend(node);
|
||||
else
|
||||
netbuffer->ackreturn = 0;
|
||||
|
@ -905,20 +1069,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
netbuffer->ack = acknum;
|
||||
|
||||
netbuffer->checksum = NetbufferChecksum();
|
||||
sendbytes += packetheaderlength + doomcom->datalength; // for stat
|
||||
sendbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||
|
||||
// simulate internet :)
|
||||
if (true || rand()<(INT32)RAND_MAX/5)
|
||||
#ifdef PACKETDROP
|
||||
// Simulate internet :)
|
||||
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
|
||||
if (!ShouldDropPacket())
|
||||
{
|
||||
#endif
|
||||
#ifdef DEBUGFILE
|
||||
if (debugfile)
|
||||
DebugPrintpacket("SEND");
|
||||
DebugPrintpacket("SENT");
|
||||
#endif
|
||||
I_NetSend();
|
||||
#ifdef PACKETDROP
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetdropquantity[netbuffer->packettype] > 0)
|
||||
packetdropquantity[netbuffer->packettype]--;
|
||||
#ifdef DEBUGFILE
|
||||
else if (debugfile)
|
||||
DebugPrintpacket("NOTSEND");
|
||||
if (debugfile)
|
||||
DebugPrintpacket("NOT SENT");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ndef NONET
|
||||
|
@ -933,7 +1107,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
//
|
||||
boolean HGetPacket(void)
|
||||
{
|
||||
// get a packet from self
|
||||
//boolean nodejustjoined;
|
||||
|
||||
// Get a packet from self
|
||||
if (rebound_tail != rebound_head)
|
||||
{
|
||||
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
|
||||
|
@ -958,16 +1134,17 @@ boolean HGetPacket(void)
|
|||
|
||||
while(true)
|
||||
{
|
||||
//nodejustjoined = I_NetGet();
|
||||
I_NetGet();
|
||||
|
||||
if (doomcom->remotenode == -1)
|
||||
if (doomcom->remotenode == -1) // No packet received
|
||||
return false;
|
||||
|
||||
getbytes += packetheaderlength + doomcom->datalength; // for stat
|
||||
getbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -976,6 +1153,7 @@ boolean HGetPacket(void)
|
|||
if (netbuffer->checksum != NetbufferChecksum())
|
||||
{
|
||||
DEBFILE("Bad packet checksum\n");
|
||||
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
|
||||
Net_CloseConnection(doomcom->remotenode);
|
||||
continue;
|
||||
}
|
||||
|
@ -985,11 +1163,26 @@ boolean HGetPacket(void)
|
|||
DebugPrintpacket("GET");
|
||||
#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())
|
||||
continue; // discarded (duplicated)
|
||||
|
||||
// a packet with just ackreturn
|
||||
// A packet with just ackreturn
|
||||
if (netbuffer->packettype == PT_NOTHING)
|
||||
{
|
||||
GotAcks();
|
||||
|
@ -1002,9 +1195,10 @@ boolean HGetPacket(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void Internal_Get(void)
|
||||
static boolean Internal_Get(void)
|
||||
{
|
||||
doomcom->remotenode = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
|
||||
|
@ -1089,7 +1283,7 @@ boolean D_CheckNetGame(void)
|
|||
|
||||
if (netgame)
|
||||
ret = true;
|
||||
if (!server && netgame)
|
||||
if (client && netgame)
|
||||
netgame = false;
|
||||
server = true; // WTF? server always true???
|
||||
// no! The deault mode is server. Client is set elsewhere
|
||||
|
@ -1230,4 +1424,6 @@ void D_CloseConnection(void)
|
|||
netgame = false;
|
||||
addedtogame = false;
|
||||
}
|
||||
|
||||
D_ResetTiccmds();
|
||||
}
|
||||
|
|
20
src/d_net.h
20
src/d_net.h
|
@ -18,10 +18,10 @@
|
|||
#ifndef __D_NET__
|
||||
#define __D_NET__
|
||||
|
||||
// Max computers in a game.
|
||||
// Max computers in a game
|
||||
#define MAXNETNODES 32
|
||||
#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)
|
||||
|
||||
|
@ -32,17 +32,17 @@ extern float lostpercent, duppercent, gamelostpercent;
|
|||
extern INT32 packetheaderlength;
|
||||
boolean Net_GetNetStat(void);
|
||||
extern INT32 getbytes;
|
||||
extern INT64 sendbytes; // realtime updated
|
||||
extern INT64 sendbytes; // Realtime updated
|
||||
|
||||
extern SINT8 nodetoplayer[MAXNETNODES];
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
||||
|
||||
INT32 Net_GetFreeAcks(boolean urgent);
|
||||
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,
|
||||
size_t packetlength);
|
||||
boolean HGetPacket(void);
|
||||
|
@ -52,9 +52,11 @@ void D_SaveBan(void);
|
|||
#endif
|
||||
boolean D_CheckNetGame(void);
|
||||
void D_CloseConnection(void);
|
||||
void Net_UnAcknowledgPacket(INT32 node);
|
||||
void Net_UnAcknowledgePacket(INT32 node);
|
||||
void Net_CloseConnection(INT32 node);
|
||||
void Net_ConnectionTimeout(INT32 node);
|
||||
void Net_AbortPacketType(UINT8 packettype);
|
||||
void Net_SendAcks(INT32 node);
|
||||
void Net_WaitAllAckReceived(UINT32 timeout);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
|
|||
static void TeamScramble_OnChange(void);
|
||||
|
||||
static void NetTimeout_OnChange(void);
|
||||
static void JoinTimeout_OnChange(void);
|
||||
|
||||
static void Ringslinger_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
|
||||
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
|
||||
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
#endif
|
||||
|
@ -365,6 +368,35 @@ boolean splitscreen = false;
|
|||
boolean circuitmap = false;
|
||||
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
|
||||
// =========================================================================
|
||||
|
@ -517,9 +549,12 @@ void D_RegisterServerCommands(void)
|
|||
// d_clisrv
|
||||
CV_RegisterVar(&cv_maxplayers);
|
||||
CV_RegisterVar(&cv_maxsend);
|
||||
CV_RegisterVar(&cv_noticedownload);
|
||||
CV_RegisterVar(&cv_downloadspeed);
|
||||
|
||||
COM_AddCommand("ping", Command_Ping_f);
|
||||
CV_RegisterVar(&cv_nettimeout);
|
||||
CV_RegisterVar(&cv_jointimeout);
|
||||
|
||||
CV_RegisterVar(&cv_skipmapcheck);
|
||||
CV_RegisterVar(&cv_sleep);
|
||||
|
@ -976,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
|
|||
return true;
|
||||
|
||||
// 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;
|
||||
|
||||
// Can change skin in intermission and whatnot.
|
||||
|
@ -1587,7 +1622,7 @@ static void Command_Map_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!server && !(adminplayer == consoleplayer))
|
||||
if (client && !(adminplayer == consoleplayer))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
return;
|
||||
|
@ -1914,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
|
|||
// You can't suicide someone else. Nice try, there.
|
||||
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)
|
||||
{
|
||||
XBOXSTATIC UINT8 buf[2];
|
||||
|
@ -2574,7 +2609,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
if (players[playernum].spectator)
|
||||
{
|
||||
players[playernum].score = 0;
|
||||
players[playernum].health = 1;
|
||||
players[playernum].rings = 0;
|
||||
if (players[playernum].mo)
|
||||
players[playernum].mo->health = 1;
|
||||
}
|
||||
|
@ -2629,7 +2664,7 @@ static void Command_Changepassword_f(void)
|
|||
// 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");
|
||||
#else
|
||||
if (!server) // cannot change remotely
|
||||
if (client) // cannot change remotely
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||
return;
|
||||
|
@ -2688,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
|
|||
|
||||
READMEM(*cp, sentmd5, 16);
|
||||
|
||||
if (!server)
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// Do the final pass to compare with the sent md5
|
||||
|
@ -2710,7 +2745,7 @@ static void Command_Verify_f(void)
|
|||
char *temp;
|
||||
INT32 playernum;
|
||||
|
||||
if (!server)
|
||||
if (client)
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||
return;
|
||||
|
@ -2794,7 +2829,7 @@ static void Command_MotD_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((netgame || multiplayer) && !server)
|
||||
if ((netgame || multiplayer) && client)
|
||||
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
|
||||
else
|
||||
{
|
||||
|
@ -3051,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
|
|||
READMEM(*cp, md5sum, 16);
|
||||
|
||||
// Only the server processes this message.
|
||||
if (!server)
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// Disallow non-printing characters and semicolons.
|
||||
|
@ -3318,6 +3353,11 @@ static void NetTimeout_OnChange(void)
|
|||
connectiontimeout = (tic_t)cv_nettimeout.value;
|
||||
}
|
||||
|
||||
static void JoinTimeout_OnChange(void)
|
||||
{
|
||||
jointimeout = (tic_t)cv_jointimeout.value;
|
||||
}
|
||||
|
||||
UINT32 timelimitintics = 0;
|
||||
|
||||
/** Deals with a timelimit change by printing the change to the console.
|
||||
|
@ -3960,7 +4000,7 @@ static void Command_Archivetest_f(void)
|
|||
}
|
||||
|
||||
// assign mobjnum
|
||||
i = 0;
|
||||
i = 1;
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
((mobj_t *)th)->mobjnum = i++;
|
||||
|
@ -4055,8 +4095,7 @@ static void Skin_OnChange(void)
|
|||
if (!Playing())
|
||||
return; // do whatever you want
|
||||
|
||||
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
|
||||
&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
|
||||
if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
|
||||
{
|
||||
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
|
||||
return;
|
||||
|
|
|
@ -101,7 +101,6 @@ extern consvar_t cv_recycler;
|
|||
extern consvar_t cv_itemfinder;
|
||||
|
||||
extern consvar_t cv_inttime, cv_advancemap, cv_playersforexit;
|
||||
extern consvar_t cv_soniccd;
|
||||
extern consvar_t cv_match_scoring;
|
||||
extern consvar_t cv_overtime;
|
||||
extern consvar_t cv_startinglives;
|
||||
|
@ -162,6 +161,8 @@ typedef enum
|
|||
MAXNETXCMD
|
||||
} netxcmd_t;
|
||||
|
||||
extern const char *netxcmdnames[MAXNETXCMD - 1];
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
|
495
src/d_netfil.c
495
src/d_netfil.c
|
@ -62,44 +62,48 @@
|
|||
|
||||
#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
|
||||
{
|
||||
INT32 ram;
|
||||
char *filename; // name of the file or ptr of the data in ram
|
||||
UINT32 size;
|
||||
union {
|
||||
char *filename; // Name of the file
|
||||
char *ram; // Pointer to the data in RAM
|
||||
} id;
|
||||
UINT32 size; // Size of the file
|
||||
UINT8 fileid;
|
||||
INT32 node; // destination
|
||||
struct filetx_s *next; // a queue
|
||||
INT32 node; // Destination
|
||||
struct filetx_s *next; // Next file in the list
|
||||
} filetx_t;
|
||||
|
||||
// current transfers (one for each node)
|
||||
// Current transfers (one for each node)
|
||||
typedef struct filetran_s
|
||||
{
|
||||
filetx_t *txlist;
|
||||
UINT32 position;
|
||||
FILE *currentfile;
|
||||
filetx_t *txlist; // Linked list of all files for the node
|
||||
UINT32 position; // The current position in the file
|
||||
FILE *currentfile; // The file currently being sent/received
|
||||
} filetran_t;
|
||||
static filetran_t transfer[MAXNETNODES];
|
||||
|
||||
// read time of file: stat _stmtime
|
||||
// write time of file: utime
|
||||
// Read time of file: stat _stmtime
|
||||
// Write time of file: utime
|
||||
|
||||
// receiver structure
|
||||
INT32 fileneedednum;
|
||||
fileneeded_t fileneeded[MAX_WADFILES];
|
||||
// Receiver structure
|
||||
INT32 fileneedednum; // Number of files needed to join the server
|
||||
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
|
||||
char downloaddir[256] = "DOWNLOAD";
|
||||
|
||||
#ifdef CLIENT_LOADINGSCREEN
|
||||
// for cl loading screen
|
||||
INT32 lastfilenum = 0;
|
||||
INT32 lastfilenum = -1;
|
||||
#endif
|
||||
|
||||
/** Fills a serverinfo packet with information about wad files loaded.
|
||||
*
|
||||
* \todo Give this function a better name since it is in global scope.
|
||||
*
|
||||
*/
|
||||
UINT8 *PutFileNeeded(void)
|
||||
{
|
||||
|
@ -111,19 +115,19 @@ UINT8 *PutFileNeeded(void)
|
|||
|
||||
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))
|
||||
filestatus = 0;
|
||||
else
|
||||
filestatus = 1; // important
|
||||
filestatus = 1; // Important
|
||||
|
||||
// Store in the upper four bits
|
||||
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))
|
||||
filestatus += (0 << 4); // won't send
|
||||
filestatus += (0 << 4); // Won't send
|
||||
else
|
||||
filestatus += (1 << 4); // will send if requested
|
||||
filestatus += (1 << 4); // Will send if requested
|
||||
|
||||
bytesused += (nameonlylength(wadfilename) + 22);
|
||||
|
||||
|
@ -144,7 +148,12 @@ UINT8 *PutFileNeeded(void)
|
|||
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)
|
||||
{
|
||||
INT32 i;
|
||||
|
@ -155,14 +164,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
|||
p = (UINT8 *)fileneededstr;
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
{
|
||||
fileneeded[i].status = FS_NOTFOUND;
|
||||
filestatus = READUINT8(p);
|
||||
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
|
||||
filestatus = READUINT8(p); // The first byte is the file status
|
||||
fileneeded[i].important = (UINT8)(filestatus & 3);
|
||||
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
|
||||
fileneeded[i].totalsize = READUINT32(p);
|
||||
fileneeded[i].phandle = NULL;
|
||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
|
||||
READMEM(p, fileneeded[i].md5sum, 16);
|
||||
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
|
||||
fileneeded[i].file = NULL; // The file isn't open yet
|
||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
|
||||
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;
|
||||
fileneeded[0].status = FS_REQUESTED;
|
||||
fileneeded[0].totalsize = UINT32_MAX;
|
||||
fileneeded[0].phandle = NULL;
|
||||
fileneeded[0].file = NULL;
|
||||
memset(fileneeded[0].md5sum, 0, 16);
|
||||
strcpy(fileneeded[0].filename, tmpsave);
|
||||
}
|
||||
|
||||
/** Checks the server to see if we CAN download all the files,
|
||||
* before starting to create them and requesting.
|
||||
*
|
||||
* \return True if we can download all the files
|
||||
*
|
||||
*/
|
||||
boolean CL_CheckDownloadable(void)
|
||||
{
|
||||
|
@ -239,8 +251,12 @@ boolean CL_CheckDownloadable(void)
|
|||
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.
|
||||
*
|
||||
* \return True if the packet was successfully sent
|
||||
* \note Sends a PT_REQUESTFILE packet
|
||||
*
|
||||
*/
|
||||
boolean CL_SendRequestFile(void)
|
||||
{
|
||||
|
@ -298,11 +314,17 @@ void Got_RequestFilePak(INT32 node)
|
|||
if (id == 0xFF)
|
||||
break;
|
||||
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 i, j;
|
||||
|
@ -333,7 +355,7 @@ INT32 CL_CheckFiles(void)
|
|||
}
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
@ -343,11 +365,11 @@ INT32 CL_CheckFiles(void)
|
|||
if (i >= fileneedednum || j >= numwadfiles)
|
||||
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))
|
||||
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);
|
||||
fileneeded[i].status = FS_OPEN;
|
||||
++i;
|
||||
|
@ -360,7 +382,7 @@ INT32 CL_CheckFiles(void)
|
|||
{
|
||||
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++)
|
||||
{
|
||||
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
|
||||
|
@ -383,7 +405,7 @@ INT32 CL_CheckFiles(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// load it now
|
||||
// Load it now
|
||||
void CL_LoadServerFiles(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
@ -394,7 +416,7 @@ void CL_LoadServerFiles(void)
|
|||
for (i = 1; i < fileneedednum; i++)
|
||||
{
|
||||
if (fileneeded[i].status == FS_OPEN)
|
||||
continue; // already loaded
|
||||
continue; // Already loaded
|
||||
else if (fileneeded[i].status == FS_FOUND)
|
||||
{
|
||||
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));
|
||||
}
|
||||
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
|
||||
static INT32 filetosend = 0;
|
||||
// Number of files to send
|
||||
// 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 *p;
|
||||
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||
filetx_t *p; // The new file request
|
||||
INT32 i;
|
||||
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;
|
||||
while (*q)
|
||||
q = &((*q)->next);
|
||||
|
||||
// Allocate a file request and append it to the file list
|
||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||
if (p)
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
else
|
||||
I_Error("SendFile: No more ram\n");
|
||||
p->filename = (char *)malloc(MAX_WADPATH);
|
||||
if (!p->filename)
|
||||
I_Error("SendFile: No more ram\n");
|
||||
if (!p)
|
||||
I_Error("SV_SendFile: No more memory\n");
|
||||
|
||||
// a minimum of security, can get only file in srb2 direcory
|
||||
strlcpy(p->filename, filename, MAX_WADPATH);
|
||||
nameonly(p->filename);
|
||||
// Initialise with zeros
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
|
||||
// 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++)
|
||||
{
|
||||
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
nameonly(wadfilename);
|
||||
if (!stricmp(wadfilename, p->filename))
|
||||
if (!stricmp(wadfilename, p->id.filename))
|
||||
{
|
||||
// copy filename with full path
|
||||
strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
// Copy file name with full path
|
||||
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle non-loaded file requests
|
||||
if (!wadfiles[i])
|
||||
{
|
||||
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
|
||||
// don't inform client (probably hacker)
|
||||
// Not found
|
||||
// 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));
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
free(p);
|
||||
*q = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
|
||||
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
|
||||
{
|
||||
// too big
|
||||
// don't inform client (client sucks, man)
|
||||
// Too big
|
||||
// Don't inform client (client sucks, man)
|
||||
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
free(p);
|
||||
*q = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
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->next = NULL; // end of list
|
||||
filetosend++;
|
||||
p->next = NULL; // End of list
|
||||
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 *p;
|
||||
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||
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;
|
||||
while (*q)
|
||||
q = &((*q)->next);
|
||||
|
||||
// Allocate a file request and append it to the file list
|
||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||
if (p)
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
else
|
||||
I_Error("SendRam: No more ram\n");
|
||||
p->ram = freemethod;
|
||||
p->filename = data;
|
||||
if (!p)
|
||||
I_Error("SV_SendRam: No more memory\n");
|
||||
|
||||
// Initialise with zeros
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
|
||||
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->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;
|
||||
|
||||
// Free the file request according to the freemethod parameter used with SV_SendFile/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)
|
||||
fclose(transfer[node].currentfile);
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
break;
|
||||
case SF_Z_RAM:
|
||||
Z_Free(p->filename);
|
||||
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
|
||||
Z_Free(p->id.ram);
|
||||
break;
|
||||
case SF_RAM:
|
||||
free(p->filename);
|
||||
case SF_NOFREERAM:
|
||||
case SF_RAM: // It's a memory block allocated with malloc, use free
|
||||
free(p->id.ram);
|
||||
case SF_NOFREERAM: // Nothing to free
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the file request from the list
|
||||
transfer[node].txlist = p->next;
|
||||
transfer[node].currentfile = NULL;
|
||||
free(p);
|
||||
filetosend--;
|
||||
|
||||
// Indicate that the transmission is over
|
||||
transfer[node].currentfile = NULL;
|
||||
|
||||
filestosend--;
|
||||
}
|
||||
|
||||
#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;
|
||||
filetx_pak *p;
|
||||
size_t size;
|
||||
filetx_t *f;
|
||||
INT32 packetsent = PACKETPERTIC, ram, i;
|
||||
INT32 packetsent, ram, i, j;
|
||||
INT32 maxpacketsent;
|
||||
|
||||
if (!filetosend)
|
||||
if (!filestosend) // No file to send
|
||||
return;
|
||||
if (!packetsent)
|
||||
packetsent++;
|
||||
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
||||
while (packetsent-- && filetosend != 0)
|
||||
|
||||
if (cv_downloadspeed.value) // New (and experimental) behavior
|
||||
{
|
||||
for (i = currentnode, ram = 0; ram < MAXNETNODES;
|
||||
i = (i+1) % MAXNETNODES, ram++)
|
||||
packetsent = cv_downloadspeed.value;
|
||||
// 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)
|
||||
goto found;
|
||||
}
|
||||
// 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:
|
||||
currentnode = (i+1) % MAXNETNODES;
|
||||
f = transfer[i].txlist;
|
||||
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;
|
||||
|
||||
transfer[i].currentfile =
|
||||
fopen(f->filename, "rb");
|
||||
fopen(f->id.filename, "rb");
|
||||
|
||||
if (!transfer[i].currentfile)
|
||||
I_Error("File %s does not exist",
|
||||
f->filename);
|
||||
f->id.filename);
|
||||
|
||||
fseek(transfer[i].currentfile, 0, SEEK_END);
|
||||
filesize = ftell(transfer[i].currentfile);
|
||||
|
@ -596,45 +715,47 @@ void FiletxTicker(void)
|
|||
// Nobody wants to transfer a file bigger
|
||||
// than 4GB!
|
||||
if (filesize >= LONG_MAX)
|
||||
I_Error("filesize of %s is too large", f->filename);
|
||||
if (-1 == filesize)
|
||||
I_Error("Error getting filesize of %s", f->filename);
|
||||
I_Error("filesize of %s is too large", f->id.filename);
|
||||
if (filesize == -1)
|
||||
I_Error("Error getting filesize of %s", f->id.filename);
|
||||
|
||||
f->size = (UINT32)filesize;
|
||||
fseek(transfer[i].currentfile, 0, SEEK_SET);
|
||||
}
|
||||
else
|
||||
transfer[i].currentfile = (FILE *)1;
|
||||
else // Sending RAM
|
||||
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
|
||||
transfer[i].position = 0;
|
||||
}
|
||||
|
||||
// Build a packet containing a file fragment
|
||||
p = &netbuffer->u.filetxpak;
|
||||
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
|
||||
if (f->size-transfer[i].position < size)
|
||||
size = f->size-transfer[i].position;
|
||||
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)
|
||||
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);
|
||||
// put flag so receiver know the totalsize
|
||||
// Put flag so receiver knows the total size
|
||||
if (transfer[i].position + size == f->size)
|
||||
p->position |= LONG(0x80000000);
|
||||
p->fileid = f->fileid;
|
||||
p->size = SHORT((UINT16)size);
|
||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||
if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
|
||||
{ // not sent for some odd reason, retry at next call
|
||||
if (!ram)
|
||||
fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
|
||||
// exit the while (can't send this one so why should i send the next?)
|
||||
break;
|
||||
|
||||
// Send the packet
|
||||
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
|
||||
{ // Success
|
||||
transfer[i].position = (UINT32)(transfer[i].position + size);
|
||||
if (transfer[i].position == f->size) // Finish?
|
||||
SV_EndFileSend(i);
|
||||
}
|
||||
else // success
|
||||
{
|
||||
transfer[i].position = (UINT32)(size+transfer[i].position);
|
||||
if (transfer[i].position == f->size) // finish ?
|
||||
EndSend(i);
|
||||
else
|
||||
{ // Not sent for some odd reason, retry at next call
|
||||
if (!ram)
|
||||
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
|
||||
// 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)
|
||||
{
|
||||
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
||||
fileneeded_t *file = &fileneeded[filenum];
|
||||
char *filename = file->filename;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (fileneeded[filenum].status == FS_REQUESTED)
|
||||
if (file->status == FS_REQUESTED)
|
||||
{
|
||||
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
|
||||
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
|
||||
if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
|
||||
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
|
||||
fileneeded[filenum].currentsize = 0;
|
||||
fileneeded[filenum].status = FS_DOWNLOADING;
|
||||
if (file->file)
|
||||
I_Error("Got_Filetxpak: already open file\n");
|
||||
file->file = fopen(filename, "wb");
|
||||
if (!file->file)
|
||||
I_Error("Can't create file %s: %s", filename, strerror(errno));
|
||||
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);
|
||||
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
||||
// use a special tric to know when file is finished (not allways used)
|
||||
// WARNING: filepak can arrive out of order so don't stop now !
|
||||
// Use a special trick to know when the file is complete (not always used)
|
||||
// WARNING: file fragments can arrive out of order so don't stop yet!
|
||||
if (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
|
||||
fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
|
||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
|
||||
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
|
||||
fileneeded[filenum].currentsize += size;
|
||||
// We can receive packet in the wrong order, anyway all os support gaped file
|
||||
fseek(file->file, pos, SEEK_SET);
|
||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
|
||||
I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
|
||||
file->currentsize += size;
|
||||
|
||||
// finished?
|
||||
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
|
||||
// Finished?
|
||||
if (file->currentsize == file->totalsize)
|
||||
{
|
||||
fclose(fileneeded[filenum].phandle);
|
||||
fileneeded[filenum].phandle = NULL;
|
||||
fileneeded[filenum].status = FS_FOUND;
|
||||
fclose(file->file);
|
||||
file->file = NULL;
|
||||
file->status = FS_FOUND;
|
||||
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
||||
fileneeded[filenum].filename);
|
||||
filename);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
Net_SendAcks(servernode);
|
||||
|
@ -702,33 +858,50 @@ void Got_Filetxpak(void)
|
|||
#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)
|
||||
EndSend(node);
|
||||
SV_EndFileSend(node);
|
||||
}
|
||||
|
||||
void CloseNetFile(void)
|
||||
{
|
||||
INT32 i;
|
||||
// is sending?
|
||||
// Is sending?
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
AbortSendFiles(i);
|
||||
SV_AbortSendFiles(i);
|
||||
|
||||
// receiving a file?
|
||||
// Receiving a file?
|
||||
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);
|
||||
// file is not complete delete it
|
||||
fclose(fileneeded[i].file);
|
||||
// File is not complete delete it
|
||||
remove(fileneeded[i].filename);
|
||||
}
|
||||
|
||||
// remove FILEFRAGMENT from acknledge list
|
||||
// Remove PT_FILEFRAGMENT from acknowledge list
|
||||
Net_AbortPacketType(PT_FILEFRAGMENT);
|
||||
}
|
||||
|
||||
// functions cut and pasted from doomatic :)
|
||||
// Functions cut and pasted from Doomatic :)
|
||||
|
||||
void nameonly(char *s)
|
||||
{
|
||||
|
|
|
@ -29,21 +29,21 @@ typedef enum
|
|||
FS_FOUND,
|
||||
FS_REQUESTED,
|
||||
FS_DOWNLOADING,
|
||||
FS_OPEN, // is opened and used in w_wad
|
||||
FS_OPEN, // Is opened and used in w_wad
|
||||
FS_MD5SUMBAD
|
||||
} filestatus_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 important;
|
||||
UINT8 willsend; // is the server willing to send it?
|
||||
UINT8 willsend; // Is the server willing to send it?
|
||||
char filename[MAX_WADPATH];
|
||||
UINT8 md5sum[16];
|
||||
// used only for download
|
||||
FILE *phandle;
|
||||
// Used only for download
|
||||
FILE *file;
|
||||
UINT32 currentsize;
|
||||
UINT32 totalsize;
|
||||
filestatus_t status; // the value returned by recsearch
|
||||
filestatus_t status; // The value returned by recsearch
|
||||
} fileneeded_t;
|
||||
|
||||
extern INT32 fileneedednum;
|
||||
|
@ -58,28 +58,25 @@ UINT8 *PutFileNeeded(void);
|
|||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
|
||||
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);
|
||||
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);
|
||||
|
||||
void FiletxTicker(void);
|
||||
void SV_FileSendTicker(void);
|
||||
void Got_Filetxpak(void);
|
||||
boolean SV_SendingFile(INT32 node);
|
||||
|
||||
boolean CL_CheckDownloadable(void);
|
||||
boolean CL_SendRequestFile(void);
|
||||
void Got_RequestFilePak(INT32 node);
|
||||
|
||||
void AbortSendFiles(INT32 node);
|
||||
void SV_AbortSendFiles(INT32 node);
|
||||
void CloseNetFile(void);
|
||||
|
||||
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,
|
||||
boolean completepath);
|
||||
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef enum
|
|||
SF_STOMPDAMAGE = 1<<9, // Always damage enemies, etc by landing on them, no matter your vunerability?
|
||||
SF_MARIODAMAGE = SF_NOJUMPDAMAGE|SF_STOMPDAMAGE, // The Mario method of being able to damage enemies, etc.
|
||||
SF_MACHINE = 1<<10, // Beep boop. Are you a robot?
|
||||
SF_NOSPINDASHDUST = 1<<11, // Don't spawn dust particles when charging a spindash
|
||||
// free up to and including 1<<31
|
||||
} skinflags_t;
|
||||
|
||||
|
@ -151,7 +152,13 @@ typedef enum
|
|||
PF_ANALOGMODE = 1<<26, // Analog mode?
|
||||
|
||||
// Can carry another player?
|
||||
PF_CANCARRY = 1<<27
|
||||
PF_CANCARRY = 1<<27,
|
||||
|
||||
// Used shield ability
|
||||
PF_SHIELDABILITY = 1<<28,
|
||||
|
||||
// Force jump damage?
|
||||
PF_FORCEJUMPDAMAGE = 1<<29
|
||||
|
||||
// free up to and including 1<<31
|
||||
} pflags_t;
|
||||
|
@ -178,23 +185,34 @@ typedef enum
|
|||
typedef enum
|
||||
{
|
||||
SH_NONE = 0,
|
||||
// Standard shields
|
||||
SH_JUMP,
|
||||
SH_ATTRACT,
|
||||
SH_ELEMENTAL,
|
||||
SH_BOMB,
|
||||
// Stupid useless unimplimented Sonic 3 shields
|
||||
SH_BUBBLEWRAP,
|
||||
SH_THUNDERCOIN,
|
||||
SH_FLAMEAURA,
|
||||
// Pity shield: the world's most basic shield ever, given to players who suck at Match
|
||||
SH_PITY,
|
||||
// The fireflower is special, it combines with other shields.
|
||||
SH_FIREFLOWER = 0x100,
|
||||
// The force shield uses the lower 8 bits to count how many hits are left.
|
||||
SH_FORCE = 0x200,
|
||||
|
||||
SH_STACK = SH_FIREFLOWER,
|
||||
// Shield flags
|
||||
SH_PROTECTFIRE = 0x400,
|
||||
SH_PROTECTWATER = 0x800,
|
||||
SH_PROTECTELECTRIC = 0x1000,
|
||||
|
||||
// Indivisible shields
|
||||
SH_PITY = 1, // the world's most basic shield ever, given to players who suck at Match
|
||||
SH_WHIRLWIND,
|
||||
SH_ARMAGEDDON,
|
||||
|
||||
// normal shields that use flags
|
||||
SH_ATTRACT = SH_PROTECTELECTRIC,
|
||||
SH_ELEMENTAL = SH_PROTECTFIRE|SH_PROTECTWATER,
|
||||
|
||||
// Sonic 3 shields
|
||||
SH_FLAMEAURA = SH_PROTECTFIRE,
|
||||
SH_BUBBLEWRAP = SH_PROTECTWATER,
|
||||
SH_THUNDERCOIN = SH_WHIRLWIND|SH_PROTECTELECTRIC,
|
||||
|
||||
// The force shield uses the lower 8 bits to count how many extra hits are left.
|
||||
SH_FORCE = 0x100,
|
||||
SH_FORCEHP = 0xFF, // to be used as a bitmask only
|
||||
|
||||
// Mostly for use with Mario mode.
|
||||
SH_FIREFLOWER = 0x200,
|
||||
|
||||
SH_STACK = SH_FIREFLOWER, // second-layer shields
|
||||
SH_NOSTACK = ~SH_STACK
|
||||
} shieldtype_t; // pw_shield
|
||||
|
||||
|
@ -297,10 +315,8 @@ typedef struct player_s
|
|||
// It is updated with cmd->aiming.
|
||||
angle_t aiming;
|
||||
|
||||
// This is only used between levels,
|
||||
// mo->health is used during levels.
|
||||
/// \todo Remove this. We don't need a second health definition for players.
|
||||
INT32 health;
|
||||
// player's ring count
|
||||
INT32 rings;
|
||||
|
||||
SINT8 pity; // i pity the fool.
|
||||
INT32 currentweapon; // current weapon selected.
|
||||
|
@ -361,8 +377,8 @@ typedef struct player_s
|
|||
UINT8 gotcontinue; // Got continue from this stage?
|
||||
|
||||
fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values)
|
||||
UINT8 jumping; // Jump counter
|
||||
UINT8 secondjump;
|
||||
UINT8 jumping; // Holding down jump button
|
||||
UINT8 secondjump; // Jump counter
|
||||
|
||||
UINT8 fly1; // Tails flying
|
||||
UINT8 scoreadd; // Used for multiple enemy attack bonus
|
||||
|
|
659
src/dehacked.c
659
src/dehacked.c
|
@ -371,7 +371,9 @@ static void clear_levels(void)
|
|||
// (no need to set num to 0, we're freeing the entire header shortly)
|
||||
Z_Free(mapheaderinfo[i]->customopts);
|
||||
|
||||
P_DeleteFlickies(i);
|
||||
P_DeleteGrades(i);
|
||||
|
||||
Z_Free(mapheaderinfo[i]);
|
||||
mapheaderinfo[i] = NULL;
|
||||
}
|
||||
|
@ -990,6 +992,34 @@ static const struct {
|
|||
{NULL, 0}
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const mobjtype_t type;
|
||||
} FLICKYTYPES[] = {
|
||||
{"BLUEBIRD", MT_FLICKY_01},
|
||||
{"RABBIT", MT_FLICKY_02},
|
||||
{"CHICKEN", MT_FLICKY_03},
|
||||
{"SEAL", MT_FLICKY_04},
|
||||
{"PIG", MT_FLICKY_05},
|
||||
{"CHIPMUNK", MT_FLICKY_06},
|
||||
{"PENGUIN", MT_FLICKY_07},
|
||||
{"FISH", MT_FLICKY_08},
|
||||
{"RAM", MT_FLICKY_09},
|
||||
{"PUFFIN", MT_FLICKY_10},
|
||||
{"COW", MT_FLICKY_11},
|
||||
{"RAT", MT_FLICKY_12},
|
||||
{"BEAR", MT_FLICKY_13},
|
||||
{"DOVE", MT_FLICKY_14},
|
||||
{"CAT", MT_FLICKY_15},
|
||||
{"CANARY", MT_FLICKY_16},
|
||||
{"a", 0}, // End of normal flickies - a lower case character so will never fastcmp valid with uppercase tmp
|
||||
//{"FLICKER", MT_FLICKER},
|
||||
{"SEED", MT_SEED},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
#define MAXFLICKIES 64
|
||||
|
||||
static void readlevelheader(MYFILE *f, INT32 num)
|
||||
{
|
||||
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
|
||||
|
@ -1088,8 +1118,82 @@ static void readlevelheader(MYFILE *f, INT32 num)
|
|||
// Now go to uppercase
|
||||
strupr(word2);
|
||||
|
||||
// List of flickies that are be freed in this map
|
||||
if (fastcmp(word, "FLICKYLIST") || fastcmp(word, "ANIMALLIST"))
|
||||
{
|
||||
if (fastcmp(word2, "NONE"))
|
||||
P_DeleteFlickies(num-1);
|
||||
else if (fastcmp(word2, "DEMO"))
|
||||
P_SetDemoFlickies(num-1);
|
||||
else if (fastcmp(word2, "ALL"))
|
||||
{
|
||||
mobjtype_t tmpflickies[MAXFLICKIES];
|
||||
|
||||
for (mapheaderinfo[num-1]->numFlickies = 0;
|
||||
((mapheaderinfo[num-1]->numFlickies < MAXFLICKIES) && FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type);
|
||||
mapheaderinfo[num-1]->numFlickies++)
|
||||
tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type;
|
||||
|
||||
if (mapheaderinfo[num-1]->numFlickies) // just in case...
|
||||
{
|
||||
size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies;
|
||||
mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL);
|
||||
M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mobjtype_t tmpflickies[MAXFLICKIES];
|
||||
mapheaderinfo[num-1]->numFlickies = 0;
|
||||
tmp = strtok(word2,",");
|
||||
// get up to the first MAXFLICKIES flickies
|
||||
do {
|
||||
if (mapheaderinfo[num-1]->numFlickies == MAXFLICKIES) // never going to get above that number
|
||||
{
|
||||
deh_warning("Level header %d: too many flickies\n", num);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fastncmp(tmp, "MT_", 3)) // support for specified mobjtypes...
|
||||
{
|
||||
i = get_mobjtype(tmp);
|
||||
if (!i)
|
||||
{
|
||||
//deh_warning("Level header %d: unknown flicky mobj type %s\n", num, tmp); -- no need for this line as get_mobjtype complains too
|
||||
continue;
|
||||
}
|
||||
tmpflickies[mapheaderinfo[num-1]->numFlickies] = i;
|
||||
}
|
||||
else // ...or a quick, limited selection of default flickies!
|
||||
{
|
||||
for (i = 0; FLICKYTYPES[i].name; i++)
|
||||
if (fastcmp(tmp, FLICKYTYPES[i].name))
|
||||
break;
|
||||
|
||||
if (!FLICKYTYPES[i].name)
|
||||
{
|
||||
deh_warning("Level header %d: unknown flicky selection %s\n", num, tmp);
|
||||
continue;
|
||||
}
|
||||
tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[i].type;
|
||||
}
|
||||
mapheaderinfo[num-1]->numFlickies++;
|
||||
} while ((tmp = strtok(NULL,",")) != NULL);
|
||||
|
||||
if (mapheaderinfo[num-1]->numFlickies)
|
||||
{
|
||||
size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies;
|
||||
mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL);
|
||||
// now we add them to the list!
|
||||
M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize);
|
||||
}
|
||||
else
|
||||
deh_warning("Level header %d: no valid flicky types found\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
// NiGHTS grades
|
||||
if (fastncmp(word, "GRADES", 6))
|
||||
else if (fastncmp(word, "GRADES", 6))
|
||||
{
|
||||
UINT8 mare = (UINT8)atoi(word + 6);
|
||||
|
||||
|
@ -1322,6 +1426,8 @@ static void readlevelheader(MYFILE *f, INT32 num)
|
|||
Z_Free(s);
|
||||
}
|
||||
|
||||
#undef MAXFLICKIES
|
||||
|
||||
static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
|
||||
{
|
||||
char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL);
|
||||
|
@ -1687,6 +1793,9 @@ static actionpointer_t actionpointers[] =
|
|||
{{A_WaterShield}, "A_WATERSHIELD"},
|
||||
{{A_ForceShield}, "A_FORCESHIELD"},
|
||||
{{A_PityShield}, "A_PITYSHIELD"},
|
||||
{{A_FlameShield}, "A_FLAMESHIELD"},
|
||||
{{A_BubbleShield}, "A_BUBBLESHIELD"},
|
||||
{{A_ThunderShield}, "A_THUNDERSHIELD"},
|
||||
{{A_GravityBox}, "A_GRAVITYBOX"},
|
||||
{{A_ScoreRise}, "A_SCORERISE"},
|
||||
{{A_ParticleSpawn}, "A_PARTICLESPAWN"},
|
||||
|
@ -1842,6 +1951,17 @@ static actionpointer_t actionpointers[] =
|
|||
{{A_BrakLobShot}, "A_BRAKLOBSHOT"},
|
||||
{{A_NapalmScatter}, "A_NAPALMSCATTER"},
|
||||
{{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"},
|
||||
{{A_FlickySpawn}, "A_FLICKYSPAWN"},
|
||||
{{A_FlickyAim}, "A_FLICKYAIM"},
|
||||
{{A_FlickyFly}, "A_FLICKYFLY"},
|
||||
{{A_FlickySoar}, "A_FLICKYSOAR"},
|
||||
{{A_FlickyCoast}, "A_FLICKYCOAST"},
|
||||
{{A_FlickyHop}, "A_FLICKYHOP"},
|
||||
{{A_FlickyFlounder}, "A_FLICKYFLOUNDER"},
|
||||
{{A_FlickyCheck}, "A_FLICKYCHECK"},
|
||||
{{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"},
|
||||
{{A_FlickyFlutter}, "A_FLICKYFLUTTER"},
|
||||
{{A_FlameParticle}, "A_FLAMEPARTICLE"},
|
||||
|
||||
{{NULL}, "NONE"},
|
||||
|
||||
|
@ -2778,7 +2898,7 @@ static void readpatch(MYFILE *f, const char *name, UINT16 wad)
|
|||
char *word2;
|
||||
char *tmp;
|
||||
INT32 i = 0, j = 0, value;
|
||||
texpatch_t patch = {0, 0, UINT16_MAX, UINT16_MAX};
|
||||
texpatch_t patch = {0, 0, UINT16_MAX, UINT16_MAX, 0};
|
||||
|
||||
// Jump to the texture this patch belongs to, which,
|
||||
// coincidentally, is always the last one on the buffer cache.
|
||||
|
@ -3378,11 +3498,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
|
|||
{
|
||||
if (i == 0 && word2[0] != '0') // If word2 isn't a number
|
||||
i = get_mobjtype(word2); // find a thing by name
|
||||
if (i < NUMMOBJTYPES && i >= 0)
|
||||
if (i < NUMMOBJTYPES && i > 0)
|
||||
readthing(f, i);
|
||||
else
|
||||
{
|
||||
deh_warning("Thing %d out of range (0 - %d)", i, NUMMOBJTYPES-1);
|
||||
deh_warning("Thing %d out of range (1 - %d)", i, NUMMOBJTYPES-1);
|
||||
ignorelines(f);
|
||||
}
|
||||
DEH_WriteUndoline(word, word2, UNDO_HEADER);
|
||||
|
@ -4279,6 +4399,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_GOOP1",
|
||||
"S_GOOP2",
|
||||
"S_GOOP3",
|
||||
"S_GOOPTRAIL",
|
||||
|
||||
// Boss 3
|
||||
"S_EGGMOBILE3_STND",
|
||||
|
@ -4834,7 +4955,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SPIKEBALL7",
|
||||
"S_SPIKEBALL8",
|
||||
|
||||
// Fire Shield's Spawn
|
||||
// Elemental Shield's Spawn
|
||||
"S_SPINFIRE1",
|
||||
"S_SPINFIRE2",
|
||||
"S_SPINFIRE3",
|
||||
|
@ -4855,7 +4976,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
// Starpost
|
||||
"S_STARPOST_IDLE",
|
||||
"S_STARPOST_FLASH",
|
||||
"S_STARPOST_STARTSPIN",
|
||||
"S_STARPOST_SPIN",
|
||||
"S_STARPOST_ENDSPIN",
|
||||
|
||||
// Big floating mine
|
||||
"S_BIGMINE1",
|
||||
|
@ -4908,6 +5031,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_RECYCLER_BOX",
|
||||
"S_SCORE1K_BOX",
|
||||
"S_SCORE10K_BOX",
|
||||
"S_FLAMEAURA_BOX",
|
||||
"S_BUBBLEWRAP_BOX",
|
||||
"S_THUNDERCOIN_BOX",
|
||||
|
||||
// Gold Repeat Monitor States (one per box)
|
||||
"S_PITY_GOLDBOX",
|
||||
|
@ -4920,6 +5046,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_INVULN_GOLDBOX",
|
||||
"S_EGGMAN_GOLDBOX",
|
||||
"S_GRAVITY_GOLDBOX",
|
||||
"S_FLAMEAURA_GOLDBOX",
|
||||
"S_BUBBLEWRAP_GOLDBOX",
|
||||
"S_THUNDERCOIN_GOLDBOX",
|
||||
|
||||
// Team Ring Boxes (these are special)
|
||||
"S_RING_REDBOX1",
|
||||
|
@ -4981,6 +5110,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SCORE10K_ICON1",
|
||||
"S_SCORE10K_ICON2",
|
||||
|
||||
"S_FLAMEAURA_ICON1",
|
||||
"S_FLAMEAURA_ICON2",
|
||||
|
||||
"S_BUBBLEWRAP_ICON1",
|
||||
"S_BUBBLEWRAP_ICON2",
|
||||
|
||||
"S_THUNDERCOIN_ICON1",
|
||||
"S_THUNDERCOIN_ICON2",
|
||||
|
||||
"S_ROCKET",
|
||||
|
||||
"S_LASER",
|
||||
|
@ -5022,21 +5160,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_DEMONFIRE6",
|
||||
|
||||
"S_GFZFLOWERA",
|
||||
"S_GFZFLOWERA2",
|
||||
|
||||
"S_GFZFLOWERB1",
|
||||
"S_GFZFLOWERB2",
|
||||
|
||||
"S_GFZFLOWERC1",
|
||||
"S_GFZFLOWERB",
|
||||
"S_GFZFLOWERC",
|
||||
|
||||
"S_BERRYBUSH",
|
||||
"S_BUSH",
|
||||
|
||||
// THZ Plant
|
||||
"S_THZPLANT1",
|
||||
"S_THZPLANT2",
|
||||
"S_THZPLANT3",
|
||||
"S_THZPLANT4",
|
||||
"S_THZFLOWERA",
|
||||
"S_THZFLOWERB",
|
||||
|
||||
// THZ Alarm
|
||||
"S_ALARM1",
|
||||
|
@ -5081,6 +5213,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_FLAME2",
|
||||
"S_FLAME3",
|
||||
"S_FLAME4",
|
||||
"S_FLAME5",
|
||||
"S_FLAME6",
|
||||
"S_FLAMEPARTICLE",
|
||||
|
||||
"S_FLAMEREST",
|
||||
|
||||
// Eggman Statue
|
||||
"S_EGGSTATUE1",
|
||||
|
@ -5142,36 +5279,13 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
// Spinning flame jets
|
||||
"S_FJSPINAXISA1", // Counter-clockwise
|
||||
"S_FJSPINAXISA2",
|
||||
"S_FJSPINAXISA3",
|
||||
"S_FJSPINAXISA4",
|
||||
"S_FJSPINAXISA5",
|
||||
"S_FJSPINAXISA6",
|
||||
"S_FJSPINAXISA7",
|
||||
"S_FJSPINAXISA8",
|
||||
"S_FJSPINAXISA9",
|
||||
"S_FJSPINHELPERA1",
|
||||
"S_FJSPINHELPERA2",
|
||||
"S_FJSPINHELPERA3",
|
||||
"S_FJSPINAXISB1", // Clockwise
|
||||
"S_FJSPINAXISB2",
|
||||
"S_FJSPINAXISB3",
|
||||
"S_FJSPINAXISB4",
|
||||
"S_FJSPINAXISB5",
|
||||
"S_FJSPINAXISB6",
|
||||
"S_FJSPINAXISB7",
|
||||
"S_FJSPINAXISB8",
|
||||
"S_FJSPINAXISB9",
|
||||
"S_FJSPINHELPERB1",
|
||||
"S_FJSPINHELPERB2",
|
||||
"S_FJSPINHELPERB3",
|
||||
|
||||
// Blade's flame
|
||||
"S_FLAMEJETFLAMEB1",
|
||||
"S_FLAMEJETFLAMEB2",
|
||||
"S_FLAMEJETFLAMEB3",
|
||||
"S_FLAMEJETFLAMEB4",
|
||||
"S_FLAMEJETFLAMEB5",
|
||||
"S_FLAMEJETFLAMEB6",
|
||||
|
||||
// Trapgoyles
|
||||
"S_TRAPGOYLE",
|
||||
|
@ -5266,8 +5380,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_BSZVINE_ORANGE",
|
||||
"S_BSZSHRUB",
|
||||
"S_BSZCLOVER",
|
||||
"S_BSZFISH",
|
||||
"S_BSZSUNFLOWER",
|
||||
"S_BIG_PALMTREE_TRUNK",
|
||||
"S_BIG_PALMTREE_TOP",
|
||||
"S_PALMTREE_TRUNK",
|
||||
"S_PALMTREE_TOP",
|
||||
|
||||
"S_DBALL1",
|
||||
"S_DBALL2",
|
||||
|
@ -5350,6 +5466,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_MAGN10",
|
||||
"S_MAGN11",
|
||||
"S_MAGN12",
|
||||
"S_MAGN13",
|
||||
|
||||
"S_FORC1",
|
||||
"S_FORC2",
|
||||
|
@ -5373,6 +5490,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_FORC19",
|
||||
"S_FORC20",
|
||||
|
||||
"S_FORC21",
|
||||
|
||||
"S_ELEM1",
|
||||
"S_ELEM2",
|
||||
"S_ELEM3",
|
||||
|
@ -5386,6 +5505,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_ELEM11",
|
||||
"S_ELEM12",
|
||||
|
||||
"S_ELEM13",
|
||||
"S_ELEM14",
|
||||
|
||||
"S_ELEMF1",
|
||||
"S_ELEMF2",
|
||||
"S_ELEMF3",
|
||||
|
@ -5394,6 +5516,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_ELEMF6",
|
||||
"S_ELEMF7",
|
||||
"S_ELEMF8",
|
||||
"S_ELEMF9",
|
||||
"S_ELEMF10",
|
||||
|
||||
"S_PITY1",
|
||||
"S_PITY2",
|
||||
|
@ -5406,6 +5530,84 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_PITY9",
|
||||
"S_PITY10",
|
||||
|
||||
"S_FIRS1",
|
||||
"S_FIRS2",
|
||||
"S_FIRS3",
|
||||
"S_FIRS4",
|
||||
"S_FIRS5",
|
||||
"S_FIRS6",
|
||||
"S_FIRS7",
|
||||
"S_FIRS8",
|
||||
"S_FIRS9",
|
||||
|
||||
"S_FIRS10",
|
||||
"S_FIRS11",
|
||||
|
||||
"S_FIRSB1",
|
||||
"S_FIRSB2",
|
||||
"S_FIRSB3",
|
||||
"S_FIRSB4",
|
||||
"S_FIRSB5",
|
||||
"S_FIRSB6",
|
||||
"S_FIRSB7",
|
||||
"S_FIRSB8",
|
||||
"S_FIRSB9",
|
||||
|
||||
"S_FIRSB10",
|
||||
|
||||
"S_BUBS1",
|
||||
"S_BUBS2",
|
||||
"S_BUBS3",
|
||||
"S_BUBS4",
|
||||
"S_BUBS5",
|
||||
"S_BUBS6",
|
||||
"S_BUBS7",
|
||||
"S_BUBS8",
|
||||
"S_BUBS9",
|
||||
|
||||
"S_BUBS10",
|
||||
"S_BUBS11",
|
||||
|
||||
"S_BUBSB1",
|
||||
"S_BUBSB2",
|
||||
"S_BUBSB3",
|
||||
"S_BUBSB4",
|
||||
|
||||
"S_BUBSB5",
|
||||
"S_BUBSB6",
|
||||
|
||||
"S_ZAPS1",
|
||||
"S_ZAPS2",
|
||||
"S_ZAPS3",
|
||||
"S_ZAPS4",
|
||||
"S_ZAPS5",
|
||||
"S_ZAPS6",
|
||||
"S_ZAPS7",
|
||||
"S_ZAPS8",
|
||||
"S_ZAPS9",
|
||||
"S_ZAPS10",
|
||||
"S_ZAPS11",
|
||||
"S_ZAPS12",
|
||||
"S_ZAPS13", // blank frame
|
||||
"S_ZAPS14",
|
||||
"S_ZAPS15",
|
||||
"S_ZAPS16",
|
||||
|
||||
"S_ZAPSB1", // blank frame
|
||||
"S_ZAPSB2",
|
||||
"S_ZAPSB3",
|
||||
"S_ZAPSB4",
|
||||
"S_ZAPSB5",
|
||||
"S_ZAPSB6",
|
||||
"S_ZAPSB7",
|
||||
"S_ZAPSB8",
|
||||
"S_ZAPSB9",
|
||||
"S_ZAPSB10",
|
||||
"S_ZAPSB11", // blank frame
|
||||
|
||||
// Thunder spark
|
||||
"S_THUNDERCOIN_SPARK",
|
||||
|
||||
// Invincibility Sparkles
|
||||
"S_IVSP",
|
||||
|
||||
|
@ -5416,43 +5618,133 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SSPK4",
|
||||
"S_SSPK5",
|
||||
|
||||
// Freed Birdie
|
||||
"S_BIRD1",
|
||||
"S_BIRD2",
|
||||
"S_BIRD3",
|
||||
// Flicky-sized bubble
|
||||
"S_FLICKY_BUBBLE",
|
||||
|
||||
// Freed Bunny
|
||||
"S_BUNNY1",
|
||||
"S_BUNNY2",
|
||||
"S_BUNNY3",
|
||||
"S_BUNNY4",
|
||||
"S_BUNNY5",
|
||||
"S_BUNNY6",
|
||||
"S_BUNNY7",
|
||||
"S_BUNNY8",
|
||||
"S_BUNNY9",
|
||||
"S_BUNNY10",
|
||||
// Bluebird
|
||||
"S_FLICKY_01_OUT",
|
||||
"S_FLICKY_01_FLAP1",
|
||||
"S_FLICKY_01_FLAP2",
|
||||
"S_FLICKY_01_FLAP3",
|
||||
|
||||
// Freed Mouse
|
||||
"S_MOUSE1",
|
||||
"S_MOUSE2",
|
||||
// Rabbit
|
||||
"S_FLICKY_02_OUT",
|
||||
"S_FLICKY_02_AIM",
|
||||
"S_FLICKY_02_HOP",
|
||||
"S_FLICKY_02_UP",
|
||||
"S_FLICKY_02_DOWN",
|
||||
|
||||
// Freed Chicken
|
||||
"S_CHICKEN1",
|
||||
"S_CHICKENHOP",
|
||||
"S_CHICKENFLY1",
|
||||
"S_CHICKENFLY2",
|
||||
// Chicken
|
||||
"S_FLICKY_03_OUT",
|
||||
"S_FLICKY_03_AIM",
|
||||
"S_FLICKY_03_HOP",
|
||||
"S_FLICKY_03_UP",
|
||||
"S_FLICKY_03_FLAP1",
|
||||
"S_FLICKY_03_FLAP2",
|
||||
|
||||
// Freed Cow
|
||||
"S_COW1",
|
||||
"S_COW2",
|
||||
"S_COW3",
|
||||
"S_COW4",
|
||||
// Seal
|
||||
"S_FLICKY_04_OUT",
|
||||
"S_FLICKY_04_AIM",
|
||||
"S_FLICKY_04_HOP",
|
||||
"S_FLICKY_04_UP",
|
||||
"S_FLICKY_04_DOWN",
|
||||
"S_FLICKY_04_SWIM1",
|
||||
"S_FLICKY_04_SWIM2",
|
||||
"S_FLICKY_04_SWIM3",
|
||||
"S_FLICKY_04_SWIM4",
|
||||
|
||||
// Red Birdie in Bubble
|
||||
"S_RBIRD1",
|
||||
"S_RBIRD2",
|
||||
"S_RBIRD3",
|
||||
// Pig
|
||||
"S_FLICKY_05_OUT",
|
||||
"S_FLICKY_05_AIM",
|
||||
"S_FLICKY_05_HOP",
|
||||
"S_FLICKY_05_UP",
|
||||
"S_FLICKY_05_DOWN",
|
||||
|
||||
// Chipmunk
|
||||
"S_FLICKY_06_OUT",
|
||||
"S_FLICKY_06_AIM",
|
||||
"S_FLICKY_06_HOP",
|
||||
"S_FLICKY_06_UP",
|
||||
"S_FLICKY_06_DOWN",
|
||||
|
||||
// Penguin
|
||||
"S_FLICKY_07_OUT",
|
||||
"S_FLICKY_07_AIML",
|
||||
"S_FLICKY_07_HOPL",
|
||||
"S_FLICKY_07_UPL",
|
||||
"S_FLICKY_07_DOWNL",
|
||||
"S_FLICKY_07_AIMR",
|
||||
"S_FLICKY_07_HOPR",
|
||||
"S_FLICKY_07_UPR",
|
||||
"S_FLICKY_07_DOWNR",
|
||||
"S_FLICKY_07_SWIM1",
|
||||
"S_FLICKY_07_SWIM2",
|
||||
"S_FLICKY_07_SWIM3",
|
||||
|
||||
// Fish
|
||||
"S_FLICKY_08_OUT",
|
||||
"S_FLICKY_08_AIM",
|
||||
"S_FLICKY_08_HOP",
|
||||
"S_FLICKY_08_FLAP1",
|
||||
"S_FLICKY_08_FLAP2",
|
||||
"S_FLICKY_08_FLAP3",
|
||||
"S_FLICKY_08_FLAP4",
|
||||
"S_FLICKY_08_SWIM1",
|
||||
"S_FLICKY_08_SWIM2",
|
||||
"S_FLICKY_08_SWIM3",
|
||||
"S_FLICKY_08_SWIM4",
|
||||
|
||||
// Ram
|
||||
"S_FLICKY_09_OUT",
|
||||
"S_FLICKY_09_AIM",
|
||||
"S_FLICKY_09_HOP",
|
||||
"S_FLICKY_09_UP",
|
||||
"S_FLICKY_09_DOWN",
|
||||
|
||||
// Puffin
|
||||
"S_FLICKY_10_OUT",
|
||||
"S_FLICKY_10_FLAP1",
|
||||
"S_FLICKY_10_FLAP2",
|
||||
|
||||
// Cow
|
||||
"S_FLICKY_11_OUT",
|
||||
"S_FLICKY_11_AIM",
|
||||
"S_FLICKY_11_RUN1",
|
||||
"S_FLICKY_11_RUN2",
|
||||
"S_FLICKY_11_RUN3",
|
||||
|
||||
// Rat
|
||||
"S_FLICKY_12_OUT",
|
||||
"S_FLICKY_12_AIM",
|
||||
"S_FLICKY_12_RUN1",
|
||||
"S_FLICKY_12_RUN2",
|
||||
"S_FLICKY_12_RUN3",
|
||||
|
||||
// Bear
|
||||
"S_FLICKY_13_OUT",
|
||||
"S_FLICKY_13_AIM",
|
||||
"S_FLICKY_13_HOP",
|
||||
"S_FLICKY_13_UP",
|
||||
"S_FLICKY_13_DOWN",
|
||||
|
||||
// Dove
|
||||
"S_FLICKY_14_OUT",
|
||||
"S_FLICKY_14_FLAP1",
|
||||
"S_FLICKY_14_FLAP2",
|
||||
"S_FLICKY_14_FLAP3",
|
||||
|
||||
// Cat
|
||||
"S_FLICKY_15_OUT",
|
||||
"S_FLICKY_15_AIM",
|
||||
"S_FLICKY_15_HOP",
|
||||
"S_FLICKY_15_UP",
|
||||
"S_FLICKY_15_DOWN",
|
||||
|
||||
// Canary
|
||||
"S_FLICKY_16_OUT",
|
||||
"S_FLICKY_16_FLAP1",
|
||||
"S_FLICKY_16_FLAP2",
|
||||
"S_FLICKY_16_FLAP3",
|
||||
|
||||
"S_YELLOWSPRING",
|
||||
"S_YELLOWSPRING2",
|
||||
|
@ -5566,6 +5858,20 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
|
||||
"S_WATERZAP",
|
||||
|
||||
// Spindash dust
|
||||
"S_SPINDUST1",
|
||||
"S_SPINDUST2",
|
||||
"S_SPINDUST3",
|
||||
"S_SPINDUST4",
|
||||
"S_SPINDUST_BUBBLE1",
|
||||
"S_SPINDUST_BUBBLE2",
|
||||
"S_SPINDUST_BUBBLE3",
|
||||
"S_SPINDUST_BUBBLE4",
|
||||
"S_SPINDUST_FIRE1",
|
||||
"S_SPINDUST_FIRE2",
|
||||
"S_SPINDUST_FIRE3",
|
||||
"S_SPINDUST_FIRE4",
|
||||
|
||||
"S_FOG1",
|
||||
"S_FOG2",
|
||||
"S_FOG3",
|
||||
|
@ -5796,20 +6102,19 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_FIREBALLEXP2",
|
||||
"S_FIREBALLEXP3",
|
||||
"S_SHELL",
|
||||
"S_SHELL1",
|
||||
"S_SHELL2",
|
||||
"S_SHELL3",
|
||||
"S_SHELL4",
|
||||
"S_PUMA1",
|
||||
"S_PUMA2",
|
||||
"S_PUMA3",
|
||||
"S_PUMA4",
|
||||
"S_PUMA5",
|
||||
"S_PUMA6",
|
||||
"S_HAMMER1",
|
||||
"S_HAMMER2",
|
||||
"S_HAMMER3",
|
||||
"S_HAMMER4",
|
||||
"S_PUMA_START1",
|
||||
"S_PUMA_START2",
|
||||
"S_PUMA_UP1",
|
||||
"S_PUMA_UP2",
|
||||
"S_PUMA_UP3",
|
||||
"S_PUMA_DOWN1",
|
||||
"S_PUMA_DOWN2",
|
||||
"S_PUMA_DOWN3",
|
||||
"S_PUMATRAIL1",
|
||||
"S_PUMATRAIL2",
|
||||
"S_PUMATRAIL3",
|
||||
"S_PUMATRAIL4",
|
||||
"S_HAMMER",
|
||||
"S_KOOPA1",
|
||||
"S_KOOPA2",
|
||||
"S_KOOPAFLAME1",
|
||||
|
@ -5938,6 +6243,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_NIGHTOPIANHELPER6",
|
||||
"S_NIGHTOPIANHELPER7",
|
||||
"S_NIGHTOPIANHELPER8",
|
||||
"S_NIGHTOPIANHELPER9",
|
||||
|
||||
"S_CRUMBLE1",
|
||||
"S_CRUMBLE2",
|
||||
|
@ -5961,10 +6267,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SPRK16",
|
||||
|
||||
// Robot Explosion
|
||||
"S_XPLD_FLICKY",
|
||||
"S_XPLD1",
|
||||
"S_XPLD2",
|
||||
"S_XPLD3",
|
||||
"S_XPLD4",
|
||||
"S_XPLD_EGGTRAP",
|
||||
|
||||
// Underwater Explosion
|
||||
"S_WPLD1",
|
||||
|
@ -6061,6 +6367,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_BOSSTANK2",
|
||||
"MT_BOSSSPIGOT",
|
||||
"MT_GOOP",
|
||||
"MT_GOOPTRAIL",
|
||||
|
||||
// Boss 3
|
||||
"MT_EGGMOBILE3",
|
||||
|
@ -6164,6 +6471,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_RECYCLER_BOX",
|
||||
"MT_SCORE1K_BOX",
|
||||
"MT_SCORE10K_BOX",
|
||||
"MT_FLAMEAURA_BOX",
|
||||
"MT_BUBBLEWRAP_BOX",
|
||||
"MT_THUNDERCOIN_BOX",
|
||||
|
||||
// Monitor boxes -- repeating (big) boxes
|
||||
"MT_PITY_GOLDBOX",
|
||||
|
@ -6176,6 +6486,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_INVULN_GOLDBOX",
|
||||
"MT_EGGMAN_GOLDBOX",
|
||||
"MT_GRAVITY_GOLDBOX",
|
||||
"MT_FLAMEAURA_GOLDBOX",
|
||||
"MT_BUBBLEWRAP_GOLDBOX",
|
||||
"MT_THUNDERCOIN_GOLDBOX",
|
||||
|
||||
// Monitor boxes -- special
|
||||
"MT_RING_REDBOX",
|
||||
|
@ -6198,6 +6511,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_RECYCLER_ICON",
|
||||
"MT_SCORE1K_ICON",
|
||||
"MT_SCORE10K_ICON",
|
||||
"MT_FLAMEAURA_ICON",
|
||||
"MT_BUBBLEWRAP_ICON",
|
||||
"MT_THUNDERCOIN_ICON",
|
||||
|
||||
// Projectiles
|
||||
"MT_ROCKET",
|
||||
|
@ -6221,7 +6537,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_BUSH",
|
||||
|
||||
// Techno Hill Scenery
|
||||
"MT_THZPLANT", // THZ Plant
|
||||
"MT_THZFLOWER1",
|
||||
"MT_THZFLOWER2",
|
||||
"MT_ALARM",
|
||||
|
||||
// Deep Sea Scenery
|
||||
|
@ -6237,6 +6554,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
// Castle Eggman Scenery
|
||||
"MT_CHAIN", // CEZ Chain
|
||||
"MT_FLAME", // Flame (has corona)
|
||||
"MT_FLAMEPARTICLE",
|
||||
"MT_EGGSTATUE", // Eggman Statue
|
||||
"MT_MACEPOINT", // Mace rotation point
|
||||
"MT_SWINGMACEPOINT", // Mace swinging point
|
||||
|
@ -6263,9 +6581,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_FLAMEJETFLAME",
|
||||
|
||||
"MT_FJSPINAXISA", // Counter-clockwise
|
||||
"MT_FJSPINHELPERA",
|
||||
"MT_FJSPINAXISB", // Clockwise
|
||||
"MT_FJSPINHELPERB",
|
||||
|
||||
"MT_FLAMEJETFLAMEB", // Blade's flame
|
||||
|
||||
|
@ -6342,30 +6658,46 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_BSZVINE_ORANGE",
|
||||
"MT_BSZSHRUB",
|
||||
"MT_BSZCLOVER",
|
||||
"MT_BSZFISH",
|
||||
"MT_BSZSUNFLOWER",
|
||||
"MT_BIG_PALMTREE_TRUNK",
|
||||
"MT_BIG_PALMTREE_TOP",
|
||||
"MT_PALMTREE_TRUNK",
|
||||
"MT_PALMTREE_TOP",
|
||||
|
||||
// Misc scenery
|
||||
"MT_DBALL",
|
||||
"MT_EGGSTATUE2",
|
||||
|
||||
// Powerup Indicators
|
||||
"MT_GREENORB", // Elemental shield mobj
|
||||
"MT_YELLOWORB", // Attract shield mobj
|
||||
"MT_BLUEORB", // Force shield mobj
|
||||
"MT_BLACKORB", // Armageddon shield mobj
|
||||
"MT_WHITEORB", // Whirlwind shield mobj
|
||||
"MT_PITYORB", // Pity shield mobj
|
||||
"MT_IVSP", // invincibility sparkles
|
||||
"MT_ELEMENTAL_ORB", // Elemental shield mobj
|
||||
"MT_ATTRACT_ORB", // Attract shield mobj
|
||||
"MT_FORCE_ORB", // Force shield mobj
|
||||
"MT_ARMAGEDDON_ORB", // Armageddon shield mobj
|
||||
"MT_WHIRLWIND_ORB", // Whirlwind shield mobj
|
||||
"MT_PITY_ORB", // Pity shield mobj
|
||||
"MT_FLAMEAURA_ORB", // Flame shield mobj
|
||||
"MT_BUBBLEWRAP_ORB", // Bubble shield mobj
|
||||
"MT_THUNDERCOIN_ORB", // Thunder shield mobj
|
||||
"MT_THUNDERCOIN_SPARK", // Thunder spark
|
||||
"MT_IVSP", // Invincibility sparkles
|
||||
"MT_SUPERSPARK", // Super Sonic Spark
|
||||
|
||||
// Freed Animals
|
||||
"MT_BIRD", // Birdie freed!
|
||||
"MT_BUNNY", // Bunny freed!
|
||||
"MT_MOUSE", // Mouse
|
||||
"MT_CHICKEN", // Chicken
|
||||
"MT_COW", // Cow
|
||||
"MT_REDBIRD", // Red Birdie in Bubble
|
||||
// Flickies
|
||||
"MT_FLICKY_01", // Bluebird
|
||||
"MT_FLICKY_02", // Rabbit
|
||||
"MT_FLICKY_03", // Chicken
|
||||
"MT_FLICKY_04", // Seal
|
||||
"MT_FLICKY_05", // Pig
|
||||
"MT_FLICKY_06", // Chipmunk
|
||||
"MT_FLICKY_07", // Penguin
|
||||
"MT_FLICKY_08", // Fish
|
||||
"MT_FLICKY_09", // Ram
|
||||
"MT_FLICKY_10", // Puffin
|
||||
"MT_FLICKY_11", // Cow
|
||||
"MT_FLICKY_12", // Rat
|
||||
"MT_FLICKY_13", // Bear
|
||||
"MT_FLICKY_14", // Dove
|
||||
"MT_FLICKY_15", // Cat
|
||||
"MT_FLICKY_16", // Canary
|
||||
|
||||
// Environmental Effects
|
||||
"MT_RAIN", // Rain
|
||||
|
@ -6376,6 +6708,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_MEDIUMBUBBLE", // medium bubble
|
||||
"MT_EXTRALARGEBUBBLE", // extra large bubble
|
||||
"MT_WATERZAP",
|
||||
"MT_SPINDUST", // Spindash dust
|
||||
"MT_TFOG",
|
||||
"MT_SEED",
|
||||
"MT_PARTICLE",
|
||||
|
@ -6434,6 +6767,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_FIREBALL",
|
||||
"MT_SHELL",
|
||||
"MT_PUMA",
|
||||
"MT_PUMATRAIL",
|
||||
"MT_HAMMER",
|
||||
"MT_KOOPA",
|
||||
"MT_KOOPAFLAME",
|
||||
|
@ -6544,35 +6878,36 @@ static const char *const MOBJFLAG_LIST[] = {
|
|||
|
||||
// \tMF2_(\S+).*// (.+) --> \t"\1", // \2
|
||||
static const char *const MOBJFLAG2_LIST[] = {
|
||||
"AXIS", // It's a NiGHTS axis! (For faster checking)
|
||||
"TWOD", // Moves like it's in a 2D level
|
||||
"DONTRESPAWN", // Don't respawn this object!
|
||||
"DONTDRAW", // Don't generate a vissprite
|
||||
"AUTOMATIC", // Thrown ring has automatic properties
|
||||
"RAILRING", // Thrown ring has rail properties
|
||||
"BOUNCERING", // Thrown ring has bounce properties
|
||||
"EXPLOSION", // Thrown ring has explosive properties
|
||||
"SCATTER", // Thrown ring has scatter properties
|
||||
"BEYONDTHEGRAVE",// Source of this missile has died and has since respawned.
|
||||
"SLIDEPUSH", // MF_PUSHABLE that pushes continuously.
|
||||
"CLASSICPUSH", // Drops straight down when object has negative Z.
|
||||
"STANDONME", // While not pushable, stand on me anyway.
|
||||
"INFLOAT", // Floating to a height for a move, don't auto float to target's height.
|
||||
"DEBRIS", // Splash ring from explosion ring
|
||||
"NIGHTSPULL", // Attracted from a paraloop
|
||||
"JUSTATTACKED", // can be pushed by other moving mobjs
|
||||
"FIRING", // turret fire
|
||||
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
|
||||
"SHADOW", // Fuzzy draw, makes targeting harder.
|
||||
"STRONGBOX", // Flag used for "strong" random monitors.
|
||||
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
|
||||
"SKULLFLY", // Special handling: skull in flight.
|
||||
"FRET", // Flashing from a previous hit
|
||||
"BOSSNOTRAP", // No Egg Trap after boss
|
||||
"BOSSFLEE", // Boss is fleeing!
|
||||
"BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
|
||||
"AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH
|
||||
"LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
|
||||
"AXIS", // It's a NiGHTS axis! (For faster checking)
|
||||
"TWOD", // Moves like it's in a 2D level
|
||||
"DONTRESPAWN", // Don't respawn this object!
|
||||
"DONTDRAW", // Don't generate a vissprite
|
||||
"AUTOMATIC", // Thrown ring has automatic properties
|
||||
"RAILRING", // Thrown ring has rail properties
|
||||
"BOUNCERING", // Thrown ring has bounce properties
|
||||
"EXPLOSION", // Thrown ring has explosive properties
|
||||
"SCATTER", // Thrown ring has scatter properties
|
||||
"BEYONDTHEGRAVE", // Source of this missile has died and has since respawned.
|
||||
"SLIDEPUSH", // MF_PUSHABLE that pushes continuously.
|
||||
"CLASSICPUSH", // Drops straight down when object has negative Z.
|
||||
"STANDONME", // While not pushable, stand on me anyway.
|
||||
"INFLOAT", // Floating to a height for a move, don't auto float to target's height.
|
||||
"DEBRIS", // Splash ring from explosion ring
|
||||
"NIGHTSPULL", // Attracted from a paraloop
|
||||
"JUSTATTACKED", // can be pushed by other moving mobjs
|
||||
"FIRING", // turret fire
|
||||
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
|
||||
"SHADOW", // Fuzzy draw, makes targeting harder.
|
||||
"STRONGBOX", // Flag used for "strong" random monitors.
|
||||
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
|
||||
"SKULLFLY", // Special handling: skull in flight.
|
||||
"FRET", // Flashing from a previous hit
|
||||
"BOSSNOTRAP", // No Egg Trap after boss
|
||||
"BOSSFLEE", // Boss is fleeing!
|
||||
"BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
|
||||
"AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH
|
||||
"LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
|
||||
"SHIELD", // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -6654,6 +6989,9 @@ static const char *const PLAYERFLAG_LIST[] = {
|
|||
/*** misc ***/
|
||||
"FORCESTRAFE", // Translate turn inputs into strafe inputs
|
||||
"ANALOGMODE", // Analog mode?
|
||||
"CANCARRY", // Can carry?
|
||||
"SHIELDABILITY", // Thokked with shield ability
|
||||
"FORCEJUMPDAMAGE", // Force jump damage
|
||||
|
||||
NULL // stop loop here.
|
||||
};
|
||||
|
@ -6998,20 +7336,27 @@ struct {
|
|||
{"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES},
|
||||
|
||||
// Shields
|
||||
// These ones use the lower 8 bits
|
||||
{"SH_NONE",SH_NONE},
|
||||
{"SH_JUMP",SH_JUMP},
|
||||
// Shield flags
|
||||
{"SH_PROTECTFIRE",SH_PROTECTFIRE},
|
||||
{"SH_PROTECTWATER",SH_PROTECTWATER},
|
||||
{"SH_PROTECTELECTRIC",SH_PROTECTELECTRIC},
|
||||
// Indivisible shields
|
||||
{"SH_PITY",SH_PITY},
|
||||
{"SH_WHIRLWIND",SH_WHIRLWIND},
|
||||
{"SH_ARMAGEDDON",SH_ARMAGEDDON},
|
||||
// normal shields that use flags
|
||||
{"SH_ATTRACT",SH_ATTRACT},
|
||||
{"SH_ELEMENTAL",SH_ELEMENTAL},
|
||||
{"SH_BOMB",SH_BOMB},
|
||||
// Sonic 3 shields
|
||||
{"SH_FLAMEAURA",SH_FLAMEAURA},
|
||||
{"SH_BUBBLEWRAP",SH_BUBBLEWRAP},
|
||||
{"SH_THUNDERCOIN",SH_THUNDERCOIN},
|
||||
{"SH_FLAMEAURA",SH_FLAMEAURA},
|
||||
{"SH_PITY",SH_PITY},
|
||||
// These ones are special and use the upper bits
|
||||
{"SH_FIREFLOWER",SH_FIREFLOWER}, // Lower bits are a normal shield stacked on top of the fire flower
|
||||
{"SH_FORCE",SH_FORCE}, // Lower bits are how many hits left, 0 is the last hit
|
||||
// Stack masks
|
||||
// The force shield uses the lower 8 bits to count how many extra hits are left.
|
||||
{"SH_FORCE",SH_FORCE},
|
||||
{"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only
|
||||
// Mostly for use with Mario mode.
|
||||
{"SH_FIREFLOWER", SH_FIREFLOWER},
|
||||
{"SH_STACK",SH_STACK},
|
||||
{"SH_NOSTACK",SH_NOSTACK},
|
||||
|
||||
|
@ -7045,6 +7390,7 @@ struct {
|
|||
{"SF_STOMPDAMAGE",SF_STOMPDAMAGE},
|
||||
{"SF_MARIODAMAGE",SF_MARIODAMAGE},
|
||||
{"SF_MACHINE",SF_MACHINE},
|
||||
{"SF_NOSPINDASHDUST",SF_NOSPINDASHDUST},
|
||||
|
||||
// Character abilities!
|
||||
// Primary
|
||||
|
@ -7093,6 +7439,22 @@ struct {
|
|||
{"PAL_MIXUP",PAL_MIXUP},
|
||||
{"PAL_RECYCLE",PAL_RECYCLE},
|
||||
{"PAL_NUKE",PAL_NUKE},
|
||||
// for P_DamageMobj
|
||||
//// Damage types
|
||||
{"DMG_WATER",DMG_WATER},
|
||||
{"DMG_FIRE",DMG_FIRE},
|
||||
{"DMG_ELECTRIC",DMG_ELECTRIC},
|
||||
{"DMG_SPIKE",DMG_SPIKE},
|
||||
{"DMG_NUKE",DMG_NUKE},
|
||||
//// Death types
|
||||
{"DMG_INSTAKILL",DMG_INSTAKILL},
|
||||
{"DMG_DROWNED",DMG_DROWNED},
|
||||
{"DMG_SPACEDROWN",DMG_SPACEDROWN},
|
||||
{"DMG_DEATHPIT",DMG_DEATHPIT},
|
||||
{"DMG_CRUSHED",DMG_CRUSHED},
|
||||
{"DMG_SPECTATOR",DMG_SPECTATOR},
|
||||
//// Masks
|
||||
{"DMG_DEATHMASK",DMG_DEATHMASK},
|
||||
|
||||
// Gametypes, for use with global var "gametype"
|
||||
{"GT_COOP",GT_COOP},
|
||||
|
@ -7201,6 +7563,11 @@ struct {
|
|||
{"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel
|
||||
{"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop.
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
// Node flags
|
||||
{"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf.
|
||||
#endif
|
||||
|
||||
// Angles
|
||||
{"ANG1",ANG1},
|
||||
{"ANG2",ANG2},
|
||||
|
@ -7346,7 +7713,7 @@ static mobjtype_t get_mobjtype(const char *word)
|
|||
if (fastcmp(word, MOBJTYPE_LIST[i]+3))
|
||||
return i;
|
||||
deh_warning("Couldn't find mobjtype named 'MT_%s'",word);
|
||||
return MT_BLUECRAWLA;
|
||||
return MT_NULL;
|
||||
}
|
||||
|
||||
static statenum_t get_state(const char *word)
|
||||
|
|
|
@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *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)
|
||||
{
|
||||
static CPUInfoFlags DOS_CPUInfo;
|
||||
|
|
|
@ -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.
|
||||
// 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".
|
||||
#define MODVERSION 21
|
||||
#define MODVERSION 22
|
||||
|
||||
// =========================================================================
|
||||
|
||||
|
@ -407,6 +407,7 @@ void M_StartupLocale(void);
|
|||
extern void *(*M_Memcpy)(void* dest, const void* src, size_t n) FUNCNONNULL;
|
||||
char *va(const char *format, ...) FUNCPRINTF;
|
||||
char *M_GetToken(const char *inputString);
|
||||
void M_UnGetToken(void);
|
||||
char *sizeu1(size_t num);
|
||||
char *sizeu2(size_t num);
|
||||
char *sizeu3(size_t num);
|
||||
|
@ -435,6 +436,9 @@ extern INT32 cv_debug;
|
|||
// Misc stuff for later...
|
||||
// =======================
|
||||
|
||||
// Modifier key variables, accessible anywhere
|
||||
extern UINT8 shiftdown, ctrldown, altdown;
|
||||
|
||||
// if we ever make our alloc stuff...
|
||||
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
|
||||
|
||||
|
|
|
@ -241,6 +241,10 @@ typedef struct
|
|||
UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below
|
||||
UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus
|
||||
|
||||
// Freed animals stuff.
|
||||
UINT8 numFlickies; ///< Internal. For freed flicky support.
|
||||
mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
|
||||
|
||||
// NiGHTS stuff.
|
||||
UINT8 numGradedMares; ///< Internal. For grade support.
|
||||
nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful.
|
||||
|
|
|
@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable)
|
|||
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) {}
|
||||
|
||||
#include "../sdl/dosstr.c"
|
||||
|
|
|
@ -974,7 +974,7 @@ static const char *credits[] = {
|
|||
"Scott \"Graue\" Feeney",
|
||||
"Nathan \"Jazz\" Giroux",
|
||||
"Thomas \"Shadow Hog\" Igoe",
|
||||
"\"Monster\" Iestyn Jealous",
|
||||
"Iestyn \"Monster Iestyn\" Jealous",
|
||||
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
|
||||
"John \"JTE\" Muniz",
|
||||
"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)
|
||||
"Andrew \"orospakr\" Clunis",
|
||||
"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",
|
||||
"Julio \"Chaos Zero 64\" Guir",
|
||||
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
|
||||
|
@ -1021,7 +1022,7 @@ static const char *credits[] = {
|
|||
"Paul \"Boinciel\" Clempson",
|
||||
"Cyan Helkaraxe",
|
||||
"Kepa \"Nev3r\" Iceta",
|
||||
"\"Monster\" Iestyn Jealous",
|
||||
"Iestyn \"Monster Iestyn\" Jealous",
|
||||
"Jarel \"Arrow\" Jones",
|
||||
"Stefan \"Stuf\" Rimalia",
|
||||
"Shane Mychal Sexton",
|
||||
|
|
|
@ -88,6 +88,7 @@ UINT8 modeattacking = ATTACKING_NONE;
|
|||
boolean disableSpeedAdjust = false;
|
||||
boolean imcontinuing = false;
|
||||
boolean runemeraldmanager = false;
|
||||
UINT16 emeraldspawndelay = 60*TICRATE;
|
||||
|
||||
// menu demo things
|
||||
UINT8 numDemos = 3;
|
||||
|
@ -2193,7 +2194,7 @@ void G_PlayerReborn(INT32 player)
|
|||
p->pflags |= PF_JUMPDOWN;
|
||||
|
||||
p->playerstate = PST_LIVE;
|
||||
p->health = 1; // 0 rings
|
||||
p->rings = 0; // 0 rings
|
||||
p->panim = PA_IDLE; // standing animation
|
||||
|
||||
if ((netgame || multiplayer) && !p->spectator)
|
||||
|
@ -4727,7 +4728,7 @@ void G_BeginRecording(void)
|
|||
// Don't do it.
|
||||
WRITEFIXED(demo_p, player->jumpfactor);
|
||||
|
||||
// Save netvar data (SONICCD, etc)
|
||||
// Save netvar data
|
||||
CV_SaveNetVars(&demo_p);
|
||||
|
||||
memset(&oldcmd,0,sizeof(oldcmd));
|
||||
|
|
|
@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
|
|||
{
|
||||
FOutVector v[4];
|
||||
FSurfaceInfo Surf;
|
||||
float sdupx, sdupy;
|
||||
|
||||
if (w < 0 || h < 0)
|
||||
return; // consistency w/ software
|
||||
|
@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
|
|||
// | /|
|
||||
// |/ |
|
||||
// 0--1
|
||||
v[0].x = v[3].x = (x - 160.0f)/160.0f;
|
||||
v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
|
||||
v[0].y = v[1].y = -(y - 100.0f)/100.0f;
|
||||
v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;
|
||||
sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
|
||||
sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.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
|
||||
v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;
|
||||
|
|
|
@ -271,6 +271,9 @@ light_t *t_lspr[NUMSPRITES] =
|
|||
&lspr[NOLIGHT], // SPR_TVRC
|
||||
&lspr[NOLIGHT], // SPR_TV1K
|
||||
&lspr[NOLIGHT], // SPR_TVTK
|
||||
&lspr[NOLIGHT], // SPR_TVFL
|
||||
&lspr[NOLIGHT], // SPR_TVBB
|
||||
&lspr[NOLIGHT], // SPR_TVZP
|
||||
|
||||
// Projectiles
|
||||
&lspr[NOLIGHT], // SPR_MISL
|
||||
|
@ -293,6 +296,7 @@ light_t *t_lspr[NUMSPRITES] =
|
|||
|
||||
// Techno Hill Scenery
|
||||
&lspr[NOLIGHT], // SPR_THZP
|
||||
&lspr[NOLIGHT], // SPR_FWR5
|
||||
&lspr[REDBALL_L], // SPR_ALRM
|
||||
|
||||
// Deep Sea Scenery
|
||||
|
@ -359,18 +363,32 @@ light_t *t_lspr[NUMSPRITES] =
|
|||
&lspr[NOLIGHT], // SPR_ELEM
|
||||
&lspr[NOLIGHT], // SPR_FORC
|
||||
&lspr[NOLIGHT], // SPR_PITY
|
||||
&lspr[NOLIGHT], // SPR_FIRS
|
||||
&lspr[NOLIGHT], // SPR_BUBS
|
||||
&lspr[NOLIGHT], // SPR_ZAPS
|
||||
&lspr[INVINCIBLE_L], // SPR_IVSP
|
||||
&lspr[SUPERSPARK_L], // SPR_SSPK
|
||||
|
||||
&lspr[NOLIGHT], // SPR_GOAL
|
||||
|
||||
// Freed Animals
|
||||
&lspr[NOLIGHT], // SPR_BIRD
|
||||
&lspr[NOLIGHT], // SPR_BUNY
|
||||
&lspr[NOLIGHT], // SPR_MOUS
|
||||
&lspr[NOLIGHT], // SPR_CHIC
|
||||
&lspr[NOLIGHT], // SPR_COWZ
|
||||
&lspr[NOLIGHT], // SPR_RBRD
|
||||
// Flickies
|
||||
&lspr[NOLIGHT], // SPR_FBUB
|
||||
&lspr[NOLIGHT], // SPR_FL01
|
||||
&lspr[NOLIGHT], // SPR_FL02
|
||||
&lspr[NOLIGHT], // SPR_FL03
|
||||
&lspr[NOLIGHT], // SPR_FL04
|
||||
&lspr[NOLIGHT], // SPR_FL05
|
||||
&lspr[NOLIGHT], // SPR_FL06
|
||||
&lspr[NOLIGHT], // SPR_FL07
|
||||
&lspr[NOLIGHT], // SPR_FL08
|
||||
&lspr[NOLIGHT], // SPR_FL09
|
||||
&lspr[NOLIGHT], // SPR_FL10
|
||||
&lspr[NOLIGHT], // SPR_FL11
|
||||
&lspr[NOLIGHT], // SPR_FL12
|
||||
&lspr[NOLIGHT], // SPR_FL13
|
||||
&lspr[NOLIGHT], // SPR_FL14
|
||||
&lspr[NOLIGHT], // SPR_FL15
|
||||
&lspr[NOLIGHT], // SPR_FL16
|
||||
|
||||
// Springs
|
||||
&lspr[NOLIGHT], // SPR_SPRY
|
||||
|
|
|
@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
|
||||
if (gr_backsector)
|
||||
{
|
||||
INT32 gr_toptexture, gr_bottomtexture;
|
||||
// two sided line
|
||||
if (gr_backsector->heightsec != -1)
|
||||
{
|
||||
|
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
}
|
||||
|
||||
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
|
||||
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
|
||||
|
||||
// check TOP TEXTURE
|
||||
if ((
|
||||
#ifdef ESLOPE
|
||||
worldhighslope < worldtopslope ||
|
||||
#endif
|
||||
worldhigh < worldtop
|
||||
) && texturetranslation[gr_sidedef->toptexture])
|
||||
) && gr_toptexture)
|
||||
{
|
||||
if (drawtextured)
|
||||
{
|
||||
fixed_t texturevpegtop; // top
|
||||
|
||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
|
||||
grTex = HWR_GetTexture(gr_toptexture);
|
||||
|
||||
// PEGGING
|
||||
if (gr_linedef->flags & ML_DONTPEGTOP)
|
||||
|
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
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
|
||||
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[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
|
||||
|
||||
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)
|
||||
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
|
||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||
}
|
||||
|
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#ifdef ESLOPE
|
||||
worldlowslope > worldbottomslope ||
|
||||
#endif
|
||||
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
|
||||
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
|
||||
{
|
||||
if (drawtextured)
|
||||
{
|
||||
fixed_t texturevpegbottom = 0; // bottom
|
||||
|
||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
|
||||
grTex = HWR_GetTexture(gr_bottomtexture);
|
||||
|
||||
// PEGGING
|
||||
#ifdef ESLOPE
|
||||
|
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
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
|
||||
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[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
|
||||
|
||||
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)
|
||||
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
|
||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||
}
|
||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
||||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||
if (gr_midtexture)
|
||||
{
|
||||
FBITFIELD blendmode;
|
||||
|
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
else
|
||||
{
|
||||
// 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 (drawtextured)
|
||||
|
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||
continue;
|
||||
|
||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||
|
||||
if (rover->master->flags & ML_TFERLINE)
|
||||
{
|
||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||
newline = rover->master->frontsector->lines[0] + linenum;
|
||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
|
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||
continue;
|
||||
|
||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||
|
||||
if (rover->master->flags & ML_TFERLINE)
|
||||
{
|
||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||
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
|
||||
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
||||
|
@ -4519,8 +4523,8 @@ static void HWR_SortVisSprites(void)
|
|||
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
|
||||
gr_vissprite_t *best = NULL;
|
||||
gr_vissprite_t unsorted;
|
||||
float bestdist;
|
||||
INT32 bestdispoffset;
|
||||
float bestdist = 0.0f;
|
||||
INT32 bestdispoffset = 0;
|
||||
|
||||
if (!gr_visspritecount)
|
||||
return;
|
||||
|
|
|
@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename)
|
|||
|
||||
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
|
||||
fseek(file, model->header.offsetSkins, SEEK_SET);
|
||||
if (model->header.numSkins > 0)
|
||||
|
@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename)
|
|||
md2_freeModel (model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
// read texture coordinates
|
||||
|
@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename)
|
|||
md2_freeModel (model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// read triangles
|
||||
|
@ -769,6 +782,7 @@ void HWR_InitMD2(void)
|
|||
md2_playermodels[s].grpatch = NULL;
|
||||
md2_playermodels[s].skin = -1;
|
||||
md2_playermodels[s].notfound = true;
|
||||
md2_playermodels[s].error = false;
|
||||
}
|
||||
for (i = 0; i < NUMSPRITES; i++)
|
||||
{
|
||||
|
@ -777,6 +791,7 @@ void HWR_InitMD2(void)
|
|||
md2_models[i].grpatch = NULL;
|
||||
md2_models[i].skin = -1;
|
||||
md2_models[i].notfound = true;
|
||||
md2_models[i].error = false;
|
||||
}
|
||||
|
||||
// read the md2.dat file
|
||||
|
@ -1378,6 +1393,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
|
|||
else
|
||||
md2 = &md2_models[spr->mobj->sprite];
|
||||
|
||||
if (md2->error)
|
||||
return; // we already failed loading this before :(
|
||||
if (!md2->model)
|
||||
{
|
||||
//CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]);
|
||||
|
@ -1391,6 +1408,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
|
|||
else
|
||||
{
|
||||
//CONS_Debug(DBG_RENDER, " FAILED\n");
|
||||
md2->error = true; // prevent endless fail
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ typedef struct
|
|||
void *blendgrpatch;
|
||||
boolean notfound;
|
||||
INT32 skin;
|
||||
boolean error;
|
||||
} md2_t;
|
||||
|
||||
extern md2_t md2_models[NUMSPRITES];
|
||||
|
|
|
@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
boolean action = false;
|
||||
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);
|
||||
flags = READUINT8(*p);
|
||||
|
@ -757,15 +757,8 @@ void HU_clearChatChars(void)
|
|||
//
|
||||
boolean HU_Responder(event_t *ev)
|
||||
{
|
||||
static boolean shiftdown = false;
|
||||
UINT8 c;
|
||||
|
||||
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
|
||||
{
|
||||
shiftdown = (ev->type == ev_keydown);
|
||||
return chat_on;
|
||||
}
|
||||
|
||||
if (ev->type != ev_keydown)
|
||||
return false;
|
||||
|
||||
|
@ -797,6 +790,14 @@ boolean HU_Responder(event_t *ev)
|
|||
}
|
||||
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;
|
||||
|
||||
// use console translations
|
||||
|
@ -1101,7 +1102,19 @@ void HU_Drawer(void)
|
|||
|
||||
// draw desynch text
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
@ -1198,7 +1211,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
|||
|
||||
V_DrawString(x + 20, y,
|
||||
((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
|
||||
| ((players[tab[i].num].health > 0) ? 0 : V_60TRANS)
|
||||
| ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS)
|
||||
| V_ALLOWLOWERCASE, tab[i].name);
|
||||
|
||||
// Draw emeralds
|
||||
|
@ -1208,7 +1221,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
|||
HU_DrawEmeralds(x-12,y+2,tab[i].emeralds);
|
||||
}
|
||||
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentPatch (x, y-4, V_80TRANS, livesback);
|
||||
else
|
||||
V_DrawSmallScaledPatch (x, y-4, 0, livesback);
|
||||
|
@ -1220,7 +1233,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
|||
V_DrawSmallScaledPatch(x, y-4, 0, superprefix[players[tab[i].num].skin]);
|
||||
else
|
||||
{
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentPatch(x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin]);
|
||||
else
|
||||
V_DrawSmallScaledPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin]);
|
||||
|
@ -1236,7 +1249,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
|||
else
|
||||
{
|
||||
colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentMappedPatch (x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin], colormap);
|
||||
else
|
||||
V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
|
||||
|
@ -1244,10 +1257,10 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
|||
}
|
||||
|
||||
if (G_GametypeUsesLives()) //show lives
|
||||
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%dx", players[tab[i].num].lives));
|
||||
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%dx", players[tab[i].num].lives));
|
||||
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
|
||||
{
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentPatch(x-32, y-4, V_60TRANS, tagico);
|
||||
else
|
||||
V_DrawSmallScaledPatch(x-32, y-4, 0, tagico);
|
||||
|
@ -1260,13 +1273,13 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
|||
if (players[tab[i].num].exiting)
|
||||
V_DrawRightAlignedString(x+240, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
|
||||
else
|
||||
V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count));
|
||||
V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count));
|
||||
}
|
||||
else
|
||||
V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
|
||||
V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
|
||||
}
|
||||
else
|
||||
V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count));
|
||||
V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count));
|
||||
|
||||
y += 16;
|
||||
}
|
||||
|
@ -1311,7 +1324,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
|
|||
strlcpy(name, tab[i].name, 9);
|
||||
V_DrawString(x + 20, y,
|
||||
((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
|
||||
| ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT)
|
||||
| ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT)
|
||||
| V_ALLOWLOWERCASE, name);
|
||||
|
||||
if (gametype == GT_CTF)
|
||||
|
@ -1337,12 +1350,12 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
|
|||
else
|
||||
{
|
||||
colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
|
||||
else
|
||||
V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
|
||||
}
|
||||
V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
|
||||
V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1367,7 +1380,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
|
|||
strlcpy(name, tab[i].name, 9);
|
||||
V_DrawString(x + 20, y,
|
||||
((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
|
||||
| ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT)
|
||||
| ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT)
|
||||
| V_ALLOWLOWERCASE, name);
|
||||
|
||||
if (G_GametypeUsesLives()) //show lives
|
||||
|
@ -1390,7 +1403,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
|
|||
V_DrawSmallScaledPatch (x, y-4, 0, superprefix[players[tab[i].num].skin]);
|
||||
else
|
||||
{
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]);
|
||||
else
|
||||
V_DrawSmallScaledPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]);
|
||||
|
@ -1406,7 +1419,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
|
|||
else
|
||||
{
|
||||
colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
|
||||
if (players[tab[i].num].health <= 0)
|
||||
if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0)
|
||||
V_DrawSmallTranslucentMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
|
||||
else
|
||||
V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
|
||||
|
@ -1421,13 +1434,13 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
|
|||
if (players[tab[i].num].exiting)
|
||||
V_DrawRightAlignedThinString(x+156, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
|
||||
else
|
||||
V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
|
||||
V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
|
||||
}
|
||||
else
|
||||
V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
|
||||
V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
|
||||
}
|
||||
else
|
||||
V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
|
||||
V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
|
||||
|
||||
y += 16;
|
||||
if (y > 160)
|
||||
|
|
|
@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
|
|||
|
||||
/** \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
|
||||
*/
|
||||
|
|
|
@ -296,6 +296,14 @@ char *I_GetEnv(const char *name);
|
|||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
97
src/i_tcp.c
97
src/i_tcp.c
|
@ -179,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
|
|||
#include "i_system.h"
|
||||
#include "i_net.h"
|
||||
#include "d_net.h"
|
||||
#include "d_netfil.h"
|
||||
#include "i_tcp.h"
|
||||
#include "m_argv.h"
|
||||
|
||||
|
@ -482,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
|||
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 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)
|
||||
{
|
||||
SINT8 j;
|
||||
|
@ -506,13 +498,81 @@ static void cleanupnodes(void)
|
|||
|
||||
// Why can't I start at zero?
|
||||
for (j = 1; j < MAXNETNODES; j++)
|
||||
//if (!(nodeingame[j] || SV_SendingFile(j)))
|
||||
if (!nodeingame[j])
|
||||
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
|
||||
|
||||
#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;
|
||||
int j;
|
||||
|
@ -535,13 +595,12 @@ static void SOCK_Get(void)
|
|||
doomcom->remotenode = (INT16)j; // good packet from a game player
|
||||
doomcom->datalength = (INT16)c;
|
||||
nodesocket[j] = mysockets[n];
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// not found
|
||||
|
||||
// find a free slot
|
||||
cleanupnodes();
|
||||
j = getfreenode();
|
||||
if (j > 0)
|
||||
{
|
||||
|
@ -564,14 +623,15 @@ static void SOCK_Get(void)
|
|||
}
|
||||
if (i == numbans)
|
||||
SOCK_bannednode[j] = false;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
DEBFILE("New node detected: No more free slots\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
doomcom->remotenode = -1; // no packet
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1256,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
|||
gaie = I_getaddrinfo(address, port, &hints, &ai);
|
||||
if (gaie == 0)
|
||||
{
|
||||
cleanupnodes();
|
||||
newnode = getfreenode();
|
||||
}
|
||||
if (newnode == -1)
|
||||
|
|
1880
src/info.c
1880
src/info.c
File diff suppressed because it is too large
Load diff
470
src/info.h
470
src/info.h
|
@ -56,6 +56,9 @@ void A_BombShield(); // Obtained Bomb Shield
|
|||
void A_WaterShield(); // Obtained Water Shield
|
||||
void A_ForceShield(); // Obtained Force Shield
|
||||
void A_PityShield(); // Obtained Pity Shield. We're... sorry.
|
||||
void A_FlameShield(); // Obtained Flame Shield
|
||||
void A_BubbleShield(); // Obtained Bubble Shield
|
||||
void A_ThunderShield(); // Obtained Thunder Shield
|
||||
void A_GravityBox();
|
||||
void A_ScoreRise(); // Rise the score logo
|
||||
void A_ParticleSpawn();
|
||||
|
@ -211,6 +214,17 @@ void A_BrakFireShot();
|
|||
void A_BrakLobShot();
|
||||
void A_NapalmScatter();
|
||||
void A_SpawnFreshCopy();
|
||||
void A_FlickySpawn();
|
||||
void A_FlickyAim();
|
||||
void A_FlickyFly();
|
||||
void A_FlickySoar();
|
||||
void A_FlickyCoast();
|
||||
void A_FlickyHop();
|
||||
void A_FlickyFlounder();
|
||||
void A_FlickyCheck();
|
||||
void A_FlickyHeightCheck();
|
||||
void A_FlickyFlutter();
|
||||
void A_FlameParticle();
|
||||
|
||||
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1
|
||||
#define NUMMOBJFREESLOTS 256
|
||||
|
@ -351,6 +365,9 @@ typedef enum sprite
|
|||
SPR_TVRC, // ReCycler
|
||||
SPR_TV1K, // 1,000 points (1 K)
|
||||
SPR_TVTK, // 10,000 points (Ten K)
|
||||
SPR_TVFL, // FLame shield
|
||||
SPR_TVBB, // BuBble shield
|
||||
SPR_TVZP, // Thunder shield (ZaP)
|
||||
|
||||
// Projectiles
|
||||
SPR_MISL,
|
||||
|
@ -372,7 +389,8 @@ typedef enum sprite
|
|||
SPR_BUS2, // GFZ Bush w/o berries
|
||||
|
||||
// Techno Hill Scenery
|
||||
SPR_THZP, // Techno Hill Zone Plant
|
||||
SPR_THZP, // THZ1 Flower
|
||||
SPR_FWR5, // Another flower
|
||||
SPR_ALRM, // THZ2 Alarm
|
||||
|
||||
// Deep Sea Scenery
|
||||
|
@ -435,18 +453,32 @@ typedef enum sprite
|
|||
SPR_ELEM, // Elemental Shield Orb and Fire
|
||||
SPR_FORC, // Force Shield Orb
|
||||
SPR_PITY, // Pity Shield Orb
|
||||
SPR_FIRS, // Flame Shield Orb
|
||||
SPR_BUBS, // Bubble Shield Orb
|
||||
SPR_ZAPS, // Thunder Shield Orb
|
||||
SPR_IVSP, // invincibility sparkles
|
||||
SPR_SSPK, // Super Sonic Spark
|
||||
|
||||
SPR_GOAL, // Special Stage goal (here because lol NiGHTS)
|
||||
|
||||
// Freed Animals
|
||||
SPR_BIRD, // Birdie freed!
|
||||
SPR_BUNY, // Bunny freed!
|
||||
SPR_MOUS, // Mouse
|
||||
SPR_CHIC, // Chicken
|
||||
SPR_COWZ, // Cow
|
||||
SPR_RBRD, // Red Birdie in Bubble
|
||||
// Flickies
|
||||
SPR_FBUB, // Flicky-sized bubble
|
||||
SPR_FL01, // Bluebird
|
||||
SPR_FL02, // Rabbit
|
||||
SPR_FL03, // Chicken
|
||||
SPR_FL04, // Seal
|
||||
SPR_FL05, // Pig
|
||||
SPR_FL06, // Chipmunk
|
||||
SPR_FL07, // Penguin
|
||||
SPR_FL08, // Fish
|
||||
SPR_FL09, // Ram
|
||||
SPR_FL10, // Puffin
|
||||
SPR_FL11, // Cow
|
||||
SPR_FL12, // Rat
|
||||
SPR_FL13, // Bear
|
||||
SPR_FL14, // Dove
|
||||
SPR_FL15, // Cat
|
||||
SPR_FL16, // Canary
|
||||
|
||||
// Springs
|
||||
SPR_SPRY, // yellow spring
|
||||
|
@ -466,6 +498,8 @@ typedef enum sprite
|
|||
SPR_SMOK,
|
||||
SPR_BUBL, // Bubble
|
||||
SPR_WZAP,
|
||||
SPR_DUST, // Spindash dust
|
||||
SPR_FPRT, // Spindash dust (flame)
|
||||
SPR_TFOG, // Teleport Fog
|
||||
SPR_SEED, // Sonic CD flower seed
|
||||
SPR_PRTL, // Particle (for fans, etc.)
|
||||
|
@ -1168,6 +1202,7 @@ typedef enum state
|
|||
S_GOOP1,
|
||||
S_GOOP2,
|
||||
S_GOOP3,
|
||||
S_GOOPTRAIL,
|
||||
|
||||
// Boss 3
|
||||
S_EGGMOBILE3_STND,
|
||||
|
@ -1723,7 +1758,7 @@ typedef enum state
|
|||
S_SPIKEBALL7,
|
||||
S_SPIKEBALL8,
|
||||
|
||||
// Fire Shield's Spawn
|
||||
// Elemental Shield's Spawn
|
||||
S_SPINFIRE1,
|
||||
S_SPINFIRE2,
|
||||
S_SPINFIRE3,
|
||||
|
@ -1744,7 +1779,9 @@ typedef enum state
|
|||
// Starpost
|
||||
S_STARPOST_IDLE,
|
||||
S_STARPOST_FLASH,
|
||||
S_STARPOST_STARTSPIN,
|
||||
S_STARPOST_SPIN,
|
||||
S_STARPOST_ENDSPIN,
|
||||
|
||||
// Big floating mine
|
||||
S_BIGMINE1,
|
||||
|
@ -1797,6 +1834,9 @@ typedef enum state
|
|||
S_RECYCLER_BOX,
|
||||
S_SCORE1K_BOX,
|
||||
S_SCORE10K_BOX,
|
||||
S_FLAMEAURA_BOX,
|
||||
S_BUBBLEWRAP_BOX,
|
||||
S_THUNDERCOIN_BOX,
|
||||
|
||||
// Gold Repeat Monitor States (one per box)
|
||||
S_PITY_GOLDBOX,
|
||||
|
@ -1809,6 +1849,9 @@ typedef enum state
|
|||
S_INVULN_GOLDBOX,
|
||||
S_EGGMAN_GOLDBOX,
|
||||
S_GRAVITY_GOLDBOX,
|
||||
S_FLAMEAURA_GOLDBOX,
|
||||
S_BUBBLEWRAP_GOLDBOX,
|
||||
S_THUNDERCOIN_GOLDBOX,
|
||||
|
||||
// Team Ring Boxes (these are special)
|
||||
S_RING_REDBOX1,
|
||||
|
@ -1870,6 +1913,15 @@ typedef enum state
|
|||
S_SCORE10K_ICON1,
|
||||
S_SCORE10K_ICON2,
|
||||
|
||||
S_FLAMEAURA_ICON1,
|
||||
S_FLAMEAURA_ICON2,
|
||||
|
||||
S_BUBBLEWRAP_ICON1,
|
||||
S_BUBBLEWRAP_ICON2,
|
||||
|
||||
S_THUNDERCOIN_ICON1,
|
||||
S_THUNDERCOIN_ICON2,
|
||||
|
||||
// ---
|
||||
|
||||
S_ROCKET,
|
||||
|
@ -1913,21 +1965,15 @@ typedef enum state
|
|||
S_DEMONFIRE6,
|
||||
|
||||
S_GFZFLOWERA,
|
||||
S_GFZFLOWERA2,
|
||||
|
||||
S_GFZFLOWERB1,
|
||||
S_GFZFLOWERB2,
|
||||
|
||||
S_GFZFLOWERC1,
|
||||
S_GFZFLOWERB,
|
||||
S_GFZFLOWERC,
|
||||
|
||||
S_BERRYBUSH,
|
||||
S_BUSH,
|
||||
|
||||
// THZ Plant
|
||||
S_THZPLANT1,
|
||||
S_THZPLANT2,
|
||||
S_THZPLANT3,
|
||||
S_THZPLANT4,
|
||||
S_THZFLOWERA,
|
||||
S_THZFLOWERB,
|
||||
|
||||
// THZ Alarm
|
||||
S_ALARM1,
|
||||
|
@ -1972,6 +2018,11 @@ typedef enum state
|
|||
S_FLAME2,
|
||||
S_FLAME3,
|
||||
S_FLAME4,
|
||||
S_FLAME5,
|
||||
S_FLAME6,
|
||||
S_FLAMEPARTICLE,
|
||||
|
||||
S_FLAMEREST,
|
||||
|
||||
// Eggman Statue
|
||||
S_EGGSTATUE1,
|
||||
|
@ -2033,36 +2084,13 @@ typedef enum state
|
|||
// Spinning flame jets
|
||||
S_FJSPINAXISA1, // Counter-clockwise
|
||||
S_FJSPINAXISA2,
|
||||
S_FJSPINAXISA3,
|
||||
S_FJSPINAXISA4,
|
||||
S_FJSPINAXISA5,
|
||||
S_FJSPINAXISA6,
|
||||
S_FJSPINAXISA7,
|
||||
S_FJSPINAXISA8,
|
||||
S_FJSPINAXISA9,
|
||||
S_FJSPINHELPERA1,
|
||||
S_FJSPINHELPERA2,
|
||||
S_FJSPINHELPERA3,
|
||||
S_FJSPINAXISB1, // Clockwise
|
||||
S_FJSPINAXISB2,
|
||||
S_FJSPINAXISB3,
|
||||
S_FJSPINAXISB4,
|
||||
S_FJSPINAXISB5,
|
||||
S_FJSPINAXISB6,
|
||||
S_FJSPINAXISB7,
|
||||
S_FJSPINAXISB8,
|
||||
S_FJSPINAXISB9,
|
||||
S_FJSPINHELPERB1,
|
||||
S_FJSPINHELPERB2,
|
||||
S_FJSPINHELPERB3,
|
||||
|
||||
// Blade's flame
|
||||
S_FLAMEJETFLAMEB1,
|
||||
S_FLAMEJETFLAMEB2,
|
||||
S_FLAMEJETFLAMEB3,
|
||||
S_FLAMEJETFLAMEB4,
|
||||
S_FLAMEJETFLAMEB5,
|
||||
S_FLAMEJETFLAMEB6,
|
||||
|
||||
// Trapgoyles
|
||||
S_TRAPGOYLE,
|
||||
|
@ -2157,8 +2185,10 @@ typedef enum state
|
|||
S_BSZVINE_ORANGE,
|
||||
S_BSZSHRUB,
|
||||
S_BSZCLOVER,
|
||||
S_BSZFISH,
|
||||
S_BSZSUNFLOWER,
|
||||
S_BIG_PALMTREE_TRUNK,
|
||||
S_BIG_PALMTREE_TOP,
|
||||
S_PALMTREE_TRUNK,
|
||||
S_PALMTREE_TOP,
|
||||
|
||||
S_DBALL1,
|
||||
S_DBALL2,
|
||||
|
@ -2241,6 +2271,7 @@ typedef enum state
|
|||
S_MAGN10,
|
||||
S_MAGN11,
|
||||
S_MAGN12,
|
||||
S_MAGN13,
|
||||
|
||||
S_FORC1,
|
||||
S_FORC2,
|
||||
|
@ -2264,6 +2295,8 @@ typedef enum state
|
|||
S_FORC19,
|
||||
S_FORC20,
|
||||
|
||||
S_FORC21,
|
||||
|
||||
S_ELEM1,
|
||||
S_ELEM2,
|
||||
S_ELEM3,
|
||||
|
@ -2277,6 +2310,9 @@ typedef enum state
|
|||
S_ELEM11,
|
||||
S_ELEM12,
|
||||
|
||||
S_ELEM13,
|
||||
S_ELEM14,
|
||||
|
||||
S_ELEMF1,
|
||||
S_ELEMF2,
|
||||
S_ELEMF3,
|
||||
|
@ -2285,6 +2321,8 @@ typedef enum state
|
|||
S_ELEMF6,
|
||||
S_ELEMF7,
|
||||
S_ELEMF8,
|
||||
S_ELEMF9,
|
||||
S_ELEMF10,
|
||||
|
||||
S_PITY1,
|
||||
S_PITY2,
|
||||
|
@ -2297,6 +2335,84 @@ typedef enum state
|
|||
S_PITY9,
|
||||
S_PITY10,
|
||||
|
||||
S_FIRS1,
|
||||
S_FIRS2,
|
||||
S_FIRS3,
|
||||
S_FIRS4,
|
||||
S_FIRS5,
|
||||
S_FIRS6,
|
||||
S_FIRS7,
|
||||
S_FIRS8,
|
||||
S_FIRS9,
|
||||
|
||||
S_FIRS10,
|
||||
S_FIRS11,
|
||||
|
||||
S_FIRSB1,
|
||||
S_FIRSB2,
|
||||
S_FIRSB3,
|
||||
S_FIRSB4,
|
||||
S_FIRSB5,
|
||||
S_FIRSB6,
|
||||
S_FIRSB7,
|
||||
S_FIRSB8,
|
||||
S_FIRSB9,
|
||||
|
||||
S_FIRSB10,
|
||||
|
||||
S_BUBS1,
|
||||
S_BUBS2,
|
||||
S_BUBS3,
|
||||
S_BUBS4,
|
||||
S_BUBS5,
|
||||
S_BUBS6,
|
||||
S_BUBS7,
|
||||
S_BUBS8,
|
||||
S_BUBS9,
|
||||
|
||||
S_BUBS10,
|
||||
S_BUBS11,
|
||||
|
||||
S_BUBSB1,
|
||||
S_BUBSB2,
|
||||
S_BUBSB3,
|
||||
S_BUBSB4,
|
||||
|
||||
S_BUBSB5,
|
||||
S_BUBSB6,
|
||||
|
||||
S_ZAPS1,
|
||||
S_ZAPS2,
|
||||
S_ZAPS3,
|
||||
S_ZAPS4,
|
||||
S_ZAPS5,
|
||||
S_ZAPS6,
|
||||
S_ZAPS7,
|
||||
S_ZAPS8,
|
||||
S_ZAPS9,
|
||||
S_ZAPS10,
|
||||
S_ZAPS11,
|
||||
S_ZAPS12,
|
||||
S_ZAPS13, // blank frame
|
||||
S_ZAPS14,
|
||||
S_ZAPS15,
|
||||
S_ZAPS16,
|
||||
|
||||
S_ZAPSB1, // blank frame
|
||||
S_ZAPSB2,
|
||||
S_ZAPSB3,
|
||||
S_ZAPSB4,
|
||||
S_ZAPSB5,
|
||||
S_ZAPSB6,
|
||||
S_ZAPSB7,
|
||||
S_ZAPSB8,
|
||||
S_ZAPSB9,
|
||||
S_ZAPSB10,
|
||||
S_ZAPSB11, // blank frame
|
||||
|
||||
//Thunder spark
|
||||
S_THUNDERCOIN_SPARK,
|
||||
|
||||
// Invincibility Sparkles
|
||||
S_IVSP,
|
||||
|
||||
|
@ -2307,43 +2423,133 @@ typedef enum state
|
|||
S_SSPK4,
|
||||
S_SSPK5,
|
||||
|
||||
// Freed Birdie
|
||||
S_BIRD1,
|
||||
S_BIRD2,
|
||||
S_BIRD3,
|
||||
// Flicky-sized bubble
|
||||
S_FLICKY_BUBBLE,
|
||||
|
||||
// Freed Bunny
|
||||
S_BUNNY1,
|
||||
S_BUNNY2,
|
||||
S_BUNNY3,
|
||||
S_BUNNY4,
|
||||
S_BUNNY5,
|
||||
S_BUNNY6,
|
||||
S_BUNNY7,
|
||||
S_BUNNY8,
|
||||
S_BUNNY9,
|
||||
S_BUNNY10,
|
||||
// Bluebird
|
||||
S_FLICKY_01_OUT,
|
||||
S_FLICKY_01_FLAP1,
|
||||
S_FLICKY_01_FLAP2,
|
||||
S_FLICKY_01_FLAP3,
|
||||
|
||||
// Freed Mouse
|
||||
S_MOUSE1,
|
||||
S_MOUSE2,
|
||||
// Rabbit
|
||||
S_FLICKY_02_OUT,
|
||||
S_FLICKY_02_AIM,
|
||||
S_FLICKY_02_HOP,
|
||||
S_FLICKY_02_UP,
|
||||
S_FLICKY_02_DOWN,
|
||||
|
||||
// Freed Chicken
|
||||
S_CHICKEN1,
|
||||
S_CHICKENHOP,
|
||||
S_CHICKENFLY1,
|
||||
S_CHICKENFLY2,
|
||||
// Chicken
|
||||
S_FLICKY_03_OUT,
|
||||
S_FLICKY_03_AIM,
|
||||
S_FLICKY_03_HOP,
|
||||
S_FLICKY_03_UP,
|
||||
S_FLICKY_03_FLAP1,
|
||||
S_FLICKY_03_FLAP2,
|
||||
|
||||
// Freed Cow
|
||||
S_COW1,
|
||||
S_COW2,
|
||||
S_COW3,
|
||||
S_COW4,
|
||||
// Seal
|
||||
S_FLICKY_04_OUT,
|
||||
S_FLICKY_04_AIM,
|
||||
S_FLICKY_04_HOP,
|
||||
S_FLICKY_04_UP,
|
||||
S_FLICKY_04_DOWN,
|
||||
S_FLICKY_04_SWIM1,
|
||||
S_FLICKY_04_SWIM2,
|
||||
S_FLICKY_04_SWIM3,
|
||||
S_FLICKY_04_SWIM4,
|
||||
|
||||
// Red Birdie in Bubble
|
||||
S_RBIRD1,
|
||||
S_RBIRD2,
|
||||
S_RBIRD3,
|
||||
// Pig
|
||||
S_FLICKY_05_OUT,
|
||||
S_FLICKY_05_AIM,
|
||||
S_FLICKY_05_HOP,
|
||||
S_FLICKY_05_UP,
|
||||
S_FLICKY_05_DOWN,
|
||||
|
||||
// Chipmunk
|
||||
S_FLICKY_06_OUT,
|
||||
S_FLICKY_06_AIM,
|
||||
S_FLICKY_06_HOP,
|
||||
S_FLICKY_06_UP,
|
||||
S_FLICKY_06_DOWN,
|
||||
|
||||
// Penguin
|
||||
S_FLICKY_07_OUT,
|
||||
S_FLICKY_07_AIML,
|
||||
S_FLICKY_07_HOPL,
|
||||
S_FLICKY_07_UPL,
|
||||
S_FLICKY_07_DOWNL,
|
||||
S_FLICKY_07_AIMR,
|
||||
S_FLICKY_07_HOPR,
|
||||
S_FLICKY_07_UPR,
|
||||
S_FLICKY_07_DOWNR,
|
||||
S_FLICKY_07_SWIM1,
|
||||
S_FLICKY_07_SWIM2,
|
||||
S_FLICKY_07_SWIM3,
|
||||
|
||||
// Fish
|
||||
S_FLICKY_08_OUT,
|
||||
S_FLICKY_08_AIM,
|
||||
S_FLICKY_08_HOP,
|
||||
S_FLICKY_08_FLAP1,
|
||||
S_FLICKY_08_FLAP2,
|
||||
S_FLICKY_08_FLAP3,
|
||||
S_FLICKY_08_FLAP4,
|
||||
S_FLICKY_08_SWIM1,
|
||||
S_FLICKY_08_SWIM2,
|
||||
S_FLICKY_08_SWIM3,
|
||||
S_FLICKY_08_SWIM4,
|
||||
|
||||
// Ram
|
||||
S_FLICKY_09_OUT,
|
||||
S_FLICKY_09_AIM,
|
||||
S_FLICKY_09_HOP,
|
||||
S_FLICKY_09_UP,
|
||||
S_FLICKY_09_DOWN,
|
||||
|
||||
// Puffin
|
||||
S_FLICKY_10_OUT,
|
||||
S_FLICKY_10_FLAP1,
|
||||
S_FLICKY_10_FLAP2,
|
||||
|
||||
// Cow
|
||||
S_FLICKY_11_OUT,
|
||||
S_FLICKY_11_AIM,
|
||||
S_FLICKY_11_RUN1,
|
||||
S_FLICKY_11_RUN2,
|
||||
S_FLICKY_11_RUN3,
|
||||
|
||||
// Rat
|
||||
S_FLICKY_12_OUT,
|
||||
S_FLICKY_12_AIM,
|
||||
S_FLICKY_12_RUN1,
|
||||
S_FLICKY_12_RUN2,
|
||||
S_FLICKY_12_RUN3,
|
||||
|
||||
// Bear
|
||||
S_FLICKY_13_OUT,
|
||||
S_FLICKY_13_AIM,
|
||||
S_FLICKY_13_HOP,
|
||||
S_FLICKY_13_UP,
|
||||
S_FLICKY_13_DOWN,
|
||||
|
||||
// Dove
|
||||
S_FLICKY_14_OUT,
|
||||
S_FLICKY_14_FLAP1,
|
||||
S_FLICKY_14_FLAP2,
|
||||
S_FLICKY_14_FLAP3,
|
||||
|
||||
// Cat
|
||||
S_FLICKY_15_OUT,
|
||||
S_FLICKY_15_AIM,
|
||||
S_FLICKY_15_HOP,
|
||||
S_FLICKY_15_UP,
|
||||
S_FLICKY_15_DOWN,
|
||||
|
||||
// Canary
|
||||
S_FLICKY_16_OUT,
|
||||
S_FLICKY_16_FLAP1,
|
||||
S_FLICKY_16_FLAP2,
|
||||
S_FLICKY_16_FLAP3,
|
||||
|
||||
S_YELLOWSPRING,
|
||||
S_YELLOWSPRING2,
|
||||
|
@ -2457,6 +2663,20 @@ typedef enum state
|
|||
|
||||
S_WATERZAP,
|
||||
|
||||
// Spindash dust
|
||||
S_SPINDUST1,
|
||||
S_SPINDUST2,
|
||||
S_SPINDUST3,
|
||||
S_SPINDUST4,
|
||||
S_SPINDUST_BUBBLE1,
|
||||
S_SPINDUST_BUBBLE2,
|
||||
S_SPINDUST_BUBBLE3,
|
||||
S_SPINDUST_BUBBLE4,
|
||||
S_SPINDUST_FIRE1,
|
||||
S_SPINDUST_FIRE2,
|
||||
S_SPINDUST_FIRE3,
|
||||
S_SPINDUST_FIRE4,
|
||||
|
||||
S_FOG1,
|
||||
S_FOG2,
|
||||
S_FOG3,
|
||||
|
@ -2687,20 +2907,19 @@ typedef enum state
|
|||
S_FIREBALLEXP2,
|
||||
S_FIREBALLEXP3,
|
||||
S_SHELL,
|
||||
S_SHELL1,
|
||||
S_SHELL2,
|
||||
S_SHELL3,
|
||||
S_SHELL4,
|
||||
S_PUMA1,
|
||||
S_PUMA2,
|
||||
S_PUMA3,
|
||||
S_PUMA4,
|
||||
S_PUMA5,
|
||||
S_PUMA6,
|
||||
S_HAMMER1,
|
||||
S_HAMMER2,
|
||||
S_HAMMER3,
|
||||
S_HAMMER4,
|
||||
S_PUMA_START1,
|
||||
S_PUMA_START2,
|
||||
S_PUMA_UP1,
|
||||
S_PUMA_UP2,
|
||||
S_PUMA_UP3,
|
||||
S_PUMA_DOWN1,
|
||||
S_PUMA_DOWN2,
|
||||
S_PUMA_DOWN3,
|
||||
S_PUMATRAIL1,
|
||||
S_PUMATRAIL2,
|
||||
S_PUMATRAIL3,
|
||||
S_PUMATRAIL4,
|
||||
S_HAMMER,
|
||||
S_KOOPA1,
|
||||
S_KOOPA2,
|
||||
S_KOOPAFLAME1,
|
||||
|
@ -2829,6 +3048,7 @@ typedef enum state
|
|||
S_NIGHTOPIANHELPER6,
|
||||
S_NIGHTOPIANHELPER7,
|
||||
S_NIGHTOPIANHELPER8,
|
||||
S_NIGHTOPIANHELPER9,
|
||||
|
||||
S_CRUMBLE1,
|
||||
S_CRUMBLE2,
|
||||
|
@ -2852,10 +3072,10 @@ typedef enum state
|
|||
S_SPRK16,
|
||||
|
||||
// Robot Explosion
|
||||
S_XPLD_FLICKY,
|
||||
S_XPLD1,
|
||||
S_XPLD2,
|
||||
S_XPLD3,
|
||||
S_XPLD4,
|
||||
S_XPLD_EGGTRAP,
|
||||
|
||||
// Underwater Explosion
|
||||
S_WPLD1,
|
||||
|
@ -2971,6 +3191,7 @@ typedef enum mobj_type
|
|||
MT_BOSSTANK2,
|
||||
MT_BOSSSPIGOT,
|
||||
MT_GOOP,
|
||||
MT_GOOPTRAIL,
|
||||
|
||||
// Boss 3
|
||||
MT_EGGMOBILE3,
|
||||
|
@ -3074,6 +3295,9 @@ typedef enum mobj_type
|
|||
MT_RECYCLER_BOX,
|
||||
MT_SCORE1K_BOX,
|
||||
MT_SCORE10K_BOX,
|
||||
MT_FLAMEAURA_BOX,
|
||||
MT_BUBBLEWRAP_BOX,
|
||||
MT_THUNDERCOIN_BOX,
|
||||
|
||||
// Monitor boxes -- repeating (big) boxes
|
||||
MT_PITY_GOLDBOX,
|
||||
|
@ -3086,6 +3310,9 @@ typedef enum mobj_type
|
|||
MT_INVULN_GOLDBOX,
|
||||
MT_EGGMAN_GOLDBOX,
|
||||
MT_GRAVITY_GOLDBOX,
|
||||
MT_FLAMEAURA_GOLDBOX,
|
||||
MT_BUBBLEWRAP_GOLDBOX,
|
||||
MT_THUNDERCOIN_GOLDBOX,
|
||||
|
||||
// Monitor boxes -- special
|
||||
MT_RING_REDBOX,
|
||||
|
@ -3108,6 +3335,9 @@ typedef enum mobj_type
|
|||
MT_RECYCLER_ICON,
|
||||
MT_SCORE1K_ICON,
|
||||
MT_SCORE10K_ICON,
|
||||
MT_FLAMEAURA_ICON,
|
||||
MT_BUBBLEWRAP_ICON,
|
||||
MT_THUNDERCOIN_ICON,
|
||||
|
||||
// Projectiles
|
||||
MT_ROCKET,
|
||||
|
@ -3131,7 +3361,8 @@ typedef enum mobj_type
|
|||
MT_BUSH,
|
||||
|
||||
// Techno Hill Scenery
|
||||
MT_THZPLANT, // THZ Plant
|
||||
MT_THZFLOWER1,
|
||||
MT_THZFLOWER2,
|
||||
MT_ALARM,
|
||||
|
||||
// Deep Sea Scenery
|
||||
|
@ -3147,6 +3378,7 @@ typedef enum mobj_type
|
|||
// Castle Eggman Scenery
|
||||
MT_CHAIN, // CEZ Chain
|
||||
MT_FLAME, // Flame (has corona)
|
||||
MT_FLAMEPARTICLE,
|
||||
MT_EGGSTATUE, // Eggman Statue
|
||||
MT_MACEPOINT, // Mace rotation point
|
||||
MT_SWINGMACEPOINT, // Mace swinging point
|
||||
|
@ -3173,9 +3405,7 @@ typedef enum mobj_type
|
|||
MT_FLAMEJETFLAME,
|
||||
|
||||
MT_FJSPINAXISA, // Counter-clockwise
|
||||
MT_FJSPINHELPERA,
|
||||
MT_FJSPINAXISB, // Clockwise
|
||||
MT_FJSPINHELPERB,
|
||||
|
||||
MT_FLAMEJETFLAMEB, // Blade's flame
|
||||
|
||||
|
@ -3252,30 +3482,46 @@ typedef enum mobj_type
|
|||
MT_BSZVINE_ORANGE,
|
||||
MT_BSZSHRUB,
|
||||
MT_BSZCLOVER,
|
||||
MT_BSZFISH,
|
||||
MT_BSZSUNFLOWER,
|
||||
MT_BIG_PALMTREE_TRUNK,
|
||||
MT_BIG_PALMTREE_TOP,
|
||||
MT_PALMTREE_TRUNK,
|
||||
MT_PALMTREE_TOP,
|
||||
|
||||
// Misc scenery
|
||||
MT_DBALL,
|
||||
MT_EGGSTATUE2,
|
||||
|
||||
// Powerup Indicators
|
||||
MT_GREENORB, // Elemental shield mobj
|
||||
MT_YELLOWORB, // Attract shield mobj
|
||||
MT_BLUEORB, // Force shield mobj
|
||||
MT_BLACKORB, // Armageddon shield mobj
|
||||
MT_WHITEORB, // Whirlwind shield mobj
|
||||
MT_PITYORB, // Pity shield mobj
|
||||
MT_IVSP, // invincibility sparkles
|
||||
MT_ELEMENTAL_ORB, // Elemental shield mobj
|
||||
MT_ATTRACT_ORB, // Attract shield mobj
|
||||
MT_FORCE_ORB, // Force shield mobj
|
||||
MT_ARMAGEDDON_ORB, // Armageddon shield mobj
|
||||
MT_WHIRLWIND_ORB, // Whirlwind shield mobj
|
||||
MT_PITY_ORB, // Pity shield mobj
|
||||
MT_FLAMEAURA_ORB, // Flame shield mobj
|
||||
MT_BUBBLEWRAP_ORB, // Bubble shield mobj
|
||||
MT_THUNDERCOIN_ORB, // Thunder shield mobj
|
||||
MT_THUNDERCOIN_SPARK, // Thunder spark
|
||||
MT_IVSP, // Invincibility sparkles
|
||||
MT_SUPERSPARK, // Super Sonic Spark
|
||||
|
||||
// Freed Animals
|
||||
MT_BIRD, // Birdie freed!
|
||||
MT_BUNNY, // Bunny freed!
|
||||
MT_MOUSE, // Mouse
|
||||
MT_CHICKEN, // Chicken
|
||||
MT_COW, // Cow
|
||||
MT_REDBIRD, // Red Birdie in Bubble
|
||||
// Flickies
|
||||
MT_FLICKY_01, // Bluebird
|
||||
MT_FLICKY_02, // Rabbit
|
||||
MT_FLICKY_03, // Chicken
|
||||
MT_FLICKY_04, // Seal
|
||||
MT_FLICKY_05, // Pig
|
||||
MT_FLICKY_06, // Chipmunk
|
||||
MT_FLICKY_07, // Penguin
|
||||
MT_FLICKY_08, // Fish
|
||||
MT_FLICKY_09, // Ram
|
||||
MT_FLICKY_10, // Puffin
|
||||
MT_FLICKY_11, // Cow
|
||||
MT_FLICKY_12, // Rat
|
||||
MT_FLICKY_13, // Bear
|
||||
MT_FLICKY_14, // Dove
|
||||
MT_FLICKY_15, // Cat
|
||||
MT_FLICKY_16, // Canary
|
||||
|
||||
// Environmental Effects
|
||||
MT_RAIN, // Rain
|
||||
|
@ -3286,6 +3532,7 @@ typedef enum mobj_type
|
|||
MT_MEDIUMBUBBLE, // medium bubble
|
||||
MT_EXTRALARGEBUBBLE, // extra large bubble
|
||||
MT_WATERZAP,
|
||||
MT_SPINDUST, // Spindash dust
|
||||
MT_TFOG,
|
||||
MT_SEED,
|
||||
MT_PARTICLE,
|
||||
|
@ -3344,6 +3591,7 @@ typedef enum mobj_type
|
|||
MT_FIREBALL,
|
||||
MT_SHELL,
|
||||
MT_PUMA,
|
||||
MT_PUMATRAIL,
|
||||
MT_HAMMER,
|
||||
MT_KOOPA,
|
||||
MT_KOOPAFLAME,
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
#define NOHUD if (hud_running) return luaL_error(L, "HUD rendering code should not call this function!");
|
||||
|
||||
|
||||
boolean luaL_checkboolean(lua_State *L, int narg) {
|
||||
luaL_checktype(L, narg, LUA_TBOOLEAN);
|
||||
return lua_toboolean(L, narg);
|
||||
|
@ -205,6 +204,41 @@ static int lib_pClosestPointOnLine(lua_State *L)
|
|||
return 2;
|
||||
}
|
||||
|
||||
static int lib_pPointOnLineSide(lua_State *L)
|
||||
{
|
||||
int n = lua_gettop(L);
|
||||
fixed_t x = luaL_checkfixed(L, 1);
|
||||
fixed_t y = luaL_checkfixed(L, 2);
|
||||
//HUDSAFE
|
||||
if (lua_isuserdata(L, 3)) // use a real linedef to get our points
|
||||
{
|
||||
line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
|
||||
if (!line)
|
||||
return LUA_ErrInvalid(L, "line_t");
|
||||
lua_pushinteger(L, P_PointOnLineSide(x, y, line));
|
||||
}
|
||||
else // use custom coordinates of our own!
|
||||
{
|
||||
vertex_t v1, v2; // fake vertexes
|
||||
line_t junk; // fake linedef
|
||||
|
||||
if (n < 6)
|
||||
return luaL_error(L, "arguments 3 to 6 not all given (expected 4 fixed-point integers)");
|
||||
|
||||
v1.x = luaL_checkfixed(L, 3);
|
||||
v1.y = luaL_checkfixed(L, 4);
|
||||
v2.x = luaL_checkfixed(L, 5);
|
||||
v2.y = luaL_checkfixed(L, 6);
|
||||
|
||||
junk.v1 = &v1;
|
||||
junk.v2 = &v2;
|
||||
junk.dx = v2.x - v1.x;
|
||||
junk.dy = v2.y - v1.y;
|
||||
lua_pushinteger(L, P_PointOnLineSide(x, y, &junk));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// P_ENEMY
|
||||
/////////////
|
||||
|
||||
|
@ -309,6 +343,19 @@ static int lib_pRemoveMobj(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// P_IsValidSprite2 technically doesn't exist, and probably never should... but too much would need to be exposed to allow this to be checked by other methods.
|
||||
|
||||
static int lib_pIsValidSprite2(lua_State *L)
|
||||
{
|
||||
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
UINT8 spr2 = (UINT8)luaL_checkinteger(L, 2);
|
||||
//HUDSAFE
|
||||
if (!mobj)
|
||||
return LUA_ErrInvalid(L, "mobj_t");
|
||||
lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes > 0)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_pSpawnMissile(lua_State *L)
|
||||
{
|
||||
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
|
@ -618,6 +665,17 @@ static int lib_pAddPlayerScore(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pStealPlayerScore(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
UINT32 amount = (UINT32)luaL_checkinteger(L, 2);
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
P_StealPlayerScore(player, amount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pPlayerInPain(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
|
@ -777,6 +835,16 @@ static int lib_pDoJumpShield(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pDoBubbleBounce(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
P_DoBubbleBounce(player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pBlackOw(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
|
@ -787,13 +855,14 @@ static int lib_pBlackOw(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pElementalFireTrail(lua_State *L)
|
||||
static int lib_pElementalFire(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
boolean cropcircle = lua_optboolean(L, 2);
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
P_ElementalFireTrail(player);
|
||||
P_ElementalFire(player, cropcircle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -848,10 +917,11 @@ static int lib_pReturnThrustY(lua_State *L)
|
|||
static int lib_pLookForEnemies(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
boolean nonenemies = lua_opttrueboolean(L, 2);
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
lua_pushboolean(L, P_LookForEnemies(player));
|
||||
lua_pushboolean(L, P_LookForEnemies(player, nonenemies));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1132,7 +1202,7 @@ static int lib_pPlayerRingBurst(lua_State *L)
|
|||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
if (num_rings == -1)
|
||||
num_rings = player->health - 1;
|
||||
num_rings = player->rings;
|
||||
P_PlayerRingBurst(player, num_rings);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1157,6 +1227,16 @@ static int lib_pPlayerWeaponAmmoBurst(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pPlayerWeaponPanelOrAmmoBurst(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
P_PlayerWeaponPanelOrAmmoBurst(player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pPlayerEmeraldBurst(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
|
@ -1264,6 +1344,16 @@ static int lib_pDoNightsScore(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pDoMatchSuper(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
P_DoMatchSuper(player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// P_SPEC
|
||||
////////////
|
||||
|
||||
|
@ -2018,6 +2108,7 @@ static luaL_Reg lib[] = {
|
|||
// p_maputil
|
||||
{"P_AproxDistance",lib_pAproxDistance},
|
||||
{"P_ClosestPointOnLine",lib_pClosestPointOnLine},
|
||||
{"P_PointOnLineSide",lib_pPointOnLineSide},
|
||||
|
||||
// p_enemy
|
||||
{"P_CheckMeleeRange", lib_pCheckMeleeRange},
|
||||
|
@ -2032,6 +2123,7 @@ static luaL_Reg lib[] = {
|
|||
// don't add P_SetMobjState or P_SetPlayerMobjState, use "mobj.state = S_NEWSTATE" instead.
|
||||
{"P_SpawnMobj",lib_pSpawnMobj},
|
||||
{"P_RemoveMobj",lib_pRemoveMobj},
|
||||
{"P_IsValidSprite2", lib_pIsValidSprite2},
|
||||
{"P_SpawnMissile",lib_pSpawnMissile},
|
||||
{"P_SpawnXYZMissile",lib_pSpawnXYZMissile},
|
||||
{"P_SpawnPointMissile",lib_pSpawnPointMissile},
|
||||
|
@ -2058,6 +2150,7 @@ static luaL_Reg lib[] = {
|
|||
{"P_GetPlayerSpinHeight",lib_pGetPlayerSpinHeight},
|
||||
{"P_GetPlayerControlDirection",lib_pGetPlayerControlDirection},
|
||||
{"P_AddPlayerScore",lib_pAddPlayerScore},
|
||||
{"P_StealPlayerScore",lib_pStealPlayerScore},
|
||||
{"P_PlayerInPain",lib_pPlayerInPain},
|
||||
{"P_DoPlayerPain",lib_pDoPlayerPain},
|
||||
{"P_ResetPlayer",lib_pResetPlayer},
|
||||
|
@ -2073,8 +2166,9 @@ static luaL_Reg lib[] = {
|
|||
{"P_GivePlayerLives",lib_pGivePlayerLives},
|
||||
{"P_ResetScore",lib_pResetScore},
|
||||
{"P_DoJumpShield",lib_pDoJumpShield},
|
||||
{"P_DoBubbleBounce",lib_pDoBubbleBounce},
|
||||
{"P_BlackOw",lib_pBlackOw},
|
||||
{"P_ElementalFireTrail",lib_pElementalFireTrail},
|
||||
{"P_ElementalFire",lib_pElementalFire},
|
||||
{"P_DoPlayerExit",lib_pDoPlayerExit},
|
||||
{"P_InstaThrust",lib_pInstaThrust},
|
||||
{"P_ReturnThrustX",lib_pReturnThrustX},
|
||||
|
@ -2108,6 +2202,7 @@ static luaL_Reg lib[] = {
|
|||
{"P_PlayerRingBurst",lib_pPlayerRingBurst},
|
||||
{"P_PlayerWeaponPanelBurst",lib_pPlayerWeaponPanelBurst},
|
||||
{"P_PlayerWeaponAmmoBurst",lib_pPlayerWeaponAmmoBurst},
|
||||
{"P_PlayerWeaponPanelOrAmmoBurst", lib_pPlayerWeaponPanelOrAmmoBurst},
|
||||
{"P_PlayerEmeraldBurst",lib_pPlayerEmeraldBurst},
|
||||
{"P_PlayerFlagBurst",lib_pPlayerFlagBurst},
|
||||
{"P_PlayRinglossSound",lib_pPlayRinglossSound},
|
||||
|
@ -2116,6 +2211,7 @@ static luaL_Reg lib[] = {
|
|||
{"P_PlayLivesJingle",lib_pPlayLivesJingle},
|
||||
{"P_CanPickupItem",lib_pCanPickupItem},
|
||||
{"P_DoNightsScore",lib_pDoNightsScore},
|
||||
{"P_DoMatchSuper",lib_pDoMatchSuper},
|
||||
|
||||
// p_spec
|
||||
{"P_Thrust",lib_pThrust},
|
||||
|
|
266
src/lua_blockmaplib.c
Normal file
266
src/lua_blockmaplib.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2016 by Iestyn "Monster Iestyn" Jealous.
|
||||
// Copyright (C) 2016 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file lua_blockmaplib.c
|
||||
/// \brief blockmap library for Lua scripting
|
||||
|
||||
#include "doomdef.h"
|
||||
#ifdef HAVE_BLUA
|
||||
#include "p_local.h"
|
||||
#include "r_main.h" // validcount
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
//#include "lua_hud.h" // hud_running errors
|
||||
|
||||
static const char *const search_opt[] = {
|
||||
"objects",
|
||||
"lines",
|
||||
NULL};
|
||||
|
||||
// a quickly-made function pointer typedef used by lib_searchBlockmap...
|
||||
// return values:
|
||||
// 0 - normal, no interruptions
|
||||
// 1 - stop search through current block
|
||||
// 2 - stop search completely
|
||||
typedef UINT8 (*blockmap_func)(lua_State *, INT32, INT32, mobj_t *);
|
||||
|
||||
static boolean blockfuncerror = false; // errors should only print once per search blockmap call
|
||||
|
||||
// Helper function for "objects" search
|
||||
static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
|
||||
{
|
||||
mobj_t *mobj, *bnext = NULL;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
return 0;
|
||||
|
||||
// Check interaction with the objects in the blockmap.
|
||||
for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext)
|
||||
{
|
||||
P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
|
||||
if (mobj == thing)
|
||||
continue; // our thing just found itself, so move on
|
||||
lua_pushvalue(L, 1); // push function
|
||||
LUA_PushUserdata(L, thing, META_MOBJ);
|
||||
LUA_PushUserdata(L, mobj, META_MOBJ);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!blockfuncerror || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
blockfuncerror = true;
|
||||
return 0; // *shrugs*
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, continue
|
||||
if (lua_toboolean(gL, -1))
|
||||
return 2; // stop whole search
|
||||
else
|
||||
return 1; // stop block search
|
||||
}
|
||||
lua_pop(gL, 1);
|
||||
if (P_MobjWasRemoved(thing) // func just popped our thing, cannot continue.
|
||||
|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
|
||||
{
|
||||
P_SetTarget(&bnext, NULL);
|
||||
return (P_MobjWasRemoved(thing)) ? 2 : 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Helper function for "lines" search
|
||||
static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
|
||||
{
|
||||
INT32 offset;
|
||||
const INT32 *list; // Big blockmap
|
||||
#ifdef POLYOBJECTS
|
||||
polymaplink_t *plink; // haleyjd 02/22/06
|
||||
#endif
|
||||
line_t *ld;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
return 0;
|
||||
|
||||
offset = y*bmapwidth + x;
|
||||
|
||||
#ifdef POLYOBJECTS
|
||||
// haleyjd 02/22/06: consider polyobject lines
|
||||
plink = polyblocklinks[offset];
|
||||
|
||||
while (plink)
|
||||
{
|
||||
polyobj_t *po = plink->po;
|
||||
|
||||
if (po->validcount != validcount) // if polyobj hasn't been checked
|
||||
{
|
||||
size_t i;
|
||||
po->validcount = validcount;
|
||||
|
||||
for (i = 0; i < po->numLines; ++i)
|
||||
{
|
||||
if (po->lines[i]->validcount == validcount) // line has been checked
|
||||
continue;
|
||||
po->lines[i]->validcount = validcount;
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
LUA_PushUserdata(L, thing, META_MOBJ);
|
||||
LUA_PushUserdata(L, po->lines[i], META_LINE);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!blockfuncerror || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
blockfuncerror = true;
|
||||
return 0; // *shrugs*
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, continue
|
||||
if (lua_toboolean(gL, -1))
|
||||
return 2; // stop whole search
|
||||
else
|
||||
return 1; // stop block search
|
||||
}
|
||||
lua_pop(gL, 1);
|
||||
if (P_MobjWasRemoved(thing))
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
plink = (polymaplink_t *)(plink->link.next);
|
||||
}
|
||||
#endif
|
||||
|
||||
offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x];
|
||||
|
||||
// First index is really empty, so +1 it.
|
||||
for (list = blockmaplump + offset + 1; *list != -1; list++)
|
||||
{
|
||||
ld = &lines[*list];
|
||||
|
||||
if (ld->validcount == validcount)
|
||||
continue; // Line has already been checked.
|
||||
|
||||
ld->validcount = validcount;
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
LUA_PushUserdata(L, thing, META_MOBJ);
|
||||
LUA_PushUserdata(L, ld, META_LINE);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!blockfuncerror || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
blockfuncerror = true;
|
||||
return 0; // *shrugs*
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, continue
|
||||
if (lua_toboolean(gL, -1))
|
||||
return 2; // stop whole search
|
||||
else
|
||||
return 1; // stop block search
|
||||
}
|
||||
lua_pop(gL, 1);
|
||||
if (P_MobjWasRemoved(thing))
|
||||
return 2;
|
||||
}
|
||||
return 0; // Everything was checked.
|
||||
}
|
||||
|
||||
// The searchBlockmap function
|
||||
// arguments: searchBlockmap(searchtype, function, mobj, [x1, x2, y1, y2])
|
||||
// return value:
|
||||
// true = search completely uninteruppted,
|
||||
// false = searching of at least one block stopped mid-way (including if the whole search was stopped)
|
||||
static int lib_searchBlockmap(lua_State *L)
|
||||
{
|
||||
int searchtype = luaL_checkoption(L, 1, "objects", search_opt);
|
||||
int n;
|
||||
mobj_t *mobj;
|
||||
INT32 xl, xh, yl, yh, bx, by;
|
||||
fixed_t x1, x2, y1, y2;
|
||||
boolean retval = true;
|
||||
UINT8 funcret = 0;
|
||||
blockmap_func searchFunc;
|
||||
|
||||
lua_remove(L, 1); // remove searchtype, stack is now function, mobj, [x1, x2, y1, y2]
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
|
||||
switch (searchtype)
|
||||
{
|
||||
case 0: // "objects"
|
||||
default:
|
||||
searchFunc = lib_searchBlockmap_Objects;
|
||||
break;
|
||||
case 1: // "lines"
|
||||
searchFunc = lib_searchBlockmap_Lines;
|
||||
break;
|
||||
}
|
||||
|
||||
// the mobj we are searching around, the "calling" mobj we could say
|
||||
mobj = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
|
||||
if (!mobj)
|
||||
return LUA_ErrInvalid(L, "mobj_t");
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n > 2) // specific x/y ranges have been supplied
|
||||
{
|
||||
if (n < 6)
|
||||
return luaL_error(L, "arguments 4 to 6 not all given (expected 4 fixed-point integers)");
|
||||
|
||||
x1 = luaL_checkfixed(L, 3);
|
||||
x2 = luaL_checkfixed(L, 4);
|
||||
y1 = luaL_checkfixed(L, 5);
|
||||
y2 = luaL_checkfixed(L, 6);
|
||||
}
|
||||
else // mobj and function only - search around mobj's radius by default
|
||||
{
|
||||
fixed_t radius = mobj->radius + MAXRADIUS;
|
||||
x1 = mobj->x - radius;
|
||||
x2 = mobj->x + radius;
|
||||
y1 = mobj->y - radius;
|
||||
y2 = mobj->y + radius;
|
||||
}
|
||||
lua_settop(L, 2); // pop everything except function, mobj
|
||||
|
||||
xl = (unsigned)(x1 - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
xh = (unsigned)(x2 - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(y1 - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yh = (unsigned)(y2 - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
|
||||
BMBOUNDFIX(xl, xh, yl, yh);
|
||||
|
||||
blockfuncerror = false; // reset
|
||||
validcount++;
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
for (by = yl; by <= yh; by++)
|
||||
{
|
||||
funcret = searchFunc(L, bx, by, mobj);
|
||||
// return value of searchFunc determines searchFunc's return value and/or when to stop
|
||||
if (funcret == 2){ // stop whole search
|
||||
lua_pushboolean(L, false); // return false
|
||||
return 1;
|
||||
}
|
||||
else if (funcret == 1) // search was interrupted for this block
|
||||
retval = false; // this changes the return value, but doesn't stop the whole search
|
||||
// else don't do anything, continue as normal
|
||||
if (P_MobjWasRemoved(mobj)){ // ...unless the original object was removed
|
||||
lua_pushboolean(L, false); // in which case we have to stop now regardless
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua_pushboolean(L, retval);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LUA_BlockmapLib(lua_State *L)
|
||||
{
|
||||
lua_register(L, "searchBlockmap", lib_searchBlockmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -43,6 +43,8 @@ enum hook {
|
|||
hook_PlayerMsg,
|
||||
hook_HurtMsg,
|
||||
hook_PlayerSpawn,
|
||||
hook_ShieldSpawn,
|
||||
hook_ShieldSpecial,
|
||||
|
||||
hook_MAX // last hook
|
||||
};
|
||||
|
@ -60,11 +62,11 @@ 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
|
||||
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_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
|
||||
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_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source); // Hook for P_KillMobj by mobj type
|
||||
UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // 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, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)
|
||||
boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for P_KillMobj by mobj type
|
||||
#define LUAh_BossDeath(mo) LUAh_MobjHook(mo, hook_BossDeath) // Hook for A_BossDeath by mobj type
|
||||
#define LUAh_MobjRemoved(mo) LUAh_MobjHook(mo, hook_MobjRemoved) // Hook for P_RemoveMobj by mobj type
|
||||
#define LUAh_JumpSpecial(player) LUAh_PlayerHook(player, hook_JumpSpecial) // Hook for P_DoJumpStuff (Any-jumping)
|
||||
|
@ -75,7 +77,9 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd
|
|||
boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name
|
||||
boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors
|
||||
boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages
|
||||
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
|
||||
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for hurt messages
|
||||
#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer
|
||||
#define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb
|
||||
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,6 +54,8 @@ const char *const hookNames[hook_MAX+1] = {
|
|||
"PlayerMsg",
|
||||
"HurtMsg",
|
||||
"PlayerSpawn",
|
||||
"ShieldSpawn",
|
||||
"ShieldSpecial",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -74,12 +76,30 @@ typedef struct hook_s* hook_p;
|
|||
|
||||
#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;
|
||||
|
||||
// Takes hook, function, and additional arguments (mobj type to act on, etc.)
|
||||
static int lib_addHook(lua_State *L)
|
||||
{
|
||||
static struct hook_s hook = {NULL, 0, 0, {0}, false};
|
||||
static UINT32 nextid;
|
||||
hook_p hookp, *lastp;
|
||||
|
||||
hook.type = luaL_checkoption(L, 1, NULL, hookNames);
|
||||
|
@ -109,6 +129,7 @@ static int lib_addHook(lua_State *L)
|
|||
hook.s.mt = MT_NULL;
|
||||
if (lua_isnumber(L, 2))
|
||||
hook.s.mt = lua_tonumber(L, 2);
|
||||
luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t");
|
||||
break;
|
||||
case hook_BotAI:
|
||||
hook.s.skinname = NULL;
|
||||
|
@ -141,18 +162,49 @@ static int lib_addHook(lua_State *L)
|
|||
|
||||
hooksAvailable[hook.type/8] |= 1<<(hook.type%8);
|
||||
|
||||
// iterate the hook metadata structs
|
||||
// set hook.id to the highest id + 1
|
||||
// set lastp to the last hook struct's "next" pointer.
|
||||
lastp = &roothook;
|
||||
hook.id = 0;
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
hook.id = nextid++;
|
||||
|
||||
// Special cases for some hook types (see the comments above mobjthinkerhooks declaration)
|
||||
switch(hook.type)
|
||||
{
|
||||
if (hookp->id >= hook.id)
|
||||
hook.id = hookp->id+1;
|
||||
lastp = &hookp->next;
|
||||
case hook_MobjThinker:
|
||||
lastp = &mobjthinkerhooks[hook.s.mt];
|
||||
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.
|
||||
hookp = ZZ_Alloc(sizeof(struct hook_s));
|
||||
memcpy(hookp, &hook, sizeof(struct hook_s));
|
||||
|
@ -183,9 +235,29 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type))
|
||||
// Look for all generic mobj hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
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)
|
||||
LUA_PushUserdata(gL, mo, META_MOBJ);
|
||||
|
@ -217,7 +289,7 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
for (hookp = playerhooks; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
|
@ -338,9 +410,38 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type))
|
||||
// Look for all generic mobj collision hooks
|
||||
for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
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)
|
||||
{
|
||||
|
@ -372,6 +473,59 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
|
|||
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
|
||||
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
|
||||
{
|
||||
|
@ -382,9 +536,33 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_TouchSpecial
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == special->type))
|
||||
// Look for all generic touch special hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
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)
|
||||
{
|
||||
|
@ -412,7 +590,7 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
|
|||
}
|
||||
|
||||
// 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)
|
||||
UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
hook_p hookp;
|
||||
UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no.
|
||||
|
@ -421,9 +599,9 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_ShouldDamage
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
|
||||
// Look for all generic should damage hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_ShouldDamage)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -455,12 +633,47 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
|
|||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
|
||||
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_pushinteger(gL, damagetype);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
if (lua_pcall(gL, 5, 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);
|
||||
}
|
||||
|
||||
lua_settop(gL, 0);
|
||||
return shouldDamage;
|
||||
}
|
||||
|
||||
// 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)
|
||||
boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
hook_p hookp;
|
||||
boolean hooked = false;
|
||||
|
@ -469,9 +682,9 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDamage
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
|
||||
// Look for all generic mobj damage hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDamage)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -498,12 +711,42 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
|
|||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
|
||||
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_pushinteger(gL, damagetype);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
lua_pushvalue(gL, -6);
|
||||
if (lua_pcall(gL, 5, 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_KillMobj by mobj type
|
||||
boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
||||
boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype)
|
||||
{
|
||||
hook_p hookp;
|
||||
boolean hooked = false;
|
||||
|
@ -512,9 +755,9 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDeath
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
|
||||
// Look for all generic mobj death hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDeath)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -539,6 +782,34 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
|||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
|
||||
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_pushinteger(gL, damagetype);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
lua_settop(gL, 0);
|
||||
return hooked;
|
||||
}
|
||||
|
@ -652,9 +923,8 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_LinedefExecute
|
||||
&& !strcmp(hookp->s.funcname, line->text))
|
||||
for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next)
|
||||
if (!strcmp(hookp->s.funcname, line->text))
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -729,7 +999,7 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg)
|
|||
}
|
||||
|
||||
// Hook for hurt messages
|
||||
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source)
|
||||
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype)
|
||||
{
|
||||
hook_p hookp;
|
||||
boolean hooked = false;
|
||||
|
@ -747,13 +1017,15 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source)
|
|||
LUA_PushUserdata(gL, player, META_PLAYER);
|
||||
LUA_PushUserdata(gL, inflictor, META_MOBJ);
|
||||
LUA_PushUserdata(gL, source, META_MOBJ);
|
||||
lua_pushinteger(gL, damagetype);
|
||||
}
|
||||
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)) {
|
||||
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);
|
||||
|
|
|
@ -226,7 +226,12 @@ static int hudinfo_num(lua_State *L)
|
|||
|
||||
static int colormap_get(lua_State *L)
|
||||
{
|
||||
return luaL_error(L, "colormap is not a struct.");
|
||||
const UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP));
|
||||
UINT32 i = luaL_checkinteger(L, 2);
|
||||
if (i >= 256)
|
||||
return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255);
|
||||
lua_pushinteger(L, colormap[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int patch_get(lua_State *L)
|
||||
|
|
|
@ -38,12 +38,22 @@ extern lua_State *gL;
|
|||
#define META_SUBSECTOR "SUBSECTOR_T*"
|
||||
#define META_SECTOR "SECTOR_T*"
|
||||
#define META_FFLOOR "FFLOOR_T*"
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
#define META_SEG "SEG_T*"
|
||||
#define META_NODE "NODE_T*"
|
||||
#endif
|
||||
#define META_MAPHEADER "MAPHEADER_T*"
|
||||
|
||||
#define META_CVAR "CONSVAR_T*"
|
||||
|
||||
#define META_SECTORLINES "SECTOR_T*LINES"
|
||||
#define META_SIDENUM "LINE_T*SIDENUM"
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
#define META_NODEBBOX "NODE_T*BBOX"
|
||||
#define META_NODECHILDREN "NODE_T*CHILDREN"
|
||||
#endif
|
||||
|
||||
#define META_BBOX "BOUNDING_BOX"
|
||||
|
||||
#define META_HUDINFO "HUDINFO_T*"
|
||||
#define META_PATCH "PATCH_T*"
|
||||
|
@ -64,6 +74,7 @@ int LUA_PlayerLib(lua_State *L);
|
|||
int LUA_SkinLib(lua_State *L);
|
||||
int LUA_ThinkerLib(lua_State *L);
|
||||
int LUA_MapLib(lua_State *L);
|
||||
int LUA_BlockmapLib(lua_State *L);
|
||||
int LUA_HudLib(lua_State *L);
|
||||
|
||||
#endif
|
||||
|
|
541
src/lua_maplib.c
541
src/lua_maplib.c
|
@ -185,6 +185,82 @@ static const char *const ffloor_opt[] = {
|
|||
"alpha",
|
||||
NULL};
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
enum seg_e {
|
||||
seg_valid = 0,
|
||||
seg_v1,
|
||||
seg_v2,
|
||||
seg_side,
|
||||
seg_offset,
|
||||
seg_angle,
|
||||
seg_sidedef,
|
||||
seg_linedef,
|
||||
seg_frontsector,
|
||||
seg_backsector,
|
||||
};
|
||||
|
||||
static const char *const seg_opt[] = {
|
||||
"valid",
|
||||
"v1",
|
||||
"v2",
|
||||
"side",
|
||||
"offset",
|
||||
"angle",
|
||||
"sidedef",
|
||||
"linedef",
|
||||
"frontsector",
|
||||
"backsector",
|
||||
NULL};
|
||||
|
||||
enum node_e {
|
||||
node_valid = 0,
|
||||
node_x,
|
||||
node_y,
|
||||
node_dx,
|
||||
node_dy,
|
||||
node_bbox,
|
||||
node_children,
|
||||
};
|
||||
|
||||
static const char *const node_opt[] = {
|
||||
"valid",
|
||||
"x",
|
||||
"y",
|
||||
"dx",
|
||||
"dy",
|
||||
"bbox",
|
||||
"children",
|
||||
NULL};
|
||||
|
||||
enum nodechild_e {
|
||||
nodechild_valid = 0,
|
||||
nodechild_right,
|
||||
nodechild_left,
|
||||
};
|
||||
|
||||
static const char *const nodechild_opt[] = {
|
||||
"valid",
|
||||
"right",
|
||||
"left",
|
||||
NULL};
|
||||
#endif
|
||||
|
||||
enum bbox_e {
|
||||
bbox_valid = 0,
|
||||
bbox_top,
|
||||
bbox_bottom,
|
||||
bbox_left,
|
||||
bbox_right,
|
||||
};
|
||||
|
||||
static const char *const bbox_opt[] = {
|
||||
"valid",
|
||||
"top",
|
||||
"bottom",
|
||||
"left",
|
||||
"right",
|
||||
NULL};
|
||||
|
||||
static const char *const array_opt[] ={"iterate",NULL};
|
||||
static const char *const valid_opt[] ={"valid",NULL};
|
||||
|
||||
|
@ -348,22 +424,12 @@ static int sector_get(lua_State *L)
|
|||
case sector_ceilingheight:
|
||||
lua_pushfixed(L, sector->ceilingheight);
|
||||
return 1;
|
||||
case sector_floorpic: { // floorpic
|
||||
levelflat_t *levelflat;
|
||||
INT16 i;
|
||||
for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
|
||||
;
|
||||
lua_pushlstring(L, levelflat->name, 8);
|
||||
case sector_floorpic: // floorpic
|
||||
lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
|
||||
return 1;
|
||||
}
|
||||
case sector_ceilingpic: { // ceilingpic
|
||||
levelflat_t *levelflat;
|
||||
INT16 i;
|
||||
for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
|
||||
;
|
||||
lua_pushlstring(L, levelflat->name, 8);
|
||||
case sector_ceilingpic: // ceilingpic
|
||||
lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
|
||||
return 1;
|
||||
}
|
||||
case sector_lightlevel:
|
||||
lua_pushinteger(L, sector->lightlevel);
|
||||
return 1;
|
||||
|
@ -400,46 +466,6 @@ static int sector_get(lua_State *L)
|
|||
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)
|
||||
{
|
||||
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
|
||||
|
@ -818,6 +844,262 @@ static int vertex_num(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
static int seg_get(lua_State *L)
|
||||
{
|
||||
seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
|
||||
enum seg_e field = luaL_checkoption(L, 2, seg_opt[0], seg_opt);
|
||||
|
||||
if (!seg)
|
||||
{
|
||||
if (field == seg_valid) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "accessed seg_t doesn't exist anymore.");
|
||||
}
|
||||
|
||||
switch(field)
|
||||
{
|
||||
case seg_valid: // valid
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
case seg_v1:
|
||||
LUA_PushUserdata(L, seg->v1, META_VERTEX);
|
||||
return 1;
|
||||
case seg_v2:
|
||||
LUA_PushUserdata(L, seg->v2, META_VERTEX);
|
||||
return 1;
|
||||
case seg_side:
|
||||
lua_pushinteger(L, seg->side);
|
||||
return 1;
|
||||
case seg_offset:
|
||||
lua_pushfixed(L, seg->offset);
|
||||
return 1;
|
||||
case seg_angle:
|
||||
lua_pushangle(L, seg->angle);
|
||||
return 1;
|
||||
case seg_sidedef:
|
||||
LUA_PushUserdata(L, seg->sidedef, META_SIDE);
|
||||
return 1;
|
||||
case seg_linedef:
|
||||
LUA_PushUserdata(L, seg->linedef, META_LINE);
|
||||
return 1;
|
||||
case seg_frontsector:
|
||||
LUA_PushUserdata(L, seg->frontsector, META_SECTOR);
|
||||
return 1;
|
||||
case seg_backsector:
|
||||
LUA_PushUserdata(L, seg->backsector, META_SECTOR);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int seg_num(lua_State *L)
|
||||
{
|
||||
seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
|
||||
lua_pushinteger(L, seg-segs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int node_get(lua_State *L)
|
||||
{
|
||||
node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
|
||||
enum node_e field = luaL_checkoption(L, 2, node_opt[0], node_opt);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
if (field == node_valid) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "accessed node_t doesn't exist anymore.");
|
||||
}
|
||||
|
||||
switch(field)
|
||||
{
|
||||
case node_valid: // valid
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
case node_x:
|
||||
lua_pushfixed(L, node->x);
|
||||
return 1;
|
||||
case node_y:
|
||||
lua_pushfixed(L, node->y);
|
||||
return 1;
|
||||
case node_dx:
|
||||
lua_pushfixed(L, node->x);
|
||||
return 1;
|
||||
case node_dy:
|
||||
lua_pushfixed(L, node->x);
|
||||
return 1;
|
||||
case node_bbox:
|
||||
LUA_PushUserdata(L, node->bbox, META_NODEBBOX);
|
||||
return 1;
|
||||
case node_children:
|
||||
LUA_PushUserdata(L, node->children, META_NODECHILDREN);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int node_num(lua_State *L)
|
||||
{
|
||||
node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
|
||||
lua_pushinteger(L, node-nodes);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
// node.bbox[i][j]: i = 0 or 1, j = 0 1 2 or 3
|
||||
// NOTE: 2D arrays are NOT double pointers,
|
||||
// the second bbox will be directly after the first in memory (hence the way the bbox is pushed here)
|
||||
// this function handles the [i] part, bbox_get handles the [j] part
|
||||
static int nodebbox_get(lua_State *L)
|
||||
{
|
||||
fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX));
|
||||
int i;
|
||||
lua_settop(L, 2);
|
||||
if (!lua_isnumber(L, 2))
|
||||
{
|
||||
int field = luaL_checkoption(L, 2, NULL, valid_opt);
|
||||
if (!bbox)
|
||||
{
|
||||
if (field == 0) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "accessed node_t doesn't exist anymore.");
|
||||
} else if (field == 0) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
i = lua_tointeger(L, 2);
|
||||
if (i < 0 || i > 1)
|
||||
return 0;
|
||||
LUA_PushUserdata(L, bbox + i*4*sizeof(fixed_t), META_BBOX);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
static int nodebbox_call(lua_State *L)
|
||||
{
|
||||
fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX));
|
||||
int i, j;
|
||||
int n = lua_gettop(L);
|
||||
|
||||
if (!bbox)
|
||||
return luaL_error(L, "accessed node bbox doesn't exist anymore.");
|
||||
if (n < 3)
|
||||
return luaL_error(L, "arguments 2 and/or 3 not given (expected node.bbox(child, coord))");
|
||||
// get child
|
||||
if (!lua_isnumber(L, 2)) {
|
||||
enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt);
|
||||
switch (field) {
|
||||
case nodechild_right: i = 0; break;
|
||||
case nodechild_left: i = 1; break;
|
||||
default:
|
||||
return luaL_error(L, "invalid node child \"%s\".", lua_tostring(L, 2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = lua_tointeger(L, 2);
|
||||
if (i < 0 || i > 1)
|
||||
return 0;
|
||||
}
|
||||
// get bbox coord
|
||||
if (!lua_isnumber(L, 3)) {
|
||||
enum bbox_e field = luaL_checkoption(L, 3, bbox_opt[0], bbox_opt);
|
||||
switch (field) {
|
||||
case bbox_top: j = BOXTOP; break;
|
||||
case bbox_bottom: j = BOXBOTTOM; break;
|
||||
case bbox_left: j = BOXLEFT; break;
|
||||
case bbox_right: j = BOXRIGHT; break;
|
||||
default:
|
||||
return luaL_error(L, "invalid bbox coordinate \"%s\".", lua_tostring(L, 3));
|
||||
}
|
||||
}
|
||||
else {
|
||||
j = lua_tointeger(L, 3);
|
||||
if (j < 0 || j > 3)
|
||||
return 0;
|
||||
}
|
||||
lua_pushinteger(L, bbox[i*4 + j]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// node.children[i]: i = 0 or 1
|
||||
static int nodechildren_get(lua_State *L)
|
||||
{
|
||||
UINT16 *children = *((UINT16 **)luaL_checkudata(L, 1, META_NODECHILDREN));
|
||||
int i;
|
||||
lua_settop(L, 2);
|
||||
if (!lua_isnumber(L, 2))
|
||||
{
|
||||
enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt);
|
||||
if (!children)
|
||||
{
|
||||
if (field == nodechild_valid) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "accessed node_t doesn't exist anymore.");
|
||||
} else if (field == nodechild_valid) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
} else switch (field) {
|
||||
case nodechild_right: i = 0; break;
|
||||
case nodechild_left: i = 1; break;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = lua_tointeger(L, 2);
|
||||
if (i < 0 || i > 1)
|
||||
return 0;
|
||||
}
|
||||
lua_pushinteger(L, children[i]);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// bounding box (aka fixed_t array with four elements)
|
||||
// NOTE: may be useful for polyobjects or other things later
|
||||
static int bbox_get(lua_State *L)
|
||||
{
|
||||
fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_BBOX));
|
||||
int i;
|
||||
lua_settop(L, 2);
|
||||
if (!lua_isnumber(L, 2))
|
||||
{
|
||||
enum bbox_e field = luaL_checkoption(L, 2, bbox_opt[0], bbox_opt);
|
||||
if (!bbox)
|
||||
{
|
||||
if (field == bbox_valid) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "accessed bbox doesn't exist anymore.");
|
||||
} else if (field == bbox_valid) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
} else switch (field) {
|
||||
case bbox_top: i = BOXTOP; break;
|
||||
case bbox_bottom: i = BOXBOTTOM; break;
|
||||
case bbox_left: i = BOXLEFT; break;
|
||||
case bbox_right: i = BOXRIGHT; break;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = lua_tointeger(L, 2);
|
||||
if (i < 0 || i > 3)
|
||||
return 0;
|
||||
}
|
||||
lua_pushinteger(L, bbox[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_iterateSectors(lua_State *L)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
@ -1048,6 +1330,100 @@ static int lib_numvertexes(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
static int lib_iterateSegs(lua_State *L)
|
||||
{
|
||||
size_t i = 0;
|
||||
if (lua_gettop(L) < 2)
|
||||
return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do <block> end'.");
|
||||
lua_settop(L, 2);
|
||||
lua_remove(L, 1); // state is unused.
|
||||
if (!lua_isnil(L, 1))
|
||||
i = (size_t)(*((seg_t **)luaL_checkudata(L, 1, META_SEG)) - segs)+1;
|
||||
if (i < numsegs)
|
||||
{
|
||||
LUA_PushUserdata(L, &segs[i], META_SEG);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_getSeg(lua_State *L)
|
||||
{
|
||||
int field;
|
||||
lua_settop(L, 2);
|
||||
lua_remove(L, 1); // dummy userdata table is unused.
|
||||
if (lua_isnumber(L, 1))
|
||||
{
|
||||
size_t i = lua_tointeger(L, 1);
|
||||
if (i >= numsegs)
|
||||
return 0;
|
||||
LUA_PushUserdata(L, &segs[i], META_SEG);
|
||||
return 1;
|
||||
}
|
||||
field = luaL_checkoption(L, 1, NULL, array_opt);
|
||||
switch(field)
|
||||
{
|
||||
case 0: // iterate
|
||||
lua_pushcfunction(L, lib_iterateSegs);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_numsegs(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, numsegs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_iterateNodes(lua_State *L)
|
||||
{
|
||||
size_t i = 0;
|
||||
if (lua_gettop(L) < 2)
|
||||
return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do <block> end'.");
|
||||
lua_settop(L, 2);
|
||||
lua_remove(L, 1); // state is unused.
|
||||
if (!lua_isnil(L, 1))
|
||||
i = (size_t)(*((node_t **)luaL_checkudata(L, 1, META_NODE)) - nodes)+1;
|
||||
if (i < numsegs)
|
||||
{
|
||||
LUA_PushUserdata(L, &nodes[i], META_NODE);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_getNode(lua_State *L)
|
||||
{
|
||||
int field;
|
||||
lua_settop(L, 2);
|
||||
lua_remove(L, 1); // dummy userdata table is unused.
|
||||
if (lua_isnumber(L, 1))
|
||||
{
|
||||
size_t i = lua_tointeger(L, 1);
|
||||
if (i >= numnodes)
|
||||
return 0;
|
||||
LUA_PushUserdata(L, &nodes[i], META_NODE);
|
||||
return 1;
|
||||
}
|
||||
field = luaL_checkoption(L, 1, NULL, array_opt);
|
||||
switch(field)
|
||||
{
|
||||
case 0: // iterate
|
||||
lua_pushcfunction(L, lib_iterateNodes);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_numnodes(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, numnodes);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ffloor_get(lua_State *L)
|
||||
{
|
||||
ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
|
||||
|
@ -1367,6 +1743,41 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L, 1);
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
luaL_newmetatable(L, META_SEG);
|
||||
lua_pushcfunction(L, seg_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, seg_num);
|
||||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
luaL_newmetatable(L, META_NODE);
|
||||
lua_pushcfunction(L, node_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, node_num);
|
||||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
luaL_newmetatable(L, META_NODEBBOX);
|
||||
//lua_pushcfunction(L, nodebbox_get);
|
||||
//lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, nodebbox_call);
|
||||
lua_setfield(L, -2, "__call");
|
||||
lua_pop(L, 1);
|
||||
|
||||
luaL_newmetatable(L, META_NODECHILDREN);
|
||||
lua_pushcfunction(L, nodechildren_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pop(L, 1);
|
||||
#endif
|
||||
|
||||
luaL_newmetatable(L, META_BBOX);
|
||||
lua_pushcfunction(L, bbox_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pop(L, 1);
|
||||
|
||||
luaL_newmetatable(L, META_MAPHEADER);
|
||||
lua_pushcfunction(L, mapheaderinfo_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -1425,6 +1836,28 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, "vertexes");
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, lib_getSeg);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, lib_numsegs);
|
||||
lua_setfield(L, -2, "__len");
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, "segs");
|
||||
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, lib_getNode);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, lib_numnodes);
|
||||
lua_setfield(L, -2, "__len");
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, "nodes");
|
||||
#endif
|
||||
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, lib_getMapheaderinfo);
|
||||
|
|
|
@ -34,6 +34,7 @@ enum mobj_e {
|
|||
mobj_angle,
|
||||
mobj_sprite,
|
||||
mobj_frame,
|
||||
mobj_sprite2,
|
||||
mobj_anim_duration,
|
||||
mobj_touching_sectorlist,
|
||||
mobj_subsector,
|
||||
|
@ -93,6 +94,7 @@ static const char *const mobj_opt[] = {
|
|||
"angle",
|
||||
"sprite",
|
||||
"frame",
|
||||
"sprite2",
|
||||
"anim_duration",
|
||||
"touching_sectorlist",
|
||||
"subsector",
|
||||
|
@ -189,6 +191,9 @@ static int mobj_get(lua_State *L)
|
|||
case mobj_frame:
|
||||
lua_pushinteger(L, mo->frame);
|
||||
break;
|
||||
case mobj_sprite2:
|
||||
lua_pushinteger(L, mo->sprite2);
|
||||
break;
|
||||
case mobj_anim_duration:
|
||||
lua_pushinteger(L, mo->anim_duration);
|
||||
break;
|
||||
|
@ -411,6 +416,9 @@ static int mobj_set(lua_State *L)
|
|||
case mobj_frame:
|
||||
mo->frame = (UINT32)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mobj_sprite2:
|
||||
mo->sprite2 = P_GetMobjSprite2(mo, (UINT8)luaL_checkinteger(L, 3));
|
||||
break;
|
||||
case mobj_anim_duration:
|
||||
mo->anim_duration = (UINT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
|
|
|
@ -122,8 +122,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushfixed(L, plr->bob);
|
||||
else if (fastcmp(field,"aiming"))
|
||||
lua_pushangle(L, plr->aiming);
|
||||
else if (fastcmp(field,"health"))
|
||||
lua_pushinteger(L, plr->health);
|
||||
else if (fastcmp(field,"rings"))
|
||||
lua_pushinteger(L, plr->rings);
|
||||
else if (fastcmp(field,"pity"))
|
||||
lua_pushinteger(L, plr->pity);
|
||||
else if (fastcmp(field,"currentweapon"))
|
||||
|
@ -382,8 +382,8 @@ static int player_set(lua_State *L)
|
|||
else if (plr == &players[secondarydisplayplayer])
|
||||
localaiming2 = plr->aiming;
|
||||
}
|
||||
else if (fastcmp(field,"health"))
|
||||
plr->health = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"rings"))
|
||||
plr->rings = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"pity"))
|
||||
plr->pity = (SINT8)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"currentweapon"))
|
||||
|
|
|
@ -48,6 +48,7 @@ static lua_CFunction liblist[] = {
|
|||
LUA_SkinLib, // skin_t, skins[]
|
||||
LUA_ThinkerLib, // thinker_t
|
||||
LUA_MapLib, // line_t, side_t, sector_t, subsector_t
|
||||
LUA_BlockmapLib, // blockmap stuff
|
||||
LUA_HudLib, // HUD stuff
|
||||
NULL
|
||||
};
|
||||
|
@ -395,6 +396,7 @@ void LUA_InvalidateLevel(void)
|
|||
{
|
||||
thinker_t *th;
|
||||
size_t i;
|
||||
ffloor_t *rover = NULL;
|
||||
if (!gL)
|
||||
return;
|
||||
|
||||
|
@ -406,7 +408,15 @@ void LUA_InvalidateLevel(void)
|
|||
for (i = 0; i < numsubsectors; i++)
|
||||
LUA_InvalidateUserdata(&subsectors[i]);
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
LUA_InvalidateUserdata(§ors[i]);
|
||||
LUA_InvalidateUserdata(sectors[i].lines);
|
||||
if (sectors[i].ffloors)
|
||||
{
|
||||
for (rover = sectors[i].ffloors; rover; rover = rover->next)
|
||||
LUA_InvalidateUserdata(rover);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
LUA_InvalidateUserdata(&lines[i]);
|
||||
|
@ -416,6 +426,16 @@ void LUA_InvalidateLevel(void)
|
|||
LUA_InvalidateUserdata(&sides[i]);
|
||||
for (i = 0; i < numvertexes; i++)
|
||||
LUA_InvalidateUserdata(&vertexes[i]);
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
for (i = 0; i < numsegs; i++)
|
||||
LUA_InvalidateUserdata(&segs[i]);
|
||||
for (i = 0; i < numnodes; i++)
|
||||
{
|
||||
LUA_InvalidateUserdata(&nodes[i]);
|
||||
LUA_InvalidateUserdata(nodes[i].bbox);
|
||||
LUA_InvalidateUserdata(nodes[i].children);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LUA_InvalidateMapthings(void)
|
||||
|
@ -455,6 +475,11 @@ enum
|
|||
ARCH_SIDE,
|
||||
ARCH_SUBSECTOR,
|
||||
ARCH_SECTOR,
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
ARCH_SEG,
|
||||
ARCH_NODE,
|
||||
#endif
|
||||
ARCH_FFLOOR,
|
||||
ARCH_MAPHEADER,
|
||||
|
||||
ARCH_TEND=0xFF,
|
||||
|
@ -474,6 +499,11 @@ static const struct {
|
|||
{META_SIDE, ARCH_SIDE},
|
||||
{META_SUBSECTOR,ARCH_SUBSECTOR},
|
||||
{META_SECTOR, ARCH_SECTOR},
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
{META_SEG, ARCH_SEG},
|
||||
{META_NODE, ARCH_NODE},
|
||||
#endif
|
||||
{META_FFLOOR, ARCH_FFLOOR},
|
||||
{META_MAPHEADER, ARCH_MAPHEADER},
|
||||
{NULL, ARCH_NULL}
|
||||
};
|
||||
|
@ -664,6 +694,56 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
|
|||
}
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
case ARCH_SEG:
|
||||
{
|
||||
seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
|
||||
if (!seg)
|
||||
WRITEUINT8(save_p, ARCH_NULL);
|
||||
else {
|
||||
WRITEUINT8(save_p, ARCH_SEG);
|
||||
WRITEUINT16(save_p, seg - segs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARCH_NODE:
|
||||
{
|
||||
node_t *node = *((node_t **)lua_touserdata(gL, myindex));
|
||||
if (!node)
|
||||
WRITEUINT8(save_p, ARCH_NULL);
|
||||
else {
|
||||
WRITEUINT8(save_p, ARCH_NODE);
|
||||
WRITEUINT16(save_p, node - nodes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case ARCH_FFLOOR:
|
||||
{
|
||||
ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
|
||||
if (!rover)
|
||||
WRITEUINT8(save_p, ARCH_NULL);
|
||||
else {
|
||||
ffloor_t *r2;
|
||||
UINT16 i = 0;
|
||||
// search for id
|
||||
for (r2 = rover->target->ffloors; r2; r2 = r2->next)
|
||||
{
|
||||
if (r2 == rover)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
if (!r2)
|
||||
WRITEUINT8(save_p, ARCH_NULL);
|
||||
else
|
||||
{
|
||||
WRITEUINT8(save_p, ARCH_FFLOOR);
|
||||
WRITEUINT16(save_p, rover->target - sectors);
|
||||
WRITEUINT16(save_p, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARCH_MAPHEADER:
|
||||
{
|
||||
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
|
||||
|
@ -842,6 +922,23 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
|
|||
case ARCH_SECTOR:
|
||||
LUA_PushUserdata(gL, §ors[READUINT16(save_p)], META_SECTOR);
|
||||
break;
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
case ARCH_SEG:
|
||||
LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG);
|
||||
break;
|
||||
case ARCH_NODE:
|
||||
LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE);
|
||||
break;
|
||||
#endif
|
||||
case ARCH_FFLOOR:
|
||||
{
|
||||
sector_t *sector = §ors[READUINT16(save_p)];
|
||||
UINT16 id = READUINT16(save_p);
|
||||
ffloor_t *rover = P_GetFFloorByID(sector, id);
|
||||
if (rover)
|
||||
LUA_PushUserdata(gL, rover, META_FFLOOR);
|
||||
break;
|
||||
}
|
||||
case ARCH_MAPHEADER:
|
||||
LUA_PushUserdata(gL, §ors[READUINT16(save_p)], META_MAPHEADER);
|
||||
break;
|
||||
|
|
|
@ -92,4 +92,7 @@ void COM_Lua_f(void);
|
|||
}\
|
||||
}
|
||||
|
||||
// uncomment if you want seg_t/node_t in Lua
|
||||
// #define HAVE_LUA_SEGS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,4 +28,4 @@ void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
|
|||
void *M_AATreeGet(aatree_t *aatree, INT32 key);
|
||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -606,7 +606,7 @@ void Command_CauseCfail_f(void)
|
|||
players[consoleplayer].mo->y = 123311; //cfail cansuled kthxbye
|
||||
players[consoleplayer].mo->z = 123311;
|
||||
players[consoleplayer].score = 1337;
|
||||
players[consoleplayer].health = 1337;
|
||||
players[consoleplayer].rings = 1337;
|
||||
players[consoleplayer].mo->destscale = 25;
|
||||
P_SetThingPosition(players[consoleplayer].mo);
|
||||
|
||||
|
@ -720,7 +720,7 @@ void Command_Setrings_f(void)
|
|||
if (COM_Argc() > 1)
|
||||
{
|
||||
// P_GivePlayerRings does value clamping
|
||||
players[consoleplayer].health = players[consoleplayer].mo->health = 1;
|
||||
players[consoleplayer].rings = 0;
|
||||
P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1)));
|
||||
if (!G_IsSpecialStage(gamemap) || !useNightsSS)
|
||||
players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings
|
||||
|
@ -1298,7 +1298,7 @@ void Command_ObjectPlace_f(void)
|
|||
// Like the classics, recover from death by entering objectplace
|
||||
if (players[0].mo->health <= 0)
|
||||
{
|
||||
players[0].mo->health = players[0].health = 1;
|
||||
players[0].mo->health = 1;
|
||||
players[0].deadtimer = 0;
|
||||
op_oldflags1 = mobjinfo[MT_PLAYER].flags;
|
||||
++players[0].lives;
|
||||
|
|
|
@ -46,41 +46,6 @@ typedef INT32 fixed_t;
|
|||
#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
|
||||
#pragma aux FixedMul = \
|
||||
"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 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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 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)
|
||||
{ // return rounded to nearest whole number, towards zero
|
||||
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 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)
|
||||
return INT32_MIN;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 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)
|
||||
return INT32_MIN;
|
||||
else if (x < FixedFloor(INT32_MAX))
|
||||
|
|
16
src/m_menu.c
16
src/m_menu.c
|
@ -183,9 +183,6 @@ static INT32 vidm_selected = 0;
|
|||
static INT32 vidm_nummodes;
|
||||
static INT32 vidm_column_size;
|
||||
|
||||
// what a headache.
|
||||
static boolean shiftdown = false;
|
||||
|
||||
//
|
||||
// PROTOTYPES
|
||||
//
|
||||
|
@ -2083,11 +2080,6 @@ boolean M_Responder(event_t *ev)
|
|||
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
|
||||
return false;
|
||||
|
||||
if (ev->type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT))
|
||||
{
|
||||
shiftdown = false;
|
||||
return false;
|
||||
}
|
||||
if (noFurtherInput)
|
||||
{
|
||||
// Ignore input after enter/escape/other buttons
|
||||
|
@ -2101,10 +2093,6 @@ boolean M_Responder(event_t *ev)
|
|||
// added 5-2-98 remap virtual keys (mouse & joystick buttons)
|
||||
switch (ch)
|
||||
{
|
||||
case KEY_LSHIFT:
|
||||
case KEY_RSHIFT:
|
||||
shiftdown = true;
|
||||
break; //return false;
|
||||
case KEY_MOUSE1:
|
||||
case KEY_JOY1:
|
||||
case KEY_JOY1 + 2:
|
||||
|
@ -3831,7 +3819,7 @@ static void M_HandleImageDef(INT32 choice)
|
|||
static void M_PandorasBox(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].health - 1, 0));
|
||||
CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0));
|
||||
CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives);
|
||||
CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues);
|
||||
M_SetupNextMenu(&SR_PandoraDef);
|
||||
|
@ -3839,7 +3827,7 @@ static void M_PandorasBox(INT32 choice)
|
|||
|
||||
static boolean M_ExitPandorasBox(void)
|
||||
{
|
||||
if (cv_dummyrings.value != max(players[consoleplayer].health - 1, 0))
|
||||
if (cv_dummyrings.value != max(players[consoleplayer].rings, 0))
|
||||
COM_ImmedExecute(va("setrings %d", cv_dummyrings.value));
|
||||
if (cv_dummylives.value != players[consoleplayer].lives)
|
||||
COM_ImmedExecute(va("setlives %d", cv_dummylives.value));
|
||||
|
|
21
src/m_misc.c
21
src/m_misc.c
|
@ -1617,6 +1617,11 @@ INT32 axtoi(const char *hexStg)
|
|||
return intValue;
|
||||
}
|
||||
|
||||
// Token parser variables
|
||||
|
||||
static UINT32 oldendPos = 0; // old value of endPos, used by M_UnGetToken
|
||||
static UINT32 endPos = 0; // now external to M_GetToken, but still static
|
||||
|
||||
/** Token parser for TEXTURES, ANIMDEFS, and potentially other lumps later down the line.
|
||||
* Was originally R_GetTexturesToken when I was coding up the TEXTURES parser, until I realized I needed it for ANIMDEFS too.
|
||||
* Parses up to the next whitespace character or comma. When finding the start of the next token, whitespace is skipped.
|
||||
|
@ -1631,7 +1636,7 @@ char *M_GetToken(const char *inputString)
|
|||
{
|
||||
static const char *stringToUse = NULL; // Populated if inputString != NULL; used otherwise
|
||||
static UINT32 startPos = 0;
|
||||
static UINT32 endPos = 0;
|
||||
// static UINT32 endPos = 0;
|
||||
static UINT32 stringLength = 0;
|
||||
static UINT8 inComment = 0; // 0 = not in comment, 1 = // Single-line, 2 = /* Multi-line */
|
||||
char *texturesToken = NULL;
|
||||
|
@ -1641,12 +1646,12 @@ char *M_GetToken(const char *inputString)
|
|||
{
|
||||
stringToUse = inputString;
|
||||
startPos = 0;
|
||||
endPos = 0;
|
||||
oldendPos = endPos = 0;
|
||||
stringLength = strlen(inputString);
|
||||
}
|
||||
else
|
||||
{
|
||||
startPos = endPos;
|
||||
startPos = oldendPos = endPos;
|
||||
}
|
||||
if (stringToUse == NULL)
|
||||
return NULL;
|
||||
|
@ -1777,6 +1782,16 @@ char *M_GetToken(const char *inputString)
|
|||
return texturesToken;
|
||||
}
|
||||
|
||||
/** Undoes the last M_GetToken call
|
||||
* The current position along the string being parsed is reset to the last saved position.
|
||||
* This exists mostly because of R_ParseTexture/R_ParsePatch honestly, but could be useful elsewhere?
|
||||
* -Monster Iestyn (22/10/16)
|
||||
*/
|
||||
void M_UnGetToken(void)
|
||||
{
|
||||
endPos = oldendPos;
|
||||
}
|
||||
|
||||
/** Count bits in a number.
|
||||
*/
|
||||
UINT8 M_CountBits(UINT32 num, UINT8 size)
|
||||
|
|
|
@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable)
|
|||
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) {}
|
||||
|
||||
#include "../sdl/dosstr.c"
|
||||
|
|
723
src/p_enemy.c
723
src/p_enemy.c
|
@ -104,6 +104,9 @@ void A_BombShield(mobj_t *actor);
|
|||
void A_WaterShield(mobj_t *actor);
|
||||
void A_ForceShield(mobj_t *actor);
|
||||
void A_PityShield(mobj_t *actor);
|
||||
void A_FlameShield(mobj_t *actor);
|
||||
void A_BubbleShield(mobj_t *actor);
|
||||
void A_ThunderShield(mobj_t *actor);
|
||||
void A_GravityBox(mobj_t *actor);
|
||||
void A_ScoreRise(mobj_t *actor);
|
||||
void A_ParticleSpawn(mobj_t *actor);
|
||||
|
@ -239,6 +242,17 @@ void A_BrakFireShot(mobj_t *actor);
|
|||
void A_BrakLobShot(mobj_t *actor);
|
||||
void A_NapalmScatter(mobj_t *actor);
|
||||
void A_SpawnFreshCopy(mobj_t *actor);
|
||||
void A_FlickySpawn(mobj_t *actor);
|
||||
void A_FlickyAim(mobj_t *actor);
|
||||
void A_FlickyFly(mobj_t *actor);
|
||||
void A_FlickySoar(mobj_t *actor);
|
||||
void A_FlickyCoast(mobj_t *actor);
|
||||
void A_FlickyHop(mobj_t *actor);
|
||||
void A_FlickyFlounder(mobj_t *actor);
|
||||
void A_FlickyCheck(mobj_t *actor);
|
||||
void A_FlickyHeightCheck(mobj_t *actor);
|
||||
void A_FlickyFlutter(mobj_t *actor);
|
||||
void A_FlameParticle(mobj_t *actor);
|
||||
|
||||
//
|
||||
// ENEMY THINKING
|
||||
|
@ -658,15 +672,15 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
|
|||
if ((netgame || multiplayer) && player->spectator)
|
||||
continue;
|
||||
|
||||
if (player->health <= 0)
|
||||
continue; // dead
|
||||
|
||||
if (player->pflags & PF_INVIS)
|
||||
continue; // ignore notarget
|
||||
|
||||
if (!player->mo || P_MobjWasRemoved(player->mo))
|
||||
continue;
|
||||
|
||||
if (player->mo->health <= 0)
|
||||
continue; // dead
|
||||
|
||||
if (dist > 0
|
||||
&& P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist)
|
||||
continue; // Too far away
|
||||
|
@ -730,7 +744,7 @@ static boolean P_LookForShield(mobj_t *actor)
|
|||
|
||||
player = &players[actor->lastlook];
|
||||
|
||||
if (player->health <= 0 || !player->mo)
|
||||
if (!player->mo || player->mo->health <= 0)
|
||||
continue; // dead
|
||||
|
||||
//When in CTF, don't pull rings that you cannot pick up.
|
||||
|
@ -738,7 +752,7 @@ static boolean P_LookForShield(mobj_t *actor)
|
|||
(actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
|
||||
continue;
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
|
||||
if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
|
||||
&& (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale)))
|
||||
{
|
||||
P_SetTarget(&actor->tracer, player->mo);
|
||||
|
@ -2121,13 +2135,15 @@ void A_Boss1Laser(mobj_t *actor)
|
|||
if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
|
||||
{
|
||||
point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET);
|
||||
point->angle = actor->angle;
|
||||
point->fuse = actor->tics+1;
|
||||
P_SetTarget(&point->target, actor->target);
|
||||
P_SetTarget(&actor->target, point);
|
||||
}
|
||||
}
|
||||
/* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path
|
||||
else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
|
||||
actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);
|
||||
actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/
|
||||
|
||||
if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)
|
||||
angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT);
|
||||
|
@ -2177,11 +2193,16 @@ void A_Boss1Laser(mobj_t *actor)
|
|||
// var1:
|
||||
// 0 - accelerative focus with friction
|
||||
// 1 - steady focus with fixed movement speed
|
||||
// var2 = unused
|
||||
// anything else - don't move
|
||||
// var2:
|
||||
// 0 - don't trace target, just move forwards
|
||||
// & 1 - change horizontal angle
|
||||
// & 2 - change vertical angle
|
||||
//
|
||||
void A_FocusTarget(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FocusTarget", actor))
|
||||
return;
|
||||
|
@ -2190,9 +2211,9 @@ void A_FocusTarget(mobj_t *actor)
|
|||
if (actor->target)
|
||||
{
|
||||
fixed_t speed = FixedMul(actor->info->speed, actor->scale);
|
||||
fixed_t dist = R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y);
|
||||
angle_t vangle = R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist);
|
||||
angle_t hangle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
|
||||
fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1);
|
||||
angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle);
|
||||
angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90);
|
||||
switch(locvar1)
|
||||
{
|
||||
case 0:
|
||||
|
@ -2553,6 +2574,7 @@ void A_1upThinker(mobj_t *actor)
|
|||
{
|
||||
P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY));
|
||||
P_SetTarget(&actor->tracer->target, actor);
|
||||
actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame
|
||||
P_SetMobjState(actor->tracer, actor->info->seestate);
|
||||
|
||||
// The overlay is going to be one tic early turning off and on
|
||||
|
@ -2813,7 +2835,7 @@ void A_BossDeath(mobj_t *mo)
|
|||
|
||||
// make sure there is a player alive for victory
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && (players[i].health > 0
|
||||
if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0)
|
||||
|| ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0))))
|
||||
break;
|
||||
|
||||
|
@ -3058,11 +3080,7 @@ void A_JumpShield(mobj_t *actor)
|
|||
|
||||
player = actor->target->player;
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_JUMP)
|
||||
{
|
||||
player->powers[pw_shield] = SH_JUMP|(player->powers[pw_shield] & SH_STACK);
|
||||
P_SpawnShieldOrb(player);
|
||||
}
|
||||
P_SwitchShield(player, SH_WHIRLWIND);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
@ -3090,11 +3108,7 @@ void A_RingShield(mobj_t *actor)
|
|||
|
||||
player = actor->target->player;
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT)
|
||||
{
|
||||
player->powers[pw_shield] = SH_ATTRACT|(player->powers[pw_shield] & SH_STACK);
|
||||
P_SpawnShieldOrb(player);
|
||||
}
|
||||
P_SwitchShield(player, SH_ATTRACT);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
@ -3291,11 +3305,12 @@ void A_BombShield(mobj_t *actor)
|
|||
|
||||
player = actor->target->player;
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_BOMB)
|
||||
{
|
||||
player->powers[pw_shield] = SH_BOMB|(player->powers[pw_shield] & SH_STACK);
|
||||
P_SpawnShieldOrb(player);
|
||||
}
|
||||
// If you already have a bomb shield, use it!
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ARMAGEDDON)
|
||||
P_BlackOw(player);
|
||||
|
||||
// Now we know for certain that we don't have a bomb shield, so add one. :3
|
||||
P_SwitchShield(player, SH_ARMAGEDDON);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
@ -3323,22 +3338,8 @@ void A_WaterShield(mobj_t *actor)
|
|||
|
||||
player = actor->target->player;
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL)
|
||||
{
|
||||
player->powers[pw_shield] = SH_ELEMENTAL|(player->powers[pw_shield] & SH_STACK);
|
||||
P_SpawnShieldOrb(player);
|
||||
}
|
||||
P_SwitchShield(player, SH_ELEMENTAL);
|
||||
|
||||
if (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)
|
||||
P_RestoreMusic(player);
|
||||
|
||||
player->powers[pw_underwater] = 0;
|
||||
|
||||
if (player->powers[pw_spacetime] > 1)
|
||||
{
|
||||
player->powers[pw_spacetime] = 0;
|
||||
P_RestoreMusic(player);
|
||||
}
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
||||
|
@ -3346,12 +3347,13 @@ void A_WaterShield(mobj_t *actor)
|
|||
//
|
||||
// Description: Awards the player a force shield.
|
||||
//
|
||||
// var1 = unused
|
||||
// var1 = Number of additional hitpoints to give
|
||||
// var2 = unused
|
||||
//
|
||||
void A_ForceShield(mobj_t *actor)
|
||||
{
|
||||
player_t *player;
|
||||
INT32 locvar1 = var1;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_ForceShield", actor))
|
||||
|
@ -3363,15 +3365,15 @@ void A_ForceShield(mobj_t *actor)
|
|||
return;
|
||||
}
|
||||
|
||||
if (locvar1 & ~SH_FORCEHP)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Invalid number of additional hitpoints.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
player = actor->target->player;
|
||||
|
||||
if (!(player->powers[pw_shield] & SH_FORCE))
|
||||
{
|
||||
player->powers[pw_shield] = SH_FORCE|(player->powers[pw_shield] & SH_STACK)|0x01;
|
||||
P_SpawnShieldOrb(player);
|
||||
}
|
||||
else
|
||||
player->powers[pw_shield] = SH_FORCE|(player->powers[pw_shield] & SH_STACK)|0x01;
|
||||
P_SwitchShield(player, SH_FORCE|locvar1);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
@ -3403,12 +3405,92 @@ void A_PityShield(mobj_t *actor)
|
|||
|
||||
player = actor->target->player;
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_PITY)
|
||||
P_SwitchShield(player, SH_PITY);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
||||
// Function: A_FlameShield
|
||||
//
|
||||
// Description: Awards the player a flame shield.
|
||||
//
|
||||
// var1 = unused
|
||||
// var2 = unused
|
||||
//
|
||||
void A_FlameShield(mobj_t *actor)
|
||||
{
|
||||
player_t *player;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlameShield", actor))
|
||||
return;
|
||||
#endif
|
||||
if (!actor->target || !actor->target->player)
|
||||
{
|
||||
player->powers[pw_shield] = SH_PITY+(player->powers[pw_shield] & SH_STACK);
|
||||
P_SpawnShieldOrb(player);
|
||||
CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
player = actor->target->player;
|
||||
|
||||
P_SwitchShield(player, SH_FLAMEAURA);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
||||
// Function: A_BubbleShield
|
||||
//
|
||||
// Description: Awards the player a bubble shield.
|
||||
//
|
||||
// var1 = unused
|
||||
// var2 = unused
|
||||
//
|
||||
void A_BubbleShield(mobj_t *actor)
|
||||
{
|
||||
player_t *player;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_BubbleShield", actor))
|
||||
return;
|
||||
#endif
|
||||
if (!actor->target || !actor->target->player)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
player = actor->target->player;
|
||||
|
||||
P_SwitchShield(player, SH_BUBBLEWRAP);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
||||
// Function: A_ThunderShield
|
||||
//
|
||||
// Description: Awards the player a thunder shield.
|
||||
//
|
||||
// var1 = unused
|
||||
// var2 = unused
|
||||
//
|
||||
void A_ThunderShield(mobj_t *actor)
|
||||
{
|
||||
player_t *player;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_ThunderShield", actor))
|
||||
return;
|
||||
#endif
|
||||
if (!actor->target || !actor->target->player)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
player = actor->target->player;
|
||||
|
||||
P_SwitchShield(player, SH_THUNDERCOIN);
|
||||
|
||||
S_StartSound(player->mo, actor->info->seesound);
|
||||
}
|
||||
|
||||
|
@ -3435,9 +3517,10 @@ void A_GravityBox(mobj_t *actor)
|
|||
}
|
||||
|
||||
player = actor->target->player;
|
||||
player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1);
|
||||
|
||||
S_StartSound(player, actor->info->activesound);
|
||||
|
||||
player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1);
|
||||
}
|
||||
|
||||
// Function: A_ScoreRise
|
||||
|
@ -3459,41 +3542,49 @@ void A_ScoreRise(mobj_t *actor)
|
|||
|
||||
// Function: A_ParticleSpawn
|
||||
//
|
||||
// Description: Spawns a particle at a specified interval
|
||||
// Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN.
|
||||
//
|
||||
// var1 = type (if 0, defaults to MT_PARTICLE)
|
||||
// var1 = unused
|
||||
// var2 = unused
|
||||
//
|
||||
void A_ParticleSpawn(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
fixed_t speed;
|
||||
mobjtype_t type;
|
||||
INT32 i = 0;
|
||||
mobj_t *spawn;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_ParticleSpawn", actor))
|
||||
return;
|
||||
#endif
|
||||
if (!actor->spawnpoint)
|
||||
{
|
||||
P_RemoveMobj(actor);
|
||||
if (!actor->health)
|
||||
return;
|
||||
|
||||
if (!actor->lastlook)
|
||||
return;
|
||||
|
||||
if (!actor->threshold)
|
||||
return;
|
||||
|
||||
for (i = 0; i < actor->lastlook; i++)
|
||||
{
|
||||
spawn = P_SpawnMobj(
|
||||
actor->x + FixedMul(FixedMul(actor->friction, actor->scale), FINECOSINE(actor->angle>>ANGLETOFINESHIFT)),
|
||||
actor->y + FixedMul(FixedMul(actor->friction, actor->scale), FINESINE(actor->angle>>ANGLETOFINESHIFT)),
|
||||
actor->z,
|
||||
(mobjtype_t)actor->threshold);
|
||||
P_SetScale(spawn, actor->scale);
|
||||
spawn->momz = FixedMul(actor->movefactor, spawn->scale);
|
||||
spawn->destscale = spawn->scale/100;
|
||||
spawn->scalespeed = spawn->scale/actor->health;
|
||||
spawn->tics = (tic_t)actor->health;
|
||||
spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP);
|
||||
spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
|
||||
if (spawn->frame & FF_ANIMATE)
|
||||
spawn->frame += P_RandomKey(spawn->state->var1);
|
||||
|
||||
actor->angle += actor->movedir;
|
||||
}
|
||||
|
||||
if (locvar1)
|
||||
type = (mobjtype_t)locvar1;
|
||||
else
|
||||
type = MT_PARTICLE;
|
||||
|
||||
speed = FixedMul((actor->spawnpoint->angle >> 12)<<FRACBITS, actor->scale);
|
||||
|
||||
spawn = P_SpawnMobj(actor->x, actor->y, actor->z, type);
|
||||
P_SetScale(spawn, actor->scale);
|
||||
spawn->momz = speed;
|
||||
spawn->destscale = FixedDiv(spawn->scale<<FRACBITS, 100<<FRACBITS);
|
||||
spawn->scalespeed = FixedDiv(((actor->spawnpoint->angle >> 8) & 63) << FRACBITS, 100<<FRACBITS);
|
||||
actor->tics = actor->spawnpoint->extrainfo + 1;
|
||||
actor->angle += (angle_t)actor->movecount;
|
||||
}
|
||||
|
||||
// Function: A_BunnyHop
|
||||
|
@ -3703,7 +3794,7 @@ void A_AttractChase(mobj_t *actor)
|
|||
|
||||
// Turn flingrings back into regular rings if attracted.
|
||||
if (actor->tracer && actor->tracer->player
|
||||
&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
|
||||
&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
|
||||
{
|
||||
mobj_t *newring;
|
||||
newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
|
||||
|
@ -3807,11 +3898,18 @@ void A_DropMine(mobj_t *actor)
|
|||
void A_FishJump(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FishJump", actor))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (locvar2)
|
||||
{
|
||||
fixed_t rad = actor->radius>>FRACBITS;
|
||||
P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<<FRACBITS, P_RandomRange(rad, -rad)<<FRACBITS, 0, (mobjtype_t)locvar2);
|
||||
}
|
||||
|
||||
if ((actor->z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale)))
|
||||
{
|
||||
fixed_t jumpval;
|
||||
|
@ -3908,7 +4006,7 @@ void A_ThrownRing(mobj_t *actor)
|
|||
// A non-homing ring getting attracted by a
|
||||
// magnetic player. If he gets too far away, make
|
||||
// sure to stop the attraction!
|
||||
if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
|
||||
if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC)
|
||||
&& P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x,
|
||||
actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale)))
|
||||
{
|
||||
|
@ -3916,7 +4014,7 @@ void A_ThrownRing(mobj_t *actor)
|
|||
}
|
||||
|
||||
if (actor->tracer && (actor->tracer->health)
|
||||
&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)// Already found someone to follow.
|
||||
&& (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow.
|
||||
{
|
||||
const INT32 temp = actor->threshold;
|
||||
actor->threshold = 32000;
|
||||
|
@ -3984,7 +4082,7 @@ void A_ThrownRing(mobj_t *actor)
|
|||
if (!P_CheckSight(actor, player->mo))
|
||||
continue; // out of sight
|
||||
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
|
||||
if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
|
||||
&& dist < FixedMul(RING_DIST/4, player->mo->scale))
|
||||
P_SetTarget(&actor->tracer, player->mo);
|
||||
return;
|
||||
|
@ -7763,7 +7861,7 @@ void A_SetObjectFlags(mobj_t *actor)
|
|||
else if (locvar2 == 1)
|
||||
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;
|
||||
|
||||
if (unlinkthings) {
|
||||
|
@ -8379,7 +8477,7 @@ void A_RingDrain(mobj_t *actor)
|
|||
}
|
||||
|
||||
player = actor->target->player;
|
||||
P_GivePlayerRings(player, -min(locvar1, player->mo->health-1));
|
||||
P_GivePlayerRings(player, -min(locvar1, player->rings));
|
||||
}
|
||||
|
||||
// Function: A_SplitShot
|
||||
|
@ -8687,7 +8785,7 @@ void A_CheckTargetRings(mobj_t *actor)
|
|||
if (!(actor->target) || !(actor->target->player))
|
||||
return;
|
||||
|
||||
if (actor->target->player->health >= locvar1)
|
||||
if (actor->target->player->rings >= locvar1)
|
||||
P_SetMobjState(actor, locvar2);
|
||||
}
|
||||
|
||||
|
@ -8709,7 +8807,7 @@ void A_CheckRings(mobj_t *actor)
|
|||
#endif
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
cntr += players[i].health-1;
|
||||
cntr += players[i].rings;
|
||||
|
||||
if (cntr >= locvar1)
|
||||
P_SetMobjState(actor, locvar2);
|
||||
|
@ -9281,7 +9379,7 @@ void A_ForceWin(mobj_t *actor)
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && (players[i].health > 0
|
||||
if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0)
|
||||
|| ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0))))
|
||||
break;
|
||||
}
|
||||
|
@ -9548,14 +9646,19 @@ void A_HomingChase(mobj_t *actor)
|
|||
// lower 16 bits = object # to fire
|
||||
// upper 16 bits = front offset
|
||||
// var2:
|
||||
// lower 16 bits = vertical angle
|
||||
// lower 15 bits = vertical angle variable
|
||||
// 16th bit:
|
||||
// - 0: use vertical angle variable as vertical angle in degrees
|
||||
// - 1: mimic P_SpawnXYZMissile
|
||||
// use z of actor minus z of missile as vertical distance to cover during momz calculation
|
||||
// use vertical angle variable as horizontal distance to cover during momz calculation
|
||||
// upper 16 bits = height offset
|
||||
//
|
||||
void A_TrapShot(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
angle_t vertang = FixedAngle(((INT16)(locvar2 & 65535))*FRACUNIT);
|
||||
boolean oldstyle = (locvar2 & 32768) ? true : false;
|
||||
mobjtype_t type = (mobjtype_t)(locvar1 & 65535);
|
||||
mobj_t *missile;
|
||||
INT16 frontoff = (INT16)(locvar1 >> 16);
|
||||
|
@ -9571,10 +9674,7 @@ void A_TrapShot(mobj_t *actor)
|
|||
y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale));
|
||||
|
||||
if (actor->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale);
|
||||
vertang = InvAngle(vertang); // flip firing angle
|
||||
}
|
||||
else
|
||||
z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale);
|
||||
|
||||
|
@ -9585,20 +9685,35 @@ void A_TrapShot(mobj_t *actor)
|
|||
|
||||
if (actor->eflags & MFE_VERTICALFLIP)
|
||||
missile->flags2 |= MF2_OBJECTFLIP;
|
||||
missile->destscale = actor->destscale;
|
||||
P_SetScale(missile, missile->destscale);
|
||||
|
||||
missile->destscale = actor->scale;
|
||||
P_SetScale(missile, actor->scale);
|
||||
|
||||
if (missile->info->seesound)
|
||||
S_StartSound(actor, missile->info->seesound);
|
||||
S_StartSound(missile, missile->info->seesound);
|
||||
|
||||
P_SetTarget(&missile->target, actor);
|
||||
missile->angle = actor->angle;
|
||||
|
||||
speed = FixedMul(missile->info->speed, missile->scale);
|
||||
|
||||
missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed));
|
||||
missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed));
|
||||
missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed);
|
||||
if (oldstyle)
|
||||
{
|
||||
missile->momx = FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed);
|
||||
missile->momy = FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed);
|
||||
// The below line basically mimics P_SpawnXYZMissile's momz calculation.
|
||||
missile->momz = (actor->z + ((actor->eflags & MFE_VERTICALFLIP) ? actor->height : 0) - z) / ((fixed_t)(locvar2 & 32767)*FRACUNIT / speed);
|
||||
P_CheckMissileSpawn(missile);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t vertang = FixedAngle(((INT16)(locvar2 & 32767))*FRACUNIT);
|
||||
if (actor->eflags & MFE_VERTICALFLIP)
|
||||
vertang = InvAngle(vertang); // flip firing angle
|
||||
missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed));
|
||||
missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed));
|
||||
missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed);
|
||||
}
|
||||
}
|
||||
|
||||
// Function: A_VileTarget
|
||||
|
@ -10271,3 +10386,421 @@ void A_SpawnFreshCopy(mobj_t *actor)
|
|||
if (newObject->info->seesound)
|
||||
S_StartSound(newObject, newObject->info->seesound);
|
||||
}
|
||||
|
||||
// Internal Flicky spawning function.
|
||||
mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers)
|
||||
{
|
||||
mobj_t *flicky;
|
||||
|
||||
if (!flickytype)
|
||||
{
|
||||
if (!mapheaderinfo[gamemap-1] || !mapheaderinfo[gamemap-1]->numFlickies) // No mapheader, no shoes, no service.
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
INT32 prandom = P_RandomKey(mapheaderinfo[gamemap-1]->numFlickies);
|
||||
flickytype = mapheaderinfo[gamemap-1]->flickies[prandom];
|
||||
}
|
||||
}
|
||||
|
||||
flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype);
|
||||
flicky->angle = actor->angle;
|
||||
|
||||
if (flickytype == MT_SEED)
|
||||
flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2;
|
||||
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
|
||||
|
||||
P_SetObjectMomZ(flicky, momz, false);
|
||||
flicky->movedir = (P_RandomChance(FRACUNIT/2) ? -1 : 1);
|
||||
flicky->fuse = P_RandomRange(595, 700); // originally 300, 350
|
||||
flicky->threshold = 0;
|
||||
|
||||
if (lookforplayers)
|
||||
P_LookForPlayers(flicky, true, false, 0);
|
||||
|
||||
return flicky;
|
||||
}
|
||||
|
||||
// Function: A_FlickySpawn
|
||||
//
|
||||
// Description: Flicky spawning function.
|
||||
//
|
||||
// var1:
|
||||
// lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type.
|
||||
// upper 16 bits: if 0, no sound is played. Else, A_Scream is called.
|
||||
// var2 = upwards thrust for spawned flicky. If zero, default value is provided.
|
||||
//
|
||||
void A_FlickySpawn(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickySpawn", actor))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (locvar1 >> 16) {
|
||||
A_Scream(actor); // A shortcut for the truly lazy.
|
||||
locvar1 &= 65535;
|
||||
}
|
||||
|
||||
P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true);
|
||||
}
|
||||
|
||||
// Internal Flicky bubbling function.
|
||||
void P_InternalFlickyBubble(mobj_t *actor)
|
||||
{
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
mobj_t *overlay;
|
||||
|
||||
if (!((actor->z + 3*actor->height/2) < actor->watertop) || !mobjinfo[actor->type].raisestate || actor->tracer)
|
||||
return;
|
||||
|
||||
overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
|
||||
P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate);
|
||||
P_SetTarget(&actor->tracer, overlay);
|
||||
P_SetTarget(&overlay->target, actor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!actor->tracer || P_MobjWasRemoved(actor->tracer))
|
||||
return;
|
||||
|
||||
P_RemoveMobj(actor->tracer);
|
||||
P_SetTarget(&actor->tracer, NULL);
|
||||
}
|
||||
|
||||
// Function: A_FlickyAim
|
||||
//
|
||||
// Description: Flicky aiming function.
|
||||
//
|
||||
// var1 = how far around the target (in angle constants) the flicky should look
|
||||
// var2 = distance from target to aim for
|
||||
//
|
||||
void A_FlickyAim(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
boolean flickyhitwall = false;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyAim", actor))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (actor->momx == actor->momy && actor->momy == 0)
|
||||
flickyhitwall = true;
|
||||
|
||||
P_InternalFlickyBubble(actor);
|
||||
P_InstaThrust(actor, 0, 0);
|
||||
|
||||
if (!actor->target)
|
||||
{
|
||||
P_LookForPlayers(actor, true, false, 0);
|
||||
actor->angle = P_RandomKey(36)*ANG10;
|
||||
return;
|
||||
}
|
||||
|
||||
if (actor->fuse > 2*TICRATE)
|
||||
{
|
||||
angle_t posvar;
|
||||
fixed_t chasevar, chasex, chasey;
|
||||
|
||||
if (flickyhitwall)
|
||||
actor->movedir *= -1;
|
||||
|
||||
posvar = ((R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + actor->movedir*locvar1) >> ANGLETOFINESHIFT) & FINEMASK;
|
||||
chasevar = FixedSqrt(max(FRACUNIT, P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y) - locvar2)) + locvar2;
|
||||
|
||||
chasex = actor->target->x + FixedMul(FINECOSINE(posvar), chasevar);
|
||||
chasey = actor->target->y + FixedMul(FINESINE(posvar), chasevar);
|
||||
|
||||
if (P_AproxDistance(chasex - actor->x, chasey - actor->y))
|
||||
actor->angle = R_PointToAngle2(actor->x, actor->y, chasex, chasey);
|
||||
}
|
||||
else if (flickyhitwall)
|
||||
{
|
||||
actor->angle += ANGLE_180;
|
||||
actor->threshold = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Internal Flicky flying function. Also usuable as an underwater swim thrust.
|
||||
void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez)
|
||||
{
|
||||
angle_t vertangle;
|
||||
|
||||
flyspeed = FixedMul(flyspeed, actor->scale);
|
||||
actor->flags |= MF_NOGRAVITY;
|
||||
|
||||
var1 = ANG30;
|
||||
var2 = 32*FRACUNIT;
|
||||
A_FlickyAim(actor);
|
||||
|
||||
chasez *= 8;
|
||||
if (!actor->target || !(actor->fuse > 2*TICRATE))
|
||||
chasez += ((actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz - 24*FRACUNIT : actor->floorz + 24*FRACUNIT);
|
||||
else
|
||||
{
|
||||
fixed_t add = actor->target->z + (actor->target->height - actor->height)/2;
|
||||
if (add > (actor->ceilingz - 24*actor->scale - actor->height))
|
||||
add = actor->ceilingz - 24*actor->scale - actor->height;
|
||||
else if (add < (actor->floorz + 24*actor->scale))
|
||||
add = actor->floorz + 24*actor->scale;
|
||||
chasez += add;
|
||||
}
|
||||
|
||||
if (!targetdist)
|
||||
targetdist = 16*FRACUNIT; //Default!
|
||||
|
||||
if (actor->target && abs(chasez - actor->z) > targetdist)
|
||||
targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
|
||||
|
||||
vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK;
|
||||
P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed));
|
||||
actor->momz = FixedMul(FINESINE(vertangle), flyspeed);
|
||||
}
|
||||
|
||||
// Function: A_FlickyFly
|
||||
//
|
||||
// Description: Flicky flying function.
|
||||
//
|
||||
// var1 = how fast to fly
|
||||
// var2 = how far ahead the target should be considered
|
||||
//
|
||||
void A_FlickyFly(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyFly", actor))
|
||||
return;
|
||||
#endif
|
||||
P_InternalFlickyFly(actor, var1, var2,
|
||||
FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK)
|
||||
);
|
||||
}
|
||||
|
||||
// Function: A_FlickySoar
|
||||
//
|
||||
// Description: Flicky soaring function - specific to puffin.
|
||||
//
|
||||
// var1 = how fast to fly
|
||||
// var2 = how far ahead the target should be considered
|
||||
//
|
||||
void A_FlickySoar(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickySoar", actor))
|
||||
return;
|
||||
#endif
|
||||
P_InternalFlickyFly(actor, var1, var2,
|
||||
2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK)))
|
||||
);
|
||||
|
||||
if (P_MobjFlip(actor)*actor->momz > 0 && actor->frame == 1 && actor->sprite == SPR_FL10)
|
||||
actor->frame = 3;
|
||||
}
|
||||
|
||||
//Function: A_FlickyCoast
|
||||
//
|
||||
// Description: Flicky swim-coasting function.
|
||||
//
|
||||
// var1 = speed to change state upon reaching
|
||||
// var2 = state to change to upon slowing down
|
||||
// the spawnstate of the mobj = state to change to when above water
|
||||
//
|
||||
void A_FlickyCoast(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyCoast", actor))
|
||||
return;
|
||||
#endif
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
actor->momx = (11*actor->momx)/12;
|
||||
actor->momy = (11*actor->momy)/12;
|
||||
actor->momz = (11*actor->momz)/12;
|
||||
|
||||
if (P_AproxDistance(P_AproxDistance(actor->momx, actor->momy), actor->momz) < locvar1)
|
||||
P_SetMobjState(actor, locvar2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
actor->flags &= ~MF_NOGRAVITY;
|
||||
P_SetMobjState(actor, mobjinfo[actor->type].spawnstate);
|
||||
}
|
||||
|
||||
// Internal Flicky hopping function.
|
||||
void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle)
|
||||
{
|
||||
if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
|
||||
|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
|
||||
{
|
||||
if (momz)
|
||||
{
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
|
||||
P_SetObjectMomZ(actor, momz, false);
|
||||
}
|
||||
P_InstaThrust(actor, angle, FixedMul(momh, actor->scale));
|
||||
}
|
||||
}
|
||||
|
||||
// Function: A_FlickyHop
|
||||
//
|
||||
// Description: Flicky hopping function.
|
||||
//
|
||||
// var1 = vertical thrust
|
||||
// var2 = horizontal thrust
|
||||
//
|
||||
void A_FlickyHop(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyHop instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyHop", actor))
|
||||
return;
|
||||
#endif
|
||||
P_InternalFlickyHop(actor, var1, var2, actor->angle);
|
||||
}
|
||||
|
||||
// Function: A_FlickyFlounder
|
||||
//
|
||||
// Description: Flicky floundering function.
|
||||
//
|
||||
// var1 = intended vertical thrust
|
||||
// var2 = intended horizontal thrust
|
||||
//
|
||||
void A_FlickyFlounder(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
angle_t hopangle;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyFlounder", actor))
|
||||
return;
|
||||
#endif
|
||||
locvar1 *= (P_RandomKey(2) + 1);
|
||||
locvar2 *= (P_RandomKey(2) + 1);
|
||||
hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2);
|
||||
P_InternalFlickyHop(actor, locvar1, locvar2, hopangle);
|
||||
}
|
||||
|
||||
// Function: A_FlickyCheck
|
||||
//
|
||||
// Description: Flicky airtime check function.
|
||||
//
|
||||
// var1 = state to change to upon touching the floor
|
||||
// var2 = state to change to upon falling
|
||||
// the meleestate of the mobj = state to change to when underwater
|
||||
//
|
||||
void A_FlickyCheck(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyCheck", actor))
|
||||
return;
|
||||
#endif
|
||||
if (locvar2 && P_MobjFlip(actor)*actor->momz < 1)
|
||||
P_SetMobjState(actor, locvar2);
|
||||
else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
|
||||
|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
|
||||
P_SetMobjState(actor, locvar1);
|
||||
else if (mobjinfo[actor->type].meleestate && (actor->eflags & MFE_UNDERWATER))
|
||||
P_SetMobjState(actor, mobjinfo[actor->type].meleestate);
|
||||
P_InternalFlickyBubble(actor);
|
||||
}
|
||||
|
||||
// Function: A_FlickyHeightCheck
|
||||
//
|
||||
// Description: Flicky height check function.
|
||||
//
|
||||
// var1 = state to change to when falling below height relative to target
|
||||
// var2 = height relative to target to change state at
|
||||
//
|
||||
void A_FlickyHeightCheck(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyHeightCheck", actor))
|
||||
return;
|
||||
#endif
|
||||
if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1
|
||||
&& ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2)
|
||||
|| (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz)))
|
||||
P_SetMobjState(actor, locvar1);
|
||||
P_InternalFlickyBubble(actor);
|
||||
}
|
||||
|
||||
// Function: A_FlickyFlutter
|
||||
//
|
||||
// Description: Flicky fluttering function - specific to chicken.
|
||||
//
|
||||
// var1 = state to change to upon touching the floor
|
||||
// var2 = state to change to upon falling
|
||||
// the meleestate of the mobj = state to change to when underwater
|
||||
//
|
||||
void A_FlickyFlutter(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to A_FlickyCheck instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyFlutter", actor))
|
||||
return;
|
||||
#endif
|
||||
A_FlickyCheck(actor);
|
||||
|
||||
var1 = ANG30;
|
||||
var2 = 32*FRACUNIT;
|
||||
A_FlickyAim(actor);
|
||||
|
||||
P_InstaThrust(actor, actor->angle, 2*actor->scale);
|
||||
if (P_MobjFlip(actor)*actor->momz < -FRACUNIT/2)
|
||||
actor->momz = -P_MobjFlip(actor)*actor->scale/2;
|
||||
}
|
||||
|
||||
#undef FLICKYHITWALL
|
||||
|
||||
// Function: A_FlameParticle
|
||||
//
|
||||
// Description: Creates the mobj's painchance at a random position around the object's radius.
|
||||
//
|
||||
// var1 = momz of particle.
|
||||
//
|
||||
void A_FlameParticle(mobj_t *actor)
|
||||
{
|
||||
mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance);
|
||||
INT32 locvar1 = var1;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlameParticle", actor))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (type)
|
||||
{
|
||||
fixed_t rad = 2*actor->radius>>FRACBITS;
|
||||
fixed_t hei = actor->height>>FRACBITS;
|
||||
mobj_t *particle = P_SpawnMobjFromMobj(actor,
|
||||
P_RandomRange(rad, -rad)<<FRACBITS,
|
||||
P_RandomRange(rad, -rad)<<FRACBITS,
|
||||
P_RandomRange(hei/2, hei)<<FRACBITS,
|
||||
type);
|
||||
P_SetObjectMomZ(particle, locvar1<<FRACBITS, false);
|
||||
}
|
||||
}
|
||||
|
|
176
src/p_floor.c
176
src/p_floor.c
|
@ -13,7 +13,11 @@
|
|||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_random.h"
|
||||
#include "p_local.h"
|
||||
#ifdef ESLOPE
|
||||
#include "p_slopes.h"
|
||||
#endif
|
||||
#include "r_state.h"
|
||||
#include "s_sound.h"
|
||||
#include "z_zone.h"
|
||||
|
@ -1141,6 +1145,7 @@ void T_MarioBlock(levelspecthink_t *block)
|
|||
block->sector->ceilingdata = NULL;
|
||||
block->sector->floorspeed = 0;
|
||||
block->sector->ceilspeed = 0;
|
||||
block->direction = 0;
|
||||
}
|
||||
|
||||
for (i = -1; (i = P_FindSectorFromTag((INT16)block->vars[0], i)) >= 0 ;)
|
||||
|
@ -1748,12 +1753,15 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
|
|||
case MT_GHOST:
|
||||
case MT_OVERLAY:
|
||||
case MT_EMERALDSPAWN:
|
||||
case MT_GREENORB:
|
||||
case MT_YELLOWORB:
|
||||
case MT_BLUEORB:
|
||||
case MT_BLACKORB:
|
||||
case MT_WHITEORB:
|
||||
case MT_PITYORB:
|
||||
case MT_ELEMENTAL_ORB:
|
||||
case MT_ATTRACT_ORB:
|
||||
case MT_FORCE_ORB:
|
||||
case MT_ARMAGEDDON_ORB:
|
||||
case MT_WHIRLWIND_ORB:
|
||||
case MT_PITY_ORB:
|
||||
case MT_FLAMEAURA_ORB:
|
||||
case MT_BUBBLEWRAP_ORB:
|
||||
case MT_THUNDERCOIN_ORB:
|
||||
case MT_IVSP:
|
||||
case MT_SUPERSPARK:
|
||||
case MT_RAIN:
|
||||
|
@ -1782,8 +1790,8 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
|
|||
break;
|
||||
}
|
||||
// Ignore popped monitors, too.
|
||||
if (node->m_thing->flags & MF_MONITOR
|
||||
&& node->m_thing->threshold == 68)
|
||||
if (node->m_thing->health == 0 // this only really applies for monitors
|
||||
|| (!(node->m_thing->flags & MF_MONITOR) && (mobjinfo[node->m_thing->type].flags & MF_MONITOR))) // gold monitor support
|
||||
continue;
|
||||
// Okay, we found something valid.
|
||||
if (!thing // take either the first thing
|
||||
|
@ -1797,10 +1805,24 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
|
|||
void T_MarioBlockChecker(levelspecthink_t *block)
|
||||
{
|
||||
line_t *masterline = block->sourceline;
|
||||
if (block->vars[2] == 1) // Don't update the textures when the block's being bumped upwards.
|
||||
return;
|
||||
if (SearchMarioNode(block->sector->touching_thinglist))
|
||||
sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture;
|
||||
{
|
||||
sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture; // Update textures
|
||||
if (masterline->backsector)
|
||||
{
|
||||
block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->ceilingpic; // Update flats to be backside's ceiling
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].toptexture;
|
||||
if (masterline->backsector)
|
||||
{
|
||||
block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->floorpic; // Update flats to be backside's floor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is the Thwomp's 'brain'. It looks around for players nearby, and if
|
||||
|
@ -2520,6 +2542,29 @@ void T_CameraScanner(elevator_t *elevator)
|
|||
}
|
||||
}
|
||||
|
||||
void T_PlaneDisplace(planedisplace_t *pd)
|
||||
{
|
||||
sector_t *control, *target;
|
||||
INT32 direction;
|
||||
fixed_t diff;
|
||||
|
||||
control = §ors[pd->control];
|
||||
target = §ors[pd->affectee];
|
||||
|
||||
if (control->floorheight == pd->last_height)
|
||||
return; // no change, no movement
|
||||
|
||||
direction = (control->floorheight > pd->last_height) ? 1 : -1;
|
||||
diff = FixedMul(control->floorheight-pd->last_height, pd->speed);
|
||||
|
||||
if (pd->type == pd_floor || pd->type == pd_both)
|
||||
T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, 0, 0, direction); // move floor
|
||||
if (pd->type == pd_ceiling || pd->type == pd_both)
|
||||
T_MovePlane(target, INT32_MAX/2, target->ceilingheight+diff, 0, 1, direction); // move ceiling
|
||||
|
||||
pd->last_height = control->floorheight;
|
||||
}
|
||||
|
||||
//
|
||||
// EV_DoFloor
|
||||
//
|
||||
|
@ -2877,18 +2922,41 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
|
|||
size_t topmostvertex = 0, bottommostvertex = 0;
|
||||
fixed_t leftx, rightx;
|
||||
fixed_t topy, bottomy;
|
||||
fixed_t topz;
|
||||
fixed_t topz, bottomz;
|
||||
fixed_t widthfactor, heightfactor;
|
||||
fixed_t a, b, c;
|
||||
mobjtype_t type = MT_ROCKCRUMBLE1;
|
||||
fixed_t spacing = (32<<FRACBITS);
|
||||
tic_t lifetime = 3*TICRATE;
|
||||
INT16 flags = 0;
|
||||
|
||||
// If the control sector has a special
|
||||
// of Section3:7-15, use the custom debris.
|
||||
if (GETSECSPECIAL(rover->master->frontsector->special, 3) >= 8)
|
||||
type = MT_ROCKCRUMBLE1+(GETSECSPECIAL(rover->master->frontsector->special, 3)-7);
|
||||
#define controlsec rover->master->frontsector
|
||||
|
||||
if (controlsec->tag != 0)
|
||||
{
|
||||
INT32 tagline = P_FindSpecialLineFromTag(14, controlsec->tag, -1);
|
||||
if (tagline != -1)
|
||||
{
|
||||
if (sides[lines[tagline].sidenum[0]].toptexture)
|
||||
type = (mobjtype_t)sides[lines[tagline].sidenum[0]].toptexture; // Set as object type in p_setup.c...
|
||||
if (sides[lines[tagline].sidenum[0]].textureoffset)
|
||||
spacing = sides[lines[tagline].sidenum[0]].textureoffset;
|
||||
if (sides[lines[tagline].sidenum[0]].rowoffset)
|
||||
{
|
||||
if (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS != -1)
|
||||
lifetime = (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS);
|
||||
else
|
||||
lifetime = 0;
|
||||
}
|
||||
flags = lines[tagline].flags;
|
||||
}
|
||||
}
|
||||
|
||||
#undef controlsec
|
||||
|
||||
// soundorg z height never gets set normally, so MEH.
|
||||
sec->soundorg.z = sec->floorheight;
|
||||
S_StartSound(&sec->soundorg, sfx_crumbl);
|
||||
S_StartSound(&sec->soundorg, mobjinfo[type].activesound);
|
||||
|
||||
// Find the outermost vertexes in the subsector
|
||||
for (i = 0; i < sec->linecount; i++)
|
||||
|
@ -2907,23 +2975,46 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
|
|||
bottommostvertex = i;
|
||||
}
|
||||
|
||||
leftx = sec->lines[leftmostvertex]->v1->x+(16<<FRACBITS);
|
||||
leftx = sec->lines[leftmostvertex]->v1->x+(spacing>>1);
|
||||
rightx = sec->lines[rightmostvertex]->v1->x;
|
||||
topy = sec->lines[topmostvertex]->v1->y-(16<<FRACBITS);
|
||||
topy = sec->lines[topmostvertex]->v1->y-(spacing>>1);
|
||||
bottomy = sec->lines[bottommostvertex]->v1->y;
|
||||
topz = *rover->topheight-(16<<FRACBITS);
|
||||
|
||||
for (a = leftx; a < rightx; a += (32<<FRACBITS))
|
||||
topz = *rover->topheight-(spacing>>1);
|
||||
bottomz = *rover->bottomheight;
|
||||
|
||||
if (flags & ML_EFFECT1)
|
||||
{
|
||||
for (b = topy; b > bottomy; b -= (32<<FRACBITS))
|
||||
widthfactor = (rightx + topy - leftx - bottomy)>>3;
|
||||
heightfactor = (topz - *rover->bottomheight)>>2;
|
||||
}
|
||||
|
||||
for (a = leftx; a < rightx; a += spacing)
|
||||
{
|
||||
for (b = topy; b > bottomy; b -= spacing)
|
||||
{
|
||||
if (R_PointInSubsector(a, b)->sector == sec)
|
||||
{
|
||||
mobj_t *spawned = NULL;
|
||||
for (c = topz; c > *rover->bottomheight; c -= (32<<FRACBITS))
|
||||
#ifdef ESLOPE
|
||||
if (*rover->t_slope)
|
||||
topz = P_GetZAt(*rover->t_slope, a, b) - (spacing>>1);
|
||||
if (*rover->b_slope)
|
||||
bottomz = P_GetZAt(*rover->b_slope, a, b);
|
||||
#endif
|
||||
|
||||
for (c = topz; c > bottomz; c -= spacing)
|
||||
{
|
||||
spawned = P_SpawnMobj(a, b, c, type);
|
||||
spawned->fuse = 3*TICRATE;
|
||||
spawned->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
|
||||
|
||||
if (flags & ML_EFFECT1)
|
||||
{
|
||||
P_InstaThrust(spawned, R_PointToAngle2(sec->soundorg.x, sec->soundorg.y, a, b), FixedDiv(P_AproxDistance(a - sec->soundorg.x, b - sec->soundorg.y), widthfactor));
|
||||
P_SetObjectMomZ(spawned, FixedDiv((c - bottomz), heightfactor), false);
|
||||
}
|
||||
|
||||
spawned->fuse = lifetime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3083,8 +3174,10 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
|
|||
return 1;
|
||||
}
|
||||
|
||||
INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mobj_t *puncher)
|
||||
INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
|
||||
{
|
||||
sector_t *roversec = rover->master->frontsector;
|
||||
fixed_t topheight = *rover->topheight;
|
||||
levelspecthink_t *block;
|
||||
mobj_t *thing;
|
||||
fixed_t oldx = 0, oldy = 0, oldz = 0;
|
||||
|
@ -3092,11 +3185,14 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
|
|||
I_Assert(puncher != NULL);
|
||||
I_Assert(puncher->player != NULL);
|
||||
|
||||
if (sec->floordata || sec->ceilingdata)
|
||||
if (roversec->floordata || roversec->ceilingdata)
|
||||
return 0;
|
||||
|
||||
if (!(rover->flags & FF_SOLID))
|
||||
rover->flags |= (FF_SOLID|FF_RENDERALL|FF_CUTLEVEL);
|
||||
|
||||
// Find an item to pop out!
|
||||
thing = SearchMarioNode(sec->touching_thinglist);
|
||||
thing = SearchMarioNode(roversec->touching_thinglist);
|
||||
|
||||
// Found something!
|
||||
if (thing)
|
||||
|
@ -3106,13 +3202,13 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
|
|||
|
||||
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&block->thinker);
|
||||
sec->floordata = block;
|
||||
sec->ceilingdata = block;
|
||||
roversec->floordata = block;
|
||||
roversec->ceilingdata = block;
|
||||
block->thinker.function.acp1 = (actionf_p1)T_MarioBlock;
|
||||
|
||||
// Set up the fields
|
||||
block->sector = sec;
|
||||
block->vars[0] = roversector->tag; // actionsector
|
||||
block->sector = roversec;
|
||||
block->vars[0] = sector->tag; // actionsector
|
||||
block->vars[1] = 4*FRACUNIT; // speed
|
||||
block->vars[2] = 1; // Up // direction
|
||||
block->vars[3] = block->sector->floorheight; // floorwasheight
|
||||
|
@ -3128,8 +3224,8 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
|
|||
}
|
||||
|
||||
P_UnsetThingPosition(thing);
|
||||
thing->x = roversector->soundorg.x;
|
||||
thing->y = roversector->soundorg.y;
|
||||
thing->x = sector->soundorg.x;
|
||||
thing->y = sector->soundorg.y;
|
||||
thing->z = topheight;
|
||||
thing->momz = FixedMul(6*FRACUNIT, thing->scale);
|
||||
P_SetThingPosition(thing);
|
||||
|
@ -3146,7 +3242,7 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
|
|||
{
|
||||
if (thing->type == MT_EMMY && thing->spawnpoint && (thing->spawnpoint->options & MTF_OBJECTSPECIAL))
|
||||
{
|
||||
mobj_t *tokenobj = P_SpawnMobj(roversector->soundorg.x, roversector->soundorg.y, topheight, MT_TOKEN);
|
||||
mobj_t *tokenobj = P_SpawnMobj(sector->soundorg.x, sector->soundorg.y, topheight, MT_TOKEN);
|
||||
P_SetTarget(&thing->tracer, tokenobj);
|
||||
P_SetTarget(&tokenobj->target, thing);
|
||||
P_SetMobjState(tokenobj, mobjinfo[MT_TOKEN].seestate);
|
||||
|
@ -3156,15 +3252,15 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
|
|||
S_StartSound(puncher, sfx_mario9); // Puncher is "close enough"
|
||||
}
|
||||
|
||||
if (itsamonitor)
|
||||
if (itsamonitor && thing)
|
||||
{
|
||||
P_UnsetThingPosition(tmthing);
|
||||
tmthing->x = oldx;
|
||||
tmthing->y = oldy;
|
||||
tmthing->z = oldz;
|
||||
tmthing->momx = 1;
|
||||
tmthing->momy = 1;
|
||||
P_SetThingPosition(tmthing);
|
||||
P_UnsetThingPosition(thing);
|
||||
thing->x = oldx;
|
||||
thing->y = oldy;
|
||||
thing->z = oldz;
|
||||
thing->momx = 1;
|
||||
thing->momy = 1;
|
||||
P_SetThingPosition(thing);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
598
src/p_inter.c
598
src/p_inter.c
|
@ -142,7 +142,10 @@ boolean P_CanPickupItem(player_t *player, boolean weapon)
|
|||
if (player->bot && weapon)
|
||||
return false;
|
||||
|
||||
if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] <= flashingtics)
|
||||
if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] < UINT16_MAX)
|
||||
return false;
|
||||
|
||||
if (player->mo && player->mo->health <= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -221,6 +224,65 @@ void P_DoNightsScore(player_t *player)
|
|||
dummymo->destscale = 2*FRACUNIT;
|
||||
}
|
||||
|
||||
//
|
||||
// P_DoMatchSuper
|
||||
//
|
||||
// Checks if you have all 7 pw_emeralds, then turns you "super". =P
|
||||
//
|
||||
void P_DoMatchSuper(player_t *player)
|
||||
{
|
||||
UINT16 match_emeralds = player->powers[pw_emeralds];
|
||||
boolean doteams = false;
|
||||
int i;
|
||||
|
||||
// If this gametype has teams, check every player on your team for emeralds.
|
||||
if (G_GametypeHasTeams())
|
||||
{
|
||||
doteams = true;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (players[i].ctfteam == player->ctfteam)
|
||||
match_emeralds |= players[i].powers[pw_emeralds];
|
||||
}
|
||||
|
||||
if (!ALL7EMERALDS(match_emeralds))
|
||||
return;
|
||||
|
||||
// Got 'em all? Turn "super"!
|
||||
emeraldspawndelay = invulntics + 1;
|
||||
player->powers[pw_emeralds] = 0;
|
||||
player->powers[pw_invulnerability] = emeraldspawndelay;
|
||||
player->powers[pw_sneakers] = emeraldspawndelay;
|
||||
if (P_IsLocalPlayer(player) && !player->powers[pw_super])
|
||||
{
|
||||
S_StopMusic();
|
||||
if (mariomode)
|
||||
G_GhostAddColor(GHC_INVINCIBLE);
|
||||
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
|
||||
}
|
||||
|
||||
// Also steal 50 points from every enemy, sealing your victory.
|
||||
P_StealPlayerScore(player, 50);
|
||||
|
||||
// In a team game?
|
||||
// Check everyone else on your team for emeralds, and turn those helpful assisting players invincible too.
|
||||
if (doteams)
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].ctfteam == player->ctfteam
|
||||
&& players[i].powers[pw_emeralds] != 0)
|
||||
{
|
||||
players[i].powers[pw_emeralds] = 0;
|
||||
player->powers[pw_invulnerability] = invulntics + 1;
|
||||
player->powers[pw_sneakers] = player->powers[pw_invulnerability];
|
||||
if (P_IsLocalPlayer(player) && !player->powers[pw_super])
|
||||
{
|
||||
S_StopMusic();
|
||||
if (mariomode)
|
||||
G_GhostAddColor(GHC_INVINCIBLE);
|
||||
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Takes action based on a ::MF_SPECIAL thing touched by a player.
|
||||
* Actually, this just checks a few things (heights, toucher->player, no
|
||||
* objectplace, no dead or disappearing things)
|
||||
|
@ -237,6 +299,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
{
|
||||
player_t *player;
|
||||
INT32 i;
|
||||
UINT8 elementalpierce;
|
||||
|
||||
if (objectplacing)
|
||||
return;
|
||||
|
@ -291,6 +354,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
#endif
|
||||
|
||||
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
|
||||
elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)
|
||||
? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
|
||||
: 0);
|
||||
|
||||
if (special->flags & MF_BOSS)
|
||||
{
|
||||
if (special->type == MT_BLACKEGGMAN)
|
||||
|
@ -300,14 +368,20 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
|
||||
if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|
||||
|| ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPDAMAGE && !(player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|
||||
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|
||||
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|
||||
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|
||||
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|
||||
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
|
||||
|| player->powers[pw_invulnerability] || player->powers[pw_super]
|
||||
|| elementalpierce) // Do you possess the ability to subdue the object?
|
||||
{
|
||||
if (P_MobjFlip(toucher)*toucher->momz < 0)
|
||||
toucher->momz = -toucher->momz;
|
||||
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
|
||||
{
|
||||
if (elementalpierce == 2)
|
||||
P_DoBubbleBounce(player);
|
||||
else
|
||||
toucher->momz = -toucher->momz;
|
||||
}
|
||||
toucher->momx = -toucher->momx;
|
||||
toucher->momy = -toucher->momy;
|
||||
P_DamageMobj(special, toucher, toucher, 1, 0);
|
||||
|
@ -333,7 +407,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
/////ENEMIES!!//////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////
|
||||
if (special->type == MT_GSNAPPER && !(((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|
||||
|| player->powers[pw_invulnerability] || player->powers[pw_super])
|
||||
|| player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce)
|
||||
&& toucher->z < special->z + special->height && toucher->z + toucher->height > special->z)
|
||||
{
|
||||
// Can only hit snapper from above
|
||||
|
@ -346,14 +420,19 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
P_DamageMobj(toucher, special, special, 1, 0);
|
||||
}
|
||||
else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|
||||
|| ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPDAMAGE && !(player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|
||||
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|
||||
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|
||||
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|
||||
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|
||||
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
|
||||
{
|
||||
if (P_MobjFlip(toucher)*toucher->momz < 0)
|
||||
toucher->momz = -toucher->momz;
|
||||
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
|
||||
{
|
||||
if (elementalpierce == 2)
|
||||
P_DoBubbleBounce(player);
|
||||
else
|
||||
toucher->momz = -toucher->momz;
|
||||
}
|
||||
|
||||
P_DamageMobj(special, toucher, toucher, 1, 0);
|
||||
}
|
||||
|
@ -445,7 +524,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
{
|
||||
INT32 pindex = special->info->mass - (INT32)pw_infinityring;
|
||||
|
||||
player->powers[special->info->mass] += (UINT16)special->info->reactiontime;
|
||||
player->powers[special->info->mass] += (UINT16)special->reactiontime;
|
||||
player->ringweapons |= 1 << (pindex-1);
|
||||
|
||||
if (player->powers[special->info->mass] > rw_maximums[pindex])
|
||||
|
@ -532,7 +611,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
|
||||
if (special->threshold)
|
||||
{
|
||||
player->powers[pw_emeralds] |= special->info->speed;
|
||||
P_DoMatchSuper(player);
|
||||
}
|
||||
else
|
||||
emeralds |= special->info->speed;
|
||||
|
||||
|
@ -553,6 +635,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
|
||||
player->powers[pw_emeralds] |= special->threshold;
|
||||
P_DoMatchSuper(player);
|
||||
break;
|
||||
|
||||
// Secret emblem thingy
|
||||
|
@ -814,16 +897,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (G_IsSpecialStage(gamemap) && !player->exiting)
|
||||
{ // In special stages, share rings. Everyone gives up theirs to the player who touched the capsule
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && (&players[i] != player) && players[i].mo->health > 1)
|
||||
if (playeringame[i] && (&players[i] != player) && players[i].rings > 0)
|
||||
{
|
||||
toucher->health += players[i].mo->health-1;
|
||||
player->health = toucher->health;
|
||||
players[i].mo->health = 1;
|
||||
players[i].health = players[i].mo->health;
|
||||
player->rings += players[i].rings;
|
||||
players[i].rings = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(player->health > 1) || player->exiting)
|
||||
if (player->rings <= 0 || player->exiting)
|
||||
return;
|
||||
|
||||
// Mark the player as 'pull into the capsule'
|
||||
|
@ -1093,15 +1174,33 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
// Mario //
|
||||
// ***** //
|
||||
case MT_SHELL:
|
||||
if (special->state == &states[S_SHELL]) // Resting anim
|
||||
{
|
||||
// Kick that sucker around!
|
||||
special->angle = toucher->angle;
|
||||
P_InstaThrust(special, special->angle, FixedMul(special->info->speed, special->scale));
|
||||
S_StartSound(toucher, sfx_mario2);
|
||||
P_SetMobjState(special, S_SHELL1);
|
||||
P_SetTarget(&special->target, toucher);
|
||||
special->threshold = (3*TICRATE)/2;
|
||||
boolean bounceon = ((P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0));
|
||||
if (special->threshold == TICRATE) // it's moving
|
||||
{
|
||||
if (bounceon)
|
||||
{
|
||||
// Stop it!
|
||||
special->momx = special->momy = 0;
|
||||
S_StartSound(toucher, sfx_mario2);
|
||||
P_SetTarget(&special->target, NULL);
|
||||
special->threshold = TICRATE - 1;
|
||||
toucher->momz = -toucher->momz;
|
||||
}
|
||||
else // can't handle in PIT_CheckThing because of landing-on causing it to stop
|
||||
P_DamageMobj(toucher, special, special->target, 1, 0);
|
||||
}
|
||||
else if (special->threshold == 0)
|
||||
{
|
||||
// Kick that sucker around!
|
||||
special->movedir = ((special->movedir == 1) ? -1 : 1);
|
||||
P_InstaThrust(special, toucher->angle, (special->info->speed*special->scale));
|
||||
S_StartSound(toucher, sfx_mario2);
|
||||
P_SetTarget(&special->target, toucher);
|
||||
special->threshold = (3*TICRATE)/2;
|
||||
if (bounceon)
|
||||
toucher->momz = -toucher->momz;
|
||||
}
|
||||
}
|
||||
return;
|
||||
case MT_AXE:
|
||||
|
@ -1134,9 +1233,17 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
case MT_FIREFLOWER:
|
||||
if (player->bot)
|
||||
return;
|
||||
player->powers[pw_shield] |= SH_FIREFLOWER;
|
||||
toucher->color = SKINCOLOR_WHITE;
|
||||
G_GhostAddColor(GHC_FIREFLOWER);
|
||||
|
||||
S_StartSound(toucher, sfx_mario3);
|
||||
|
||||
player->powers[pw_shield] = (player->powers[pw_shield] & SH_NOSTACK)|SH_FIREFLOWER;
|
||||
|
||||
if (!(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability])))
|
||||
{
|
||||
player->mo->color = SKINCOLOR_WHITE;
|
||||
G_GhostAddColor(GHC_FIREFLOWER);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// *************** //
|
||||
|
@ -1305,7 +1412,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
}
|
||||
else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|
||||
|| ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPDAMAGE))
|
||||
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|
||||
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|
||||
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|
||||
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
|
||||
|
@ -1380,7 +1487,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
|
||||
if (player->powers[pw_invulnerability] || player->powers[pw_flashing]
|
||||
|| (player->powers[pw_super] && !(ALL7EMERALDS(player->powers[pw_emeralds]))))
|
||||
|| player->powers[pw_super])
|
||||
return;
|
||||
if (player->powers[pw_shield] || player->bot) //If One-Hit Shield
|
||||
{
|
||||
|
@ -1390,11 +1497,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
else
|
||||
{
|
||||
P_PlayRinglossSound(toucher);
|
||||
if (toucher->health > 10)
|
||||
toucher->health -= 10;
|
||||
if (player->rings >= 10)
|
||||
player->rings -= 10;
|
||||
else
|
||||
toucher->health = 1;
|
||||
player->health = toucher->health;
|
||||
player->rings = 0;
|
||||
}
|
||||
|
||||
P_DoPlayerPain(player, special, NULL);
|
||||
|
@ -1418,7 +1524,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
|
||||
case MT_EXTRALARGEBUBBLE:
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
|
||||
if (player->powers[pw_shield] & SH_PROTECTWATER)
|
||||
return;
|
||||
if (maptol & TOL_NIGHTS)
|
||||
return;
|
||||
|
@ -1496,6 +1602,9 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
|
|||
if (!player)
|
||||
return; // Impossible!
|
||||
|
||||
if (!player->mo)
|
||||
return; // Also impossible!
|
||||
|
||||
if (player->spectator)
|
||||
return; // No messages for dying (crushed) spectators.
|
||||
|
||||
|
@ -1503,11 +1612,11 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
|
|||
return; // Presumably it's obvious what's happening in splitscreen.
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUAh_HurtMsg(player, inflictor, source))
|
||||
if (LUAh_HurtMsg(player, inflictor, source, damagetype))
|
||||
return;
|
||||
#endif
|
||||
|
||||
deadtarget = (player->health <= 0);
|
||||
deadtarget = (player->mo->health <= 0);
|
||||
|
||||
// Target's name
|
||||
snprintf(targetname, sizeof(targetname), "%s%s%s",
|
||||
|
@ -1541,8 +1650,10 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
|
|||
else switch (inflictor->type)
|
||||
{
|
||||
case MT_PLAYER:
|
||||
if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB)
|
||||
if (damagetype == DMG_NUKE) // SH_ARMAGEDDON, armageddon shield
|
||||
str = M_GetText("%s%s's armageddon blast %s %s.\n");
|
||||
else if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && (inflictor->player->pflags & PF_SHIELDABILITY))
|
||||
str = M_GetText("%s%s's flame stomp %s %s.\n");
|
||||
else if (inflictor->player->powers[pw_invulnerability])
|
||||
str = M_GetText("%s%s's invincibility aura %s %s.\n");
|
||||
else if (inflictor->player->powers[pw_super])
|
||||
|
@ -1699,7 +1810,7 @@ void P_CheckTimeLimit(void)
|
|||
return;
|
||||
|
||||
//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 (leveltime == (timelimitintics + 1))
|
||||
|
@ -1710,7 +1821,7 @@ void P_CheckTimeLimit(void)
|
|||
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1950,7 +2061,6 @@ boolean P_CheckRacers(void)
|
|||
*/
|
||||
void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype)
|
||||
{
|
||||
mobjtype_t item;
|
||||
mobj_t *mo;
|
||||
|
||||
if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL))
|
||||
|
@ -1974,7 +2084,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
target->health = 0; // This makes it easy to check if something's dead elsewhere.
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUAh_MobjDeath(target, inflictor, source) || P_MobjWasRemoved(target))
|
||||
if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target))
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
@ -2166,81 +2276,80 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
if (source && target && target->player && source->player)
|
||||
P_PlayVictorySound(source); // Killer laughs at you. LAUGHS! BWAHAHAHA!
|
||||
|
||||
#ifdef OLDANIMALSPAWNING
|
||||
// Drop stuff.
|
||||
// This determines the kind of object spawned
|
||||
// during the death frame of a thing.
|
||||
if (!mariomode // Don't show birds, etc. in Mario Mode Tails 12-23-2001
|
||||
&& target->flags & MF_ENEMY)
|
||||
{
|
||||
if (cv_soniccd.value)
|
||||
item = MT_SEED;
|
||||
else
|
||||
mobjtype_t item;
|
||||
INT32 prandom;
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
INT32 prandom;
|
||||
case MT_REDCRAWLA:
|
||||
case MT_GOLDBUZZ:
|
||||
case MT_SKIM:
|
||||
case MT_UNIDUS:
|
||||
item = MT_FLICKY_02/*MT_BUNNY*/;
|
||||
break;
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_REDCRAWLA:
|
||||
case MT_GOLDBUZZ:
|
||||
case MT_SKIM:
|
||||
case MT_UNIDUS:
|
||||
item = MT_BUNNY;
|
||||
break;
|
||||
case MT_BLUECRAWLA:
|
||||
case MT_JETTBOMBER:
|
||||
case MT_GFZFISH:
|
||||
item = MT_FLICKY_01/*MT_BIRD*/;
|
||||
break;
|
||||
|
||||
case MT_BLUECRAWLA:
|
||||
case MT_JETTBOMBER:
|
||||
case MT_GFZFISH:
|
||||
item = MT_BIRD;
|
||||
break;
|
||||
case MT_JETTGUNNER:
|
||||
case MT_CRAWLACOMMANDER:
|
||||
case MT_REDBUZZ:
|
||||
case MT_DETON:
|
||||
item = MT_FLICKY_12/*MT_MOUSE*/;
|
||||
break;
|
||||
|
||||
case MT_JETTGUNNER:
|
||||
case MT_CRAWLACOMMANDER:
|
||||
case MT_REDBUZZ:
|
||||
case MT_DETON:
|
||||
item = MT_MOUSE;
|
||||
break;
|
||||
case MT_GSNAPPER:
|
||||
case MT_EGGGUARD:
|
||||
case MT_SPRINGSHELL:
|
||||
item = MT_FLICKY_11/*MT_COW*/;
|
||||
break;
|
||||
|
||||
case MT_GSNAPPER:
|
||||
case MT_EGGGUARD:
|
||||
case MT_SPRINGSHELL:
|
||||
item = MT_COW;
|
||||
break;
|
||||
case MT_MINUS:
|
||||
case MT_VULTURE:
|
||||
case MT_POINTY:
|
||||
case MT_YELLOWSHELL:
|
||||
item = MT_FLICKY_03/*MT_CHICKEN*/;
|
||||
break;
|
||||
|
||||
case MT_MINUS:
|
||||
case MT_VULTURE:
|
||||
case MT_POINTY:
|
||||
case MT_YELLOWSHELL:
|
||||
item = MT_CHICKEN;
|
||||
break;
|
||||
case MT_AQUABUZZ:
|
||||
item = MT_FLICKY_01/*MT_REDBIRD*/;
|
||||
break;
|
||||
|
||||
case MT_AQUABUZZ:
|
||||
item = MT_REDBIRD;
|
||||
break;
|
||||
default:
|
||||
if (target->info->doomednum)
|
||||
prandom = target->info->doomednum%5; // "Random" animal for new enemies.
|
||||
else
|
||||
prandom = P_RandomKey(5); // No placable object, just use a random number.
|
||||
|
||||
default:
|
||||
if (target->info->doomednum)
|
||||
prandom = target->info->doomednum%5; // "Random" animal for new enemies.
|
||||
else
|
||||
prandom = P_RandomKey(5); // No placable object, just use a random number.
|
||||
|
||||
switch(prandom)
|
||||
{
|
||||
default: item = MT_BUNNY; break;
|
||||
case 1: item = MT_BIRD; break;
|
||||
case 2: item = MT_MOUSE; break;
|
||||
case 3: item = MT_COW; break;
|
||||
case 4: item = MT_CHICKEN; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch(prandom)
|
||||
{
|
||||
default: item = MT_FLICKY_02/*MT_BUNNY*/; break;
|
||||
case 1: item = MT_FLICKY_01/*MT_BIRD*/; break;
|
||||
case 2: item = MT_FLICKY_12/*MT_MOUSE*/; break;
|
||||
case 3: item = MT_FLICKY_11/*MT_COW*/; break;
|
||||
case 4: item = MT_FLICKY_03/*MT_CHICKEN*/; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mo = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2) - FixedMul(mobjinfo[item].height / 2, target->scale), item);
|
||||
mo->destscale = target->scale;
|
||||
P_SetScale(mo, mo->destscale);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
// Other death animation effects
|
||||
else switch(target->type)
|
||||
switch(target->type)
|
||||
{
|
||||
case MT_BOUNCEPICKUP:
|
||||
case MT_RAILPICKUP:
|
||||
|
@ -2258,24 +2367,27 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
break;
|
||||
|
||||
case MT_PLAYER:
|
||||
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
|
||||
target->momx = target->momy = target->momz = 0;
|
||||
if (damagetype == DMG_DROWNED) // drowned
|
||||
{
|
||||
target->movedir = damagetype; // we're MOVING the Damage Into anotheR function... Okay, this is a bit of a hack.
|
||||
if (target->player->charflags & SF_MACHINE)
|
||||
S_StartSound(target, sfx_fizzle);
|
||||
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
|
||||
target->momx = target->momy = target->momz = 0;
|
||||
|
||||
if (damagetype == DMG_DROWNED) // drowned
|
||||
{
|
||||
target->movedir = damagetype; // we're MOVING the Damage Into anotheR function... Okay, this is a bit of a hack.
|
||||
if (target->player->charflags & SF_MACHINE)
|
||||
S_StartSound(target, sfx_fizzle);
|
||||
else
|
||||
S_StartSound(target, sfx_drown);
|
||||
// Don't jump up when drowning
|
||||
}
|
||||
else
|
||||
S_StartSound(target, sfx_drown);
|
||||
// Don't jump up when drowning
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetObjectMomZ(target, 14*FRACUNIT, false);
|
||||
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // Spikes
|
||||
S_StartSound(target, sfx_spkdth);
|
||||
else
|
||||
P_PlayDeathSound(target);
|
||||
{
|
||||
P_SetObjectMomZ(target, 14*FRACUNIT, false);
|
||||
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // Spikes
|
||||
S_StartSound(target, sfx_spkdth);
|
||||
else
|
||||
P_PlayDeathSound(target);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -2442,8 +2554,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
|
|||
player_t *player = target->player;
|
||||
tic_t oldnightstime = player->nightstime;
|
||||
|
||||
if (!player->powers[pw_flashing]
|
||||
&& !(player->pflags & PF_GODMODE))
|
||||
if (!player->powers[pw_flashing])
|
||||
{
|
||||
angle_t fa;
|
||||
|
||||
|
@ -2558,27 +2669,18 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
|
|||
return true;
|
||||
}
|
||||
|
||||
if (target->health <= 1) // Death
|
||||
if (player->rings > 0) // Ring loss
|
||||
{
|
||||
P_PlayRinglossSound(target);
|
||||
P_PlayerRingBurst(player, player->rings);
|
||||
}
|
||||
else // Death
|
||||
{
|
||||
P_PlayDeathSound(target);
|
||||
P_PlayVictorySound(source); // Killer laughs at you! LAUGHS! BWAHAHAHHAHAA!!
|
||||
}
|
||||
else if (target->health > 1) // Ring loss
|
||||
{
|
||||
P_PlayRinglossSound(target);
|
||||
P_PlayerRingBurst(player, player->mo->health - 1);
|
||||
}
|
||||
|
||||
if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
|
||||
{
|
||||
player->health -= 10;
|
||||
if (player->health < 2)
|
||||
player->health = 2;
|
||||
target->health = player->health;
|
||||
}
|
||||
else
|
||||
player->health = target->health = 1;
|
||||
|
||||
player->rings = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2629,7 +2731,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
|
|||
// Burst weapons and emeralds in Match/CTF only
|
||||
if (source && (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF))
|
||||
{
|
||||
P_PlayerRingBurst(player, player->health - 1);
|
||||
P_PlayerRingBurst(player, player->rings);
|
||||
P_PlayerEmeraldBurst(player, false);
|
||||
}
|
||||
|
||||
|
@ -2733,22 +2835,21 @@ void P_RemoveShield(player_t *player)
|
|||
{
|
||||
if (player->powers[pw_shield] & SH_FORCE)
|
||||
{ // Multi-hit
|
||||
if ((player->powers[pw_shield] & 0xFF) == 0)
|
||||
player->powers[pw_shield] &= ~SH_FORCE;
|
||||
else
|
||||
if (player->powers[pw_shield] & SH_FORCEHP)
|
||||
player->powers[pw_shield]--;
|
||||
else
|
||||
player->powers[pw_shield] &= SH_STACK;
|
||||
}
|
||||
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_NONE)
|
||||
{ // Second layer shields
|
||||
player->powers[pw_shield] = SH_NONE;
|
||||
// Reset fireflower
|
||||
if (!player->powers[pw_super])
|
||||
if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability])))
|
||||
{
|
||||
player->mo->color = player->skincolor;
|
||||
G_GhostAddColor(GHC_NORMAL);
|
||||
}
|
||||
player->powers[pw_shield] = SH_NONE;
|
||||
}
|
||||
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) // Give them what's coming to them!
|
||||
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ARMAGEDDON) // Give them what's coming to them!
|
||||
{
|
||||
P_BlackOw(player); // BAM!
|
||||
player->pflags |= PF_JUMPDOWN;
|
||||
|
@ -2757,7 +2858,7 @@ void P_RemoveShield(player_t *player)
|
|||
player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK;
|
||||
}
|
||||
|
||||
static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage)
|
||||
static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
// Must do pain first to set flashing -- P_RemoveShield can cause damage
|
||||
P_DoPlayerPain(player, source, inflictor);
|
||||
|
@ -2766,7 +2867,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
|
||||
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
|
||||
|
||||
if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes
|
||||
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes
|
||||
S_StartSound(player->mo, sfx_spkdth);
|
||||
else
|
||||
S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss.
|
||||
|
@ -2791,15 +2892,12 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
|
||||
static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
if (!(inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])))
|
||||
{
|
||||
P_DoPlayerPain(player, source, inflictor);
|
||||
P_DoPlayerPain(player, source, inflictor);
|
||||
|
||||
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
|
||||
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
|
||||
|
||||
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes
|
||||
S_StartSound(player->mo, sfx_spkdth);
|
||||
}
|
||||
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes
|
||||
S_StartSound(player->mo, sfx_spkdth);
|
||||
|
||||
if (source && source->player && !player->powers[pw_super]) //don't score points against super players
|
||||
{
|
||||
|
@ -2821,6 +2919,10 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN
|
|||
|
||||
// Ring loss sound plays despite hitting spikes
|
||||
P_PlayRinglossSound(player->mo); // Ringledingle!
|
||||
P_PlayerRingBurst(player, damage);
|
||||
player->rings -= damage;
|
||||
if (player->rings < 0)
|
||||
player->rings = 0;
|
||||
}
|
||||
|
||||
/** Damages an object, which may or may not be a player.
|
||||
|
@ -2869,7 +2971,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
// Everything above here can't be forced.
|
||||
if (!metalrecording)
|
||||
{
|
||||
UINT8 shouldForce = LUAh_ShouldDamage(target, inflictor, source, damage);
|
||||
UINT8 shouldForce = LUAh_ShouldDamage(target, inflictor, source, damage, damagetype);
|
||||
if (P_MobjWasRemoved(target))
|
||||
return (shouldForce == 1); // mobj was removed
|
||||
if (shouldForce == 1)
|
||||
|
@ -2912,7 +3014,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage) || P_MobjWasRemoved(target))
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
|
@ -2940,7 +3042,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage) || P_MobjWasRemoved(target))
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
|
@ -2950,7 +3052,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
#ifdef HAVE_BLUA
|
||||
else if (target->flags & MF_ENEMY)
|
||||
{
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage) || P_MobjWasRemoved(target))
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -2964,18 +3066,24 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (player->exiting)
|
||||
return false;
|
||||
|
||||
if (player->pflags & PF_GODMODE)
|
||||
return false;
|
||||
|
||||
if (!(target->player->pflags & (PF_NIGHTSMODE|PF_NIGHTSFALL)) && (maptol & TOL_NIGHTS))
|
||||
return false;
|
||||
|
||||
switch (damagetype)
|
||||
{
|
||||
case DMG_WATER:
|
||||
if (player->powers[pw_shield] & SH_PROTECTWATER)
|
||||
return false; // Invincible to water damage
|
||||
break;
|
||||
case DMG_FIRE:
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
|
||||
return false; // Invincible to water/fire damage
|
||||
if (player->powers[pw_shield] & SH_PROTECTFIRE)
|
||||
return false; // Invincible to fire damage
|
||||
break;
|
||||
case DMG_ELECTRIC:
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)
|
||||
if (player->powers[pw_shield] & SH_PROTECTELECTRIC)
|
||||
return false; // Invincible to electric damage
|
||||
break;
|
||||
default:
|
||||
|
@ -2991,11 +3099,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false; // Don't hit yourself with your own paraloop, baka
|
||||
if (source && source->player && !cv_friendlyfire.value
|
||||
&& (gametype == GT_COOP
|
||||
|| (G_GametypeHasTeams() && target->player->ctfteam == source->player->ctfteam)))
|
||||
|| (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam)))
|
||||
return false; // Don't run eachother over in special stages and team games and such
|
||||
}
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage))
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype))
|
||||
return true;
|
||||
#endif
|
||||
P_NiGHTSDamage(target, source); // -5s :(
|
||||
|
@ -3004,7 +3112,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
if (!force && inflictor && inflictor->flags & MF_FIRE)
|
||||
{
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
|
||||
if (player->powers[pw_shield] & SH_PROTECTFIRE)
|
||||
return false; // Invincible to fire objects
|
||||
|
||||
if (G_PlatformGametype() && inflictor && source && source->player)
|
||||
|
@ -3026,12 +3134,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!force && player->pflags & PF_GODMODE)
|
||||
return false;
|
||||
|
||||
// Instant-Death
|
||||
if (damagetype & DMG_DEATHMASK)
|
||||
{
|
||||
P_KillPlayer(player, source, damage);
|
||||
player->rings = 0;
|
||||
}
|
||||
else if (metalrecording)
|
||||
{
|
||||
if (!inflictor)
|
||||
|
@ -3045,19 +3153,19 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false; // Metal Sonic walk through flame !!
|
||||
else
|
||||
{ // Oh no! Metal Sonic is hit !!
|
||||
P_ShieldDamage(player, inflictor, source, damage);
|
||||
P_ShieldDamage(player, inflictor, source, damage, damagetype);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] // ignore bouncing & such in invulnerability
|
||||
|| (player->powers[pw_super] && !(ALL7EMERALDS(player->powers[pw_emeralds]) && inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player))))
|
||||
|| player->powers[pw_super])
|
||||
{
|
||||
if (force || (inflictor && (inflictor->flags & MF_MISSILE)
|
||||
&& (inflictor->flags2 & MF2_SUPERFIRE)
|
||||
&& player->powers[pw_super]))
|
||||
{
|
||||
#ifdef HAVE_BLUA
|
||||
if (!LUAh_MobjDamage(target, inflictor, source, damage))
|
||||
if (!LUAh_MobjDamage(target, inflictor, source, damage, damagetype))
|
||||
#endif
|
||||
P_SuperDamage(player, inflictor, source, damage);
|
||||
return true;
|
||||
|
@ -3066,67 +3174,35 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false;
|
||||
}
|
||||
#ifdef HAVE_BLUA
|
||||
else if (LUAh_MobjDamage(target, inflictor, source, damage))
|
||||
else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype))
|
||||
return true;
|
||||
#endif
|
||||
else if (!player->powers[pw_super] && (player->powers[pw_shield] || player->bot)) //If One-Hit Shield
|
||||
else if (player->powers[pw_shield] || player->bot) //If One-Hit Shield
|
||||
{
|
||||
P_ShieldDamage(player, inflictor, source, damage);
|
||||
P_ShieldDamage(player, inflictor, source, damage, damagetype);
|
||||
damage = 0;
|
||||
}
|
||||
else if (player->mo->health > 1) // No shield but have rings.
|
||||
else if (player->rings > 0) // No shield but have rings.
|
||||
{
|
||||
damage = player->mo->health - 1;
|
||||
damage = player->rings;
|
||||
P_RingDamage(player, inflictor, source, damage, damagetype);
|
||||
damage = 0;
|
||||
}
|
||||
// To reduce griefing potential, don't allow players to be killed
|
||||
// by friendly fire. Spilling their rings and other items is enough.
|
||||
else if (!force && G_GametypeHasTeams()
|
||||
&& source && source->player && (source->player->ctfteam == player->ctfteam)
|
||||
&& cv_friendlyfire.value)
|
||||
{
|
||||
damage = 0;
|
||||
P_ShieldDamage(player, inflictor, source, damage, damagetype);
|
||||
}
|
||||
else // No shield, no rings, no invincibility.
|
||||
{
|
||||
// To reduce griefing potential, don't allow players to be killed
|
||||
// by friendly fire. Spilling their rings and other items is enough.
|
||||
if (force || !(G_GametypeHasTeams()
|
||||
&& source && source->player && (source->player->ctfteam == player->ctfteam)
|
||||
&& cv_friendlyfire.value))
|
||||
{
|
||||
damage = 1;
|
||||
P_KillPlayer(player, source, damage);
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = 0;
|
||||
P_ShieldDamage(player, inflictor, source, damage);
|
||||
}
|
||||
damage = 1;
|
||||
P_KillPlayer(player, source, damage);
|
||||
}
|
||||
|
||||
if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
|
||||
{
|
||||
if (player->powers[pw_shield])
|
||||
{
|
||||
P_RemoveShield(player);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->health -= (10 * (1 << (INT32)(player->powers[pw_super] / 10500)));
|
||||
if (player->health < 2)
|
||||
player->health = 2;
|
||||
}
|
||||
|
||||
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
|
||||
P_PlayerFlagBurst(player, false);
|
||||
}
|
||||
else if (damagetype & DMG_DEATHMASK)
|
||||
player->health = 0;
|
||||
else
|
||||
{
|
||||
player->health -= damage; // mirror mobj health here
|
||||
target->player->powers[pw_flashing] = flashingtics;
|
||||
if (damage > 0) // don't spill emeralds/ammo/panels for shield damage
|
||||
P_PlayerRingBurst(player, damage);
|
||||
}
|
||||
|
||||
if (player->health < 0)
|
||||
player->health = 0;
|
||||
|
||||
P_HitDeathMessages(player, inflictor, source, damagetype);
|
||||
|
||||
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
|
||||
|
@ -3138,13 +3214,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
P_DamageMobj(source, target, target, 1, 0);
|
||||
|
||||
// do the damage
|
||||
if (player && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]) && inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player))
|
||||
{
|
||||
target->health -= (10 * (1 << (INT32)(player->powers[pw_super] / 10500)));
|
||||
if (target->health < 2)
|
||||
target->health = 2;
|
||||
}
|
||||
else if (damagetype & DMG_DEATHMASK)
|
||||
if (damagetype & DMG_DEATHMASK)
|
||||
target->health = 0;
|
||||
else
|
||||
target->health -= damage;
|
||||
|
@ -3159,10 +3229,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
}
|
||||
|
||||
if (player)
|
||||
{
|
||||
if (!(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])))
|
||||
P_ResetPlayer(target->player);
|
||||
}
|
||||
P_ResetPlayer(target->player);
|
||||
else
|
||||
switch (target->type)
|
||||
{
|
||||
|
@ -3185,16 +3252,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
// if not intent on another player,
|
||||
// chase after this one
|
||||
P_SetTarget(&target->target, source);
|
||||
if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL)
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
if (!(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])))
|
||||
P_SetPlayerMobjState(target, target->info->seestate);
|
||||
}
|
||||
else
|
||||
P_SetMobjState(target, target->info->seestate);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -3220,7 +3277,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
|
|||
return;
|
||||
|
||||
// If no health, don't spawn ring!
|
||||
if (player->mo->health <= 1)
|
||||
if (player->rings <= 0)
|
||||
num_rings = 0;
|
||||
|
||||
if (num_rings > 32 && !(player->pflags & PF_NIGHTSFALL))
|
||||
|
@ -3230,11 +3287,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
|
|||
P_PlayerEmeraldBurst(player, false);
|
||||
|
||||
// Spill weapons first
|
||||
if (player->ringweapons)
|
||||
P_PlayerWeaponPanelBurst(player);
|
||||
|
||||
// Spill the ammo
|
||||
P_PlayerWeaponAmmoBurst(player);
|
||||
P_PlayerWeaponPanelOrAmmoBurst(player);
|
||||
|
||||
for (i = 0; i < num_rings; i++)
|
||||
{
|
||||
|
@ -3491,6 +3544,75 @@ void P_PlayerWeaponAmmoBurst(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
void P_PlayerWeaponPanelOrAmmoBurst(player_t *player)
|
||||
{
|
||||
mobj_t *mo;
|
||||
angle_t fa;
|
||||
fixed_t ns;
|
||||
INT32 i = 0;
|
||||
fixed_t z;
|
||||
|
||||
#define SETUP_DROP(thingtype) \
|
||||
z = player->mo->z; \
|
||||
if (player->mo->eflags & MFE_VERTICALFLIP) \
|
||||
z += player->mo->height - mobjinfo[thingtype].height; \
|
||||
fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK; \
|
||||
ns = FixedMul(3*FRACUNIT, player->mo->scale); \
|
||||
|
||||
#define DROP_WEAPON(rwflag, pickup, ammo, power) \
|
||||
if (player->ringweapons & rwflag) \
|
||||
{ \
|
||||
player->ringweapons &= ~rwflag; \
|
||||
SETUP_DROP(pickup) \
|
||||
mo = P_SpawnMobj(player->mo->x, player->mo->y, z, pickup); \
|
||||
mo->reactiontime = 0; \
|
||||
mo->flags2 |= MF2_DONTRESPAWN; \
|
||||
mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \
|
||||
P_SetTarget(&mo->target, player->mo); \
|
||||
mo->fuse = 12*TICRATE; \
|
||||
mo->destscale = player->mo->scale; \
|
||||
P_SetScale(mo, player->mo->scale); \
|
||||
mo->momx = FixedMul(FINECOSINE(fa),ns); \
|
||||
if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \
|
||||
mo->momy = FixedMul(FINESINE(fa),ns); \
|
||||
P_SetObjectMomZ(mo, 4*FRACUNIT, false); \
|
||||
if (i & 1) \
|
||||
P_SetObjectMomZ(mo, 4*FRACUNIT, true); \
|
||||
++i; \
|
||||
} \
|
||||
else if (player->powers[power] > 0) \
|
||||
{ \
|
||||
SETUP_DROP(ammo) \
|
||||
mo = P_SpawnMobj(player->mo->x, player->mo->y, z, ammo); \
|
||||
mo->health = player->powers[power]; \
|
||||
mo->flags2 |= MF2_DONTRESPAWN; \
|
||||
mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \
|
||||
P_SetTarget(&mo->target, player->mo); \
|
||||
mo->fuse = 12*TICRATE; \
|
||||
mo->destscale = player->mo->scale; \
|
||||
P_SetScale(mo, player->mo->scale); \
|
||||
mo->momx = FixedMul(FINECOSINE(fa),ns); \
|
||||
if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \
|
||||
mo->momy = FixedMul(FINESINE(fa),ns); \
|
||||
P_SetObjectMomZ(mo, 3*FRACUNIT, false); \
|
||||
if (i & 1) \
|
||||
P_SetObjectMomZ(mo, 3*FRACUNIT, true); \
|
||||
player->powers[power] = 0; \
|
||||
++i; \
|
||||
}
|
||||
|
||||
DROP_WEAPON(RW_BOUNCE, MT_BOUNCEPICKUP, MT_BOUNCERING, pw_bouncering);
|
||||
DROP_WEAPON(RW_RAIL, MT_RAILPICKUP, MT_RAILRING, pw_railring);
|
||||
DROP_WEAPON(RW_AUTO, MT_AUTOPICKUP, MT_AUTOMATICRING, pw_automaticring);
|
||||
DROP_WEAPON(RW_EXPLODE, MT_EXPLODEPICKUP, MT_EXPLOSIONRING, pw_explosionring);
|
||||
DROP_WEAPON(RW_SCATTER, MT_SCATTERPICKUP, MT_SCATTERRING, pw_scatterring);
|
||||
DROP_WEAPON(RW_GRENADE, MT_GRENADEPICKUP, MT_GRENADERING, pw_grenadering);
|
||||
DROP_WEAPON(0, 0, MT_INFINITYRING, pw_infinityring);
|
||||
|
||||
#undef DROP_WEAPON
|
||||
#undef SETUP_DROP
|
||||
}
|
||||
|
||||
//
|
||||
// P_PlayerEmeraldBurst
|
||||
//
|
||||
|
|
|
@ -59,9 +59,10 @@
|
|||
|
||||
#define AIMINGTOSLOPE(aiming) FINESINE((aiming>>ANGLETOFINESHIFT) & FINEMASK)
|
||||
|
||||
#define mariomode (maptol & TOL_MARIO)
|
||||
#define twodlevel (maptol & TOL_2D)
|
||||
|
||||
#define mariomode (maptol & TOL_MARIO)
|
||||
|
||||
#define P_GetPlayerHeight(player) FixedMul(player->height, player->mo->scale)
|
||||
#define P_GetPlayerSpinHeight(player) FixedMul(player->spinheight, player->mo->scale)
|
||||
|
||||
|
@ -124,6 +125,7 @@ extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate;
|
|||
|
||||
INT32 P_GetPlayerControlDirection(player_t *player);
|
||||
void P_AddPlayerScore(player_t *player, UINT32 amount);
|
||||
void P_StealPlayerScore(player_t *player, UINT32 amount);
|
||||
void P_ResetCamera(player_t *player, camera_t *thiscam);
|
||||
boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam);
|
||||
void P_SlideCameraMove(camera_t *thiscam);
|
||||
|
@ -142,6 +144,7 @@ boolean P_InQuicksand(mobj_t *mo);
|
|||
void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative);
|
||||
void P_RestoreMusic(player_t *player);
|
||||
void P_SpawnShieldOrb(player_t *player);
|
||||
void P_SwitchShield(player_t *player, UINT16 shieldtype);
|
||||
mobj_t *P_SpawnGhostMobj(mobj_t *mobj);
|
||||
void P_GivePlayerRings(player_t *player, INT32 num_rings);
|
||||
void P_GivePlayerLives(player_t *player, INT32 numlives);
|
||||
|
@ -151,8 +154,9 @@ void P_ResetScore(player_t *player);
|
|||
boolean P_AutoPause(void);
|
||||
|
||||
void P_DoJumpShield(player_t *player);
|
||||
void P_DoBubbleBounce(player_t *player);
|
||||
void P_BlackOw(player_t *player);
|
||||
void P_ElementalFireTrail(player_t *player);
|
||||
void P_ElementalFire(player_t *player, boolean cropcircle);
|
||||
|
||||
void P_DoPityCheck(player_t *player);
|
||||
void P_PlayerThink(player_t *player);
|
||||
|
@ -165,7 +169,7 @@ fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move);
|
|||
fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move);
|
||||
void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
|
||||
|
||||
boolean P_LookForEnemies(player_t *player);
|
||||
boolean P_LookForEnemies(player_t *player, boolean nonenemies);
|
||||
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
|
||||
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
|
||||
boolean P_SuperReady(player_t *player);
|
||||
|
@ -211,6 +215,7 @@ void P_PrecipitationEffects(void);
|
|||
void P_RemoveMobj(mobj_t *th);
|
||||
boolean P_MobjWasRemoved(mobj_t *th);
|
||||
void P_RemoveSavegameMobj(mobj_t *th);
|
||||
UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2);
|
||||
boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state);
|
||||
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
|
||||
void P_RunShields(void);
|
||||
|
@ -290,6 +295,11 @@ boolean P_CheckMissileRange(mobj_t *actor);
|
|||
void P_NewChaseDir(mobj_t *actor);
|
||||
boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist);
|
||||
|
||||
mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers);
|
||||
void P_InternalFlickyBubble(mobj_t *actor);
|
||||
void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez);
|
||||
void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle);
|
||||
|
||||
//
|
||||
// P_MAP
|
||||
//
|
||||
|
@ -380,7 +390,8 @@ typedef struct BasicFF_s
|
|||
#define DMG_FIRE 2
|
||||
#define DMG_ELECTRIC 3
|
||||
#define DMG_SPIKE 4
|
||||
//#define DMG_SPECIALSTAGE 5
|
||||
#define DMG_NUKE 5 // bomb shield
|
||||
//#define DMG_SPECIALSTAGE 6
|
||||
//// Death types - cannot be combined with damage types
|
||||
#define DMG_INSTAKILL 0x80
|
||||
#define DMG_DROWNED 0x80+1
|
||||
|
@ -399,6 +410,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
void P_PlayerRingBurst(player_t *player, INT32 num_rings); /// \todo better fit in p_user.c
|
||||
void P_PlayerWeaponPanelBurst(player_t *player);
|
||||
void P_PlayerWeaponAmmoBurst(player_t *player);
|
||||
void P_PlayerWeaponPanelOrAmmoBurst(player_t *player);
|
||||
void P_PlayerEmeraldBurst(player_t *player, boolean toss);
|
||||
|
||||
void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck);
|
||||
|
@ -413,6 +425,7 @@ void P_ResetStarposts(void);
|
|||
|
||||
boolean P_CanPickupItem(player_t *player, boolean weapon);
|
||||
void P_DoNightsScore(player_t *player);
|
||||
void P_DoMatchSuper(player_t *player);
|
||||
|
||||
//
|
||||
// P_SPEC
|
||||
|
|
54
src/p_map.c
54
src/p_map.c
|
@ -203,7 +203,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
}
|
||||
}
|
||||
|
||||
pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these.
|
||||
pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY); // I still need these.
|
||||
jumping = object->player->jumping;
|
||||
secondjump = object->player->secondjump;
|
||||
P_ResetPlayer(object->player);
|
||||
|
@ -768,8 +768,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
}
|
||||
}
|
||||
|
||||
if (tmthing->type == MT_SHELL && tmthing->threshold > TICRATE)
|
||||
return true;
|
||||
// damage / explode
|
||||
if (tmthing->flags & MF_ENEMY) // An actual ENEMY! (Like the deton, for example)
|
||||
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
|
||||
|
@ -810,7 +808,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmthing->y = thing->y;
|
||||
P_SetThingPosition(tmthing);
|
||||
}
|
||||
else
|
||||
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial
|
||||
P_DamageMobj(thing, tmthing, tmthing->target, 1, 0);
|
||||
|
||||
// don't traverse any more
|
||||
|
@ -969,10 +967,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
if (G_RingSlingerGametype() && (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam))
|
||||
{
|
||||
if ((tmthing->player->powers[pw_invulnerability] || tmthing->player->powers[pw_super])
|
||||
if ((tmthing->player->powers[pw_invulnerability] || tmthing->player->powers[pw_super] || (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) && (tmthing->player->pflags & PF_SHIELDABILITY)))
|
||||
&& !thing->player->powers[pw_super])
|
||||
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
|
||||
else if ((thing->player->powers[pw_invulnerability] || thing->player->powers[pw_super])
|
||||
else if ((thing->player->powers[pw_invulnerability] || thing->player->powers[pw_super] || (((thing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) && (thing->player->pflags & PF_SHIELDABILITY)))
|
||||
&& !tmthing->player->powers[pw_super])
|
||||
P_DamageMobj(tmthing, thing, thing, 1, 0);
|
||||
}
|
||||
|
@ -1052,24 +1050,41 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height
|
||||
&& thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z)
|
||||
{
|
||||
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
|
||||
UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY)
|
||||
? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
|
||||
: 0);
|
||||
if (thing->flags & MF_MONITOR
|
||||
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|
||||
|| ((tmthing->player->pflags & PF_JUMPED)
|
||||
&& !(tmthing->player->charflags & SF_NOJUMPDAMAGE
|
||||
&& !(tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|
||||
&& (tmthing->player->pflags & PF_FORCEJUMPDAMAGE
|
||||
|| !(tmthing->player->charflags & SF_NOJUMPSPIN)
|
||||
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|
||||
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|
||||
|| ((tmthing->player->charflags & SF_STOMPDAMAGE)
|
||||
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))))
|
||||
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|
||||
|| elementalpierce))
|
||||
{
|
||||
player_t *player = tmthing->player;
|
||||
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
|
||||
fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
|
||||
fixed_t *z = &tmthing->z; // aau.
|
||||
P_DamageMobj(thing, tmthing, tmthing, 1, 0); // break the monitor
|
||||
// Going down? Then bounce back up.
|
||||
if ((P_MobjWasRemoved(thing) // Monitor was removed
|
||||
|| !thing->health) // or otherwise popped
|
||||
&& (flipval*(*momz) < 0)) // monitor is on the floor and you're going down, or on the ceiling and you're going up
|
||||
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
|
||||
return false;
|
||||
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
|
||||
&& (elementalpierce != 1)) // you're not piercing through the monitor...
|
||||
{
|
||||
if (elementalpierce == 2)
|
||||
P_DoBubbleBounce(player);
|
||||
else
|
||||
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
|
||||
}
|
||||
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
|
||||
return false;
|
||||
else
|
||||
*z -= *momz; // to ensure proper collision.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1084,8 +1099,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
else if (thing->flags & MF_MONITOR && tmthing->player
|
||||
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|
||||
|| ((tmthing->player->pflags & PF_JUMPED)
|
||||
&& !(tmthing->player->charflags & SF_NOJUMPDAMAGE
|
||||
&& !(tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|
||||
&& (tmthing->player->pflags & PF_FORCEJUMPDAMAGE
|
||||
|| !(tmthing->player->charflags & SF_NOJUMPSPIN)
|
||||
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|
||||
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|
||||
|| ((tmthing->player->charflags & SF_STOMPDAMAGE)
|
||||
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)))
|
||||
|
@ -1124,7 +1140,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->player && tmthing->z + tmthing->height > topz
|
||||
&& tmthing->z + tmthing->height < tmthing->ceilingz)
|
||||
{
|
||||
tmfloorz = tmceilingz = INT32_MIN; // block while in air
|
||||
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
|
||||
return false;
|
||||
|
||||
tmfloorz = tmceilingz = topz; // block while in air
|
||||
#ifdef ESLOPE
|
||||
tmceilingslope = NULL;
|
||||
#endif
|
||||
|
@ -1167,7 +1186,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->player && tmthing->z < topz
|
||||
&& tmthing->z > tmthing->floorz)
|
||||
{
|
||||
tmfloorz = tmceilingz = INT32_MAX; // block while in air
|
||||
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
|
||||
return false;
|
||||
|
||||
tmfloorz = tmceilingz = topz; // block while in air
|
||||
#ifdef ESLOPE
|
||||
tmfloorslope = NULL;
|
||||
#endif
|
||||
|
|
|
@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
|
|||
side_t *side = &sides[linedef->sidenum[0]];
|
||||
fixed_t textop, texbottom, texheight;
|
||||
fixed_t texmid, delta1, delta2;
|
||||
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
|
||||
|
||||
// Get the midtexture's height
|
||||
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
|
||||
if (texnum) {
|
||||
// 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
|
||||
// don't remove this code unless solid midtextures
|
||||
// on non-solid polyobjects should NEVER happen in the future
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
// don't remove this code unless solid midtextures
|
||||
// on non-solid polyobjects should NEVER happen in the future
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = opentop + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
{
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = opentop + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texmid = texbottom+(textop-texbottom)/2;
|
||||
texmid = texbottom+(textop-texbottom)/2;
|
||||
|
||||
delta1 = abs(mobj->z - texmid);
|
||||
delta2 = abs(thingtop - texmid);
|
||||
delta1 = abs(mobj->z - texmid);
|
||||
delta2 = abs(thingtop - texmid);
|
||||
|
||||
if (delta1 > delta2) { // Below
|
||||
if (opentop > texbottom)
|
||||
opentop = texbottom;
|
||||
} else { // Above
|
||||
if (openbottom < textop)
|
||||
openbottom = textop;
|
||||
if (delta1 > delta2) { // Below
|
||||
if (opentop > texbottom)
|
||||
opentop = texbottom;
|
||||
} else { // Above
|
||||
if (openbottom < textop)
|
||||
openbottom = textop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1030
src/p_mobj.c
1030
src/p_mobj.c
File diff suppressed because it is too large
Load diff
|
@ -193,6 +193,7 @@ typedef enum
|
|||
MF2_BOSSDEAD = 1<<26, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
|
||||
MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH
|
||||
MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
|
||||
MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
|
||||
// free: to and including 1<<31
|
||||
} mobjflag2_t;
|
||||
|
||||
|
@ -453,5 +454,6 @@ void P_EmeraldManager(void);
|
|||
extern mapthing_t *huntemeralds[MAXHUNTEMERALDS];
|
||||
extern INT32 numhuntemeralds;
|
||||
extern boolean runemeraldmanager;
|
||||
extern UINT16 emeraldspawndelay;
|
||||
extern INT32 numstarposts;
|
||||
#endif
|
||||
|
|
|
@ -128,7 +128,7 @@ static void P_NetArchivePlayers(void)
|
|||
WRITEANGLE(save_p, players[i].aiming);
|
||||
WRITEANGLE(save_p, players[i].awayviewaiming);
|
||||
WRITEINT32(save_p, players[i].awayviewtics);
|
||||
WRITEINT32(save_p, players[i].health);
|
||||
WRITEINT32(save_p, players[i].rings);
|
||||
|
||||
WRITESINT8(save_p, players[i].pity);
|
||||
WRITEINT32(save_p, players[i].currentweapon);
|
||||
|
@ -308,7 +308,7 @@ static void P_NetUnArchivePlayers(void)
|
|||
players[i].aiming = READANGLE(save_p);
|
||||
players[i].awayviewaiming = READANGLE(save_p);
|
||||
players[i].awayviewtics = READINT32(save_p);
|
||||
players[i].health = READINT32(save_p);
|
||||
players[i].rings = READINT32(save_p);
|
||||
|
||||
players[i].pity = READSINT8(save_p);
|
||||
players[i].currentweapon = READINT32(save_p);
|
||||
|
@ -470,6 +470,7 @@ static void P_NetUnArchivePlayers(void)
|
|||
#define SD_TAG 0x10
|
||||
#define SD_FLOORANG 0x20
|
||||
#define SD_CEILANG 0x40
|
||||
#define SD_TAGLIST 0x80
|
||||
|
||||
#define LD_FLAG 0x01
|
||||
#define LD_SPECIAL 0x02
|
||||
|
@ -519,10 +520,9 @@ static void P_NetArchiveWorld(void)
|
|||
//
|
||||
// flats
|
||||
//
|
||||
// P_AddLevelFlat should not add but just return the number
|
||||
if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
|
||||
if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
|
||||
diff |= SD_FLOORPIC;
|
||||
if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats))
|
||||
if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
|
||||
diff |= SD_CEILPIC;
|
||||
|
||||
if (ss->lightlevel != SHORT(ms->lightlevel))
|
||||
|
@ -545,6 +545,8 @@ static void P_NetArchiveWorld(void)
|
|||
|
||||
if (ss->tag != SHORT(ms->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
|
||||
if (ss->ffloors)
|
||||
|
@ -592,16 +594,17 @@ static void P_NetArchiveWorld(void)
|
|||
WRITEFIXED(put, ss->ceiling_xoffs);
|
||||
if (diff2 & SD_CYOFFS)
|
||||
WRITEFIXED(put, ss->ceiling_yoffs);
|
||||
if (diff2 & SD_TAG)
|
||||
{
|
||||
if (diff2 & SD_TAG) // save only the tag
|
||||
WRITEINT16(put, ss->tag);
|
||||
WRITEINT32(put, ss->firsttag);
|
||||
WRITEINT32(put, ss->nexttag);
|
||||
}
|
||||
if (diff2 & SD_FLOORANG)
|
||||
WRITEANGLE(put, ss->floorpic_angle);
|
||||
if (diff2 & SD_CEILANG)
|
||||
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
|
||||
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
|
||||
|
@ -762,12 +765,12 @@ static void P_NetUnArchiveWorld(void)
|
|||
sectors[i].ceilingheight = READFIXED(get);
|
||||
if (diff & SD_FLOORPIC)
|
||||
{
|
||||
sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats);
|
||||
sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
|
||||
get += 8;
|
||||
}
|
||||
if (diff & SD_CEILPIC)
|
||||
{
|
||||
sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats);
|
||||
sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
|
||||
get += 8;
|
||||
}
|
||||
if (diff & SD_LIGHT)
|
||||
|
@ -784,12 +787,11 @@ static void P_NetUnArchiveWorld(void)
|
|||
if (diff2 & SD_CYOFFS)
|
||||
sectors[i].ceiling_yoffs = READFIXED(get);
|
||||
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].nexttag = READINT32(get);
|
||||
P_ChangeSectorTag(i, tag);
|
||||
}
|
||||
if (diff2 & SD_FLOORANG)
|
||||
sectors[i].floorpic_angle = READANGLE(get);
|
||||
|
@ -972,6 +974,7 @@ typedef enum
|
|||
tc_noenemies,
|
||||
tc_eachtime,
|
||||
tc_disappear,
|
||||
tc_planedisplace,
|
||||
#ifdef POLYOBJECTS
|
||||
tc_polyrotate, // haleyjd 03/26/06: polyobjects
|
||||
tc_polymove,
|
||||
|
@ -1095,7 +1098,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
|
|||
diff |= MD_TRACER;
|
||||
if (mobj->friction != ORIG_FRICTION)
|
||||
diff |= MD_FRICTION;
|
||||
if (mobj->movefactor != ORIG_FRICTION_FACTOR)
|
||||
if (mobj->movefactor != FRACUNIT)
|
||||
diff |= MD_MOVEFACTOR;
|
||||
if (mobj->fuse)
|
||||
diff |= MD_FUSE;
|
||||
|
@ -1535,6 +1538,21 @@ static void SaveDisappearThinker(const thinker_t *th, const UINT8 type)
|
|||
WRITEINT32(save_p, ht->exists);
|
||||
}
|
||||
|
||||
//
|
||||
// SavePlaneDisplaceThinker
|
||||
//
|
||||
// Saves a planedisplace_t thinker
|
||||
//
|
||||
static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type)
|
||||
{
|
||||
const planedisplace_t *ht = (const void *)th;
|
||||
WRITEUINT8(save_p, type);
|
||||
WRITEINT32(save_p, ht->affectee);
|
||||
WRITEINT32(save_p, ht->control);
|
||||
WRITEFIXED(save_p, ht->last_height);
|
||||
WRITEFIXED(save_p, ht->speed);
|
||||
WRITEUINT8(save_p, ht->type);
|
||||
}
|
||||
#ifdef POLYOBJECTS
|
||||
|
||||
//
|
||||
|
@ -1816,6 +1834,12 @@ static void P_NetArchiveThinkers(void)
|
|||
SaveDisappearThinker(th, tc_disappear);
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace)
|
||||
{
|
||||
SavePlaneDisplaceThinker(th, tc_planedisplace);
|
||||
continue;
|
||||
}
|
||||
#ifdef POLYOBJECTS
|
||||
else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
|
||||
{
|
||||
|
@ -2081,7 +2105,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
|
|||
if (diff & MD_MOVEFACTOR)
|
||||
mobj->movefactor = READFIXED(save_p);
|
||||
else
|
||||
mobj->movefactor = ORIG_FRICTION_FACTOR;
|
||||
mobj->movefactor = FRACUNIT;
|
||||
if (diff & MD_FUSE)
|
||||
mobj->fuse = READINT32(save_p);
|
||||
if (diff & MD_WATERTOP)
|
||||
|
@ -2484,6 +2508,23 @@ static inline void LoadDisappearThinker(actionf_p1 thinker)
|
|||
P_AddThinker(&ht->thinker);
|
||||
}
|
||||
|
||||
//
|
||||
// LoadPlaneDisplaceThinker
|
||||
//
|
||||
// Loads a planedisplace_t thinker
|
||||
//
|
||||
static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
|
||||
{
|
||||
planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
|
||||
ht->thinker.function.acp1 = thinker;
|
||||
ht->affectee = READINT32(save_p);
|
||||
ht->control = READINT32(save_p);
|
||||
ht->last_height = READFIXED(save_p);
|
||||
ht->speed = READFIXED(save_p);
|
||||
ht->type = READUINT8(save_p);
|
||||
P_AddThinker(&ht->thinker);
|
||||
}
|
||||
|
||||
#ifdef POLYOBJECTS
|
||||
|
||||
//
|
||||
|
@ -2628,6 +2669,7 @@ static void P_NetUnArchiveThinkers(void)
|
|||
thinker_t *next;
|
||||
UINT8 tclass;
|
||||
UINT8 restoreNum = false;
|
||||
UINT32 i;
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
|
||||
I_Error("Bad $$$.sav at archive block Thinkers");
|
||||
|
@ -2648,6 +2690,12 @@ static void P_NetUnArchiveThinkers(void)
|
|||
iquetail = iquehead = 0;
|
||||
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
|
||||
for (;;)
|
||||
{
|
||||
|
@ -2760,6 +2808,10 @@ static void P_NetUnArchiveThinkers(void)
|
|||
case tc_disappear:
|
||||
LoadDisappearThinker((actionf_p1)T_Disappear);
|
||||
break;
|
||||
|
||||
case tc_planedisplace:
|
||||
LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
|
||||
break;
|
||||
#ifdef POLYOBJECTS
|
||||
case tc_polyrotate:
|
||||
LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
|
||||
|
@ -3306,7 +3358,7 @@ void P_SaveNetGame(void)
|
|||
{
|
||||
thinker_t *th;
|
||||
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);
|
||||
P_NetArchiveMisc();
|
||||
|
|
107
src/p_setup.c
107
src/p_setup.c
|
@ -160,6 +160,33 @@ FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg)
|
|||
I_Error("Invalid or corrupt map.\nLook in log file or text console for technical details.");
|
||||
}
|
||||
|
||||
/** Sets a header's flickies to be equivalent to the original Freed Animals
|
||||
*
|
||||
* \param i The header to set flickies for
|
||||
*/
|
||||
void P_SetDemoFlickies(INT16 i)
|
||||
{
|
||||
mapheaderinfo[i]->numFlickies = 5;
|
||||
mapheaderinfo[i]->flickies = Z_Realloc(mapheaderinfo[i]->flickies, 5*sizeof(mobjtype_t), PU_STATIC, NULL);
|
||||
mapheaderinfo[i]->flickies[0] = MT_FLICKY_02/*MT_BUNNY*/;
|
||||
mapheaderinfo[i]->flickies[1] = MT_FLICKY_01/*MT_BIRD*/;
|
||||
mapheaderinfo[i]->flickies[2] = MT_FLICKY_12/*MT_MOUSE*/;
|
||||
mapheaderinfo[i]->flickies[3] = MT_FLICKY_11/*MT_COW*/;
|
||||
mapheaderinfo[i]->flickies[4] = MT_FLICKY_03/*MT_CHICKEN*/;
|
||||
}
|
||||
|
||||
/** Clears a header's flickies
|
||||
*
|
||||
* \param i The header to clear flickies for
|
||||
*/
|
||||
void P_DeleteFlickies(INT16 i)
|
||||
{
|
||||
if (mapheaderinfo[i]->flickies)
|
||||
Z_Free(mapheaderinfo[i]->flickies);
|
||||
mapheaderinfo[i]->flickies = NULL;
|
||||
mapheaderinfo[i]->numFlickies = 0;
|
||||
}
|
||||
|
||||
#define NUMLAPS_DEFAULT 4
|
||||
|
||||
/** Clears the data from a single map header.
|
||||
|
@ -223,6 +250,12 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
|
|||
mapheaderinfo[num]->levelflags = 0;
|
||||
DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE);
|
||||
mapheaderinfo[num]->menuflags = 0;
|
||||
// Flickies. Nope, no delfile support here either
|
||||
#if 1 // equivalent to "FlickyList = DEMO"
|
||||
P_SetDemoFlickies(num);
|
||||
#else // equivalent to "FlickyList = NONE"
|
||||
P_DeleteFlickies(num);
|
||||
#endif
|
||||
// TODO grades support for delfile (pfft yeah right)
|
||||
P_DeleteGrades(num);
|
||||
// an even further impossibility, delfile custom opts support
|
||||
|
@ -241,6 +274,7 @@ void P_AllocMapHeader(INT16 i)
|
|||
if (!mapheaderinfo[i])
|
||||
{
|
||||
mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL);
|
||||
mapheaderinfo[i]->flickies = NULL;
|
||||
mapheaderinfo[i]->grades = NULL;
|
||||
}
|
||||
P_ClearSingleMapHeaderInfo(i + 1);
|
||||
|
@ -574,6 +608,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
|
|||
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)
|
||||
{
|
||||
UINT8 *data;
|
||||
|
@ -614,6 +711,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
|
|||
ss->special = SHORT(ms->special);
|
||||
ss->tag = SHORT(ms->tag);
|
||||
ss->nexttag = ss->firsttag = -1;
|
||||
ss->spawn_nexttag = ss->spawn_firsttag = -1;
|
||||
|
||||
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
|
||||
ss->validcount = 0;
|
||||
|
@ -1463,6 +1561,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
|
|||
sd->text[6] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // Speed pad parameters
|
||||
case 414: // Play SFX
|
||||
{
|
||||
sd->toptexture = sd->midtexture = sd->bottomtexture = 0;
|
||||
|
@ -1476,6 +1576,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
|
|||
break;
|
||||
}
|
||||
|
||||
case 14: // Bustable block parameters
|
||||
case 15: // Fan particle spawner parameters
|
||||
case 425: // Calls P_SetMobjState on calling mobj
|
||||
case 434: // Custom Power
|
||||
case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors
|
||||
|
@ -2086,6 +2188,7 @@ static void P_LevelInitStuff(void)
|
|||
// special stage tokens, emeralds, and ring total
|
||||
tokenbits = 0;
|
||||
runemeraldmanager = false;
|
||||
emeraldspawndelay = 60*TICRATE;
|
||||
nummaprings = 0;
|
||||
|
||||
// emerald hunt
|
||||
|
@ -2128,7 +2231,7 @@ static void P_LevelInitStuff(void)
|
|||
players[i].gotcontinue = false;
|
||||
|
||||
players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0;
|
||||
players[i].health = 1;
|
||||
players[i].rings = 0;
|
||||
players[i].aiming = 0;
|
||||
players[i].pflags &= ~PF_TIMEOVER;
|
||||
|
||||
|
@ -2585,7 +2688,7 @@ boolean P_SetupLevel(boolean skipprecip)
|
|||
lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
|
||||
|
||||
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
|
||||
CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette);
|
||||
CON_SetupBackColormap();
|
||||
|
||||
// SRB2 determines the sky texture to be used depending on the map header.
|
||||
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
|
||||
|
|
|
@ -47,6 +47,8 @@ typedef struct
|
|||
extern size_t numlevelflats;
|
||||
extern levelflat_t *levelflats;
|
||||
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 mapthing_t *mapthings;
|
||||
|
@ -66,6 +68,9 @@ void P_WriteThings(lumpnum_t lump);
|
|||
size_t P_PrecacheLevelFlats(void);
|
||||
void P_AllocMapHeader(INT16 i);
|
||||
|
||||
void P_SetDemoFlickies(INT16 i);
|
||||
void P_DeleteFlickies(INT16 i);
|
||||
|
||||
// Needed for NiGHTS
|
||||
void P_ReloadRings(void);
|
||||
void P_DeleteGrades(INT16 i);
|
||||
|
|
|
@ -804,6 +804,39 @@ void P_SlopeLaunch(mobj_t *mo)
|
|||
mo->standingslope = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// P_GetWallTransferMomZ
|
||||
//
|
||||
// It would be nice to have a single function that does everything necessary for slope-to-wall transfer.
|
||||
// However, it needs to be seperated out in P_XYMovement to take into account momentum before and after hitting the wall.
|
||||
// This just performs the necessary calculations for getting the base vertical momentum; the horizontal is already reasonably calculated by P_SlideMove.
|
||||
fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope)
|
||||
{
|
||||
vector3_t slopemom, axis;
|
||||
angle_t ang;
|
||||
|
||||
if (mo->standingslope->flags & SL_NOPHYSICS)
|
||||
return 0;
|
||||
|
||||
// If there's physics, time for launching.
|
||||
// Doesn't kill the vertical momentum as much as P_SlopeLaunch does.
|
||||
ang = slope->zangle + ANG15*((slope->zangle > 0) ? 1 : -1);
|
||||
if (ang > ANGLE_90 && ang < ANGLE_180)
|
||||
ang = ((slope->zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards
|
||||
|
||||
slopemom.x = mo->momx;
|
||||
slopemom.y = mo->momy;
|
||||
slopemom.z = 3*(mo->momz/2);
|
||||
|
||||
axis.x = -slope->d.y;
|
||||
axis.y = slope->d.x;
|
||||
axis.z = 0;
|
||||
|
||||
FV3_Rotate(&slopemom, &axis, ang >> ANGLETOFINESHIFT);
|
||||
|
||||
return 2*(slopemom.z/3);
|
||||
}
|
||||
|
||||
// Function to help handle landing on slopes
|
||||
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y);
|
|||
void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
|
||||
void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
|
||||
void P_SlopeLaunch(mobj_t *mo);
|
||||
fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope);
|
||||
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
|
||||
void P_ButteredSlope(mobj_t *mo);
|
||||
|
||||
|
|
397
src/p_spec.c
397
src/p_spec.c
|
@ -51,6 +51,9 @@ mobj_t *skyboxmo[2];
|
|||
// Amount (dx, dy) vector linedef is shifted right to get scroll amount
|
||||
#define SCROLL_SHIFT 5
|
||||
|
||||
// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize.
|
||||
#define MAXFLATSIZE (2048<<FRACBITS)
|
||||
|
||||
/** Animated texture descriptor
|
||||
* This keeps track of an animated texture or an animated flat.
|
||||
* \sa P_UpdateSpecials, P_InitPicAnims, animdef_t
|
||||
|
@ -108,6 +111,7 @@ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinker
|
|||
static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec);
|
||||
static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer);
|
||||
static void P_AddSpikeThinker(sector_t *sec, INT32 referrer);
|
||||
static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee);
|
||||
|
||||
|
||||
//SoM: 3/7/2000: New sturcture without limits.
|
||||
|
@ -1519,6 +1523,8 @@ static inline void P_InitTagLists(void)
|
|||
size_t j = (unsigned)sectors[i].tag % numsectors;
|
||||
sectors[i].nexttag = sectors[j].firsttag;
|
||||
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--)
|
||||
|
@ -1621,10 +1627,10 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|
|||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
|
||||
if (!players[i].mo || players[i].mo->health < 1)
|
||||
if (!players[i].mo || players[i].rings <= 0)
|
||||
continue;
|
||||
|
||||
rings += players[i].mo->health-1;
|
||||
rings += players[i].rings;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1632,7 +1638,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|
|||
if (!(actor && actor->player))
|
||||
return false; // no player to count rings from here, sorry
|
||||
|
||||
rings = actor->health-1;
|
||||
rings = actor->player->rings;
|
||||
}
|
||||
|
||||
if (triggerline->flags & ML_NOCLIMB)
|
||||
|
@ -2438,7 +2444,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
|||
{
|
||||
fixed_t sfxnum;
|
||||
|
||||
sfxnum = sides[line->sidenum[0]].toptexture; //P_AproxDistance(line->dx, line->dy)>>FRACBITS;
|
||||
sfxnum = sides[line->sidenum[0]].toptexture;
|
||||
|
||||
if (line->tag != 0 && line->flags & ML_EFFECT5)
|
||||
{
|
||||
|
@ -3593,10 +3599,9 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
|||
break;
|
||||
case 9: // Ring Drainer (Floor Touch)
|
||||
case 10: // Ring Drainer (No Floor Touch)
|
||||
if (leveltime % (TICRATE/2) == 0 && player->mo->health > 1)
|
||||
if (leveltime % (TICRATE/2) == 0 && player->rings > 0)
|
||||
{
|
||||
player->mo->health--;
|
||||
player->health--;
|
||||
player->rings--;
|
||||
S_StartSound(player->mo, sfx_itemup);
|
||||
}
|
||||
break;
|
||||
|
@ -3604,7 +3609,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
|||
if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super] || player->exiting || player->bot)
|
||||
break;
|
||||
|
||||
if (!(player->powers[pw_shield] || player->mo->health > 1)) // Don't do anything if no shield or rings anyway
|
||||
if (!(player->powers[pw_shield] || player->rings > 0)) // Don't do anything if no shield or rings anyway
|
||||
break;
|
||||
|
||||
if (player->powers[pw_shield])
|
||||
|
@ -3612,14 +3617,13 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
|||
P_RemoveShield(player);
|
||||
S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss.
|
||||
}
|
||||
else if (player->mo->health > 1)
|
||||
else if (player->rings > 0)
|
||||
{
|
||||
P_PlayRinglossSound(player->mo);
|
||||
if (player->mo->health > 10)
|
||||
player->mo->health -= 10;
|
||||
if (player->rings >= 10)
|
||||
player->rings -= 10;
|
||||
else
|
||||
player->mo->health = 1;
|
||||
player->health = player->mo->health;
|
||||
player->rings = 0;
|
||||
}
|
||||
|
||||
P_DoPlayerPain(player, NULL, NULL); // this does basically everything that was here before
|
||||
|
@ -3628,7 +3632,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
|||
P_PlayerFlagBurst(player, false);
|
||||
break;
|
||||
case 12: // Space Countdown
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL && !player->powers[pw_spacetime])
|
||||
if (!(player->powers[pw_shield] & SH_PROTECTWATER) && !player->powers[pw_spacetime])
|
||||
player->powers[pw_spacetime] = spacetimetics + 1;
|
||||
break;
|
||||
case 13: // Ramp Sector (Increase step-up/down)
|
||||
|
@ -3728,14 +3732,13 @@ DoneSection2:
|
|||
// Process Section 3
|
||||
switch (special)
|
||||
{
|
||||
case 1: // Ice/Sludge
|
||||
case 1: // Unused
|
||||
case 2: // Wind/Current
|
||||
case 3: // Ice/Sludge and Wind/Current
|
||||
case 3: // Unused
|
||||
case 4: // Conveyor Belt
|
||||
break;
|
||||
|
||||
case 5: // Speed pad w/o spin
|
||||
case 6: // Speed pad w/ spin
|
||||
case 5: // Speed pad
|
||||
if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2)
|
||||
break;
|
||||
|
||||
|
@ -3745,9 +3748,16 @@ DoneSection2:
|
|||
{
|
||||
angle_t lineangle;
|
||||
fixed_t linespeed;
|
||||
fixed_t sfxnum;
|
||||
|
||||
lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
|
||||
linespeed = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y);
|
||||
linespeed = sides[lines[i].sidenum[0]].textureoffset;
|
||||
|
||||
if (linespeed == 0)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sector->tag);
|
||||
break;
|
||||
}
|
||||
|
||||
player->mo->angle = lineangle;
|
||||
|
||||
|
@ -3777,7 +3787,7 @@ DoneSection2:
|
|||
|
||||
P_InstaThrust(player->mo, player->mo->angle, linespeed);
|
||||
|
||||
if (GETSECSPECIAL(sector->special, 3) == 6 && (player->charability2 == CA2_SPINDASH))
|
||||
if ((lines[i].flags & ML_EFFECT5) && (player->charability2 == CA2_SPINDASH)) // Roll!
|
||||
{
|
||||
if (!(player->pflags & PF_SPINNING))
|
||||
player->pflags |= PF_SPINNING;
|
||||
|
@ -3786,19 +3796,26 @@ DoneSection2:
|
|||
}
|
||||
|
||||
player->powers[pw_flashing] = TICRATE/3;
|
||||
S_StartSound(player->mo, sfx_spdpad);
|
||||
|
||||
sfxnum = sides[lines[i].sidenum[0]].toptexture;
|
||||
|
||||
if (!sfxnum)
|
||||
sfxnum = sfx_spdpad;
|
||||
|
||||
S_StartSound(player->mo, sfxnum);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // Bustable block sprite parameter
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 6: // Unused
|
||||
case 7: // Unused
|
||||
case 8: // Unused
|
||||
case 9: // Unused
|
||||
case 10: // Unused
|
||||
case 11: // Unused
|
||||
case 12: // Unused
|
||||
case 13: // Unused
|
||||
case 14: // Unused
|
||||
case 15: // Unused
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3968,8 +3985,14 @@ DoneSection2:
|
|||
}
|
||||
|
||||
// Grab speed and sequence values
|
||||
speed = abs(lines[lineindex].dx)/8;
|
||||
sequence = abs(lines[lineindex].dy)>>FRACBITS;
|
||||
speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8;
|
||||
sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS;
|
||||
|
||||
if (speed == 0)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence);
|
||||
break;
|
||||
}
|
||||
|
||||
// scan the thinkers
|
||||
// to find the first waypoint
|
||||
|
@ -4041,8 +4064,14 @@ DoneSection2:
|
|||
}
|
||||
|
||||
// Grab speed and sequence values
|
||||
speed = -(abs(lines[lineindex].dx)/8); // Negative means reverse
|
||||
sequence = abs(lines[lineindex].dy)>>FRACBITS;
|
||||
speed = -abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; // Negative means reverse
|
||||
sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS;
|
||||
|
||||
if (speed == 0)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence);
|
||||
break;
|
||||
}
|
||||
|
||||
// scan the thinkers
|
||||
// to find the last waypoint
|
||||
|
@ -4082,6 +4111,7 @@ DoneSection2:
|
|||
player->speed = speed;
|
||||
player->pflags |= PF_SPINNING;
|
||||
player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY);
|
||||
player->climbing = 0;
|
||||
|
||||
if (player->mo->state-states != S_PLAY_SPIN)
|
||||
{
|
||||
|
@ -4180,8 +4210,14 @@ DoneSection2:
|
|||
}
|
||||
|
||||
// Grab speed and sequence values
|
||||
speed = abs(lines[lineindex].dx)/8;
|
||||
sequence = abs(lines[lineindex].dy)>>FRACBITS;
|
||||
speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8;
|
||||
sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS;
|
||||
|
||||
if (speed == 0)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence);
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the closest waypoint
|
||||
// Find the preceding waypoint
|
||||
|
@ -4797,6 +4833,13 @@ void P_UpdateSpecials(void)
|
|||
}
|
||||
}
|
||||
|
||||
/** Gets a 3Dfloor by control sector.
|
||||
*
|
||||
* \param sec Target sector.
|
||||
* \param sec2 Control sector.
|
||||
* \return Pointer to found 3Dfloor, or NULL.
|
||||
* \sa P_GetFFloorByID
|
||||
*/
|
||||
static inline ffloor_t *P_GetFFloorBySec(sector_t *sec, sector_t *sec2)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
|
@ -4809,6 +4852,26 @@ static inline ffloor_t *P_GetFFloorBySec(sector_t *sec, sector_t *sec2)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/** Gets a 3Dfloor by ID number.
|
||||
*
|
||||
* \param sec Target sector.
|
||||
* \param id ID of 3Dfloor in target sector. Note that the first FOF's ID is 0.
|
||||
* \return Pointer to found 3Dfloor, or NULL.
|
||||
* \sa P_GetFFloorBySec
|
||||
*/
|
||||
ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
UINT16 i = 0;
|
||||
|
||||
if (!sec->ffloors)
|
||||
return NULL;
|
||||
for (rover = sec->ffloors; rover; rover = rover->next)
|
||||
if (i++ == id)
|
||||
return rover;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Adds a newly formed 3Dfloor structure to a sector's ffloors list.
|
||||
*
|
||||
* \param sec Target sector.
|
||||
|
@ -5001,7 +5064,8 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
|
|||
|
||||
if ((flags & FF_MARIO))
|
||||
{
|
||||
P_AddBlockThinker(sec2, master);
|
||||
if (!(flags & FF_SHATTERBOTTOM)) // Don't change the textures of a brick block, just a question block
|
||||
P_AddBlockThinker(sec2, master);
|
||||
CheckForMarioBlocks = true;
|
||||
}
|
||||
|
||||
|
@ -5101,6 +5165,33 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
|
|||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a plane displacement thinker.
|
||||
* Whenever the "control" sector moves,
|
||||
* the "affectee" sector's floor or ceiling plane moves too!
|
||||
*
|
||||
* \param speed Rate of movement relative to control sector
|
||||
* \param control Control sector.
|
||||
* \param affectee Target sector.
|
||||
* \sa P_SpawnSpecials, T_PlaneDisplace
|
||||
* \author Monster Iestyn
|
||||
*/
|
||||
static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee)
|
||||
{
|
||||
planedisplace_t *displace;
|
||||
|
||||
// create and initialize new displacement thinker
|
||||
displace = Z_Calloc(sizeof (*displace), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&displace->thinker);
|
||||
|
||||
displace->thinker.function.acp1 = (actionf_p1)T_PlaneDisplace;
|
||||
displace->affectee = affectee;
|
||||
displace->control = control;
|
||||
displace->last_height = sectors[control].floorheight;
|
||||
displace->speed = speed;
|
||||
displace->type = type;
|
||||
}
|
||||
|
||||
/** Adds a Mario block thinker, which changes the block's texture between blank
|
||||
* and ? depending on whether it has contents.
|
||||
* Needed in case objects respawn inside.
|
||||
|
@ -5339,7 +5430,7 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
|
|||
elevator->distance = FixedInt(AngleFixed(angle));
|
||||
}
|
||||
|
||||
static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA;
|
||||
static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT;
|
||||
|
||||
/** Flashes a laser block.
|
||||
*
|
||||
|
@ -5359,10 +5450,12 @@ void T_LaserFlash(laserthink_t *flash)
|
|||
if (!ffloor || !(ffloor->flags & FF_EXISTS))
|
||||
return;
|
||||
|
||||
if (leveltime & 1)
|
||||
ffloor->flags |= FF_RENDERALL;
|
||||
if (leveltime & 2)
|
||||
//ffloor->flags |= FF_RENDERALL;
|
||||
ffloor->alpha = 0xB0;
|
||||
else
|
||||
ffloor->flags &= ~FF_RENDERALL;
|
||||
//ffloor->flags &= ~FF_RENDERALL;
|
||||
ffloor->alpha = 0x90;
|
||||
|
||||
sourcesec = ffloor->master->frontsector; // Less to type!
|
||||
|
||||
|
@ -5386,6 +5479,10 @@ void T_LaserFlash(laserthink_t *flash)
|
|||
&& thing->flags & MF_BOSS)
|
||||
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);
|
||||
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
|
||||
|
||||
|
@ -5586,32 +5683,27 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
// Init line EFFECTs
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
// set line specials to 0 here too, same reason as above
|
||||
if (netgame || multiplayer)
|
||||
if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups...
|
||||
{
|
||||
// future: nonet flag?
|
||||
}
|
||||
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
|
||||
{
|
||||
lines[i].special = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
|
||||
// set line specials to 0 here too, same reason as above
|
||||
if (netgame || multiplayer)
|
||||
{
|
||||
// future: nonet flag?
|
||||
}
|
||||
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
|
||||
{
|
||||
lines[i].special = 0;
|
||||
continue;
|
||||
}
|
||||
if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
|
||||
else
|
||||
{
|
||||
lines[i].special = 0;
|
||||
continue;
|
||||
}
|
||||
if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))
|
||||
{
|
||||
lines[i].special = 0;
|
||||
continue;
|
||||
if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
|
||||
|| (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
|
||||
|| (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)))
|
||||
{
|
||||
lines[i].special = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5657,47 +5749,53 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case 7: // Flat alignment
|
||||
if (lines[i].flags & ML_EFFECT4) // Align angle
|
||||
case 7: // Flat alignment - redone by toast
|
||||
if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something...
|
||||
{
|
||||
if (!(lines[i].flags & ML_EFFECT5)) // Align floor unless ALLTRIGGER flag is set
|
||||
angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y));
|
||||
fixed_t xoffs;
|
||||
fixed_t yoffs;
|
||||
|
||||
if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set
|
||||
{
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
|
||||
xoffs = sides[lines[i].sidenum[0]].textureoffset;
|
||||
yoffs = sides[lines[i].sidenum[0]].rowoffset;
|
||||
}
|
||||
else // Otherwise, set calculated offsets such that line's v1 is the apparent origin
|
||||
{
|
||||
fixed_t cosinecomponent = FINECOSINE(flatangle>>ANGLETOFINESHIFT);
|
||||
fixed_t sinecomponent = FINESINE(flatangle>>ANGLETOFINESHIFT);
|
||||
xoffs = (-FixedMul(lines[i].v1->x, cosinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, sinecomponent) % MAXFLATSIZE); // No danger of overflow thanks to the strategically placed modulo operations.
|
||||
yoffs = (FixedMul(lines[i].v1->x, sinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, cosinecomponent) % MAXFLATSIZE); // Ditto.
|
||||
}
|
||||
|
||||
if (!(lines[i].flags & ML_BOUNCY)) // Align ceiling unless BOUNCY flag is set
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
{
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
|
||||
}
|
||||
}
|
||||
else // Do offsets
|
||||
{
|
||||
if (!(lines[i].flags & ML_BLOCKMONSTERS)) // Align floor unless BLOCKMONSTERS flag is set
|
||||
{
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
if (!(lines[i].flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set
|
||||
{
|
||||
sectors[s].floor_xoffs += lines[i].dx;
|
||||
sectors[s].floor_yoffs += lines[i].dy;
|
||||
sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = flatangle;
|
||||
sectors[s].floor_xoffs += xoffs;
|
||||
sectors[s].floor_yoffs += yoffs;
|
||||
// saved for netgames
|
||||
sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs;
|
||||
sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lines[i].flags & ML_NOCLIMB)) // Align ceiling unless NOCLIMB flag is set
|
||||
{
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
if (!(lines[i].flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set
|
||||
{
|
||||
sectors[s].ceiling_xoffs += lines[i].dx;
|
||||
sectors[s].ceiling_yoffs += lines[i].dy;
|
||||
sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = flatangle;
|
||||
sectors[s].ceiling_xoffs += xoffs;
|
||||
sectors[s].ceiling_yoffs += yoffs;
|
||||
// saved for netgames
|
||||
sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs;
|
||||
sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Otherwise, print a helpful warning. Can I do no less?
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"),
|
||||
lines[i].tag);
|
||||
break;
|
||||
|
||||
case 8: // Sector Parameters
|
||||
|
@ -5809,6 +5907,19 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
P_AddBridgeThinker(&lines[i], §ors[s]);*/
|
||||
break;
|
||||
|
||||
case 66: // Displace floor by front sector
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s);
|
||||
break;
|
||||
case 67: // Displace ceiling by front sector
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s);
|
||||
break;
|
||||
case 68: // Displace both floor AND ceiling by front sector
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
|
||||
P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s);
|
||||
break;
|
||||
|
||||
case 100: // FOF (solid, opaque, shadows)
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers);
|
||||
break;
|
||||
|
@ -5823,11 +5934,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
// Draw the 'insides' of the block too
|
||||
if (lines[i].flags & ML_NOCLIMB)
|
||||
{
|
||||
ffloorflags |= FF_CUTLEVEL;
|
||||
ffloorflags |= FF_BOTHPLANES;
|
||||
ffloorflags |= FF_ALLSIDES;
|
||||
ffloorflags &= ~FF_EXTRA;
|
||||
ffloorflags &= ~FF_CUTEXTRA;
|
||||
ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
|
||||
ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
|
||||
}
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
|
@ -5934,11 +6042,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
// Draw the 'insides' of the block too
|
||||
if (lines[i].flags & ML_EFFECT2)
|
||||
{
|
||||
ffloorflags |= FF_CUTLEVEL;
|
||||
ffloorflags |= FF_BOTHPLANES;
|
||||
ffloorflags |= FF_ALLSIDES;
|
||||
ffloorflags &= ~FF_EXTRA;
|
||||
ffloorflags &= ~FF_CUTEXTRA;
|
||||
ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
|
||||
ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
|
||||
}
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
|
@ -5952,11 +6057,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
// Draw the 'insides' of the block too
|
||||
if (lines[i].flags & ML_EFFECT2)
|
||||
{
|
||||
ffloorflags |= FF_CUTLEVEL;
|
||||
ffloorflags |= FF_BOTHPLANES;
|
||||
ffloorflags |= FF_ALLSIDES;
|
||||
ffloorflags &= ~FF_EXTRA;
|
||||
ffloorflags &= ~FF_CUTEXTRA;
|
||||
ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
|
||||
ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
|
||||
}
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
|
@ -5980,11 +6082,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
// Draw the 'insides' of the block too
|
||||
if (lines[i].flags & ML_EFFECT2)
|
||||
{
|
||||
ffloorflags |= FF_CUTLEVEL;
|
||||
ffloorflags |= FF_BOTHPLANES;
|
||||
ffloorflags |= FF_ALLSIDES;
|
||||
ffloorflags &= ~FF_EXTRA;
|
||||
ffloorflags &= ~FF_CUTEXTRA;
|
||||
ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
|
||||
ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
|
||||
}
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
|
@ -5998,11 +6097,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
// Draw the 'insides' of the block too
|
||||
if (lines[i].flags & ML_EFFECT2)
|
||||
{
|
||||
ffloorflags |= FF_CUTLEVEL;
|
||||
ffloorflags |= FF_BOTHPLANES;
|
||||
ffloorflags |= FF_ALLSIDES;
|
||||
ffloorflags &= ~FF_EXTRA;
|
||||
ffloorflags &= ~FF_CUTEXTRA;
|
||||
ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
|
||||
ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
|
||||
}
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
|
@ -6180,7 +6276,13 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
break;
|
||||
|
||||
case 250: // Mario Block
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO, secthinkers);
|
||||
ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO;
|
||||
if (lines[i].flags & ML_NOCLIMB)
|
||||
ffloorflags |= FF_SHATTERBOTTOM;
|
||||
if (lines[i].flags & ML_EFFECT1)
|
||||
ffloorflags &= ~(FF_SOLID|FF_RENDERALL|FF_CUTLEVEL);
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
break;
|
||||
|
||||
case 251: // A THWOMP!
|
||||
|
@ -6194,10 +6296,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
break;
|
||||
|
||||
case 252: // Shatter block (breaks when touched)
|
||||
ffloorflags = FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER;
|
||||
if (lines[i].flags & ML_NOCLIMB)
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_SHATTERBOTTOM, secthinkers);
|
||||
else
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER, secthinkers);
|
||||
ffloorflags |= FF_SOLID|FF_SHATTERBOTTOM;
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
break;
|
||||
|
||||
case 253: // Translucent shatter block (see 76)
|
||||
|
@ -6205,10 +6308,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
break;
|
||||
|
||||
case 254: // Bustable block
|
||||
ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP;
|
||||
if (lines[i].flags & ML_NOCLIMB)
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_ONLYKNUX, secthinkers);
|
||||
else
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP, secthinkers);
|
||||
ffloorflags |= FF_ONLYKNUX;
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
break;
|
||||
|
||||
case 255: // Spin bust block (breaks when jumped or spun downwards onto)
|
||||
|
@ -6220,10 +6324,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
|||
break;
|
||||
|
||||
case 257: // Quicksand
|
||||
ffloorflags = FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES;
|
||||
if (lines[i].flags & ML_EFFECT5)
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES|FF_RIPPLE, secthinkers);
|
||||
else
|
||||
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES, secthinkers);
|
||||
ffloorflags |= FF_RIPPLE;
|
||||
|
||||
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
|
||||
break;
|
||||
|
||||
case 258: // Laser block
|
||||
|
@ -6984,7 +7089,6 @@ void T_Disappear(disappear_t *d)
|
|||
/** Adds friction thinker.
|
||||
*
|
||||
* \param friction Friction value, 0xe800 is normal.
|
||||
* \param movefactor Inertia factor.
|
||||
* \param affectee Target sector.
|
||||
* \param roverfriction FOF or not
|
||||
* \sa T_Friction, P_SpawnFriction
|
||||
|
@ -7022,22 +7126,10 @@ void T_Friction(friction_t *f)
|
|||
|
||||
sec = sectors + f->affectee;
|
||||
|
||||
// Make sure the sector type hasn't changed
|
||||
// Get FOF control sector
|
||||
if (f->roverfriction)
|
||||
{
|
||||
referrer = sectors + f->referrer;
|
||||
|
||||
if (!(GETSECSPECIAL(referrer->special, 3) == 1
|
||||
|| GETSECSPECIAL(referrer->special, 3) == 3))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(GETSECSPECIAL(sec->special, 3) == 1
|
||||
|| GETSECSPECIAL(sec->special, 3) == 3))
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign the friction value to players on the floor, non-floating,
|
||||
// and clipped. Normally the object's friction value is kept at
|
||||
// ORIG_FRICTION and this thinker changes it for icy or muddy floors.
|
||||
|
@ -7067,14 +7159,16 @@ void T_Friction(friction_t *f)
|
|||
|| (f->friction < thing->friction))
|
||||
{
|
||||
thing->friction = f->friction;
|
||||
thing->movefactor = f->movefactor;
|
||||
if (thing->player)
|
||||
thing->movefactor = f->movefactor;
|
||||
}
|
||||
}
|
||||
else if (P_GetSpecialBottomZ(thing, sec, sec) == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction?
|
||||
|| f->friction < thing->friction))
|
||||
{
|
||||
thing->friction = f->friction;
|
||||
thing->movefactor = f->movefactor;
|
||||
if (thing->player)
|
||||
thing->movefactor = f->movefactor;
|
||||
}
|
||||
}
|
||||
node = node->m_thinglist_next;
|
||||
|
@ -7090,33 +7184,32 @@ static void P_SpawnFriction(void)
|
|||
size_t i;
|
||||
line_t *l = lines;
|
||||
register INT32 s;
|
||||
fixed_t length; // line length controls magnitude
|
||||
fixed_t strength; // frontside texture offset controls magnitude
|
||||
fixed_t friction; // friction value to be applied during movement
|
||||
INT32 movefactor; // applied to each player move to simulate inertia
|
||||
|
||||
for (i = 0; i < numlines; i++, l++)
|
||||
if (l->special == 540)
|
||||
{
|
||||
length = P_AproxDistance(l->dx, l->dy)>>FRACBITS;
|
||||
friction = (0x1EB8*length)/0x80 + 0xD000;
|
||||
strength = sides[l->sidenum[0]].textureoffset>>FRACBITS;
|
||||
if (strength > 0) // sludge
|
||||
strength = strength*2; // otherwise, the maximum sludginess value is +967...
|
||||
|
||||
// The following might seem odd. At the time of movement,
|
||||
// the move distance is multiplied by 'friction/0x10000', so a
|
||||
// higher friction value actually means 'less friction'.
|
||||
friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800
|
||||
|
||||
if (friction > FRACUNIT)
|
||||
friction = FRACUNIT;
|
||||
if (friction < 0)
|
||||
friction = 0;
|
||||
|
||||
// The following check might seem odd. At the time of movement,
|
||||
// the move distance is multiplied by 'friction/0x10000', so a
|
||||
// higher friction value actually means 'less friction'.
|
||||
|
||||
if (friction > ORIG_FRICTION) // ice
|
||||
movefactor = ((0x10092 - friction)*(0x70))/0x158;
|
||||
movefactor = FixedDiv(ORIG_FRICTION, friction);
|
||||
if (movefactor < FRACUNIT)
|
||||
movefactor = 8*movefactor - 7*FRACUNIT;
|
||||
else
|
||||
movefactor = ((friction - 0xDB34)*(0xA))/0x80;
|
||||
|
||||
// killough 8/28/98: prevent odd situations
|
||||
if (movefactor < 32)
|
||||
movefactor = 32;
|
||||
movefactor = FRACUNIT;
|
||||
|
||||
for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;)
|
||||
Add_Friction(friction, movefactor, s, -1);
|
||||
|
@ -7366,12 +7459,10 @@ void T_Pusher(pusher_t *p)
|
|||
{
|
||||
referrer = §ors[p->referrer];
|
||||
|
||||
if (!(GETSECSPECIAL(referrer->special, 3) == 2
|
||||
|| GETSECSPECIAL(referrer->special, 3) == 3))
|
||||
if (GETSECSPECIAL(referrer->special, 3) != 2)
|
||||
return;
|
||||
}
|
||||
else if (!(GETSECSPECIAL(sec->special, 3) == 2
|
||||
|| GETSECSPECIAL(sec->special, 3) == 3))
|
||||
else if (GETSECSPECIAL(sec->special, 3) != 2)
|
||||
return;
|
||||
|
||||
// For constant pushers (wind/current) there are 3 situations:
|
||||
|
|
26
src/p_spec.h
26
src/p_spec.h
|
@ -64,6 +64,8 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|
|||
void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller);
|
||||
void P_ChangeSectorTag(UINT32 sector, INT16 newtag);
|
||||
|
||||
ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id);
|
||||
|
||||
//
|
||||
// P_LIGHTS
|
||||
//
|
||||
|
@ -323,7 +325,7 @@ INT32 EV_StartCrumble(sector_t *sector, ffloor_t *rover,
|
|||
|
||||
INT32 EV_DoContinuousFall(sector_t *sec, sector_t *pbacksector, fixed_t spd, boolean backwards);
|
||||
|
||||
INT32 EV_MarioBlock(sector_t *sector, sector_t *roversector, fixed_t topheight, mobj_t *puncher);
|
||||
INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher);
|
||||
|
||||
void T_MoveFloor(floormove_t *movefloor);
|
||||
|
||||
|
@ -386,7 +388,7 @@ typedef struct
|
|||
{
|
||||
thinker_t thinker; ///< Thinker structure for friction.
|
||||
INT32 friction; ///< Friction value, 0xe800 = normal.
|
||||
INT32 movefactor; ///< Inertia factor when adding to momentum.
|
||||
INT32 movefactor; ///< Inertia factor when adding to momentum, FRACUNIT = normal.
|
||||
INT32 affectee; ///< Number of affected sector.
|
||||
INT32 referrer; ///< If roverfriction == true, then this will contain the sector # of the control sector where the effect was applied.
|
||||
UINT8 roverfriction; ///< flag for whether friction originated from a FOF or not
|
||||
|
@ -448,6 +450,26 @@ void T_Disappear(disappear_t *d);
|
|||
void T_Pusher(pusher_t *p);
|
||||
mobj_t *P_GetPushThing(UINT32 s);
|
||||
|
||||
// Plane displacement
|
||||
typedef struct
|
||||
{
|
||||
thinker_t thinker; ///< Thinker structure for plane displacement effect.
|
||||
INT32 affectee; ///< Number of affected sector.
|
||||
INT32 control; ///< Control sector used to control plane positions.
|
||||
fixed_t last_height; ///< Last known height of control sector.
|
||||
fixed_t speed; ///< Plane movement speed.
|
||||
/** Types of plane displacement effects.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
pd_floor, ///< Displace floor.
|
||||
pd_ceiling, ///< Displace ceiling.
|
||||
pd_both, ///< Displace both floor AND ceiling.
|
||||
} type;
|
||||
} planedisplace_t;
|
||||
|
||||
void T_PlaneDisplace(planedisplace_t *pd);
|
||||
|
||||
void P_CalcHeight(player_t *player);
|
||||
|
||||
sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo);
|
||||
|
|
|
@ -469,7 +469,7 @@ static inline void P_DoSpecialStageStuff(void)
|
|||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
{
|
||||
ssrings += (players[i].mo->health-1);
|
||||
ssrings += players[i].rings;
|
||||
|
||||
// If in water, deplete timer 6x as fast.
|
||||
if ((players[i].mo->eflags & MFE_TOUCHWATER)
|
||||
|
|
962
src/p_user.c
962
src/p_user.c
File diff suppressed because it is too large
Load diff
67
src/r_bsp.c
67
src/r_bsp.c
|
@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
|
|||
static sector_t tempsec; // Deep water hack
|
||||
extracolormap_t *floorcolormap;
|
||||
extracolormap_t *ceilingcolormap;
|
||||
fixed_t floorcenterz, ceilingcenterz;
|
||||
|
||||
#ifdef RANGECHECK
|
||||
if (num >= numsubsectors)
|
||||
|
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
|
|||
|
||||
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.
|
||||
if (frontsector->ffloors)
|
||||
{
|
||||
|
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
|
|||
sub->sector->moved = frontsector->moved = false;
|
||||
}
|
||||
|
||||
light = R_GetPlaneLight(frontsector,
|
||||
#ifdef ESLOPE
|
||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->floorheight, false);
|
||||
light = R_GetPlaneLight(frontsector, floorcenterz, false);
|
||||
if (frontsector->floorlightsec == -1)
|
||||
floorlightlevel = *frontsector->lightlist[light].lightlevel;
|
||||
floorcolormap = frontsector->lightlist[light].extra_colormap;
|
||||
light = R_GetPlaneLight(frontsector,
|
||||
#ifdef ESLOPE
|
||||
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->ceilingheight, false);
|
||||
light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
|
||||
if (frontsector->ceilinglightsec == -1)
|
||||
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
|
||||
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,
|
||||
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, frontsector->f_slope
|
||||
#endif
|
||||
|
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
|
|||
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
|
||||
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
|
||||
ceilingcolormap, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, frontsector->c_slope
|
||||
#endif
|
||||
|
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
|
|||
if (frontsector->ffloors)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
|
||||
fixed_t heightcheck, planecenterz;
|
||||
|
||||
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].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 =
|
||||
#ifdef ESLOPE
|
||||
*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,
|
||||
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
|
||||
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, *rover->b_slope
|
||||
#endif
|
||||
|
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
|
|||
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
|
||||
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
|
||||
frontsector->lightlist[light].extra_colormap, rover
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, *rover->t_slope
|
||||
#endif
|
||||
|
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
|
|||
polysec = po->lines[0]->backsector;
|
||||
ffloor[numffloors].plane = NULL;
|
||||
|
||||
if (polysec->floorheight <= frontsector->ceilingheight
|
||||
&& polysec->floorheight >= frontsector->floorheight
|
||||
if (polysec->floorheight <= ceilingcenterz
|
||||
&& polysec->floorheight >= floorcenterz
|
||||
&& (viewz < polysec->floorheight))
|
||||
{
|
||||
fixed_t xoff, yoff;
|
||||
|
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
|
|||
polysec->floorpic_angle-po->angle,
|
||||
NULL,
|
||||
NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, po
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, NULL // will ffloors be slopable eventually?
|
||||
#endif
|
||||
);
|
||||
//ffloor[numffloors].plane->polyobj = po;
|
||||
|
||||
ffloor[numffloors].height = polysec->floorheight;
|
||||
ffloor[numffloors].polyobj = po;
|
||||
|
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
|
|||
|
||||
ffloor[numffloors].plane = NULL;
|
||||
|
||||
if (polysec->ceilingheight >= frontsector->floorheight
|
||||
&& polysec->ceilingheight <= frontsector->ceilingheight
|
||||
if (polysec->ceilingheight >= floorcenterz
|
||||
&& polysec->ceilingheight <= ceilingcenterz
|
||||
&& (viewz > polysec->ceilingheight))
|
||||
{
|
||||
fixed_t xoff, yoff;
|
||||
|
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
|
|||
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
|
||||
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
|
||||
NULL, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, po
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, NULL // will ffloors be slopable eventually?
|
||||
#endif
|
||||
);
|
||||
//ffloor[numffloors].plane->polyobj = po;
|
||||
|
||||
ffloor[numffloors].polyobj = po;
|
||||
ffloor[numffloors].height = polysec->ceilingheight;
|
||||
|
|
138
src/r_data.c
138
src/r_data.c
|
@ -160,6 +160,7 @@ static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, INT32 orig
|
|||
if (position < 0)
|
||||
{
|
||||
count += position;
|
||||
source -= position; // start further down the column
|
||||
position = 0;
|
||||
}
|
||||
|
||||
|
@ -173,6 +174,44 @@ static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, INT32 orig
|
|||
}
|
||||
}
|
||||
|
||||
static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, INT32 originy, INT32 cacheheight, INT32 patchheight)
|
||||
{
|
||||
INT32 count, position;
|
||||
UINT8 *source, *dest;
|
||||
INT32 topdelta, prevdelta = -1;
|
||||
|
||||
while (patch->topdelta != 0xff)
|
||||
{
|
||||
topdelta = patch->topdelta;
|
||||
if (topdelta <= prevdelta)
|
||||
topdelta += prevdelta;
|
||||
prevdelta = topdelta;
|
||||
topdelta = patchheight-patch->length-topdelta;
|
||||
source = (UINT8 *)patch + 2 + patch->length; // patch + 3 + (patch->length-1)
|
||||
count = patch->length;
|
||||
position = originy + topdelta;
|
||||
|
||||
if (position < 0)
|
||||
{
|
||||
count += position;
|
||||
source += position; // start further UP the column
|
||||
position = 0;
|
||||
}
|
||||
|
||||
if (position + count > cacheheight)
|
||||
count = cacheheight - position;
|
||||
|
||||
dest = cache + position;
|
||||
if (count > 0)
|
||||
{
|
||||
for (; dest < cache + position + count; --source)
|
||||
*dest++ = *source;
|
||||
}
|
||||
|
||||
patch = (column_t *)((UINT8 *)patch + patch->length + 4);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// R_GenerateTexture
|
||||
//
|
||||
|
@ -191,7 +230,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
|
|||
texture_t *texture;
|
||||
texpatch_t *patch;
|
||||
patch_t *realpatch;
|
||||
int x, x1, x2, i;
|
||||
int x, x1, x2, i, width, height;
|
||||
size_t blocksize;
|
||||
column_t *patchcol;
|
||||
UINT32 *colofs;
|
||||
|
@ -239,6 +278,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
|
|||
if (holey)
|
||||
{
|
||||
texture->holes = true;
|
||||
texture->flip = patch->flip;
|
||||
blocksize = W_LumpLengthPwad(patch->wad, patch->lump);
|
||||
block = Z_Calloc(blocksize, PU_STATIC, // will change tag at end of this function
|
||||
&texturecache[texnum]);
|
||||
|
@ -249,6 +289,14 @@ static UINT8 *R_GenerateTexture(size_t texnum)
|
|||
colofs = (UINT32 *)(void *)(block + 8);
|
||||
texturecolumnofs[texnum] = colofs;
|
||||
blocktex = block;
|
||||
if (patch->flip & 1) // flip the patch horizontally
|
||||
{
|
||||
UINT32 *realcolofs = (UINT32 *)realpatch->columnofs;
|
||||
for (x = 0; x < texture->width; x++)
|
||||
colofs[x] = realcolofs[texture->width-1-x]; // swap with the offset of the other side of the texture
|
||||
}
|
||||
// we can't as easily flip the patch vertically sadly though,
|
||||
// we have wait until the texture itself is drawn to do that
|
||||
for (x = 0; x < texture->width; x++)
|
||||
colofs[x] = LONG(LONG(colofs[x]) + 3);
|
||||
goto done;
|
||||
|
@ -259,11 +307,12 @@ static UINT8 *R_GenerateTexture(size_t texnum)
|
|||
|
||||
// multi-patch textures (or 'composite')
|
||||
texture->holes = false;
|
||||
texture->flip = 0;
|
||||
blocksize = (texture->width * 4) + (texture->width * texture->height);
|
||||
texturememory += blocksize;
|
||||
block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]);
|
||||
|
||||
memset(block, 0xF7, blocksize+1); // Transparency hack
|
||||
memset(block, 0xFF, blocksize+1); // Transparency hack
|
||||
|
||||
// columns lookup table
|
||||
colofs = (UINT32 *)(void *)block;
|
||||
|
@ -277,7 +326,9 @@ static UINT8 *R_GenerateTexture(size_t texnum)
|
|||
{
|
||||
realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
|
||||
x1 = patch->originx;
|
||||
x2 = x1 + SHORT(realpatch->width);
|
||||
width = SHORT(realpatch->width);
|
||||
height = SHORT(realpatch->height);
|
||||
x2 = x1 + width;
|
||||
|
||||
if (x1 < 0)
|
||||
x = 0;
|
||||
|
@ -289,11 +340,17 @@ static UINT8 *R_GenerateTexture(size_t texnum)
|
|||
|
||||
for (; x < x2; x++)
|
||||
{
|
||||
patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1]));
|
||||
if (patch->flip & 1)
|
||||
patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[(x1+width-1)-x]));
|
||||
else
|
||||
patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1]));
|
||||
|
||||
// generate column ofset lookup
|
||||
colofs[x] = LONG((x * texture->height) + (texture->width*4));
|
||||
R_DrawColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height);
|
||||
if (patch->flip & 2)
|
||||
R_DrawFlippedColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height, height);
|
||||
else
|
||||
R_DrawColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,6 +360,32 @@ done:
|
|||
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
|
||||
//
|
||||
|
@ -469,6 +552,7 @@ void R_LoadTextures(void)
|
|||
texture->height = SHORT(patchlump->height)*patchcount;
|
||||
texture->patchcount = patchcount;
|
||||
texture->holes = false;
|
||||
texture->flip = 0;
|
||||
|
||||
// Allocate information for the texture's patches.
|
||||
for (k = 0; k < patchcount; k++)
|
||||
|
@ -479,6 +563,7 @@ void R_LoadTextures(void)
|
|||
patch->originy = (INT16)(k*patchlump->height);
|
||||
patch->wad = (UINT16)w;
|
||||
patch->lump = texstart + j;
|
||||
patch->flip = 0;
|
||||
}
|
||||
|
||||
Z_Unlock(patchlump);
|
||||
|
@ -502,6 +587,7 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
|
|||
char *patchName = NULL;
|
||||
INT16 patchXPos;
|
||||
INT16 patchYPos;
|
||||
UINT8 flip = 0;
|
||||
texpatch_t *resultPatch = NULL;
|
||||
lumpnum_t patchLumpNum;
|
||||
|
||||
|
@ -598,6 +684,47 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
|
|||
}
|
||||
Z_Free(texturesToken);
|
||||
|
||||
// Patch parameters block (OPTIONAL)
|
||||
// added by Monster Iestyn (22/10/16)
|
||||
|
||||
// Left Curly Brace
|
||||
texturesToken = M_GetToken(NULL);
|
||||
if (texturesToken == NULL)
|
||||
; // move on and ignore, R_ParseTextures will deal with this
|
||||
else
|
||||
{
|
||||
if (strcmp(texturesToken,"{")==0)
|
||||
{
|
||||
Z_Free(texturesToken);
|
||||
texturesToken = M_GetToken(NULL);
|
||||
if (texturesToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters should be",patchName);
|
||||
}
|
||||
while (strcmp(texturesToken,"}")!=0)
|
||||
{
|
||||
if (stricmp(texturesToken, "FLIPX")==0)
|
||||
flip |= 1;
|
||||
else if (stricmp(texturesToken, "FLIPY")==0)
|
||||
flip |= 2;
|
||||
Z_Free(texturesToken);
|
||||
|
||||
texturesToken = M_GetToken(NULL);
|
||||
if (texturesToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters or right curly brace should be",patchName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is not what we wanted...
|
||||
// undo last read so R_ParseTextures can re-get the token for its own purposes
|
||||
M_UnGetToken();
|
||||
}
|
||||
Z_Free(texturesToken);
|
||||
}
|
||||
|
||||
if (actuallyLoadPatch == true)
|
||||
{
|
||||
// Check lump exists
|
||||
|
@ -608,6 +735,7 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
|
|||
resultPatch->originy = patchYPos;
|
||||
resultPatch->lump = patchLumpNum & 65535;
|
||||
resultPatch->wad = patchLumpNum>>16;
|
||||
resultPatch->flip = flip;
|
||||
// Clean up a little after ourselves
|
||||
Z_Free(patchName);
|
||||
// Then return it
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef struct
|
|||
// Block origin (always UL), which has already accounted for the internal origin of the patch.
|
||||
INT16 originx, originy;
|
||||
UINT16 wad, lump;
|
||||
UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both
|
||||
} texpatch_t;
|
||||
|
||||
// A maptexturedef_t describes a rectangular texture,
|
||||
|
@ -42,6 +43,7 @@ typedef struct
|
|||
char name[8];
|
||||
INT16 width, height;
|
||||
boolean holes;
|
||||
UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both
|
||||
|
||||
// All the patches[patchcount] are drawn back to front into the cached texture.
|
||||
INT16 patchcount;
|
||||
|
@ -65,6 +67,9 @@ extern CV_PossibleValue_t Color_cons_t[];
|
|||
void R_LoadTextures(void);
|
||||
void R_FlushTextureCache(void);
|
||||
|
||||
INT32 R_GetTextureNum(INT32 texnum);
|
||||
void R_CheckTextureCache(INT32 tex);
|
||||
|
||||
// Retrieve column data for span blitting.
|
||||
UINT8 *R_GetColumn(fixed_t tex, INT32 col);
|
||||
|
||||
|
|
11
src/r_defs.h
11
src/r_defs.h
|
@ -203,6 +203,7 @@ typedef struct r_lightlist_s
|
|||
fixed_t heightstep;
|
||||
fixed_t botheight;
|
||||
fixed_t botheightstep;
|
||||
fixed_t startheight; // for repeating midtextures
|
||||
INT16 lightlevel;
|
||||
extracolormap_t *extra_colormap;
|
||||
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
|
||||
#ifdef ESLOPE
|
||||
typedef enum {
|
||||
|
@ -392,6 +384,7 @@ typedef struct sector_s
|
|||
#endif
|
||||
|
||||
// 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)
|
||||
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
|
||||
|
|
|
@ -162,6 +162,7 @@ void R_DrawSplat_8(void);
|
|||
void R_DrawTranslucentSplat_8(void);
|
||||
void R_DrawTranslucentSpan_8(void);
|
||||
void R_Draw2sMultiPatchColumn_8(void);
|
||||
void R_Draw2sMultiPatchTranslucentColumn_8(void);
|
||||
void R_DrawFogSpan_8(void);
|
||||
void R_DrawFogColumn_8(void);
|
||||
void R_DrawColumnShadowed_8(void);
|
||||
|
|
|
@ -203,6 +203,103 @@ void R_Draw2sMultiPatchColumn_8(void)
|
|||
}
|
||||
}
|
||||
|
||||
void R_Draw2sMultiPatchTranslucentColumn_8(void)
|
||||
{
|
||||
INT32 count;
|
||||
register UINT8 *dest;
|
||||
register fixed_t frac;
|
||||
fixed_t fracstep;
|
||||
|
||||
count = dc_yh - dc_yl;
|
||||
|
||||
if (count < 0) // Zero length, column does not exceed a pixel.
|
||||
return;
|
||||
|
||||
#ifdef RANGECHECK
|
||||
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Framebuffer destination address.
|
||||
// Use ylookup LUT to avoid multiply with ScreenWidth.
|
||||
// Use columnofs LUT for subwindows?
|
||||
|
||||
//dest = ylookup[dc_yl] + columnofs[dc_x];
|
||||
dest = &topleft[dc_yl*vid.width + dc_x];
|
||||
|
||||
count++;
|
||||
|
||||
// Determine scaling, which is the only mapping to be done.
|
||||
fracstep = dc_iscale;
|
||||
//frac = dc_texturemid + (dc_yl - centery)*fracstep;
|
||||
frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires);
|
||||
|
||||
// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
|
||||
// This is as fast as it gets.
|
||||
{
|
||||
register const UINT8 *source = dc_source;
|
||||
register const UINT8 *transmap = dc_transmap;
|
||||
register const lighttable_t *colormap = dc_colormap;
|
||||
register INT32 heightmask = dc_texheight-1;
|
||||
register UINT8 val;
|
||||
if (dc_texheight & heightmask) // not a power of 2 -- killough
|
||||
{
|
||||
heightmask++;
|
||||
heightmask <<= FRACBITS;
|
||||
|
||||
if (frac < 0)
|
||||
while ((frac += heightmask) < 0);
|
||||
else
|
||||
while (frac >= heightmask)
|
||||
frac -= heightmask;
|
||||
|
||||
do
|
||||
{
|
||||
// Re-map color indices from wall texture column
|
||||
// using a lighting/special effects LUT.
|
||||
// heightmask is the Tutti-Frutti fix
|
||||
val = source[frac>>FRACBITS];
|
||||
|
||||
if (val != TRANSPARENTPIXEL)
|
||||
*dest = colormap[*(transmap + (val<<8) + (*dest))];
|
||||
|
||||
dest += vid.width;
|
||||
|
||||
// Avoid overflow.
|
||||
if (fracstep > 0x7FFFFFFF - frac)
|
||||
frac += fracstep - heightmask;
|
||||
else
|
||||
frac += fracstep;
|
||||
|
||||
while (frac >= heightmask)
|
||||
frac -= heightmask;
|
||||
} while (--count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((count -= 2) >= 0) // texture height is a power of 2
|
||||
{
|
||||
val = source[(frac>>FRACBITS) & heightmask];
|
||||
if (val != TRANSPARENTPIXEL)
|
||||
*dest = colormap[*(transmap + (val<<8) + (*dest))];
|
||||
dest += vid.width;
|
||||
frac += fracstep;
|
||||
val = source[(frac>>FRACBITS) & heightmask];
|
||||
if (val != TRANSPARENTPIXEL)
|
||||
*dest = colormap[*(transmap + (val<<8) + (*dest))];
|
||||
dest += vid.width;
|
||||
frac += fracstep;
|
||||
}
|
||||
if (count & 1)
|
||||
{
|
||||
val = source[(frac>>FRACBITS) & heightmask];
|
||||
if (val != TRANSPARENTPIXEL)
|
||||
*dest = colormap[*(transmap + (val<<8) + (*dest))];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief The R_DrawShadeColumn_8 function
|
||||
Experiment to make software go faster. Taken from the Boom source
|
||||
*/
|
||||
|
|
65
src/r_main.c
65
src/r_main.c
|
@ -148,7 +148,6 @@ consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo,
|
|||
consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_soniccd = {"soniccd", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
@ -366,69 +365,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t 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
|
||||
// Returns the texture mapping scale for the current line (horizontal span)
|
||||
|
@ -1424,7 +1360,6 @@ void R_RegisterEngineStuff(void)
|
|||
{
|
||||
CV_RegisterVar(&cv_gravity);
|
||||
CV_RegisterVar(&cv_tailspickup);
|
||||
CV_RegisterVar(&cv_soniccd);
|
||||
CV_RegisterVar(&cv_allowmlook);
|
||||
CV_RegisterVar(&cv_homremoval);
|
||||
CV_RegisterVar(&cv_flipcam);
|
||||
|
|
12
src/r_main.h
12
src/r_main.h
|
@ -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_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);
|
||||
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
|
||||
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
|
||||
|
|
|
@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
|
|||
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 *pfloor
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, polyobj_t *polyobj
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, pslope_t *slope
|
||||
#endif
|
||||
|
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
|||
#ifdef POLYOBJECTS_PLANES
|
||||
if (check->polyobj && pfloor)
|
||||
continue;
|
||||
if (polyobj != check->polyobj)
|
||||
continue;
|
||||
#endif
|
||||
if (height == check->height && picnum == check->picnum
|
||||
&& lightlevel == check->lightlevel
|
||||
|
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
|||
check->viewangle = viewangle;
|
||||
check->plangle = plangle;
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
check->polyobj = NULL;
|
||||
check->polyobj = polyobj;
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
check->slope = slope;
|
||||
|
@ -720,7 +725,11 @@ void R_DrawPlanes(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (pl->ffloor != NULL)
|
||||
if (pl->ffloor != NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
|| pl->polyobj != NULL
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
R_DrawSinglePlane(pl);
|
||||
|
|
|
@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
|
|||
void R_DrawPlanes(void);
|
||||
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
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, polyobj_t *polyobj
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, pslope_t *slope
|
||||
#endif
|
||||
|
|
160
src/r_segs.c
160
src/r_segs.c
|
@ -271,11 +271,20 @@ static void R_Render2sidedMultiPatchColumn(column_t *column)
|
|||
|
||||
if (colfunc == wallcolfunc)
|
||||
twosmultipatchfunc();
|
||||
else if (colfunc == fuzzcolfunc)
|
||||
twosmultipatchtransfunc();
|
||||
else
|
||||
colfunc();
|
||||
}
|
||||
}
|
||||
|
||||
// quick wrapper for R_DrawFlippedMaskedColumn so it can be set as a colfunc_2s value
|
||||
// uses column2s_length for texture->height as above
|
||||
static void R_DrawFlippedMaskedSegColumn(column_t *column)
|
||||
{
|
||||
R_DrawFlippedMaskedColumn(column, column2s_length);
|
||||
}
|
||||
|
||||
void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
||||
{
|
||||
size_t pindex;
|
||||
|
@ -300,7 +309,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
curline = ds->curline;
|
||||
frontsector = curline->frontsector;
|
||||
backsector = curline->backsector;
|
||||
texnum = texturetranslation[curline->sidedef->midtexture];
|
||||
texnum = R_GetTextureNum(curline->sidedef->midtexture);
|
||||
windowbottom = windowtop = sprbotscreen = INT32_MAX;
|
||||
|
||||
// hack translucent linedef types (900-909 for transtables 1-9)
|
||||
|
@ -344,10 +353,21 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
rw_scalestep = ds->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
|
||||
// are not stored per-column with post info in SRB2
|
||||
if (textures[texnum]->holes)
|
||||
colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
|
||||
{
|
||||
if (textures[texnum]->flip & 2) // vertically flipped?
|
||||
{
|
||||
colfunc_2s = R_DrawFlippedMaskedSegColumn;
|
||||
column2s_length = textures[texnum]->height;
|
||||
}
|
||||
else
|
||||
colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
|
||||
}
|
||||
else
|
||||
{
|
||||
colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info)
|
||||
|
@ -391,6 +411,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
|
||||
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
|
||||
#endif
|
||||
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
|
||||
rlight->lightlevel = *light->lightlevel;
|
||||
rlight->extra_colormap = light->extra_colormap;
|
||||
rlight->flags = light->flags;
|
||||
|
@ -484,6 +505,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
{
|
||||
rw_scalestep = ds->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
|
||||
|
@ -700,6 +729,14 @@ static void R_DrawRepeatMaskedColumn(column_t *col)
|
|||
} while (sprtopscreen < sprbotscreen);
|
||||
}
|
||||
|
||||
static void R_DrawRepeatFlippedMaskedColumn(column_t *col)
|
||||
{
|
||||
do {
|
||||
R_DrawFlippedMaskedColumn(col, column2s_length);
|
||||
sprtopscreen += dc_texheight*spryscale;
|
||||
} while (sprtopscreen < sprbotscreen);
|
||||
}
|
||||
|
||||
//
|
||||
// R_RenderThickSideRange
|
||||
// Renders all the thick sides in the given range.
|
||||
|
@ -746,7 +783,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
curline = ds->curline;
|
||||
backsector = pfloor->target;
|
||||
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;
|
||||
|
||||
|
@ -754,7 +791,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
{
|
||||
size_t linenum = curline->linedef-backsector->lines[0];
|
||||
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)
|
||||
|
@ -1024,10 +1061,21 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
|
||||
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
|
||||
// are not stored per-column with post info anymore in Doom Legacy
|
||||
if (textures[texnum]->holes)
|
||||
colfunc_2s = R_DrawRepeatMaskedColumn; //render the usual 2sided single-patch packed texture
|
||||
{
|
||||
if (textures[texnum]->flip & 2) // vertically flipped?
|
||||
{
|
||||
colfunc_2s = R_DrawRepeatFlippedMaskedColumn;
|
||||
column2s_length = textures[texnum]->height;
|
||||
}
|
||||
else
|
||||
colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture
|
||||
}
|
||||
else
|
||||
{
|
||||
colfunc_2s = R_Render2sidedMultiPatchColumn; //render multipatch with no holes (no post_t info)
|
||||
|
@ -1936,14 +1984,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
|
||||
if (!backsector)
|
||||
{
|
||||
fixed_t texheight;
|
||||
// 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
|
||||
markfloor = markceiling = true;
|
||||
#ifdef ESLOPE
|
||||
if (linedef->flags & ML_EFFECT2) {
|
||||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
|
||||
rw_midtexturemid = frontsector->floorheight + texheight - viewz;
|
||||
else
|
||||
rw_midtexturemid = frontsector->ceilingheight - viewz;
|
||||
}
|
||||
|
@ -1952,10 +2002,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
|
||||
rw_midtexturemid = worldbottom + texheight;
|
||||
rw_midtextureslide = floorfrontslide;
|
||||
#else
|
||||
vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
|
||||
vtop = frontsector->floorheight + texheight;
|
||||
// bottom of texture at bottom
|
||||
rw_midtexturemid = vtop - viewz;
|
||||
#endif
|
||||
|
@ -2187,76 +2237,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
#endif
|
||||
)
|
||||
{
|
||||
fixed_t texheight;
|
||||
// top texture
|
||||
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
|
||||
&& linedef->sidenum[1] != 0xffff)
|
||||
{
|
||||
// Special case... use offsets from 2nd side but only if it has a texture.
|
||||
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.
|
||||
toptexture = texturetranslation[sidedef->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
|
||||
}
|
||||
toptexture = R_GetTextureNum(sidedef->toptexture);
|
||||
texheight = textureheight[toptexture];
|
||||
}
|
||||
else
|
||||
{
|
||||
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_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||
if (linedef->flags & ML_DONTPEGTOP)
|
||||
{
|
||||
// top of texture at top
|
||||
rw_toptexturemid = worldtop;
|
||||
#ifdef ESLOPE
|
||||
rw_toptextureslide = ceilingfrontslide;
|
||||
#endif
|
||||
}
|
||||
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
||||
else
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
|
||||
rw_toptextureslide = ceilingbackslide;
|
||||
#else
|
||||
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
|
||||
// bottom of texture
|
||||
rw_toptexturemid = vtop - viewz;
|
||||
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 + texheight;
|
||||
rw_toptextureslide = ceilingbackslide;
|
||||
#else
|
||||
vtop = backsector->ceilingheight + texheight;
|
||||
// bottom of texture
|
||||
rw_toptexturemid = vtop - viewz;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
// check BOTTOM TEXTURE
|
||||
|
@ -2267,7 +2291,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
) //seulement si VISIBLE!!!
|
||||
{
|
||||
// bottom texture
|
||||
bottomtexture = texturetranslation[sidedef->bottomtexture];
|
||||
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||
|
@ -2552,7 +2576,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
|
||||
ds_p->numthicksides = numthicksides = i;
|
||||
}
|
||||
if (sidedef->midtexture)
|
||||
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
|
||||
{
|
||||
// masked midtexture
|
||||
if (!ds_p->thicksidecol)
|
||||
|
@ -3164,12 +3188,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
if (maskedtexture && !(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))
|
||||
{
|
||||
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++;
|
||||
}
|
||||
|
|
|
@ -712,7 +712,7 @@ void R_DrawMaskedColumn(column_t *column)
|
|||
dc_texturemid = basetexturemid;
|
||||
}
|
||||
|
||||
static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
|
||||
void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
|
||||
{
|
||||
INT32 topscreen;
|
||||
INT32 bottomscreen;
|
||||
|
@ -1349,7 +1349,7 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
if (sortscale < linkscale)
|
||||
dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0)
|
||||
|
||||
sortscale = linkscale; // now make sure it's linked
|
||||
sortscale = linkscale; // now make sure it's linked
|
||||
}
|
||||
|
||||
// PORTAL SPRITE CLIPPING
|
||||
|
@ -1885,21 +1885,25 @@ static void R_CreateDrawNodes(void)
|
|||
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)
|
||||
{
|
||||
#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->seg = ds;
|
||||
}
|
||||
|
@ -1942,6 +1946,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)
|
||||
return;
|
||||
|
||||
|
@ -1998,13 +2025,16 @@ static void R_CreateDrawNodes(void)
|
|||
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
|
||||
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)
|
||||
break;
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
if (r2->seg->frontscale[i] > rover->sortscale)
|
||||
break;
|
||||
}
|
||||
if (i > x2)
|
||||
continue;
|
||||
}
|
||||
if (i > x2)
|
||||
continue;
|
||||
|
||||
entry = R_CreateDrawNode(NULL);
|
||||
(entry->prev = r2->prev)->next = entry;
|
||||
|
@ -2880,6 +2910,7 @@ void R_AddSkins(UINT16 wadnum)
|
|||
GETFLAG(STOMPDAMAGE)
|
||||
GETFLAG(MARIODAMAGE)
|
||||
GETFLAG(MACHINE)
|
||||
GETFLAG(NOSPINDASHDUST)
|
||||
#undef GETFLAG
|
||||
|
||||
else // let's check if it's a sound, otherwise error out
|
||||
|
|
|
@ -46,6 +46,7 @@ extern fixed_t windowtop;
|
|||
extern fixed_t windowbottom;
|
||||
|
||||
void R_DrawMaskedColumn(column_t *column);
|
||||
void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight);
|
||||
void R_SortVisSprites(void);
|
||||
|
||||
//faB: find sprites in wadfile, replace existing, add new ones
|
||||
|
|
|
@ -607,6 +607,13 @@ void S_StartSound(const void *origin, sfxenum_t sfx_id)
|
|||
sfx_id = sfx_mario6;
|
||||
break;
|
||||
case sfx_shield:
|
||||
case sfx_wirlsg:
|
||||
case sfx_forcsg:
|
||||
case sfx_elemsg:
|
||||
case sfx_armasg:
|
||||
case sfx_s3k3e:
|
||||
case sfx_s3k3f:
|
||||
case sfx_s3k41:
|
||||
sfx_id = sfx_mario3;
|
||||
break;
|
||||
case sfx_itemup:
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#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
|
||||
#endif
|
||||
|
||||
|
@ -49,6 +49,7 @@ void (*splatfunc)(void); // span drawer w/ transparency
|
|||
void (*basespanfunc)(void); // default span func for color mode
|
||||
void (*transtransfunc)(void); // translucent translated column drawer
|
||||
void (*twosmultipatchfunc)(void); // for cols with transparent pixels
|
||||
void (*twosmultipatchtransfunc)(void); // for cols with transparent pixels AND translucency
|
||||
|
||||
// ------------------
|
||||
// global video state
|
||||
|
@ -127,6 +128,7 @@ void SCR_SetMode(void)
|
|||
fuzzcolfunc = R_DrawTranslucentColumn_8;
|
||||
walldrawerfunc = R_DrawWallColumn_8;
|
||||
twosmultipatchfunc = R_Draw2sMultiPatchColumn_8;
|
||||
twosmultipatchtransfunc = R_Draw2sMultiPatchTranslucentColumn_8;
|
||||
#ifdef RUSEASM
|
||||
if (R_ASM)
|
||||
{
|
||||
|
|
|
@ -136,6 +136,7 @@ extern void (*basespanfunc)(void);
|
|||
extern void (*splatfunc)(void);
|
||||
extern void (*transtransfunc)(void);
|
||||
extern void (*twosmultipatchfunc)(void);
|
||||
extern void (*twosmultipatchtransfunc)(void);
|
||||
|
||||
// -----
|
||||
// CPUID
|
||||
|
|
|
@ -295,6 +295,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="..\i_tcp.c" />
|
||||
<ClCompile Include="..\lua_baselib.c" />
|
||||
<ClCompile Include="..\lua_blockmaplib.c" />
|
||||
<ClCompile Include="..\lua_consolelib.c" />
|
||||
<ClCompile Include="..\lua_hooklib.c" />
|
||||
<ClCompile Include="..\lua_hudlib.c" />
|
||||
|
|
|
@ -633,6 +633,9 @@
|
|||
<ClCompile Include="..\lua_baselib.c">
|
||||
<Filter>LUA</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lua_blockmaplib.c">
|
||||
<Filter>LUA</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lua_consolelib.c">
|
||||
<Filter>LUA</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -2647,6 +2647,47 @@ INT32 I_PutEnv(char *variable)
|
|||
#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
|
||||
|
||||
\param path string path to check
|
||||
|
|
|
@ -33,14 +33,6 @@
|
|||
#pragma warning(default : 4214 4244)
|
||||
#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
|
||||
#include "i_ttf.h"
|
||||
#endif
|
||||
|
@ -189,14 +181,14 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
|
|||
wasfullscreen = SDL_TRUE;
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
}
|
||||
else if (!fullscreen && wasfullscreen)
|
||||
else if (wasfullscreen)
|
||||
{
|
||||
wasfullscreen = SDL_FALSE;
|
||||
SDL_SetWindowFullscreen(window, 0);
|
||||
SDL_SetWindowSize(window, width, height);
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
|
||||
}
|
||||
else if (!wasfullscreen)
|
||||
else
|
||||
{
|
||||
// Reposition window only in windowed mode
|
||||
SDL_SetWindowSize(window, width, height);
|
||||
|
@ -282,129 +274,70 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
|
|||
}
|
||||
switch (code)
|
||||
{
|
||||
case SDL_SCANCODE_F11: // F11 and F12 are
|
||||
return KEY_F11; // separated from the
|
||||
case SDL_SCANCODE_F12: // rest of the function
|
||||
return KEY_F12; // keys
|
||||
// F11 and F12 are separated from the rest of the function keys
|
||||
case SDL_SCANCODE_F11: return KEY_F11;
|
||||
case SDL_SCANCODE_F12: return KEY_F12;
|
||||
|
||||
case SDL_SCANCODE_KP_0:
|
||||
return KEY_KEYPAD0;
|
||||
case SDL_SCANCODE_KP_1:
|
||||
return KEY_KEYPAD1;
|
||||
case SDL_SCANCODE_KP_2:
|
||||
return KEY_KEYPAD2;
|
||||
case SDL_SCANCODE_KP_3:
|
||||
return KEY_KEYPAD3;
|
||||
case SDL_SCANCODE_KP_4:
|
||||
return KEY_KEYPAD4;
|
||||
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_KP_0: return KEY_KEYPAD0;
|
||||
case SDL_SCANCODE_KP_1: return KEY_KEYPAD1;
|
||||
case SDL_SCANCODE_KP_2: return KEY_KEYPAD2;
|
||||
case SDL_SCANCODE_KP_3: return KEY_KEYPAD3;
|
||||
case SDL_SCANCODE_KP_4: return KEY_KEYPAD4;
|
||||
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:
|
||||
return KEY_ENTER;
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
return KEY_ESCAPE;
|
||||
case SDL_SCANCODE_BACKSPACE:
|
||||
return KEY_BACKSPACE;
|
||||
case SDL_SCANCODE_TAB:
|
||||
return KEY_TAB;
|
||||
case SDL_SCANCODE_SPACE:
|
||||
return KEY_SPACE;
|
||||
case SDL_SCANCODE_MINUS:
|
||||
return KEY_MINUS;
|
||||
case SDL_SCANCODE_EQUALS:
|
||||
return KEY_EQUALS;
|
||||
case SDL_SCANCODE_LEFTBRACKET:
|
||||
return '[';
|
||||
case SDL_SCANCODE_RIGHTBRACKET:
|
||||
return ']';
|
||||
case SDL_SCANCODE_BACKSLASH:
|
||||
return '\\';
|
||||
case SDL_SCANCODE_NONUSHASH:
|
||||
return '#';
|
||||
case SDL_SCANCODE_SEMICOLON:
|
||||
return ';';
|
||||
case SDL_SCANCODE_APOSTROPHE:
|
||||
return '\'';
|
||||
case SDL_SCANCODE_GRAVE:
|
||||
return '`';
|
||||
case SDL_SCANCODE_COMMA:
|
||||
return ',';
|
||||
case SDL_SCANCODE_PERIOD:
|
||||
return '.';
|
||||
case SDL_SCANCODE_SLASH:
|
||||
return '/';
|
||||
case SDL_SCANCODE_CAPSLOCK:
|
||||
return KEY_CAPSLOCK;
|
||||
case SDL_SCANCODE_PRINTSCREEN:
|
||||
return 0; // undefined?
|
||||
case SDL_SCANCODE_SCROLLLOCK:
|
||||
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_RETURN: return KEY_ENTER;
|
||||
case SDL_SCANCODE_ESCAPE: return KEY_ESCAPE;
|
||||
case SDL_SCANCODE_BACKSPACE: return KEY_BACKSPACE;
|
||||
case SDL_SCANCODE_TAB: return KEY_TAB;
|
||||
case SDL_SCANCODE_SPACE: return KEY_SPACE;
|
||||
case SDL_SCANCODE_MINUS: return KEY_MINUS;
|
||||
case SDL_SCANCODE_EQUALS: return KEY_EQUALS;
|
||||
case SDL_SCANCODE_LEFTBRACKET: return '[';
|
||||
case SDL_SCANCODE_RIGHTBRACKET: return ']';
|
||||
case SDL_SCANCODE_BACKSLASH: return '\\';
|
||||
case SDL_SCANCODE_NONUSHASH: return '#';
|
||||
case SDL_SCANCODE_SEMICOLON: return ';';
|
||||
case SDL_SCANCODE_APOSTROPHE: return '\'';
|
||||
case SDL_SCANCODE_GRAVE: return '`';
|
||||
case SDL_SCANCODE_COMMA: return ',';
|
||||
case SDL_SCANCODE_PERIOD: return '.';
|
||||
case SDL_SCANCODE_SLASH: return '/';
|
||||
case SDL_SCANCODE_CAPSLOCK: return KEY_CAPSLOCK;
|
||||
case SDL_SCANCODE_PRINTSCREEN: return 0; // undefined?
|
||||
case SDL_SCANCODE_SCROLLLOCK: 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:
|
||||
return KEY_LSHIFT;
|
||||
case SDL_SCANCODE_RSHIFT:
|
||||
return KEY_RSHIFT;
|
||||
case SDL_SCANCODE_LCTRL:
|
||||
return KEY_LCTRL;
|
||||
case SDL_SCANCODE_RCTRL:
|
||||
return KEY_RCTRL;
|
||||
case SDL_SCANCODE_LALT:
|
||||
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;
|
||||
case SDL_SCANCODE_LSHIFT: return KEY_LSHIFT;
|
||||
case SDL_SCANCODE_RSHIFT: return KEY_RSHIFT;
|
||||
case SDL_SCANCODE_LCTRL: return KEY_LCTRL;
|
||||
case SDL_SCANCODE_RCTRL: return KEY_RCTRL;
|
||||
case SDL_SCANCODE_LALT: 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
|
||||
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());
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
#if 1
|
||||
(void)infoSurface;
|
||||
(void)SurfaceText;
|
||||
SDL2STUB();
|
||||
#else
|
||||
INT32 vfBPP;
|
||||
const SDL_Surface *VidSur = SDL_GetVideoSurface();
|
||||
|
||||
if (!infoSurface)
|
||||
return;
|
||||
|
@ -453,49 +381,12 @@ static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
|
|||
CONS_Printf("\x82" "%s\n", SurfaceText);
|
||||
CONS_Printf(M_GetText(" %ix%i at %i bit color\n"), infoSurface->w, infoSurface->h, vfBPP);
|
||||
|
||||
if (infoSurface->flags&SDL_HWSURFACE)
|
||||
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)
|
||||
if (infoSurface->flags&SDL_PREALLOC)
|
||||
CONS_Printf("%s", M_GetText(" Uses preallocated memory\n"));
|
||||
else
|
||||
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)
|
||||
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)
|
||||
|
@ -579,23 +470,6 @@ static void VID_Command_Mode_f (void)
|
|||
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)
|
||||
{
|
||||
(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.
|
||||
// This is because wheel messages don't have an up/down state.
|
||||
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)
|
||||
|
@ -1494,11 +1156,6 @@ void VID_PrepareModeList(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void SDLESSet(void)
|
||||
{
|
||||
SDL2STUB();
|
||||
}
|
||||
|
||||
INT32 VID_SetMode(INT32 modeNum)
|
||||
{
|
||||
SDLdoUngrabMouse();
|
||||
|
@ -1550,6 +1207,12 @@ INT32 VID_SetMode(INT32 modeNum)
|
|||
static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
|
@ -1568,38 +1231,43 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
|
|||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
{
|
||||
window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
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;
|
||||
flags |= SDL_WINDOW_OPENGL;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
realwidth, realheight, flags);
|
||||
if (window != NULL)
|
||||
renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0));
|
||||
if (renderer == NULL)
|
||||
{
|
||||
renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0));
|
||||
if (renderer != NULL)
|
||||
{
|
||||
SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
|
||||
}
|
||||
else return SDL_FALSE;
|
||||
CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError());
|
||||
return SDL_FALSE;
|
||||
}
|
||||
else return SDL_FALSE;
|
||||
SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
|
@ -1620,7 +1288,7 @@ static void Impl_SetWindowIcon(void)
|
|||
{
|
||||
return;
|
||||
}
|
||||
SDL2STUB();
|
||||
//SDL2STUB(); // Monster Iestyn: why is this stubbed?
|
||||
SDL_SetWindowIcon(window, icoSurface);
|
||||
}
|
||||
|
||||
|
@ -1718,7 +1386,6 @@ void I_StartupGraphics(void)
|
|||
borderlesswindow = M_CheckParm("-borderless");
|
||||
|
||||
//SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2);
|
||||
SDLESSet();
|
||||
VID_Command_ModeList_f();
|
||||
#ifdef HWRENDER
|
||||
if (M_CheckParm("-opengl") || rendermode == render_opengl)
|
||||
|
|
|
@ -1214,7 +1214,7 @@
|
|||
C01FCF4B08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
||||
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
NORMALSRB2,
|
||||
|
@ -1226,7 +1226,7 @@
|
|||
C01FCF4C08A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
||||
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
|
|
@ -220,7 +220,7 @@ static Mix_Chunk *ds2chunk(void *stream)
|
|||
break;
|
||||
default: // convert arbitrary hz to 44100.
|
||||
step = 0;
|
||||
frac = ((UINT32)freq << FRACBITS) / 44100;
|
||||
frac = ((UINT32)freq << FRACBITS) / 44100 + 1; //Add 1 to counter truncation.
|
||||
while (i < samples)
|
||||
{
|
||||
o = (INT16)(*s+0x80)<<8; // changed signedness and shift up to 16 bits
|
||||
|
|
|
@ -24,7 +24,6 @@ boolean OglSdlSurface(INT32 w, INT32 h);
|
|||
|
||||
void OglSdlFinishUpdate(boolean vidwait);
|
||||
|
||||
extern SDL_Window *window;
|
||||
extern SDL_Renderer *renderer;
|
||||
extern SDL_GLContext sdlglcontext;
|
||||
extern Uint16 realwidth;
|
||||
|
|
|
@ -71,4 +71,7 @@ void I_GetConsoleEvents(void);
|
|||
|
||||
void SDLforceUngrabMouse(void);
|
||||
|
||||
// Needed for some WIN32 functions
|
||||
extern SDL_Window *window;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2666,6 +2666,18 @@ INT32 I_PutEnv(char *variable)
|
|||
#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
|
||||
|
||||
\param path string path to check
|
||||
|
|
|
@ -1214,7 +1214,7 @@
|
|||
C01FCF4B08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
||||
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
NORMALSRB2,
|
||||
|
@ -1226,7 +1226,7 @@
|
|||
C01FCF4C08A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
||||
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
|
|
@ -165,8 +165,12 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"rail1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"rail2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"rlaunc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"shield", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"shldls", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"shield", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // generic GET!
|
||||
{"wirlsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Whirlwind GET!
|
||||
{"forcsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Force GET!
|
||||
{"elemsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Elemental GET!
|
||||
{"armasg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Armaggeddon GET!
|
||||
{"shldls", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // You LOSE!
|
||||
{"spdpad", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"spkdth", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"spring", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
|
@ -183,6 +187,7 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"wdjump", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
{"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
|
||||
// Menu, interface
|
||||
{"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR},
|
||||
|
|
|
@ -229,6 +229,10 @@ typedef enum
|
|||
sfx_rail2,
|
||||
sfx_rlaunc,
|
||||
sfx_shield,
|
||||
sfx_wirlsg,
|
||||
sfx_forcsg,
|
||||
sfx_elemsg,
|
||||
sfx_armasg,
|
||||
sfx_shldls,
|
||||
sfx_spdpad,
|
||||
sfx_spkdth,
|
||||
|
@ -246,6 +250,7 @@ typedef enum
|
|||
sfx_wdjump,
|
||||
sfx_mswarp,
|
||||
sfx_mspogo,
|
||||
sfx_boingf,
|
||||
|
||||
// Menu, interface
|
||||
sfx_chchng,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue