Merge branch 'master' into appveyor

This commit is contained in:
Alam Ed Arias 2017-01-06 20:27:11 -05:00
commit 5514cca497
43 changed files with 2630 additions and 1941 deletions

3
debian/docs vendored
View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -31,15 +31,15 @@
// //
// NETWORKING // NETWORKING
// //
// gametic is the tic about to be (or currently being) run // gametic is the tic about to (or currently being) run
// server: // Server:
// maketic is the tic that hasn't had control made for it yet // maketic is the tic that hasn't had control made for it yet
// nettics: is the tic for each node // nettics is the tic for each node
// firsttictosend: is the lowest value of nettics // firstticstosend is the lowest value of nettics
// client: // Client:
// neededtic: is the tic needed by the client to run the game // neededtic is the tic needed by the client to run the game
// firsttictosend: is used to optimize a condition // firstticstosend is used to optimize a condition
// normally maketic >= gametic > 0 // Normally maketic >= gametic > 0
#define FORCECLOSE 0x8000 #define FORCECLOSE 0x8000
tic_t connectiontimeout = (15*TICRATE); tic_t connectiontimeout = (15*TICRATE);
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// Some structs and functions for acknowledgement of packets // Some structs and functions for acknowledgement of packets
// ----------------------------------------------------------------- // -----------------------------------------------------------------
#define MAXACKPACKETS 96 // minimum number of nodes #define MAXACKPACKETS 96 // Minimum number of nodes (wat)
#define MAXACKTOSEND 96 #define MAXACKTOSEND 96
#define URGENTFREESLOTENUM 10 #define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11) #define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET #ifndef NONET
@ -139,10 +139,10 @@ typedef struct
{ {
UINT8 acknum; UINT8 acknum;
UINT8 nextacknum; UINT8 nextacknum;
UINT8 destinationnode; UINT8 destinationnode; // The node to send the ack to
tic_t senttime; tic_t senttime; // The time when the ack was sent
UINT16 length; UINT16 length; // The packet size
UINT16 resentnum; UINT16 resentnum; // The number of
union { union {
SINT8 raw[MAXPACKETLENGTH]; SINT8 raw[MAXPACKETLENGTH];
doomdata_t data; doomdata_t data;
@ -212,11 +212,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
return d; return d;
} }
// return a free acknum and copy netbuffer in the ackpak table /** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
*
* \param freeack The address to store the free acknum at
* \param lowtimer ???
* \return True if a free acknum was found
*/
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{ {
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
INT32 i, numfreeslote = 0; INT32 i, numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{ {
@ -227,10 +232,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
for (i = 0; i < MAXACKPACKETS; i++) for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum) if (!ackpak[i].acknum)
{ {
// for low priority packet, make sure let freeslotes so urgents packets can be sent // For low priority packets, make sure to let freeslots so urgent packets can be sent
numfreeslote++; if (netbuffer->packettype >= PT_CANFAIL)
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM) {
continue; numfreeslot++;
if (numfreeslot <= URGENTFREESLOTNUM)
continue;
}
ackpak[i].acknum = node->nextacknum; ackpak[i].acknum = node->nextacknum;
ackpak[i].nextacknum = node->nextacknum; ackpak[i].nextacknum = node->nextacknum;
@ -241,7 +249,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
ackpak[i].length = doomcom->datalength; ackpak[i].length = doomcom->datalength;
if (lowtimer) if (lowtimer)
{ {
// lowtime mean can't be sent now so try it soon as possible // Lowtime means can't be sent now so try it as soon as possible
ackpak[i].senttime = 0; ackpak[i].senttime = 0;
ackpak[i].resentnum = 1; ackpak[i].resentnum = 1;
} }
@ -254,7 +262,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
*freeack = ackpak[i].acknum; *freeack = ackpak[i].acknum;
sendackpacket++; // for stat sendackpacket++; // For stat
return true; return true;
} }
@ -266,14 +274,14 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false; return false;
} }
// Get a ack to send in the queu of this node // Get a ack to send in the queue of this node
static UINT8 GetAcktosend(INT32 node) static UINT8 GetAcktosend(INT32 node)
{ {
nodes[node].lasttimeacktosend_sent = I_GetTime(); nodes[node].lasttimeacktosend_sent = I_GetTime();
return nodes[node].firstacktosend; return nodes[node].firstacktosend;
} }
static void Removeack(INT32 i) static void RemoveAck(INT32 i)
{ {
INT32 node = ackpak[i].destinationnode; INT32 node = ackpak[i].destinationnode;
#ifndef NEWPING #ifndef NEWPING
@ -294,27 +302,27 @@ static void Removeack(INT32 i)
Net_CloseConnection(node); Net_CloseConnection(node);
} }
// we have got a packet proceed the ack request and ack return // We have got a packet, proceed the ack request and ack return
static boolean Processackpak(void) static boolean Processackpak(void)
{ {
INT32 i; INT32 i;
boolean goodpacket = true; boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
// received an ack return, so remove the ack in the list // Received an ack return, so remove the ack in the list
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0) if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
{ {
node->remotefirstack = netbuffer->ackreturn; node->remotefirstack = netbuffer->ackreturn;
// search the ackbuffer and free it // Search the ackbuffer and free it
for (i = 0; i < MAXACKPACKETS; i++) for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{ {
Removeack(i); RemoveAck(i);
} }
} }
// received a packet with ack, queue it to send the ack back // Received a packet with ack, queue it to send the ack back
if (netbuffer->ack) if (netbuffer->ack)
{ {
UINT8 ack = netbuffer->ack; UINT8 ack = netbuffer->ack;
@ -323,23 +331,23 @@ static boolean Processackpak(void)
{ {
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack)); DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
duppacket++; duppacket++;
goodpacket = false; // discard packet (duplicate) goodpacket = false; // Discard packet (duplicate)
} }
else else
{ {
// check if it is not already in the queue // Check if it is not already in the queue
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
if (node->acktosend[i] == ack) if (node->acktosend[i] == ack)
{ {
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
duppacket++; duppacket++;
goodpacket = false; // discard packet (duplicate) goodpacket = false; // Discard packet (duplicate)
break; break;
} }
if (goodpacket) if (goodpacket)
{ {
// is a good packet so increment the acknowledge number, // Is a good packet so increment the acknowledge number,
// then search for a "hole" in the queue // Then search for a "hole" in the queue
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1); UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
if (!nextfirstack) if (!nextfirstack)
nextfirstack = 1; nextfirstack = 1;
@ -383,10 +391,10 @@ static boolean Processackpak(void)
} }
} }
} }
else // out of order packet else // Out of order packet
{ {
// don't increment firsacktosend, put it in asktosend queue // Don't increment firsacktosend, put it in asktosend queue
// will be incremented when the nextfirstack comes (code above) // Will be incremented when the nextfirstack comes (code above)
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND); UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack)); DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
if (newhead != node->acktosend_tail) if (newhead != node->acktosend_tail)
@ -394,8 +402,8 @@ static boolean Processackpak(void)
node->acktosend[node->acktosend_head] = ack; node->acktosend[node->acktosend_head] = ack;
node->acktosend_head = newhead; node->acktosend_head = newhead;
} }
else // buffer full discard packet, sender will resend it else // Buffer full discard packet, sender will resend it
{ // we can admit the packet but we will not detect the duplication after :( { // We can admit the packet but we will not detect the duplication after :(
DEBFILE("no more freeackret\n"); DEBFILE("no more freeackret\n");
goodpacket = false; goodpacket = false;
} }
@ -430,25 +438,24 @@ static void GotAcks(void)
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
{ {
if (ackpak[i].acknum == netbuffer->u.textcmd[j]) if (ackpak[i].acknum == netbuffer->u.textcmd[j])
Removeack(i); RemoveAck(i);
else // nextacknum is first equal to acknum, then when receiving bigger ack
// nextacknum is first equal to acknum, then when receiving bigger ack // there is big chance the packet is lost
// there is big chance the packet is lost // When resent, nextacknum = nodes[node].nextacknum
// when resent, nextacknum = nodes[node].nextacknum // will redo the same but with different value
// will redo the same but with different value else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0 && ackpak[i].senttime > 0)
&& ackpak[i].senttime > 0) {
{ ackpak[i].senttime--; // hurry up
ackpak[i].senttime--; // hurry up }
}
} }
} }
#endif #endif
static inline void Net_ConnectionTimeout(INT32 node) static inline void Net_ConnectionTimeout(INT32 node)
{ {
// send a very special packet to self (hack the reboundstore queue) // Send a very special packet to self (hack the reboundstore queue)
// main code will handle it // Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT; reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
reboundstore[rebound_head].ack = 0; reboundstore[rebound_head].ack = 0;
reboundstore[rebound_head].ackreturn = 0; reboundstore[rebound_head].ackreturn = 0;
@ -456,12 +463,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1); reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
rebound_head = (rebound_head+1) % MAXREBOUND; rebound_head = (rebound_head+1) % MAXREBOUND;
// do not redo it quickly (if we do not close connection it is // Do not redo it quickly (if we do not close connection it is
// for a good reason!) // for a good reason!)
nodes[node].lasttimepacketreceived = I_GetTime(); nodes[node].lasttimepacketreceived = I_GetTime();
} }
// resend the data if needed // Resend the data if needed
void Net_AckTicker(void) void Net_AckTicker(void)
{ {
#ifndef NONET #ifndef NONET
@ -497,7 +504,7 @@ void Net_AckTicker(void)
ackpak[i].senttime = I_GetTime(); ackpak[i].senttime = I_GetTime();
ackpak[i].resentnum++; ackpak[i].resentnum++;
ackpak[i].nextacknum = node->nextacknum; ackpak[i].nextacknum = node->nextacknum;
retransmit++; // for stat retransmit++; // For stat
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum, HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
(size_t)(ackpak[i].length - BASEPACKETSIZE)); (size_t)(ackpak[i].length - BASEPACKETSIZE));
} }
@ -505,11 +512,11 @@ void Net_AckTicker(void)
for (i = 1; i < MAXNETNODES; i++) for (i = 1; i < MAXNETNODES; i++)
{ {
// this is something like node open flag // This is something like node open flag
if (nodes[i].firstacktosend) if (nodes[i].firstacktosend)
{ {
// we haven't sent a packet for a long time // We haven't sent a packet for a long time
// acknowledge packet if needed // Acknowledge packet if needed
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime()) if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
Net_SendAcks(i); Net_SendAcks(i);
@ -523,9 +530,9 @@ void Net_AckTicker(void)
#endif #endif
} }
// remove last packet received ack before resending the ackret // Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....) // (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgPacket(INT32 node) void Net_UnAcknowledgePacket(INT32 node)
{ {
#ifdef NONET #ifdef NONET
(void)node; (void)node;
@ -564,20 +571,29 @@ void Net_UnAcknowledgPacket(INT32 node)
#endif #endif
} }
boolean Net_AllAckReceived(void)
{
#ifndef NONET #ifndef NONET
/** Checks if all acks have been received
*
* \return True if all acks have been received
*
*/
static boolean Net_AllAcksReceived(void)
{
INT32 i; INT32 i;
for (i = 0; i < MAXACKPACKETS; i++) for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum) if (ackpak[i].acknum)
return false; return false;
#endif
return true; return true;
} }
#endif
// wait for all ackreturns with timeout in seconds /** Waits for all ackreturns
*
* \param timeout Timeout in seconds
*
*/
void Net_WaitAllAckReceived(UINT32 timeout) void Net_WaitAllAckReceived(UINT32 timeout)
{ {
#ifdef NONET #ifdef NONET
@ -587,7 +603,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
timeout = tictac + timeout*NEWTICRATE; timeout = tictac + timeout*NEWTICRATE;
HGetPacket(); HGetPacket();
while (timeout > I_GetTime() && !Net_AllAckReceived()) while (timeout > I_GetTime() && !Net_AllAcksReceived())
{ {
while (tictac == I_GetTime()) while (tictac == I_GetTime())
I_Sleep(); I_Sleep();
@ -598,18 +614,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
#endif #endif
} }
static void InitNode(INT32 node) static void InitNode(node_t *node)
{ {
nodes[node].acktosend_head = nodes[node].acktosend_tail = 0; node->acktosend_head = node->acktosend_tail = 0;
#ifndef NEWPING #ifndef NEWPING
nodes[node].ping = PINGDEFAULT; node->ping = PINGDEFAULT;
nodes[node].varping = VARPINGDEFAULT; node->varping = VARPINGDEFAULT;
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping); node->timeout = TIMEOUT(node->ping, node->varping);
#endif #endif
nodes[node].firstacktosend = 0; node->firstacktosend = 0;
nodes[node].nextacknum = 1; node->nextacknum = 1;
nodes[node].remotefirstack = 0; node->remotefirstack = 0;
nodes[node].flags = 0; node->flags = 0;
} }
static void InitAck(void) static void InitAck(void)
@ -622,9 +638,14 @@ static void InitAck(void)
#endif #endif
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
InitNode(i); InitNode(&nodes[i]);
} }
/** Removes all acks of a given packet type
*
* \param packettype The packet type to forget
*
*/
void Net_AbortPacketType(UINT8 packettype) void Net_AbortPacketType(UINT8 packettype)
{ {
#ifdef NONET #ifdef NONET
@ -676,8 +697,8 @@ void Net_CloseConnection(INT32 node)
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
} }
InitNode(node); InitNode(&nodes[node]);
AbortSendFiles(node); SV_AbortSendFiles(node);
I_NetFreeNodenum(node); I_NetFreeNodenum(node);
#endif #endif
} }
@ -729,9 +750,15 @@ static void fprintfstring(char *s, size_t len)
} }
if (mode) if (mode)
fprintf(debugfile, "]"); fprintf(debugfile, "]");
}
static void fprintfstringnewline(char *s, size_t len)
{
fprintfstring(s, len);
fprintf(debugfile, "\n"); fprintf(debugfile, "\n");
} }
/// \warning Keep this up-to-date if you add/remove/rename packet types
static const char *packettypename[NUMPACKETTYPE] = static const char *packettypename[NUMPACKETTYPE] =
{ {
"NOTHING", "NOTHING",
@ -749,15 +776,22 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKINFO", "ASKINFO",
"SERVERINFO", "SERVERINFO",
"PLAYERINFO",
"REQUESTFILE", "REQUESTFILE",
"ASKINFOVIAMS", "ASKINFOVIAMS",
"PLAYERCONFIGS", "RESYNCHEND",
"RESYNCHGET",
"FILEFRAGMENT", "FILEFRAGMENT",
"TEXTCMD", "TEXTCMD",
"TEXTCMD2", "TEXTCMD2",
"CLIENTJOIN", "CLIENTJOIN",
"NODETIMEOUT", "NODETIMEOUT",
"RESYNCHING",
#ifdef NEWPING
"PING"
#endif
}; };
static void DebugPrintpacket(const char *header) static void DebugPrintpacket(const char *header)
@ -770,20 +804,29 @@ static void DebugPrintpacket(const char *header)
{ {
case PT_ASKINFO: case PT_ASKINFO:
case PT_ASKINFOVIAMS: case PT_ASKINFOVIAMS:
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) ); fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
break; break;
case PT_CLIENTJOIN: case PT_CLIENTJOIN:
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers, fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
netbuffer->u.clientcfg.mode); netbuffer->u.clientcfg.mode);
break; break;
case PT_SERVERTICS: case PT_SERVERTICS:
{
servertics_pak *serverpak = &netbuffer->u.serverpak;
ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics];
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd;
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ", fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots, (UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
netbuffer->u.serverpak.numtics, fprintfstring((char *)cmd, 3);
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]))); if (ntxtcmd > 4)
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])); fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]);
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
}
fprintf(debugfile, "\n");
break; break;
}
case PT_CLIENTCMD: case PT_CLIENTCMD:
case PT_CLIENT2CMD: case PT_CLIENT2CMD:
case PT_CLIENTMIS: case PT_CLIENTMIS:
@ -797,7 +840,8 @@ static void DebugPrintpacket(const char *header)
case PT_TEXTCMD: case PT_TEXTCMD:
case PT_TEXTCMD2: case PT_TEXTCMD2:
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]); fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
break; break;
case PT_SERVERCFG: case PT_SERVERCFG:
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d " fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
@ -813,7 +857,7 @@ static void DebugPrintpacket(const char *header)
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname, netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
netbuffer->u.serverinfo.fileneedednum, netbuffer->u.serverinfo.fileneedednum,
(UINT32)LONG(netbuffer->u.serverinfo.time)); (UINT32)LONG(netbuffer->u.serverinfo.time));
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded, fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength (UINT8)((UINT8 *)netbuffer + doomcom->datalength
- (UINT8 *)netbuffer->u.serverinfo.fileneeded)); - (UINT8 *)netbuffer->u.serverinfo.fileneeded));
break; break;
@ -827,20 +871,100 @@ static void DebugPrintpacket(const char *header)
break; break;
case PT_REQUESTFILE: case PT_REQUESTFILE:
default: // write as a raw packet default: // write as a raw packet
fprintfstring((char *)netbuffer->u.textcmd, fprintfstringnewline((char *)netbuffer->u.textcmd,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd)); (UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
break; break;
} }
} }
#endif #endif
#ifdef PACKETDROP
static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
static INT32 packetdroprate = 0;
void Command_Drop(void)
{
INT32 packetquantity;
const char *packetname;
size_t i;
if (COM_Argc() < 2)
{
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
"drop reset: cancel all packet drops");
return;
}
if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
{
memset(packetdropquantity, 0, sizeof(packetdropquantity));
return;
}
if (COM_Argc() >= 3)
{
packetquantity = atoi(COM_Argv(2));
if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
{
CONS_Printf("Invalid quantity\n");
return;
}
}
else
packetquantity = -1;
packetname = COM_Argv(1);
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
for (i = 0; i < NUMPACKETTYPE; i++)
packetdropquantity[i] = packetquantity;
else
{
for (i = 0; i < NUMPACKETTYPE; i++)
if (!stricmp(packetname, packettypename[i]))
{
packetdropquantity[i] = packetquantity;
return;
}
CONS_Printf("Unknown packet name\n");
}
}
void Command_Droprate(void)
{
INT32 droprate;
if (COM_Argc() < 2)
{
CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
return;
}
droprate = atoi(COM_Argv(1));
if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
{
CONS_Printf("Packet drop rate must be between 0 and 100!\n");
return;
}
packetdroprate = droprate;
}
static boolean ShouldDropPacket(void)
{
return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
}
#endif
// //
// HSendPacket // HSendPacket
// //
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength) boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
{ {
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE); doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
if (node == 0) // packet is to go back to us if (node == 0) // Packet is to go back to us
{ {
if ((rebound_head+1) % MAXREBOUND == rebound_tail) if ((rebound_head+1) % MAXREBOUND == rebound_tail)
{ {
@ -871,7 +995,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
(void)reliable; (void)reliable;
(void)acknum; (void)acknum;
#else #else
// do this before GetFreeAcknum because this function backup // do this before GetFreeAcknum because this function backups
// the current packet // the current packet
doomcom->remotenode = (INT16)node; doomcom->remotenode = (INT16)node;
if (doomcom->datalength <= 0) if (doomcom->datalength <= 0)
@ -884,7 +1008,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
return false; return false;
} }
if (node < MAXNETNODES) // can be a broadcast if (node < MAXNETNODES) // Can be a broadcast
netbuffer->ackreturn = GetAcktosend(node); netbuffer->ackreturn = GetAcktosend(node);
else else
netbuffer->ackreturn = 0; netbuffer->ackreturn = 0;
@ -905,20 +1029,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
netbuffer->ack = acknum; netbuffer->ack = acknum;
netbuffer->checksum = NetbufferChecksum(); netbuffer->checksum = NetbufferChecksum();
sendbytes += packetheaderlength + doomcom->datalength; // for stat sendbytes += packetheaderlength + doomcom->datalength; // For stat
// simulate internet :) #ifdef PACKETDROP
if (true || rand()<(INT32)RAND_MAX/5) // Simulate internet :)
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
if (!ShouldDropPacket())
{ {
#endif
#ifdef DEBUGFILE #ifdef DEBUGFILE
if (debugfile) if (debugfile)
DebugPrintpacket("SEND"); DebugPrintpacket("SENT");
#endif #endif
I_NetSend(); I_NetSend();
#ifdef PACKETDROP
} }
else
{
if (packetdropquantity[netbuffer->packettype] > 0)
packetdropquantity[netbuffer->packettype]--;
#ifdef DEBUGFILE #ifdef DEBUGFILE
else if (debugfile) if (debugfile)
DebugPrintpacket("NOTSEND"); DebugPrintpacket("NOT SENT");
#endif
}
#endif #endif
#endif // ndef NONET #endif // ndef NONET
@ -933,7 +1067,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
// //
boolean HGetPacket(void) boolean HGetPacket(void)
{ {
// get a packet from self // Get a packet from self
if (rebound_tail != rebound_head) if (rebound_tail != rebound_head)
{ {
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
@ -963,11 +1097,11 @@ boolean HGetPacket(void)
if (doomcom->remotenode == -1) if (doomcom->remotenode == -1)
return false; return false;
getbytes += packetheaderlength + doomcom->datalength; // for stat getbytes += packetheaderlength + doomcom->datalength; // For stat
if (doomcom->remotenode >= MAXNETNODES) if (doomcom->remotenode >= MAXNETNODES)
{ {
DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode)); DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
continue; continue;
} }
@ -1230,4 +1364,6 @@ void D_CloseConnection(void)
netgame = false; netgame = false;
addedtogame = false; addedtogame = false;
} }
D_ResetTiccmds();
} }

View File

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

View File

@ -365,6 +365,35 @@ boolean splitscreen = false;
boolean circuitmap = false; boolean circuitmap = false;
INT32 adminplayer = -1; INT32 adminplayer = -1;
/// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] =
{
"NAMEANDCOLOR",
"WEAPONPREF",
"KICK",
"NETVAR",
"SAY",
"MAP",
"EXITLEVEL",
"ADDFILE",
"PAUSE",
"ADDPLAYER",
"TEAMCHANGE",
"CLEARSCORES",
"LOGIN",
"VERIFIED",
"RANDOMSEED",
"RUNSOC",
"REQADDFILE",
"DELFILE",
"SETMOTD",
"SUICIDE",
#ifdef HAVE_BLUA
"LUACMD",
"LUAVAR"
#endif
};
// ========================================================================= // =========================================================================
// SERVER STARTUP // SERVER STARTUP
// ========================================================================= // =========================================================================

View File

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

View File

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

View File

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

View File

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

View File

@ -394,6 +394,9 @@ extern INT32 cv_debug;
// Misc stuff for later... // Misc stuff for later...
// ======================= // =======================
// Modifier key variables, accessible anywhere
extern UINT8 shiftdown, ctrldown, altdown;
// if we ever make our alloc stuff... // if we ever make our alloc stuff...
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL) #define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -757,15 +757,8 @@ void HU_clearChatChars(void)
// //
boolean HU_Responder(event_t *ev) boolean HU_Responder(event_t *ev)
{ {
static boolean shiftdown = false;
UINT8 c; UINT8 c;
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
{
shiftdown = (ev->type == ev_keydown);
return chat_on;
}
if (ev->type != ev_keydown) if (ev->type != ev_keydown)
return false; return false;
@ -797,6 +790,14 @@ boolean HU_Responder(event_t *ev)
} }
else // if chat_on else // if chat_on
{ {
// Ignore modifier keys
// Note that we do this here so users can still set
// their chat keys to one of these, if they so desire.
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
return true;
c = (UINT8)ev->data1; c = (UINT8)ev->data1;
// use console translations // use console translations

View File

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

View File

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

View File

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

View File

@ -46,41 +46,6 @@ typedef INT32 fixed_t;
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT)) #define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
/** \brief The TMulScale16 function
\param a a parameter of type fixed_t
\param b a parameter of type fixed_t
\param c a parameter of type fixed_t
\param d a parameter of type fixed_t
\param e a parameter of type fixed_t
\param f a parameter of type fixed_t
\return fixed_t
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
{ \
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
+ ((INT64)e * (INT64)f)) >> 16); \
}
/** \brief The DMulScale16 function
\param a a parameter of type fixed_t
\param b a parameter of type fixed_t
\param c a parameter of type fixed_t
\param d a parameter of type fixed_t
\return fixed_t
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
{ \
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
}
#if defined (__WATCOMC__) && FRACBITS == 16 #if defined (__WATCOMC__) && FRACBITS == 16
#pragma aux FixedMul = \ #pragma aux FixedMul = \
"imul ebx", \ "imul ebx", \

View File

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

View File

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

View File

@ -2585,7 +2585,7 @@ boolean P_SetupLevel(boolean skipprecip)
lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap)); lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette); CON_SetupBackColormap();
// now part of level loading since in future each level may have // now part of level loading since in future each level may have
// its own anim texture sequences, switches etc. // its own anim texture sequences, switches etc.

View File

@ -224,15 +224,6 @@ typedef struct linechain_s
// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
typedef struct secplane_t
{
// the plane is defined as a*x + b*y + c*z + d = 0
// ic is 1/c, for faster Z calculations
fixed_t a, b, c, d, ic;
} secplane_t;
// Slopes // Slopes
#ifdef ESLOPE #ifdef ESLOPE
typedef enum { typedef enum {

View File

@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
return R_PointToDist2(viewx, viewy, x, y); return R_PointToDist2(viewx, viewy, x, y);
} }
/***************************************
*** Zdoom C++ to Legacy C conversion ***
****************************************/
// Utility to find the Z height at an XY location in a sector (for slopes)
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
{
return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
}
// Returns the value of z at (x,y) if d is equal to dist
fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
{
return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
}
// Flips the plane's vertical orientiation, so that if it pointed up,
// it will point down, and vice versa.
void R_SecplaneFlipVert(secplane_t *secplane)
{
secplane->a = -secplane->a;
secplane->b = -secplane->b;
secplane->c = -secplane->c;
secplane->d = -secplane->d;
secplane->ic = -secplane->ic;
}
// Returns true if 2 planes are the same
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
{
return original->a == other->a && original->b == other->b
&& original->c == other->c && original->d == other->d;
}
// Returns true if 2 planes are different
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
{
return original->a != other->a || original->b != other->b
|| original->c != other->c || original->d != other->d;
}
// Moves a plane up/down by hdiff units
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
{
secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
}
// Returns how much this plane's height would change if d were set to oldd
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
{
return FixedMul(oldd - secplane->d, secplane->ic);
}
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
}
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
}
// //
// R_ScaleFromGlobalAngle // R_ScaleFromGlobalAngle
// Returns the texture mapping scale for the current line (horizontal span) // Returns the texture mapping scale for the current line (horizontal span)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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