diff --git a/src/android/i_system.c b/src/android/i_system.c index 150cbd505..58fca7c19 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable) return -1; } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + void I_RegisterSysCommands(void) {} #include "../sdl/dosstr.c" diff --git a/src/console.c b/src/console.c index be4eee210..3702dd560 100644 --- a/src/console.c +++ b/src/console.c @@ -84,19 +84,23 @@ UINT32 con_scalefactor; // text size scale factor // hold 32 last lines of input for history #define CON_MAXPROMPTCHARS 256 -#define CON_PROMPTCHAR '>' +#define CON_PROMPTCHAR '$' static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines static INT32 inputline; // current input line number static INT32 inputhist; // line number of history input line to restore -static size_t input_cx; // position in current input line +static size_t input_cur; // position of cursor in line +static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected") +static size_t input_len; // length of current line, used to bound cursor and such +// notice: input does NOT include the "$" at the start of the line. - 11/3/16 // protos. static void CON_InputInit(void); static void CON_RecalcSize(void); static void CONS_hudlines_Change(void); +static void CONS_backcolor_Change(void); static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth); //static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth); @@ -129,10 +133,12 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"} // whether to use console background picture, or translucent mode static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"}, - {2, "Blue"}, {3, "Green"}, {4, "Gray"}, - {5, "Red"}, {0, NULL}}; -consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"}, + {3, "Red"}, {4, "Orange"}, {5, "Yellow"}, + {6, "Green"}, {7, "Blue"}, {8, "Purple"}, + {9, "Magenta"}, {10, "Aqua"}, + {0, NULL}}; +consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL}; static void CON_Print(char *msg); @@ -219,8 +225,9 @@ static void CONS_Bind_f(void) // CONSOLE SETUP //====================================================================== -// Prepare a colormap for GREEN ONLY translucency over background -// +// Font colormap colors +// TODO: This could probably be improved somehow... +// These colormaps are 99% identical, with just a few changed bytes UINT8 *yellowmap; UINT8 *purplemap; UINT8 *lgreenmap; @@ -229,44 +236,52 @@ UINT8 *graymap; UINT8 *redmap; UINT8 *orangemap; -// Console BG colors -UINT8 *cwhitemap; -UINT8 *corangemap; -UINT8 *cbluemap; -UINT8 *cgreenmap; -UINT8 *cgraymap; -UINT8 *credmap; +// Console BG color +UINT8 *consolebgmap = NULL; -void CON_ReSetupBackColormap(UINT16 num) +void CON_SetupBackColormap(void) { - UINT16 i, j; - UINT8 k; - UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE); + UINT16 i, palsum; + UINT8 j, palindex, shift; + UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE); - // setup the green translucent background colormaps - for (i = 0, k = 0; i < 768; i += 3, k++) + if (!consolebgmap) + consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); + + shift = 6; // 12 colors -- shift of 7 means 6 colors + switch (cons_backcolor.value) { - j = pal[i] + pal[i+1] + pal[i+2]; - cwhitemap[k] = (UINT8)(15 - (j>>6)); - corangemap[k] = (UINT8)(63 - (j>>6)); - cbluemap[k] = (UINT8)(159 - (j>>6)); - cgreenmap[k] = (UINT8)(111 - (j>>6)); - cgraymap[k] = (UINT8)(31 - (j>>6)); - credmap[k] = (UINT8)(47 - (j>>6)); + case 0: palindex = 15; break; // White + case 1: palindex = 31; break; // Gray + case 2: palindex = 239; break; // Brown + case 3: palindex = 47; break; // Red + case 4: palindex = 63; break; // Orange + case 5: palindex = 79; shift = 7; break; // Yellow + case 6: palindex = 111; break; // Green + case 7: palindex = 159; break; // Blue + case 8: palindex = 199; shift = 7; break; // Purple + case 9: palindex = 187; break; // Magenta + case 10: palindex = 139; break; // Aqua + // Default green + default: palindex = 175; break; +} + + // setup background colormap + for (i = 0, j = 0; i < 768; i += 3, j++) + { + palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift; + consolebgmap[j] = (UINT8)(palindex - palsum); } } -static void CON_SetupBackColormap(void) +static void CONS_backcolor_Change(void) { - INT32 i, j, k; - UINT8 *pal; + CON_SetupBackColormap(); +} - cwhitemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - corangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - cbluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - cgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - cgraymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - credmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); +static void CON_SetupColormaps(void) +{ + INT32 i; yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); @@ -276,20 +291,6 @@ static void CON_SetupBackColormap(void) redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - pal = W_CacheLumpName("PLAYPAL", PU_CACHE); - - // setup the green translucent background colormaps - for (i = 0, k = 0; i < 768; i += 3, k++) - { - j = pal[i] + pal[i+1] + pal[i+2]; - cwhitemap[k] = (UINT8)(15 - (j>>6)); - corangemap[k] = (UINT8)(63 - (j>>6)); - cbluemap[k] = (UINT8)(159 - (j>>6)); - cgreenmap[k] = (UINT8)(111 - (j>>6)); - cgraymap[k] = (UINT8)(31 - (j>>6)); - credmap[k] = (UINT8)(47 - (j>>6)); - } - // setup the other colormaps, for console text // these don't need to be aligned, unless you convert the @@ -320,6 +321,9 @@ static void CON_SetupBackColormap(void) redmap[9] = (UINT8)32; orangemap[3] = (UINT8)52; orangemap[9] = (UINT8)57; + + // Init back colormap + CON_SetupBackColormap(); } // Setup the console text buffer @@ -343,7 +347,7 @@ void CON_Init(void) con_width = 0; CON_RecalcSize(); - CON_SetupBackColormap(); + CON_SetupColormaps(); //note: CON_Ticker should always execute at least once before D_Display() con_clipviewtop = -1; // -1 does not clip @@ -386,14 +390,10 @@ void CON_Init(void) // static void CON_InputInit(void) { - INT32 i; - // prepare the first prompt line memset(inputlines, 0, sizeof (inputlines)); - for (i = 0; i < 32; i++) - inputlines[i][0] = CON_PROMPTCHAR; inputline = 0; - input_cx = 1; + input_cur = input_sel = input_len = 0; } //====================================================================== @@ -618,13 +618,91 @@ void CON_Ticker(void) } } +// +// ---- +// +// Shortcuts for adding and deleting characters, strings, and sections +// Necessary due to moving cursor +// + +static void CON_InputClear(void) +{ + memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); + input_cur = input_sel = input_len = 0; +} + +static void CON_InputSetString(const char *c) +{ + memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); + strcpy(inputlines[inputline], c); + input_cur = input_sel = input_len = strlen(c); +} + +static void CON_InputAddString(const char *c) +{ + size_t csize = strlen(c); + if (input_len + csize > CON_MAXPROMPTCHARS-1) + return; + if (input_cur != input_len) + memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur); + memcpy(&inputlines[inputline][input_cur], c, csize); + input_len += csize; + input_sel = (input_cur += csize); +} + +static void CON_InputDelSelection(void) +{ + size_t start, end, len; + if (input_cur > input_sel) + { + start = input_sel; + end = input_cur; + } + else + { + start = input_cur; + end = input_sel; + } + len = (end - start); + + if (end != input_len) + memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end); + memset(&inputlines[inputline][input_len - len], 0, len); + + input_len -= len; + input_sel = input_cur = start; +} + +static void CON_InputAddChar(char c) +{ + if (input_len >= CON_MAXPROMPTCHARS-1) + return; + if (input_cur != input_len) + memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur); + inputlines[inputline][input_cur++] = c; + inputlines[inputline][++input_len] = 0; + input_sel = input_cur; +} + +static void CON_InputDelChar(void) +{ + if (!input_cur) + return; + if (input_cur != input_len) + memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur); + inputlines[inputline][--input_len] = 0; + input_sel = --input_cur; +} + +// +// ---- +// + // Handles console key input // boolean CON_Responder(event_t *ev) { - static boolean consdown; - static boolean shiftdown; - static boolean ctrldown; + static UINT8 consdown = false; // console is treated differently due to rare usage // sequential completions a la 4dos static char completion[80]; @@ -639,13 +717,8 @@ boolean CON_Responder(event_t *ev) // let go keyup events, don't eat them if (ev->type != ev_keydown && ev->type != ev_console) { - if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT) - shiftdown = false; - else if (ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL) - ctrldown = false; - else if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1]) + if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1]) consdown = false; - return false; } @@ -684,94 +757,110 @@ boolean CON_Responder(event_t *ev) consoletoggle = true; return true; } - } - // eat shift only if console active - if (key == KEY_LSHIFT || key == KEY_RSHIFT) - { - shiftdown = true; + // Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas + if (key == KEY_LSHIFT || key == KEY_RSHIFT + || key == KEY_LCTRL || key == KEY_RCTRL + || key == KEY_LALT || key == KEY_RALT) return true; - } - // same for ctrl - if (key == KEY_LCTRL || key == KEY_RCTRL) + // ctrl modifier -- changes behavior, adds shortcuts + if (ctrldown) { - ctrldown = true; - return true; + // show all cvars/commands that match what we have inputted + if (key == KEY_TAB) + { + size_t i, len; + + if (!completion[0]) + { + if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' ')) + return true; + strcpy(completion, inputlines[inputline]); + comskips = varskips = 0; + } + len = strlen(completion); + + //first check commands + CONS_Printf("\nCommands:\n"); + for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i)) + CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len); + if (i == 0) CONS_Printf(" (none)\n"); + + //now we move on to CVARs + CONS_Printf("Variables:\n"); + for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i)) + CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len); + if (i == 0) CONS_Printf(" (none)\n"); + + return true; + } + // --- + + if (key == KEY_HOME) // oldest text in buffer + { + con_scrollup = (con_totallines-((con_curlines-16)>>3)); + return true; + } + else if (key == KEY_END) // most recent text in buffer + { + con_scrollup = 0; + return true; + } + + if (key == 'x' || key == 'X') + { + if (input_sel > input_cur) + I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur); + else + I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel); + CON_InputDelSelection(); + completion[0] = 0; + return true; + } + else if (key == 'c' || key == 'C') + { + if (input_sel > input_cur) + I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur); + else + I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel); + return true; + } + else if (key == 'v' || key == 'V') + { + const char *paste = I_ClipboardPaste(); + if (input_sel != input_cur) + CON_InputDelSelection(); + if (paste != NULL) + CON_InputAddString(paste); + completion[0] = 0; + return true; + } + + // Select all + if (key == 'a' || key == 'A') + { + input_sel = 0; + input_cur = input_len; + return true; + } + + // don't eat the key + return false; } // command completion forward (tab) and backward (shift-tab) if (key == KEY_TAB) { - // show all cvars/commands that match what we have inputted - if (ctrldown) - { - UINT32 i; - size_t stop = input_cx - 1; - char nameremainder[255]; - - if (input_cx < 2 || strlen(inputlines[inputline]+1) >= 80) - return true; - - strcpy(completion, inputlines[inputline]+1); - - // trimming: stop at the first newline - for (i = 0; i < input_cx - 1; ++i) - { - if (completion[i] == ' ') - { - completion[i] = '\0'; - stop = i; - break; - } - } - - i = 0; - - //first check commands - CONS_Printf("\nCommands:\n"); - - for (cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, i)) - { - strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop)); - nameremainder[strlen(cmd)-(stop)] = '\0'; - - CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder); - ++i; - } - if (i == 0) - CONS_Printf(" (none)\n"); - - i = 0; - - //now we move on to CVARs - CONS_Printf("Variables:\n"); - - for (cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, i)) - { - strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop)); - nameremainder[strlen(cmd)-(stop)] = '\0'; - - CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder); - ++i; - } - if (i == 0) - CONS_Printf(" (none)\n"); - - return true; - } - // sequential command completion forward and backward // remember typing for several completions (a-la-4dos) - if (inputlines[inputline][input_cx-1] != ' ') + if (!completion[0]) { - if (strlen(inputlines[inputline]+1) < 80) - strcpy(completion, inputlines[inputline]+1); - else - completion[0] = 0; - + if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' ')) + return true; + strcpy(completion, inputlines[inputline]); comskips = varskips = 0; } else @@ -783,37 +872,26 @@ boolean CON_Responder(event_t *ev) if (--varskips < 0) comskips = -comskips - 2; } - else if (comskips > 0) - comskips--; + else if (comskips > 0) comskips--; } else { - if (comskips < 0) - varskips++; - else - comskips++; + if (comskips < 0) varskips++; + else comskips++; } } if (comskips >= 0) { cmd = COM_CompleteCommand(completion, comskips); - if (!cmd) - // dirty: make sure if comskips is zero, to have a neg value + if (!cmd) // dirty: make sure if comskips is zero, to have a neg value comskips = -comskips - 1; } if (comskips < 0) cmd = CV_CompleteVar(completion, varskips); if (cmd) - { - memset(inputlines[inputline]+1, 0, CON_MAXPROMPTCHARS-1); - strcpy(inputlines[inputline]+1, cmd); - input_cx = strlen(cmd) + 1; - inputlines[inputline][input_cx] = ' '; - input_cx++; - inputlines[inputline][input_cx] = 0; - } + CON_InputSetString(va("%s ", cmd)); else { if (comskips > 0) @@ -839,47 +917,80 @@ boolean CON_Responder(event_t *ev) return true; } - if (key == KEY_HOME) // oldest text in buffer + if (key == KEY_LEFTARROW) { - con_scrollup = (con_totallines-((con_curlines-16)>>3)); + if (input_cur != 0) + --input_cur; + if (!shiftdown) + input_sel = input_cur; return true; } - else if (key == KEY_END) // most recent text in buffer + else if (key == KEY_RIGHTARROW) { - con_scrollup = 0; + if (input_cur < input_len) + ++input_cur; + if (!shiftdown) + input_sel = input_cur; return true; } + else if (key == KEY_HOME) + { + input_cur = 0; + if (!shiftdown) + input_sel = input_cur; + return true; + } + else if (key == KEY_END) + { + input_cur = input_len; + if (!shiftdown) + input_sel = input_cur; + return true; + } + + // At this point we're messing with input + // Clear completion + completion[0] = 0; // command enter if (key == KEY_ENTER) { - if (input_cx < 2) + if (!input_len) return true; // push the command - COM_BufAddText(inputlines[inputline]+1); + COM_BufAddText(inputlines[inputline]); COM_BufAddText("\n"); - CONS_Printf("%s\n", inputlines[inputline]); + CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]); inputline = (inputline+1) & 31; inputhist = inputline; - - memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); - inputlines[inputline][0] = CON_PROMPTCHAR; - input_cx = 1; + CON_InputClear(); return true; } - // backspace command prompt - if (key == KEY_BACKSPACE) + // backspace and delete command prompt + if (input_sel != input_cur) { - if (input_cx > 1) + if (key == KEY_BACKSPACE || key == KEY_DEL) { - input_cx--; - inputlines[inputline][input_cx] = 0; + CON_InputDelSelection(); + return true; } + } + else if (key == KEY_BACKSPACE) + { + CON_InputDelChar(); + return true; + } + else if (key == KEY_DEL) + { + if (input_cur == input_len) + return true; + ++input_cur; + CON_InputDelChar(); return true; } @@ -888,18 +999,15 @@ boolean CON_Responder(event_t *ev) { // copy one of the previous inputlines to the current do - { inputhist = (inputhist - 1) & 31; // cycle back - } while (inputhist != inputline && !inputlines[inputhist][1]); + while (inputhist != inputline && !inputlines[inputhist][0]); // stop at the last history input line, which is the // current line + 1 because we cycle through the 32 input lines if (inputhist == inputline) inputhist = (inputline + 1) & 31; - M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS); - input_cx = strlen(inputlines[inputline]); - + CON_InputSetString(inputlines[inputhist]); return true; } @@ -909,23 +1017,14 @@ boolean CON_Responder(event_t *ev) if (inputhist == inputline) return true; do - { inputhist = (inputhist + 1) & 31; - } while (inputhist != inputline && !inputlines[inputhist][1]); - - memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); + while (inputhist != inputline && !inputlines[inputhist][0]); // back to currentline if (inputhist == inputline) - { - inputlines[inputline][0] = CON_PROMPTCHAR; - input_cx = 1; - } + CON_InputClear(); else - { - strcpy(inputlines[inputline], inputlines[inputhist]); - input_cx = strlen(inputlines[inputline]); - } + CON_InputSetString(inputlines[inputhist]); return true; } @@ -950,15 +1049,12 @@ boolean CON_Responder(event_t *ev) return false; // add key to cmd line here - if (input_cx < CON_MAXPROMPTCHARS) - { - if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers - key = key + 'a' - 'A'; + if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers + key = key + 'a' - 'A'; - inputlines[inputline][input_cx] = (char)key; - inputlines[inputline][input_cx + 1] = 0; - input_cx++; - } + if (input_sel != input_cur) + CON_InputDelSelection(); + CON_InputAddChar(key); return true; } @@ -1242,26 +1338,89 @@ void CONS_Error(const char *msg) // static void CON_DrawInput(void) { - char *p; - size_t c; - INT32 x, y; INT32 charwidth = (INT32)con_scalefactor << 3; - - // input line scrolls left if it gets too long - p = inputlines[inputline]; - if (input_cx >= con_width-11) - p += input_cx - (con_width-11) + 1; + const char *p = inputlines[inputline]; + size_t c, clen, cend; + UINT8 lellip = 0, rellip = 0; + INT32 x, y, i; y = con_curlines - 12 * con_scalefactor; + x = charwidth*2; - for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth) - V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + clen = con_width-13; - // draw the blinking cursor - // - x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth); - if (con_tick < 4) - V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + if (input_len <= clen) + { + c = 0; + clen = input_len; + } + else // input line scrolls left if it gets too long + { + clen -= 2; // There will always be some extra truncation -- but where is what we'll find out + + if (input_cur <= clen/2) + { + // Close enough to right edge to show all + c = 0; + // Always will truncate right side from this position, so always draw right ellipsis + rellip = 1; + } + else + { + // Cursor in the middle (or right side) of input + // Move over for the ellipsis + c = input_cur - (clen/2) + 2; + x += charwidth*2; + lellip = 1; + + if (c + clen >= input_len) + { + // Cursor in the right side of input + // We were too far over, so move back + c = input_len - clen; + } + else + { + // Cursor in the middle -- ellipses on both sides + clen -= 2; + rellip = 1; + } + } + } + + if (lellip) + { + x -= charwidth*3; + if (input_sel < c) + V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART); + for (i = 0; i < 3; ++i, x += charwidth) + V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); + } + else + V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); + + for (cend = c + clen; c < cend; ++c, x += charwidth) + { + if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c)) + { + V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 77 | V_NOSCALESTART); + V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value); + } + else + V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + + if (c == input_cur && con_tick >= 4) + V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + } + if (cend == input_cur && con_tick >= 4) + V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + if (rellip) + { + if (input_sel > cend) + V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART); + for (i = 0; i < 3; ++i, x += charwidth) + V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); + } } // draw the last lines of console text to the top of the screen @@ -1417,7 +1576,7 @@ static void CON_DrawConsole(void) { // inu: no more width (was always 0 and vid.width) if (rendermode != render_none) - V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background + V_DrawFadeConsBack(con_curlines); // translucent background } // draw console text lines from top to bottom diff --git a/src/console.h b/src/console.h index 47af65e21..8cf6483ff 100644 --- a/src/console.h +++ b/src/console.h @@ -40,11 +40,10 @@ extern consvar_t cons_backcolor; extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap; -// Console bg colors: -extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap, - *credmap; +// Console bg color (auto updated to match) +extern UINT8 *consolebgmap; -void CON_ReSetupBackColormap(UINT16 num); +void CON_SetupBackColormap(void); void CON_ClearHUD(void); // clear heads up messages void CON_Ticker(void); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 734173f8d..7ea95cfb8 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -495,7 +495,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); // Score is resynched in the rspfirm resync packet - rsp->health = 0; // resynched with mo health + rsp->rings = LONG(players[i].rings); rsp->lives = players[i].lives; rsp->continues = players[i].continues; rsp->scoreadd = players[i].scoreadd; @@ -582,7 +582,6 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->hasmo = true; rsp->health = LONG(players[i].mo->health); - rsp->angle = (angle_t)LONG(players[i].mo->angle); rsp->x = LONG(players[i].mo->x); rsp->y = LONG(players[i].mo->y); @@ -625,7 +624,7 @@ static void resynch_read_player(resynch_pak *rsp) players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); // Score is resynched in the rspfirm resync packet - players[i].health = rsp->health; + players[i].rings = LONG(rsp->rings); players[i].lives = rsp->lives; players[i].continues = rsp->continues; players[i].scoreadd = rsp->scoreadd; @@ -2254,7 +2253,7 @@ static void CL_RemovePlayer(INT32 playernum) } count--; - rings = players[playernum].health - 1; + rings = players[playernum].rings; increment = rings/count; for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index f86c09b45..21ef3a46b 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -155,7 +155,7 @@ typedef struct UINT16 powers[NUMPOWERS]; // Score is resynched in the confirm resync packet - INT32 health; + INT32 rings; SINT8 lives; SINT8 continues; UINT8 scoreadd; @@ -236,6 +236,7 @@ typedef struct //player->mo stuff UINT8 hasmo; //boolean + INT32 health; angle_t angle; fixed_t x; fixed_t y; diff --git a/src/d_main.c b/src/d_main.c index 2ac72a9da..63f6bd02c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -73,6 +73,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "dehacked.h" // Dehacked list test #include "m_cond.h" // condition initialization #include "fastcmp.h" +#include "keys.h" #ifdef CMAKECONFIG #include "config.h" @@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev) void D_PostEvent_end(void) {}; #endif +// modifier keys +UINT8 shiftdown = 0; // 0x1 left, 0x2 right +UINT8 ctrldown = 0; // 0x1 left, 0x2 right +UINT8 altdown = 0; // 0x1 left, 0x2 right +// +// D_ModifierKeyResponder +// Sets global shift/ctrl/alt variables, never actually eats events +// +static inline void D_ModifierKeyResponder(event_t *ev) +{ + if (ev->type == ev_keydown) switch (ev->data1) + { + case KEY_LSHIFT: shiftdown |= 0x1; return; + case KEY_RSHIFT: shiftdown |= 0x2; return; + case KEY_LCTRL: ctrldown |= 0x1; return; + case KEY_RCTRL: ctrldown |= 0x2; return; + case KEY_LALT: altdown |= 0x1; return; + case KEY_RALT: altdown |= 0x2; return; + default: return; + } + else if (ev->type == ev_keyup) switch (ev->data1) + { + case KEY_LSHIFT: shiftdown &= ~0x1; return; + case KEY_RSHIFT: shiftdown &= ~0x2; return; + case KEY_LCTRL: ctrldown &= ~0x1; return; + case KEY_RCTRL: ctrldown &= ~0x2; return; + case KEY_LALT: altdown &= ~0x1; return; + case KEY_RALT: altdown &= ~0x2; return; + default: return; + } +} + // // D_ProcessEvents // Send all the events of the given timestamp down the responder chain @@ -188,6 +221,9 @@ void D_ProcessEvents(void) { ev = &events[eventtail]; + // Set global shift/ctrl/alt down variables + D_ModifierKeyResponder(ev); // never eats events + // Screenshots over everything so that they can be taken anywhere. if (M_ScreenshotResponder(ev)) continue; // ate the event @@ -837,6 +873,18 @@ static void IdentifyVersion(void) I_Error("File %s has been modified with non-music lumps",musicfile); } #endif + +#if 1 // This section can be deleted when music_new is merged with music.dta + { + const char *musicfile = "music_new.dta"; + const char *musicpath = va(pandf,srb2waddir,musicfile); + int ms = W_VerifyNMUSlumps(musicpath); // Don't forget the music! + if (ms == 1) + D_AddFile(musicpath); + else if (ms == 0) + I_Error("File %s has been modified with non-music lumps",musicfile); + } +#endif } /* ======================================================================== */ diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 65b415e65..784d07bca 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2574,7 +2574,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) if (players[playernum].spectator) { players[playernum].score = 0; - players[playernum].health = 1; + players[playernum].rings = 0; if (players[playernum].mo) players[playernum].mo->health = 1; } diff --git a/src/d_player.h b/src/d_player.h index bd553d9fa..49f6cfade 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -297,10 +297,8 @@ typedef struct player_s // It is updated with cmd->aiming. angle_t aiming; - // This is only used between levels, - // mo->health is used during levels. - /// \todo Remove this. We don't need a second health definition for players. - INT32 health; + // player's ring count + INT32 rings; SINT8 pity; // i pity the fool. INT32 currentweapon; // current weapon selected. diff --git a/src/dehacked.c b/src/dehacked.c index e06e9752f..347bae8c9 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1659,6 +1659,9 @@ static actionpointer_t actionpointers[] = {{A_Pain}, "A_PAIN"}, {{A_Fall}, "A_FALL"}, {{A_MonitorPop}, "A_MONITORPOP"}, + {{A_GoldMonitorPop}, "A_GOLDMONITORPOP"}, + {{A_GoldMonitorRestore}, "A_GOLDMONITORRESTORE"}, + {{A_GoldMonitorSparkle}, "A_GOLDMONITORSPARKLE"}, {{A_Look}, "A_LOOK"}, {{A_Chase}, "A_CHASE"}, {{A_FaceStabChase}, "A_FACESTABCHASE"}, @@ -4869,170 +4872,114 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CANNONLAUNCHER2", "S_CANNONLAUNCHER3", - // Super Ring Box - "S_SUPERRINGBOX", - "S_SUPERRINGBOX1", - "S_SUPERRINGBOX2", - "S_SUPERRINGBOX3", - "S_SUPERRINGBOX4", - "S_SUPERRINGBOX5", - "S_SUPERRINGBOX6", + // Monitor Miscellany + "S_BOXSPARKLE1", + "S_BOXSPARKLE2", + "S_BOXSPARKLE3", - // Red Team Ring Box - "S_REDRINGBOX", - "S_REDRINGBOX1", + "S_BOX_FLICKER", + "S_BOX_POP1", + "S_BOX_POP2", - // Blue Team Ring Box - "S_BLUERINGBOX", - "S_BLUERINGBOX1", + "S_GOLDBOX_FLICKER", + "S_GOLDBOX_OFF1", + "S_GOLDBOX_OFF2", + "S_GOLDBOX_OFF3", + "S_GOLDBOX_OFF4", + "S_GOLDBOX_OFF5", + "S_GOLDBOX_OFF6", + "S_GOLDBOX_OFF7", - // Super Sneakers Box - "S_SHTV", - "S_SHTV1", - "S_SHTV2", - "S_SHTV3", - "S_SHTV4", - "S_SHTV5", - "S_SHTV6", + // Monitor States (one per box) + "S_MYSTERY_BOX", + "S_RING_BOX", + "S_PITY_BOX", + "S_ATTRACT_BOX", + "S_FORCE_BOX", + "S_ARMAGEDDON_BOX", + "S_WHIRLWIND_BOX", + "S_ELEMENTAL_BOX", + "S_SNEAKERS_BOX", + "S_INVULN_BOX", + "S_1UP_BOX", + "S_EGGMAN_BOX", + "S_MIXUP_BOX", + "S_GRAVITY_BOX", + "S_RECYCLER_BOX", + "S_SCORE1K_BOX", + "S_SCORE10K_BOX", - // Invincibility Box - "S_PINV", - "S_PINV1", - "S_PINV2", - "S_PINV3", - "S_PINV4", - "S_PINV5", - "S_PINV6", + // Gold Repeat Monitor States (one per box) + "S_PITY_GOLDBOX", + "S_ATTRACT_GOLDBOX", + "S_FORCE_GOLDBOX", + "S_ARMAGEDDON_GOLDBOX", + "S_WHIRLWIND_GOLDBOX", + "S_ELEMENTAL_GOLDBOX", + "S_SNEAKERS_GOLDBOX", + "S_INVULN_GOLDBOX", + "S_EGGMAN_GOLDBOX", + "S_GRAVITY_GOLDBOX", - // 1-Up Box - "S_PRUP", - "S_PRUP1", - "S_PRUP2", - "S_PRUP3", - "S_PRUP4", - "S_PRUP5", - "S_PRUP6", + // Team Ring Boxes (these are special) + "S_RING_REDBOX1", + "S_RING_REDBOX2", + "S_REDBOX_POP1", + "S_REDBOX_POP2", - // Ring Shield Box - "S_YLTV", - "S_YLTV1", - "S_YLTV2", - "S_YLTV3", - "S_YLTV4", - "S_YLTV5", - "S_YLTV6", + "S_RING_BLUEBOX1", + "S_RING_BLUEBOX2", + "S_BLUEBOX_POP1", + "S_BLUEBOX_POP2", - // Force Shield Box - "S_BLTV1", - "S_BLTV2", - "S_BLTV3", - "S_BLTV4", - "S_BLTV5", - "S_BLTV6", - "S_BLTV7", + // Box Icons -- 2 states each, animation and action + "S_RING_ICON1", + "S_RING_ICON2", - // Bomb Shield Box - "S_BKTV1", - "S_BKTV2", - "S_BKTV3", - "S_BKTV4", - "S_BKTV5", - "S_BKTV6", - "S_BKTV7", + "S_PITY_ICON1", + "S_PITY_ICON2", - // Jump Shield Box - "S_WHTV1", - "S_WHTV2", - "S_WHTV3", - "S_WHTV4", - "S_WHTV5", - "S_WHTV6", - "S_WHTV7", + "S_ATTRACT_ICON1", + "S_ATTRACT_ICON2", - // Water Shield Box - "S_GRTV", - "S_GRTV1", - "S_GRTV2", - "S_GRTV3", - "S_GRTV4", - "S_GRTV5", - "S_GRTV6", + "S_FORCE_ICON1", + "S_FORCE_ICON2", - // Pity Shield Box - "S_PITV1", - "S_PITV2", - "S_PITV3", - "S_PITV4", - "S_PITV5", - "S_PITV6", - "S_PITV7", + "S_ARMAGEDDON_ICON1", + "S_ARMAGEDDON_ICON2", - // Eggman Box - "S_EGGTV1", - "S_EGGTV2", - "S_EGGTV3", - "S_EGGTV4", - "S_EGGTV5", - "S_EGGTV6", - "S_EGGTV7", + "S_WHIRLWIND_ICON1", + "S_WHIRLWIND_ICON2", - // Teleport Box - "S_MIXUPBOX1", - "S_MIXUPBOX2", - "S_MIXUPBOX3", - "S_MIXUPBOX4", - "S_MIXUPBOX5", - "S_MIXUPBOX6", - "S_MIXUPBOX7", + "S_ELEMENTAL_ICON1", + "S_ELEMENTAL_ICON2", - // Recycler Box - "S_RECYCLETV1", - "S_RECYCLETV2", - "S_RECYCLETV3", - "S_RECYCLETV4", - "S_RECYCLETV5", - "S_RECYCLETV6", - "S_RECYCLETV7", + "S_SNEAKERS_ICON1", + "S_SNEAKERS_ICON2", - // Question Box - "S_RANDOMBOX1", - "S_RANDOMBOX2", - "S_RANDOMBOX3", + "S_INVULN_ICON1", + "S_INVULN_ICON2", - // Gravity Boots Box - "S_GBTV1", - "S_GBTV2", - "S_GBTV3", - "S_GBTV4", - "S_GBTV5", - "S_GBTV6", - "S_GBTV7", + "S_1UP_ICON1", + "S_1UP_ICON2", - // Score boxes - "S_SCORETVA1", - "S_SCORETVA2", - "S_SCORETVA3", - "S_SCORETVA4", - "S_SCORETVA5", - "S_SCORETVA6", - "S_SCORETVA7", - "S_SCORETVB1", - "S_SCORETVB2", - "S_SCORETVB3", - "S_SCORETVB4", - "S_SCORETVB5", - "S_SCORETVB6", - "S_SCORETVB7", + "S_EGGMAN_ICON1", + "S_EGGMAN_ICON2", - // Monitor Explosion - "S_MONITOREXPLOSION1", - "S_MONITOREXPLOSION2", + "S_MIXUP_ICON1", + "S_MIXUP_ICON2", - "S_REDMONITOREXPLOSION1", - "S_REDMONITOREXPLOSION2", + "S_GRAVITY_ICON1", + "S_GRAVITY_ICON2", - "S_BLUEMONITOREXPLOSION1", - "S_BLUEMONITOREXPLOSION2", + "S_RECYCLER_ICON1", + "S_RECYCLER_ICON2", + + "S_SCORE1K_ICON1", + "S_SCORE1K_ICON2", + + "S_SCORE10K_ICON1", + "S_SCORE10K_ICON2", "S_ROCKET", @@ -6046,70 +5993,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ROCKCRUMBLEO", "S_ROCKCRUMBLEP", - "S_SRB1_CRAWLA1", - "S_SRB1_CRAWLA2", - "S_SRB1_CRAWLA3", - "S_SRB1_CRAWLA4", - - "S_SRB1_BAT1", - "S_SRB1_BAT2", - "S_SRB1_BAT3", - "S_SRB1_BAT4", - - "S_SRB1_ROBOFISH1", - "S_SRB1_ROBOFISH2", - "S_SRB1_ROBOFISH3", - - "S_SRB1_VOLCANOGUY1", - "S_SRB1_VOLCANOGUY2", - - "S_SRB1_HOPPY1", - "S_SRB1_HOPPY2", - - "S_SRB1_HOPPYWATER1", - "S_SRB1_HOPPYWATER2", - - "S_SRB1_HOPPYSKYLAB1", - - "S_SRB1_MMZFLYING1", - "S_SRB1_MMZFLYING2", - "S_SRB1_MMZFLYING3", - "S_SRB1_MMZFLYING4", - "S_SRB1_MMZFLYING5", - - "S_SRB1_UFO1", - "S_SRB1_UFO2", - - "S_SRB1_GRAYBOT1", - "S_SRB1_GRAYBOT2", - "S_SRB1_GRAYBOT3", - "S_SRB1_GRAYBOT4", - "S_SRB1_GRAYBOT5", - "S_SRB1_GRAYBOT6", - - "S_SRB1_ROBOTOPOLIS1", - "S_SRB1_ROBOTOPOLIS2", - - "S_SRB1_RBZBUZZ1", - "S_SRB1_RBZBUZZ2", - - "S_SRB1_RBZSPIKES1", - "S_SRB1_RBZSPIKES2", - - "S_SRB1_METALSONIC1", - "S_SRB1_METALSONIC2", - "S_SRB1_METALSONIC3", - - "S_SRB1_GOLDBOT1", - "S_SRB1_GOLDBOT2", - "S_SRB1_GOLDBOT3", - "S_SRB1_GOLDBOT4", - "S_SRB1_GOLDBOT5", - "S_SRB1_GOLDBOT6", - - "S_SRB1_GENREX1", - "S_SRB1_GENREX2", - #ifdef SEENAMES "S_NAMECHECK", #endif @@ -6260,47 +6143,61 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BIGAIRMINE", "MT_CANNONLAUNCHER", - // Monitor Boxes - "MT_SUPERRINGBOX", - "MT_REDRINGBOX", - "MT_BLUERINGBOX", - "MT_SNEAKERTV", - "MT_INV", - "MT_PRUP", // 1up Box - "MT_YELLOWTV", // Attract shield TV - "MT_BLUETV", // Force shield TV - "MT_BLACKTV", // Bomb shield TV - "MT_WHITETV", // Jump shield TV - "MT_GREENTV", // Elemental shield TV - "MT_PITYTV", // Pity shield TV - "MT_EGGMANBOX", - "MT_MIXUPBOX", - "MT_RECYCLETV", - "MT_RECYCLEICO", - "MT_QUESTIONBOX", - "MT_GRAVITYBOX", - "MT_SCORETVSMALL", - "MT_SCORETVLARGE", - // Monitor miscellany - "MT_MONITOREXPLOSION", - "MT_REDMONITOREXPLOSION", - "MT_BLUEMONITOREXPLOSION", - "MT_RINGICO", - "MT_SHOESICO", - "MT_INVCICO", - "MT_1UPICO", - "MT_YSHIELDICO", - "MT_BSHIELDICO", - "MT_KSHIELDICO", - "MT_WSHIELDICO", - "MT_GSHIELDICO", - "MT_PITYSHIELDICO", - "MT_EGGMANICO", - "MT_MIXUPICO", - "MT_GRAVITYICO", - "MT_SCOREICOSMALL", - "MT_SCOREICOLARGE", + "MT_BOXSPARKLE", + + // Monitor boxes -- regular + "MT_RING_BOX", + "MT_PITY_BOX", + "MT_ATTRACT_BOX", + "MT_FORCE_BOX", + "MT_ARMAGEDDON_BOX", + "MT_WHIRLWIND_BOX", + "MT_ELEMENTAL_BOX", + "MT_SNEAKERS_BOX", + "MT_INVULN_BOX", + "MT_1UP_BOX", + "MT_EGGMAN_BOX", + "MT_MIXUP_BOX", + "MT_MYSTERY_BOX", + "MT_GRAVITY_BOX", + "MT_RECYCLER_BOX", + "MT_SCORE1K_BOX", + "MT_SCORE10K_BOX", + + // Monitor boxes -- repeating (big) boxes + "MT_PITY_GOLDBOX", + "MT_ATTRACT_GOLDBOX", + "MT_FORCE_GOLDBOX", + "MT_ARMAGEDDON_GOLDBOX", + "MT_WHIRLWIND_GOLDBOX", + "MT_ELEMENTAL_GOLDBOX", + "MT_SNEAKERS_GOLDBOX", + "MT_INVULN_GOLDBOX", + "MT_EGGMAN_GOLDBOX", + "MT_GRAVITY_GOLDBOX", + + // Monitor boxes -- special + "MT_RING_REDBOX", + "MT_RING_BLUEBOX", + + // Monitor icons + "MT_RING_ICON", + "MT_PITY_ICON", + "MT_ATTRACT_ICON", + "MT_FORCE_ICON", + "MT_ARMAGEDDON_ICON", + "MT_WHIRLWIND_ICON", + "MT_ELEMENTAL_ICON", + "MT_SNEAKERS_ICON", + "MT_INVULN_ICON", + "MT_1UP_ICON", + "MT_EGGMAN_ICON", + "MT_MIXUP_ICON", + "MT_GRAVITY_ICON", + "MT_RECYCLER_ICON", + "MT_SCORE1K_ICON", + "MT_SCORE10K_ICON", // Projectiles "MT_ROCKET", @@ -6606,22 +6503,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_ROCKCRUMBLE15", "MT_ROCKCRUMBLE16", - "MT_SRB1_CRAWLA", - "MT_SRB1_BAT", - "MT_SRB1_ROBOFISH", - "MT_SRB1_VOLCANOGUY", - "MT_SRB1_HOPPY", - "MT_SRB1_HOPPYWATER", - "MT_SRB1_HOPPYSKYLAB", - "MT_SRB1_MMZFLYING", - "MT_SRB1_UFO", - "MT_SRB1_GRAYBOT", - "MT_SRB1_ROBOTOPOLIS", - "MT_SRB1_RBZBUZZ", - "MT_SRB1_RBZSPIKES", - "MT_SRB1_METALSONIC", - "MT_SRB1_GOLDBOT", - "MT_SRB1_GENREX", #ifdef SEENAMES "MT_NAMECHECK", #endif @@ -6633,7 +6514,7 @@ static const char *const MOBJFLAG_LIST[] = { "SHOOTABLE", "NOSECTOR", "NOBLOCKMAP", - "AMBUSH", + "PAPERCOLLISION", "PUSHABLE", "BOSS", "SPAWNCEILING", @@ -6690,6 +6571,8 @@ static const char *const MOBJFLAG2_LIST[] = { "BOSSNOTRAP", // No Egg Trap after boss "BOSSFLEE", // Boss is fleeing! "BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) + "AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH + "LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) NULL }; @@ -7012,9 +6895,13 @@ struct { // Frame settings {"FF_FRAMEMASK",FF_FRAMEMASK}, + {"FF_VERTICALFLIP",FF_VERTICALFLIP}, + {"FF_PAPERSPRITE",FF_PAPERSPRITE}, {"FF_SPR2ENDSTATE",FF_SPR2ENDSTATE}, - {"FF_MIDDLESTARTCHANCE",FF_MIDDLESTARTCHANCE}, + {"FF_SPR2MIDSTART",FF_SPR2MIDSTART}, {"FF_ANIMATE",FF_ANIMATE}, + {"FF_RANDOMANIM",FF_RANDOMANIM}, + {"FF_GLOBALANIM",FF_GLOBALANIM}, {"FF_FULLBRIGHT",FF_FULLBRIGHT}, {"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSSHIFT",FF_TRANSSHIFT}, @@ -7206,6 +7093,22 @@ struct { {"PAL_MIXUP",PAL_MIXUP}, {"PAL_RECYCLE",PAL_RECYCLE}, {"PAL_NUKE",PAL_NUKE}, + // for P_DamageMobj + //// Damage types + {"DMG_WATER",DMG_WATER}, + {"DMG_FIRE",DMG_FIRE}, + {"DMG_ELECTRIC",DMG_ELECTRIC}, + {"DMG_SPIKE",DMG_SPIKE}, + {"DMG_NUKE",DMG_NUKE}, + //// Death types + {"DMG_INSTAKILL",DMG_INSTAKILL}, + {"DMG_DROWNED",DMG_DROWNED}, + {"DMG_SPACEDROWN",DMG_SPACEDROWN}, + {"DMG_DEATHPIT",DMG_DEATHPIT}, + {"DMG_CRUSHED",DMG_CRUSHED}, + {"DMG_SPECTATOR",DMG_SPECTATOR}, + //// Masks + {"DMG_DEATHMASK",DMG_DEATHMASK}, // Gametypes, for use with global var "gametype" {"GT_COOP",GT_COOP}, diff --git a/src/djgppdos/i_system.c b/src/djgppdos/i_system.c index 854d68f4d..dae9ed16e 100644 --- a/src/djgppdos/i_system.c +++ b/src/djgppdos/i_system.c @@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *variable) return putenv(variable); } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + const CPUInfoFlags *I_CPUInfo(void) { static CPUInfoFlags DOS_CPUInfo; diff --git a/src/doomdef.h b/src/doomdef.h index 3f504d25f..f599b5f81 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -435,6 +435,9 @@ extern INT32 cv_debug; // Misc stuff for later... // ======================= +// Modifier key variables, accessible anywhere +extern UINT8 shiftdown, ctrldown, altdown; + // if we ever make our alloc stuff... #define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL) @@ -536,4 +539,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// \note You should leave this enabled unless you're working with a future SRB2 version. #define MUSICSLOT_COMPATIBILITY +/// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. +//#define PAPER_COLLISIONCORRECTION + #endif // __DOOMDEF__ diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index c1e48b60b..a3fe3077c 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable) return -1; } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + void I_RegisterSysCommands(void) {} #include "../sdl/dosstr.c" diff --git a/src/f_finale.c b/src/f_finale.c index 81c530e6a..78e9ada17 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -559,7 +559,7 @@ static void F_IntroDrawScene(void) if (finalecount < 4) S_StopMusic(); if (finalecount == 4) - S_ChangeMusicInternal("stjr", false); + S_ChangeMusicInternal("_stjr", false); x = (BASEVIDWIDTH<pflags |= PF_JUMPDOWN; p->playerstate = PST_LIVE; - p->health = 1; // 0 rings + p->rings = 0; // 0 rings p->panim = PA_IDLE; // standing animation if ((netgame || multiplayer) && !p->spectator) @@ -5621,7 +5622,7 @@ boolean G_CheckDemoStatus(void) 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. #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); demorecording = false; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 60183b58e..f23753ee5 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) { FOutVector v[4]; FSurfaceInfo Surf; + float sdupx, sdupy; if (w < 0 || h < 0) return; // consistency w/ software @@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) // | /| // |/ | // 0--1 - v[0].x = v[3].x = (x - 160.0f)/160.0f; - v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f; - v[0].y = v[1].y = -(y - 100.0f)/100.0f; - v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f; + sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; + sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; + + if (color & V_NOSCALESTART) + sdupx = sdupy = 2.0f; + + v[0].x = v[3].x = (x*sdupx)/vid.width - 1; + v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1; + v[0].y = v[1].y = 1-(y*sdupy)/vid.height; + v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height; //Hurdler: do we still use this argb color? if not, we should remove it v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 7dfc6f624..9e5d92e0b 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -247,27 +247,30 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_BMNE // Monitor Boxes - &lspr[NOLIGHT], // SPR_SRBX - &lspr[NOLIGHT], // SPR_RRBX - &lspr[NOLIGHT], // SPR_BRBX - &lspr[NOLIGHT], // SPR_SHTV - &lspr[NOLIGHT], // SPR_PINV - &lspr[NOLIGHT], // SPR_YLTV - &lspr[NOLIGHT], // SPR_BLTV - &lspr[NOLIGHT], // SPR_BKTV - &lspr[NOLIGHT], // SPR_WHTV - &lspr[NOLIGHT], // SPR_GRTV - &lspr[NOLIGHT], // SPR_ELTV - &lspr[NOLIGHT], // SPR_EGGB - &lspr[NOLIGHT], // SPR_MIXU - &lspr[NOLIGHT], // SPR_RECY - &lspr[NOLIGHT], // SPR_QUES - &lspr[NOLIGHT], // SPR_GBTV - &lspr[NOLIGHT], // SPR_PRUP - &lspr[NOLIGHT], // SPR_PTTV + &lspr[NOLIGHT], // SPR_MSTV + &lspr[NOLIGHT], // SPR_XLTV - // Monitor Miscellany - &lspr[NOLIGHT], // SPR_MTEX + &lspr[NOLIGHT], // SPR_TRRI + &lspr[NOLIGHT], // SPR_TBRI + + &lspr[NOLIGHT], // SPR_TVRI + &lspr[NOLIGHT], // SPR_TVPI + &lspr[NOLIGHT], // SPR_TVAT + &lspr[NOLIGHT], // SPR_TVFO + &lspr[NOLIGHT], // SPR_TVAR + &lspr[NOLIGHT], // SPR_TVWW + &lspr[NOLIGHT], // SPR_TVEL + &lspr[NOLIGHT], // SPR_TVSS + &lspr[NOLIGHT], // SPR_TVIV + &lspr[NOLIGHT], // SPR_TV1U + &lspr[NOLIGHT], // SPR_TV1P + &lspr[NOLIGHT], // SPR_TVEG + &lspr[NOLIGHT], // SPR_TVMX + &lspr[NOLIGHT], // SPR_TVMY + &lspr[NOLIGHT], // SPR_TVGV + &lspr[NOLIGHT], // SPR_TVRC + &lspr[NOLIGHT], // SPR_TV1K + &lspr[NOLIGHT], // SPR_TVTK // Projectiles &lspr[NOLIGHT], // SPR_MISL @@ -473,23 +476,6 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_GWLG &lspr[NOLIGHT], // SPR_GWLR - // SRB1 Sprites - &lspr[NOLIGHT], // SPR_SRBA - &lspr[NOLIGHT], // SPR_SRBB - &lspr[NOLIGHT], // SPR_SRBC - &lspr[NOLIGHT], // SPR_SRBD - &lspr[NOLIGHT], // SPR_SRBE - &lspr[NOLIGHT], // SPR_SRBF - &lspr[NOLIGHT], // SPR_SRBG - &lspr[NOLIGHT], // SPR_SRBH - &lspr[NOLIGHT], // SPR_SRBI - &lspr[NOLIGHT], // SPR_SRBJ - &lspr[NOLIGHT], // SPR_SRBK - &lspr[NOLIGHT], // SPR_SRBL - &lspr[NOLIGHT], // SPR_SRBM - &lspr[NOLIGHT], // SPR_SRBN - &lspr[NOLIGHT], // SPR_SRBO - // Free slots &lspr[NOLIGHT], &lspr[NOLIGHT], diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c8372aaae..270229ad0 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -45,7 +45,7 @@ #include "hw_md2.h" #define R_FAKEFLOORS -//#define HWPRECIP +#define HWPRECIP #define SORTING //#define POLYSKY @@ -4401,7 +4401,6 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) FOutVector *wv; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; - sector_t *sector; if (!spr->mobj) return; @@ -4455,19 +4454,38 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) //Hurdler: 25/04/2000: now support colormap in hardware mode HWR_GetMappedPatch(gpatch, spr->colormap); - sector = spr->mobj->subsector->sector; - - if (sector->ffloors) + // colormap test { - ffloor_t *caster = sector->lightlist[R_GetPlaneLight(sector, spr->mobj->z, false)].caster; - sector = caster ? §ors[caster->secnum] : sector; - } + sector_t *sector = spr->mobj->subsector->sector; + UINT8 lightlevel = 255; + extracolormap_t *colormap = sector->extra_colormap; - // sprite lighting by modulating the RGB components - if (sector->extra_colormap) - Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,sector->extra_colormap->rgba,sector->extra_colormap->fadergba, false, false); + if (sector->numlights) + { + INT32 light; + + light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before + + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = *sector->lightlist[light].lightlevel; + + if (sector->lightlist[light].extra_colormap) + colormap = sector->lightlist[light].extra_colormap; + } else - Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,NORMALFOG,FADEFOG, false, false); + { + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = sector->lightlevel; + + if (sector->extra_colormap) + colormap = sector->extra_colormap; + } + + if (colormap) + Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); + else + Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + } if (spr->mobj->flags2 & MF2_SHADOW) { @@ -5040,6 +5058,8 @@ static void HWR_ProjectSprite(mobj_t *thing) size_t lumpoff; unsigned rot; UINT8 flip; + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); + angle_t ang; INT32 heightsec, phs; @@ -5139,7 +5159,7 @@ static void HWR_ProjectSprite(mobj_t *thing) tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; x2 = gr_windowcenterx + (tx * gr_centerx / tz); - if (thing->eflags & MFE_VERTICALFLIP) + if (vflip) { gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; gzt = gz + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale; @@ -5216,10 +5236,7 @@ static void HWR_ProjectSprite(mobj_t *thing) //CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n", // thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]); - if (thing->eflags & MFE_VERTICALFLIP) - vis->vflip = true; - else - vis->vflip = false; + vis->vflip = vflip; vis->precip = false; } @@ -5296,6 +5313,11 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) // vis = HWR_NewVisSprite(); vis->x1 = x1; +#if 0 + vis->x2 = x2; +#else + (void)x2; +#endif vis->x2 = tx; vis->tz = tz; vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST @@ -5308,7 +5330,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) // set top/bottom coords vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz; - vis->sectorlight = 0xff; vis->precip = true; } #endif diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index fa4699810..7edf02db0 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename) model->header.numSkins = 1; +#define MD2LIMITCHECK(field, max, msgname) \ + if (field > max) \ + { \ + CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \ + md2_freeModel (model); \ + return 0; \ + } + + // Uncomment if these are actually needed +// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins") +// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates") + MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles") + MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames") + MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices") + +#undef MD2LIMITCHECK + // read skins fseek(file, model->header.offsetSkins, SEEK_SET); if (model->header.numSkins > 0) @@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename) md2_freeModel (model); return 0; } - - ; } // read texture coordinates @@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename) md2_freeModel (model); return 0; } - - } // read triangles @@ -769,6 +782,7 @@ void HWR_InitMD2(void) md2_playermodels[s].grpatch = NULL; md2_playermodels[s].skin = -1; md2_playermodels[s].notfound = true; + md2_playermodels[s].error = false; } for (i = 0; i < NUMSPRITES; i++) { @@ -777,6 +791,7 @@ void HWR_InitMD2(void) md2_models[i].grpatch = NULL; md2_models[i].skin = -1; md2_models[i].notfound = true; + md2_models[i].error = false; } // read the md2.dat file @@ -1349,7 +1364,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) UINT32 durs = spr->mobj->state->tics; UINT32 tics = spr->mobj->tics; md2_frame_t *curr, *next = NULL; - const UINT8 flip = (UINT8)((spr->mobj->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP); + const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP)); spritedef_t *sprdef; spriteframe_t *sprframe; float finalscale; @@ -1378,6 +1393,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr) else md2 = &md2_models[spr->mobj->sprite]; + if (md2->error) + return; // we already failed loading this before :( if (!md2->model) { //CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]); @@ -1391,6 +1408,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) else { //CONS_Debug(DBG_RENDER, " FAILED\n"); + md2->error = true; // prevent endless fail return; } } @@ -1464,7 +1482,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) p.x = FIXED_TO_FLOAT(spr->mobj->x); p.y = FIXED_TO_FLOAT(spr->mobj->y)+md2->offset; - if (spr->mobj->eflags & MFE_VERTICALFLIP) + if (flip) p.z = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height); else p.z = FIXED_TO_FLOAT(spr->mobj->z); diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 36078268b..5a7e6d2b3 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -123,6 +123,7 @@ typedef struct void *blendgrpatch; boolean notfound; INT32 skin; + boolean error; } md2_t; extern md2_t md2_models[NUMSPRITES]; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index ec747305e..5878bbf5e 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -757,15 +757,8 @@ void HU_clearChatChars(void) // boolean HU_Responder(event_t *ev) { - static boolean shiftdown = false; UINT8 c; - if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT) - { - shiftdown = (ev->type == ev_keydown); - return chat_on; - } - if (ev->type != ev_keydown) return false; @@ -1198,7 +1191,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I V_DrawString(x + 20, y, ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | ((players[tab[i].num].health > 0) ? 0 : V_60TRANS) + | ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS) | V_ALLOWLOWERCASE, tab[i].name); // Draw emeralds @@ -1208,7 +1201,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I HU_DrawEmeralds(x-12,y+2,tab[i].emeralds); } - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentPatch (x, y-4, V_80TRANS, livesback); else V_DrawSmallScaledPatch (x, y-4, 0, livesback); @@ -1220,7 +1213,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I V_DrawSmallScaledPatch(x, y-4, 0, superprefix[players[tab[i].num].skin]); else { - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentPatch(x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin]); else V_DrawSmallScaledPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin]); @@ -1236,7 +1229,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentMappedPatch (x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin], colormap); else V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); @@ -1244,10 +1237,10 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } if (G_GametypeUsesLives()) //show lives - V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%dx", players[tab[i].num].lives)); + V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) { - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentPatch(x-32, y-4, V_60TRANS, tagico); else V_DrawSmallScaledPatch(x-32, y-4, 0, tagico); @@ -1260,13 +1253,13 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (players[tab[i].num].exiting) V_DrawRightAlignedString(x+240, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); else - V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count)); + V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count)); } else - V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); + V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); } else - V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count)); + V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count)); y += 16; } @@ -1311,7 +1304,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) strlcpy(name, tab[i].name, 9); V_DrawString(x + 20, y, ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT) + | ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT) | V_ALLOWLOWERCASE, name); if (gametype == GT_CTF) @@ -1337,12 +1330,12 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); else V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); } - V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); } } @@ -1367,7 +1360,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline strlcpy(name, tab[i].name, 9); V_DrawString(x + 20, y, ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT) + | ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT) | V_ALLOWLOWERCASE, name); if (G_GametypeUsesLives()) //show lives @@ -1390,7 +1383,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline V_DrawSmallScaledPatch (x, y-4, 0, superprefix[players[tab[i].num].skin]); else { - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]); else V_DrawSmallScaledPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]); @@ -1406,7 +1399,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - if (players[tab[i].num].health <= 0) + if (players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) V_DrawSmallTranslucentMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); else V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); @@ -1421,13 +1414,13 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline if (players[tab[i].num].exiting) V_DrawRightAlignedThinString(x+156, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); else - V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); } else - V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); + V_DrawRightAlignedThinString(x+156, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); } else - V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+120, y, ((players[tab[i].num].mo && players[tab[i].num].mo->health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); y += 16; if (y > 160) diff --git a/src/i_system.h b/src/i_system.h index c161851e0..d61f2d16e 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -296,6 +296,14 @@ char *I_GetEnv(const char *name); INT32 I_PutEnv(char *variable); +/** \brief Put data in system clipboard +*/ +INT32 I_ClipboardCopy(const char *data, size_t size); + +/** \brief Retrieve data from system clipboard +*/ +const char *I_ClipboardPaste(void); + void I_RegisterSysCommands(void); #endif diff --git a/src/info.c b/src/info.c index ed5de0125..d9567b37f 100644 --- a/src/info.c +++ b/src/info.c @@ -25,35 +25,343 @@ #endif // Hey, moron! If you change this table, don't forget about the sprite enum in info.h and the sprite lights in hw_light.c! +// For the sake of constant merge conflicts, let's spread this out char sprnames[NUMSPRITES + 1][5] = { - "NULL","UNKN","THOK","PLAY","POSS","SPOS","FISH","BUZZ","RBUZ","JETB", - "JETW","JETG","CCOM","DETN","SKIM","TRET","TURR","SHRP","JJAW","SNLR", - "VLTR","PNTY","ARCH","CBFS","SPSH","ESHI","GSNP","MNUS","SSHL","UNID", - "BBUZ","JETF","EGGM","EGGN","TNKA","TNKB","SPNK","GOOP","EGGO","PRPL", - "FAKE","EGGP","EFIR","EGGQ","EGGR","BRAK","BGOO","BMSL","EGGT","RCKT", - "ELEC","TARG","NPLM","MNPL","METL","MSCF","MSCB","RING","TRNG","EMMY", - "TOKE","RFLG","BFLG","NWNG","EMBM","CEMG","EMER","FANS","BBLS","SIGN", - "STEM","SPIK","SFLM","USPK","STPT","BMNE","SRBX","RRBX","BRBX","SHTV", - "PINV","YLTV","BLTV","BKTV","WHTV","GRTV","ELTV","EGGB","MIXU","RECY", - "QUES","GBTV","PRUP","PTTV","MTEX","MISL","TORP","ENRG","MINE","JBUL", - "TRLS","CBLL","AROW","CFIR","FWR1","FWR2","FWR3","FWR4","BUS1","BUS2", - "THZP","ALRM","GARG","SEWE","DRIP","CRL1","CRL2","CRL3","BCRY","CHAN", - "FLAM","ESTA","SMCH","BMCH","SMCE","BMCE","BTBL","STBL","CACT","FLME", - "DFLM","XMS1","XMS2","XMS3","BSZ1","BSZ2","BSZ3","BSZ4","BSZ5","BSZ6", - "BSZ7","BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN", - "ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC", - "COWZ","RBRD","SPRY","SPRR","SPRB","YSPR","RSPR","SSWY","SSWR","SSWB", - "RAIN","SNO1","SPLH","SPLA","SMOK","BUBL","WZAP","TFOG","SEED","PRTL", - "SCOR","DRWN","TTAG","GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE", - "RNGS","RNGG","PIKB","PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE", - "TSCR","COIN","CPRK","GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM", - "KOOP","BFLM","MAXE","MUS1","MUS2","TOAD","NDRN","NSPK","NBMP","HOOP", - "NSCR","NPRU","CAPS","SPRK","BOM1","BOM2","BOM3","BOM4","ROIA","ROIB", - "ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII","ROIJ","ROIK","ROIL", - "ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR","SRBA","SRBB","SRBC", - "SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK","SRBL","SRBM", - "SRBN","SRBO", + "NULL", // invisible object + "UNKN", + + "THOK", // Thok! mobj + "PLAY", + + // Enemies + "POSS", + "SPOS", + "FISH", // Greenflower Fish + "BUZZ", // Buzz (Gold) + "RBUZ", // Buzz (Red) + "JETB", // Jetty-Syn Bomber + "JETW", // Jetty-Syn Water Bomber + "JETG", // Jetty-Syn Gunner + "CCOM", // Crawla Commander + "DETN", // Deton + "SKIM", // Skim mine dropper + "TRET", + "TURR", // Pop-Up Turret + "SHRP", // Sharp + "JJAW", // Jet Jaw + "SNLR", // Snailer + "VLTR", // Vulture + "PNTY", // Pointy + "ARCH", // Robo-Hood + "CBFS", // CastleBot FaceStabber (Egg Knight?) + "SPSH", // Egg Guard + "ESHI", // Egg Shield for Egg Guard + "GSNP", // Green Snapper + "MNUS", // Minus + "SSHL", // Spring Shell + "UNID", // Unidus + "BBUZ", // AquaBuzz, for Azure Temple + + // Generic Boss Items + "JETF", // Boss jet fumes + + // Boss 1 (Greenflower) + "EGGM", + + // Boss 2 (Techno Hill) + "EGGN", // Boss 2 + "TNKA", // Boss 2 Tank 1 + "TNKB", // Boss 2 Tank 2 + "SPNK", // Boss 2 Spigot + "GOOP", // Boss 2 Goop + + // Boss 3 (Deep Sea) + "EGGO", // Boss 3 + "PRPL", // Boss 3 Propeller + "FAKE", // Boss 3 Fakemobile + + // Boss 4 (Castle Eggman) + "EGGP", + "EFIR", // Boss 4 jet flame + + // Boss 5 (Arid Canyon) + "EGGQ", + + // Boss 6 (Red Volcano) + "EGGR", + + // Boss 7 (Dark City) + "BRAK", + "BGOO", // Goop + "BMSL", + + // Boss 8 (Egg Rock) + "EGGT", + + // Cy-Brak-Demon; uses "BRAK" as well, but has some extras + "RCKT", // Rockets! + "ELEC", // Electricity! + "TARG", // Targeting reticules! + "NPLM", // Big napalm bombs! + "MNPL", // Mini napalm bombs! + + // Metal Sonic + "METL", + "MSCF", + "MSCB", + + // Collectible Items + "RING", + "TRNG", // Team Rings + "EMMY", // emerald test + "TOKE", // Special Stage Token + "RFLG", // Red CTF Flag + "BFLG", // Blue CTF Flag + "NWNG", // NiGHTS Wing collectable item. + "EMBM", // Emblem + "CEMG", // Chaos Emeralds + "EMER", // Emerald Hunt + + // Interactive Objects + "FANS", + "BBLS", // water bubble source + "SIGN", // Level end sign + "STEM", // Steam riser + "SPIK", // Spike Ball + "SFLM", // Spin fire + "USPK", // Floor spike + "STPT", // Starpost + "BMNE", // Big floating mine + + // Monitor Boxes + "MSTV", // MiSc TV sprites + "XLTV", // eXtra Large TV sprites + + "TRRI", // Red team: 10 RIngs + "TBRI", // Blue team: 10 RIngs + + "TVRI", // 10 RIng + "TVPI", // PIty shield + "TVAT", // ATtraction shield + "TVFO", // FOrce shield + "TVAR", // ARmageddon shield + "TVWW", // WhirlWind shield + "TVEL", // ELemental shield + "TVSS", // Super Sneakers + "TVIV", // InVincibility + "TV1U", // 1Up + "TV1P", // 1uP (textless) + "TVEG", // EGgman + "TVMX", // MiXup + "TVMY", // MYstery + "TVGV", // GraVity boots + "TVRC", // ReCycler + "TV1K", // 1,000 points (1 K) + "TVTK", // 10,000 points (Ten K) + + // Projectiles + "MISL", + "TORP", // Torpedo + "ENRG", // Energy ball + "MINE", // Skim mine + "JBUL", // Jetty-Syn Bullet + "TRLS", + "CBLL", // Cannonball + "AROW", // Arrow + "CFIR", // Colored fire of various sorts + + // Greenflower Scenery + "FWR1", + "FWR2", // GFZ Sunflower + "FWR3", // GFZ budding flower + "FWR4", + "BUS1", // GFZ Bush w/ berries + "BUS2", // GFZ Bush w/o berries + + // Techno Hill Scenery + "THZP", // Techno Hill Zone Plant + "ALRM", // THZ2 Alarm + + // Deep Sea Scenery + "GARG", // Deep Sea Gargoyle + "SEWE", // Deep Sea Seaweed + "DRIP", // Dripping water + "CRL1", // Coral 1 + "CRL2", // Coral 2 + "CRL3", // Coral 3 + "BCRY", // Blue Crystal + + // Castle Eggman Scenery + "CHAN", // CEZ Chain + "FLAM", // Flame + "ESTA", // Eggman esta una estatua! + "SMCH", // Small Mace Chain + "BMCH", // Big Mace Chain + "SMCE", // Small Mace + "BMCE", // Big Mace + + // Arid Canyon Scenery + "BTBL", // Big tumbleweed + "STBL", // Small tumbleweed + "CACT", // Cacti sprites + + // Red Volcano Scenery + "FLME", // Flame jet + "DFLM", // Blade's flame + + // Dark City Scenery + + // Egg Rock Scenery + + // Christmas Scenery + "XMS1", + "XMS2", + "XMS3", + + // Botanic Serenity Scenery + "BSZ1", // Tall flowers + "BSZ2", // Medium flowers + "BSZ3", // Small flowers + "BSZ4", // Tulip + "BSZ5", // Cluster of Tulips + "BSZ6", // Bush + "BSZ7", // Vine + "BSZ8", // Misc things + + // Misc Scenery + "STLG", // Stalagmites + "DBAL", // Disco + "RCRY", // ATZ Red Crystal (Target) + + // Powerup Indicators + "ARMA", // Armageddon Shield Orb + "ARMF", // Armageddon Shield Ring, Front + "ARMB", // Armageddon Shield Ring, Back + "WIND", // Whirlwind Shield Orb + "MAGN", // Attract Shield Orb + "ELEM", // Elemental Shield Orb and Fire + "FORC", // Force Shield Orb + "PITY", // Pity Shield Orb + "IVSP", // invincibility sparkles + "SSPK", // Super Sonic Spark + + "GOAL", // Special Stage goal (here because lol NiGHTS) + + // Freed Animals + "BIRD", // Birdie freed! + "BUNY", // Bunny freed! + "MOUS", // Mouse + "CHIC", // Chicken + "COWZ", // Cow + "RBRD", // Red Birdie in Bubble + + // Springs + "SPRY", // yellow spring + "SPRR", // red spring + "SPRB", // Blue springs + "YSPR", // Yellow Diagonal Spring + "RSPR", // Red Diagonal Spring + "SSWY", // Yellow Side Spring + "SSWR", // Red Side Spring + "SSWB", // Blue Side Spring + + // Environmental Effects + "RAIN", // Rain + "SNO1", // Snowflake + "SPLH", // Water Splish + "SPLA", // Water Splash + "SMOK", + "BUBL", // Bubble + "WZAP", + "TFOG", // Teleport Fog + "SEED", // Sonic CD flower seed + "PRTL", // Particle (for fans, etc.) + + // Game Indicators + "SCOR", // Score logo + "DRWN", // Drowning Timer + "TTAG", // Tag Sign + "GFLG", // Got Flag sign + + // Ring Weapons + "RRNG", // Red Ring + "RNGB", // Bounce Ring + "RNGR", // Rail Ring + "RNGI", // Infinity Ring + "RNGA", // Automatic Ring + "RNGE", // Explosion Ring + "RNGS", // Scatter Ring + "RNGG", // Grenade Ring + + "PIKB", // Bounce Ring Pickup + "PIKR", // Rail Ring Pickup + "PIKA", // Automatic Ring Pickup + "PIKE", // Explosion Ring Pickup + "PIKS", // Scatter Ring Pickup + "PIKG", // Grenade Ring Pickup + + "TAUT", // Thrown Automatic Ring + "TGRE", // Thrown Grenade Ring + "TSCR", // Thrown Scatter Ring + + // Mario-specific stuff + "COIN", + "CPRK", + "GOOM", + "BGOM", + "FFWR", + "FBLL", + "SHLL", + "PUMA", + "HAMM", + "KOOP", + "BFLM", + "MAXE", + "MUS1", + "MUS2", + "TOAD", + + // NiGHTS Stuff + "NDRN", // NiGHTS drone + "NSPK", // NiGHTS sparkle + "NBMP", // NiGHTS Bumper + "HOOP", // NiGHTS hoop sprite + "NSCR", // NiGHTS score sprite + "NPRU", // Nights Powerups + "CAPS", // Capsule thingy for NiGHTS + + // Debris + "SPRK", // spark + "BOM1", // Robot Explosion + "BOM2", // Boss Explosion 1 + "BOM3", // Boss Explosion 2 + "BOM4", // Underwater Explosion + + // Crumbly rocks + "ROIA", + "ROIB", + "ROIC", + "ROID", + "ROIE", + "ROIF", + "ROIG", + "ROIH", + "ROII", + "ROIJ", + "ROIK", + "ROIL", + "ROIM", + "ROIN", + "ROIO", + "ROIP", + + // Blue Spheres + "BBAL", + + // Gravity Well Objects + "GWLG", + "GWLR", }; char spr2names[NUMPLAYERSPRITES][5] = @@ -149,8 +457,8 @@ enum playersprite free_spr2 = SPR2_FIRSTFREESLOT; state_t states[NUMSTATES] = { // frame is masked through FF_FRAMEMASK - // FF_ANIMATE (0x4000) makes simple state animations (var1 #frames, var2 tic delay) - // FF_FULLBRIGHT (0x8000) activates the fullbright colormap + // FF_ANIMATE makes simple state animations (var1 #frames, var2 tic delay) + // FF_FULLBRIGHT activates the fullbright colormap // use FF_TRANS10 - FF_TRANS90 for easy translucency // (or tr_trans10<skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes > 0))); + return 1; +} + static int lib_pSpawnMissile(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -618,6 +631,17 @@ static int lib_pAddPlayerScore(lua_State *L) return 0; } +static int lib_pStealPlayerScore(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + UINT32 amount = (UINT32)luaL_checkinteger(L, 2); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + P_StealPlayerScore(player, amount); + return 0; +} + static int lib_pPlayerInPain(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -1132,7 +1156,7 @@ static int lib_pPlayerRingBurst(lua_State *L) if (!player) return LUA_ErrInvalid(L, "player_t"); if (num_rings == -1) - num_rings = player->health - 1; + num_rings = player->rings; P_PlayerRingBurst(player, num_rings); return 0; } @@ -1157,6 +1181,16 @@ static int lib_pPlayerWeaponAmmoBurst(lua_State *L) return 0; } +static int lib_pPlayerWeaponPanelOrAmmoBurst(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + P_PlayerWeaponPanelOrAmmoBurst(player); + return 0; +} + static int lib_pPlayerEmeraldBurst(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -1264,6 +1298,16 @@ static int lib_pDoNightsScore(lua_State *L) return 0; } +static int lib_pDoMatchSuper(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + P_DoMatchSuper(player); + return 0; +} + // P_SPEC //////////// @@ -2005,6 +2049,7 @@ static luaL_Reg lib[] = { // don't add P_SetMobjState or P_SetPlayerMobjState, use "mobj.state = S_NEWSTATE" instead. {"P_SpawnMobj",lib_pSpawnMobj}, {"P_RemoveMobj",lib_pRemoveMobj}, + {"P_IsValidSprite2", lib_pIsValidSprite2}, {"P_SpawnMissile",lib_pSpawnMissile}, {"P_SpawnXYZMissile",lib_pSpawnXYZMissile}, {"P_SpawnPointMissile",lib_pSpawnPointMissile}, @@ -2031,6 +2076,7 @@ static luaL_Reg lib[] = { {"P_GetPlayerSpinHeight",lib_pGetPlayerSpinHeight}, {"P_GetPlayerControlDirection",lib_pGetPlayerControlDirection}, {"P_AddPlayerScore",lib_pAddPlayerScore}, + {"P_StealPlayerScore",lib_pStealPlayerScore}, {"P_PlayerInPain",lib_pPlayerInPain}, {"P_DoPlayerPain",lib_pDoPlayerPain}, {"P_ResetPlayer",lib_pResetPlayer}, @@ -2081,6 +2127,7 @@ static luaL_Reg lib[] = { {"P_PlayerRingBurst",lib_pPlayerRingBurst}, {"P_PlayerWeaponPanelBurst",lib_pPlayerWeaponPanelBurst}, {"P_PlayerWeaponAmmoBurst",lib_pPlayerWeaponAmmoBurst}, + {"P_PlayerWeaponPanelOrAmmoBurst", lib_pPlayerWeaponPanelOrAmmoBurst}, {"P_PlayerEmeraldBurst",lib_pPlayerEmeraldBurst}, {"P_PlayerFlagBurst",lib_pPlayerFlagBurst}, {"P_PlayRinglossSound",lib_pPlayRinglossSound}, @@ -2089,6 +2136,7 @@ static luaL_Reg lib[] = { {"P_PlayLivesJingle",lib_pPlayLivesJingle}, {"P_CanPickupItem",lib_pCanPickupItem}, {"P_DoNightsScore",lib_pDoNightsScore}, + {"P_DoMatchSuper",lib_pDoMatchSuper}, // p_spec {"P_Thrust",lib_pThrust}, diff --git a/src/lua_hook.h b/src/lua_hook.h index bed32edac..97d447d2e 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -62,9 +62,9 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_Touch #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 #define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type -UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Should mobj take damage?) -boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) -boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source); // Hook for P_KillMobj by mobj type +UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Should mobj take damage?) +boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) +boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for P_KillMobj by mobj type #define LUAh_BossDeath(mo) LUAh_MobjHook(mo, hook_BossDeath) // Hook for A_BossDeath by mobj type #define LUAh_MobjRemoved(mo) LUAh_MobjHook(mo, hook_MobjRemoved) // Hook for P_RemoveMobj by mobj type #define LUAh_JumpSpecial(player) LUAh_PlayerHook(player, hook_JumpSpecial) // Hook for P_DoJumpStuff (Any-jumping) @@ -75,7 +75,7 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages -boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages +boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for hurt messages #define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 1b9652571..e95b75eda 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -412,7 +412,7 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) } // Hook for P_DamageMobj by mobj type (Should mobj take damage?) -UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) +UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. @@ -431,14 +431,16 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -460,7 +462,7 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 } // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) -boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) +boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { hook_p hookp; boolean hooked = false; @@ -479,14 +481,16 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -503,7 +507,7 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 } // Hook for P_KillMobj by mobj type -boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) +boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) { hook_p hookp; boolean hooked = false; @@ -521,13 +525,15 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 0)) { + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -729,7 +735,7 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) } // Hook for hurt messages -boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source) +boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) { hook_p hookp; boolean hooked = false; @@ -747,13 +753,15 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source) LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 0)) { + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 7aadd9c0e..60cbbe501 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -369,6 +369,8 @@ static int libd_drawScaled(lua_State *L) x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); scale = luaL_checkinteger(L, 3); + if (scale < 0) + return luaL_error(L, "negative scale"); patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH)); flags = luaL_optinteger(L, 5, 0); if (!lua_isnoneornil(L, 6)) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 6bb1388fc..9ebc38a61 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -34,6 +34,7 @@ enum mobj_e { mobj_angle, mobj_sprite, mobj_frame, + mobj_sprite2, mobj_anim_duration, mobj_touching_sectorlist, mobj_subsector, @@ -93,6 +94,7 @@ static const char *const mobj_opt[] = { "angle", "sprite", "frame", + "sprite2", "anim_duration", "touching_sectorlist", "subsector", @@ -189,6 +191,9 @@ static int mobj_get(lua_State *L) case mobj_frame: lua_pushinteger(L, mo->frame); break; + case mobj_sprite2: + lua_pushinteger(L, mo->sprite2); + break; case mobj_anim_duration: lua_pushinteger(L, mo->anim_duration); break; @@ -411,6 +416,9 @@ static int mobj_set(lua_State *L) case mobj_frame: mo->frame = (UINT32)luaL_checkinteger(L, 3); break; + case mobj_sprite2: + mo->sprite2 = P_GetMobjSprite2(mo, (UINT8)luaL_checkinteger(L, 3)); + break; case mobj_anim_duration: mo->anim_duration = (UINT16)luaL_checkinteger(L, 3); break; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index d3e01a430..29f1c6ff0 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -122,8 +122,8 @@ static int player_get(lua_State *L) lua_pushfixed(L, plr->bob); else if (fastcmp(field,"aiming")) lua_pushangle(L, plr->aiming); - else if (fastcmp(field,"health")) - lua_pushinteger(L, plr->health); + else if (fastcmp(field,"rings")) + lua_pushinteger(L, plr->rings); else if (fastcmp(field,"pity")) lua_pushinteger(L, plr->pity); else if (fastcmp(field,"currentweapon")) @@ -382,8 +382,8 @@ static int player_set(lua_State *L) else if (plr == &players[secondarydisplayplayer]) localaiming2 = plr->aiming; } - else if (fastcmp(field,"health")) - plr->health = (INT32)luaL_checkinteger(L, 3); + else if (fastcmp(field,"rings")) + plr->rings = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"pity")) plr->pity = (SINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"currentweapon")) diff --git a/src/m_cheat.c b/src/m_cheat.c index 1c5f835cb..ce9519799 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -452,7 +452,7 @@ void Command_RTeleport_f(void) else inty = 0; - ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); + ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) { CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); @@ -606,7 +606,7 @@ void Command_CauseCfail_f(void) players[consoleplayer].mo->y = 123311; //cfail cansuled kthxbye players[consoleplayer].mo->z = 123311; players[consoleplayer].score = 1337; - players[consoleplayer].health = 1337; + players[consoleplayer].rings = 1337; players[consoleplayer].mo->destscale = 25; P_SetThingPosition(players[consoleplayer].mo); @@ -720,7 +720,7 @@ void Command_Setrings_f(void) if (COM_Argc() > 1) { // P_GivePlayerRings does value clamping - players[consoleplayer].health = players[consoleplayer].mo->health = 1; + players[consoleplayer].rings = 0; P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1))); if (!G_IsSpecialStage(gamemap) || !useNightsSS) players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings @@ -1054,7 +1054,7 @@ void OP_NightsObjectplace(player_t *player) if (!OP_HeightOkay(player, false)) return; - if (player->mo->target->flags & MF_AMBUSH) + if (player->mo->target->flags2 & MF2_AMBUSH) angle = (UINT16)player->anotherflyangle; else { @@ -1165,19 +1165,20 @@ void OP_ObjectplaceMovement(player_t *player) if (player->pflags & PF_ATTACKDOWN) { // Are ANY objectplace buttons pressed? If no, remove flag. - if (!(cmd->buttons & (BT_ATTACK|BT_TOSSFLAG|BT_CAMRIGHT|BT_CAMLEFT))) + if (!(cmd->buttons & (BT_ATTACK|BT_TOSSFLAG|BT_WEAPONNEXT|BT_WEAPONPREV))) player->pflags &= ~PF_ATTACKDOWN; // Do nothing. return; } - if (cmd->buttons & BT_CAMLEFT) + if (cmd->buttons & BT_WEAPONPREV) { OP_CycleThings(-1); player->pflags |= PF_ATTACKDOWN; } - else if (cmd->buttons & BT_CAMRIGHT) + + if (cmd->buttons & BT_WEAPONNEXT) { OP_CycleThings(1); player->pflags |= PF_ATTACKDOWN; @@ -1264,10 +1265,10 @@ void Command_ObjectPlace_f(void) HU_DoCEcho(va(M_GetText( "\\\\\\\\\\\\\\\\\\\\\\\\\x82" " Objectplace Controls: \x80\\\\" - "Camera L/R: Cycle mapthings\\" - " Jump: Float up \\" - " Spin: Float down \\" - " Fire Ring: Place object \\"))); + "Weapon Next/Prev: Cycle mapthings\\" + " Jump: Float up \\" + " Spin: Float down \\" + " Fire Ring: Place object \\"))); } // Save all the player's data. @@ -1297,7 +1298,7 @@ void Command_ObjectPlace_f(void) // Like the classics, recover from death by entering objectplace if (players[0].mo->health <= 0) { - players[0].mo->health = players[0].health = 1; + players[0].mo->health = 1; players[0].deadtimer = 0; op_oldflags1 = mobjinfo[MT_PLAYER].flags; ++players[0].lives; diff --git a/src/m_cond.c b/src/m_cond.c index 3933815e5..5e23d4080 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -565,7 +565,7 @@ extraemblem_t extraemblems[MAXEXTRAEMBLEMS] = {"Game Complete", "Complete 1P Mode", 10, 'X', SKINCOLOR_BLUE, 0}, {"All Emeralds", "Complete 1P Mode with all Emeralds", 11, 'V', SKINCOLOR_GREY, 0}, {"Perfect Bonus", "Perfect Bonus on a non-secret stage", 30, 'P', SKINCOLOR_GOLD, 0}, - {"SRB1 Remake", "Complete SRB1 Remake", 21, 'O', SKINCOLOR_RUST, 0}, + {"PLACEHOLDER", "PLACEHOLDER", 0, 'O', SKINCOLOR_RUST, 0}, {"NiGHTS Mastery", "Show your mastery of NiGHTS!", 22, 'W', SKINCOLOR_TEAL, 0}, }; @@ -586,9 +586,9 @@ unlockable_t unlockables[MAXUNLOCKABLES] = /* 08 */ {"BONUS LEVELS", "", 100, 0, SECRET_HEADER, 0, true, true, 0}, - /* 09 */ {"SRB1 Remake", "Collect 20 Emblems", 130, 40, SECRET_WARP, 101, false, false, 0}, + /* 09 */ {"PLACEHOLDER", "PLACEHOLDER", 0, 0, SECRET_NONE, 0, true, true, 0}, /* 10 */ {"Mario Koopa Blast", "Collect 60 Emblems", 110, 42, SECRET_WARP, 30, false, false, 0}, - /* 11 */ {"SRB1 Level Select", "Complete SRB1 Remake", 140, 21, SECRET_LEVELSELECT, 2, false, true, 0}, + /* 11 */ {"PLACEHOLDER", "PLACEHOLDER", 0, 0, SECRET_NONE, 0, true, true, 0}, /* 12 */ {"Spring Hill Zone", "Collect 100 Emblems", 0, 44, SECRET_NONE, 0, false, false, 0}, /* 13 */ {"Black Hole", "A Rank in all Special Stages", 0, 50, SECRET_NONE, 0, false, true, 0}, @@ -624,9 +624,6 @@ void M_SetupDefaultConditionSets(void) // -- 20: Beat AGZ M_AddRawCondition(20, 1, UC_MAPBEATEN, 40, 0, 0); - // -- 21: Beat SRB1 Remake - M_AddRawCondition(21, 1, UC_MAPBEATEN, 132, 0, 0); - // -- 22: Beat Black Hole M_AddRawCondition(22, 1, UC_MAPBEATEN, 57, 0, 0); diff --git a/src/m_menu.c b/src/m_menu.c index d2c730504..f682cd1b5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -183,9 +183,6 @@ static INT32 vidm_selected = 0; static INT32 vidm_nummodes; static INT32 vidm_column_size; -// what a headache. -static boolean shiftdown = false; - // // PROTOTYPES // @@ -2083,11 +2080,6 @@ boolean M_Responder(event_t *ev) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) return false; - if (ev->type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)) - { - shiftdown = false; - return false; - } if (noFurtherInput) { // Ignore input after enter/escape/other buttons @@ -2101,10 +2093,6 @@ boolean M_Responder(event_t *ev) // added 5-2-98 remap virtual keys (mouse & joystick buttons) switch (ch) { - case KEY_LSHIFT: - case KEY_RSHIFT: - shiftdown = true; - break; //return false; case KEY_MOUSE1: case KEY_JOY1: case KEY_JOY1 + 2: @@ -3831,7 +3819,7 @@ static void M_HandleImageDef(INT32 choice) static void M_PandorasBox(INT32 choice) { (void)choice; - CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].health - 1, 0)); + CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0)); CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives); CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues); M_SetupNextMenu(&SR_PandoraDef); @@ -3839,7 +3827,7 @@ static void M_PandorasBox(INT32 choice) static boolean M_ExitPandorasBox(void) { - if (cv_dummyrings.value != max(players[consoleplayer].health - 1, 0)) + if (cv_dummyrings.value != max(players[consoleplayer].rings, 0)) COM_ImmedExecute(va("setrings %d", cv_dummyrings.value)); if (cv_dummylives.value != players[consoleplayer].lives) COM_ImmedExecute(va("setlives %d", cv_dummylives.value)); @@ -4836,7 +4824,7 @@ static void M_SetupChoosePlayer(INT32 choice) if (Playing() == false) { S_StopMusic(); - S_ChangeMusicInternal("chrsel", true); + S_ChangeMusicInternal("_chsel", true); } SP_PlayerDef.prevMenu = currentMenu; @@ -5271,7 +5259,7 @@ void M_DrawTimeAttackMenu(void) lumpnum_t lumpnum; char beststr[40]; - S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback + S_ChangeMusicInternal("_inter", true); // Eww, but needed for when user hits escape during demo playback V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); @@ -5434,7 +5422,7 @@ static void M_TimeAttack(INT32 choice) itemOn = tastart; // "Start" is selected. G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusicInternal("racent", true); + S_ChangeMusicInternal("_inter", true); } // Drawing function for Nights Attack @@ -5444,7 +5432,7 @@ void M_DrawNightsAttackMenu(void) lumpnum_t lumpnum; char beststr[40]; - S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback + S_ChangeMusicInternal("_inter", true); // Eww, but needed for when user hits escape during demo playback V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); @@ -5567,7 +5555,7 @@ static void M_NightsAttack(INT32 choice) itemOn = nastart; // "Start" is selected. G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusicInternal("racent", true); + S_ChangeMusicInternal("_inter", true); } // Player has selected the "START" from the nights attack screen @@ -5801,7 +5789,7 @@ static void M_ModeAttackEndGame(INT32 choice) itemOn = currentMenu->lastOn; G_SetGamestate(GS_TIMEATTACK); modeattacking = ATTACKING_NONE; - S_ChangeMusicInternal("racent", true); + S_ChangeMusicInternal("_inter", true); // Update replay availability. CV_AddValue(&cv_nextmap, 1); CV_AddValue(&cv_nextmap, -1); @@ -7016,7 +7004,7 @@ static void M_ToggleDigital(void) if (nodigimusic) return; S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); S_StopMusic(); - S_ChangeMusicInternal("lclear", false); + S_ChangeMusicInternal("_clear", false); M_StartMessage(M_GetText("Digital Music Enabled\n"), NULL, MM_NOTHING); } else @@ -7043,7 +7031,7 @@ static void M_ToggleMIDI(void) I_InitMIDIMusic(); if (nomidimusic) return; S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); - S_ChangeMusicInternal("lclear", false); + S_ChangeMusicInternal("_clear", false); M_StartMessage(M_GetText("MIDI Music Enabled\n"), NULL, MM_NOTHING); } else diff --git a/src/m_misc.c b/src/m_misc.c index 457214e33..cfe73d88f 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString) || stringToUse[startPos] == '\r' || stringToUse[startPos] == '\n' || stringToUse[startPos] == '\0' + || stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason || inComment != 0) && startPos < stringLength) { @@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString) && stringToUse[endPos] != ',' && stringToUse[endPos] != '{' && stringToUse[endPos] != '}' + && stringToUse[endPos] != '"' // see above && inComment == 0) && endPos < stringLength) { diff --git a/src/nds/i_system.c b/src/nds/i_system.c index 0ed58029c..3e5c4b8c6 100644 --- a/src/nds/i_system.c +++ b/src/nds/i_system.c @@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable) return -1; } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + void I_RegisterSysCommands(void) {} #include "../sdl/dosstr.c" diff --git a/src/p_enemy.c b/src/p_enemy.c index 24fa8ce6b..9bc487baa 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -86,6 +86,9 @@ void A_Scream(mobj_t *actor); void A_Pain(mobj_t *actor); void A_1upThinker(mobj_t *actor); void A_MonitorPop(mobj_t *actor); +void A_GoldMonitorPop(mobj_t *actor); +void A_GoldMonitorRestore(mobj_t *actor); +void A_GoldMonitorSparkle(mobj_t *actor); void A_Explode(mobj_t *actor); void A_BossDeath(mobj_t *actor); void A_CustomPower(mobj_t *actor); @@ -655,15 +658,15 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed if ((netgame || multiplayer) && player->spectator) continue; - if (player->health <= 0) - continue; // dead - if (player->pflags & PF_INVIS) continue; // ignore notarget if (!player->mo || P_MobjWasRemoved(player->mo)) continue; + if (player->mo->health <= 0) + continue; // dead + if (dist > 0 && P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist) continue; // Too far away @@ -727,7 +730,7 @@ static boolean P_LookForShield(mobj_t *actor) player = &players[actor->lastlook]; - if (player->health <= 0 || !player->mo) + if (!player->mo || player->mo->health <= 0) continue; // dead //When in CTF, don't pull rings that you cannot pick up. @@ -818,6 +821,32 @@ static int P_RecycleCompare(const void *p1, const void *p2) } #endif +// Handles random monitor weights via console. +static mobjtype_t P_DoRandomBoxChances(void) +{ + mobjtype_t spawnchance[256]; + INT32 numchoices = 0, i = 0; + +#define QUESTIONBOXCHANCES(type, cvar) \ +for (i = cvar.value; i; --i) spawnchance[numchoices++] = type + QUESTIONBOXCHANCES(MT_RING_ICON, cv_superring); + QUESTIONBOXCHANCES(MT_SNEAKERS_ICON, cv_supersneakers); + QUESTIONBOXCHANCES(MT_INVULN_ICON, cv_invincibility); + QUESTIONBOXCHANCES(MT_WHIRLWIND_ICON, cv_jumpshield); + QUESTIONBOXCHANCES(MT_ELEMENTAL_ICON, cv_watershield); + QUESTIONBOXCHANCES(MT_ATTRACT_ICON, cv_ringshield); + QUESTIONBOXCHANCES(MT_FORCE_ICON, cv_forceshield); + QUESTIONBOXCHANCES(MT_ARMAGEDDON_ICON, cv_bombshield); + QUESTIONBOXCHANCES(MT_1UP_ICON, cv_1up); + QUESTIONBOXCHANCES(MT_EGGMAN_ICON, cv_eggmanbox); + QUESTIONBOXCHANCES(MT_MIXUP_ICON, cv_teleporters); + QUESTIONBOXCHANCES(MT_RECYCLER_ICON, cv_recycler); +#undef QUESTIONBOXCHANCES + + if (numchoices == 0) return MT_NULL; + return spawnchance[P_RandomKey(numchoices)]; +} + // // ACTION ROUTINES // @@ -2510,7 +2539,6 @@ void A_1upThinker(mobj_t *actor) if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0) { // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite. - actor->frame = 0; if (actor->tracer) { P_RemoveMobj(actor->tracer); actor->tracer = NULL; @@ -2518,11 +2546,20 @@ void A_1upThinker(mobj_t *actor) return; } + // We're using the overlay, so use the overlay 1up box (no text) + actor->sprite = SPR_TV1P; + if (!actor->tracer) { P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY)); P_SetTarget(&actor->tracer->target, actor); + actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame P_SetMobjState(actor->tracer, actor->info->seestate); + + // The overlay is going to be one tic early turning off and on + // because it's going to get its thinker run the frame we spawned it. + // So make it take one tic longer if it just spawned. + ++actor->tracer->tics; } actor->tracer->color = players[closestplayer].mo->color; @@ -2538,139 +2575,200 @@ void A_1upThinker(mobj_t *actor) // void A_MonitorPop(mobj_t *actor) { - mobj_t *remains; - mobjtype_t explode; mobjtype_t item = 0; - mobjtype_t newbox; + mobj_t *newmobj; #ifdef HAVE_BLUA if (LUA_CallAction("A_MonitorPop", actor)) return; #endif - // de-solidify + // Spawn the "pop" explosion. + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); + P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_EXPLODE); + + // We're dead now. De-solidify. actor->health = 0; P_UnsetThingPosition(actor); actor->flags &= ~MF_SOLID; actor->flags |= MF_NOCLIP; P_SetThingPosition(actor); - // Monitor explosion - explode = mobjinfo[actor->info->speed].mass; - remains = P_SpawnMobj(actor->x, actor->y, - ((actor->eflags & MFE_VERTICALFLIP) ? (actor->z + 3*(actor->height/4) - FixedMul(mobjinfo[explode].height, actor->scale)) : (actor->z + actor->height/4)), explode); - if (actor->eflags & MFE_VERTICALFLIP) + if (actor->info->damage == MT_UNKNOWN) { - remains->eflags |= MFE_VERTICALFLIP; - remains->flags2 |= MF2_OBJECTFLIP; - } - remains->destscale = actor->destscale; - P_SetScale(remains, actor->scale); + // MT_UNKNOWN is random. Because it's unknown to us... get it? + item = P_DoRandomBoxChances(); - remains = P_SpawnMobj(actor->x, actor->y, - ((actor->eflags & MFE_VERTICALFLIP) ? (actor->z + actor->height - FixedMul(mobjinfo[actor->info->speed].height, actor->scale)) : actor->z), - actor->info->speed); - remains->type = actor->type; // Transfer type information - P_UnsetThingPosition(remains); - if (sector_list) - { - P_DelSeclist(sector_list); - sector_list = NULL; - } - P_SetThingPosition(remains); - remains->destscale = actor->destscale; - P_SetScale(remains, actor->scale); - remains->flags = actor->flags; // Transfer flags - remains->flags2 = actor->flags2; // Transfer flags2 - remains->fuse = actor->fuse; // Transfer respawn timer - remains->threshold = 68; - remains->skin = NULL; - - P_SetTarget(&tmthing, remains); - - if (actor->info->deathsound) - S_StartSound(remains, actor->info->deathsound); - - switch (actor->type) - { - case MT_QUESTIONBOX: // Random! + if (item == MT_NULL) { - mobjtype_t spawnchance[256]; - INT32 numchoices = 0, i = 0; - -#define QUESTIONBOXCHANCES(type, cvar) \ -for (i = cvar.value; i; --i) spawnchance[numchoices++] = type - - QUESTIONBOXCHANCES(MT_SUPERRINGBOX, cv_superring); - QUESTIONBOXCHANCES(MT_SNEAKERTV, cv_supersneakers); - QUESTIONBOXCHANCES(MT_INV, cv_invincibility); - QUESTIONBOXCHANCES(MT_WHITETV, cv_jumpshield); - QUESTIONBOXCHANCES(MT_GREENTV, cv_watershield); - QUESTIONBOXCHANCES(MT_YELLOWTV, cv_ringshield); - QUESTIONBOXCHANCES(MT_BLUETV, cv_forceshield); - QUESTIONBOXCHANCES(MT_BLACKTV, cv_bombshield); - QUESTIONBOXCHANCES(MT_PRUP, cv_1up); - QUESTIONBOXCHANCES(MT_EGGMANBOX, cv_eggmanbox); - QUESTIONBOXCHANCES(MT_MIXUPBOX, cv_teleporters); - QUESTIONBOXCHANCES(MT_RECYCLETV, cv_recycler); - -#undef QUESTIONBOXCHANCES - - if (numchoices == 0) - { - CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); - return; - } - - newbox = spawnchance[P_RandomKey(numchoices)]; - item = mobjinfo[newbox].damage; - - remains->flags &= ~MF_AMBUSH; - break; - } - default: - item = actor->info->damage; - break; - } - - if (item != 0) - { - mobj_t *newmobj; - - if (actor->eflags & MFE_VERTICALFLIP) - { - newmobj = P_SpawnMobj(actor->x, actor->y, actor->z + actor->height - FixedMul(13*FRACUNIT + mobjinfo[item].height, actor->scale), item); - newmobj->eflags |= MFE_VERTICALFLIP; - } - else - newmobj = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(13*FRACUNIT, actor->scale), item); - - newmobj->destscale = actor->destscale; - P_SetScale(newmobj, actor->scale); - P_SetTarget(&newmobj->target, actor->target); // Transfer target - if (item == MT_1UPICO && newmobj->target->player) - { - if (actor->tracer) // Remove the old lives icon. - P_RemoveMobj(actor->tracer); - - if (!newmobj->target->skin || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) - newmobj->frame -= 2; // No lives icon for this player, use the default. - else - { // Spawn the lives icon. - remains = P_SpawnMobj(newmobj->x, newmobj->y, newmobj->z, MT_OVERLAY); - P_SetTarget(&remains->target, newmobj); - P_SetTarget(&newmobj->tracer, remains); - - remains->color = newmobj->target->player->mo->color; - remains->skin = &skins[newmobj->target->player->skin]; - P_SetMobjState(remains, newmobj->info->seestate); - } + CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); + return; } } else - CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n"); + item = actor->info->damage; - P_RemoveMobj(actor); + if (item == 0) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n"); + return; + } + + newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item); + P_SetTarget(&newmobj->target, actor->target); // Transfer target + + if (item == MT_1UP_ICON) + { + if (actor->tracer) // Remove the old lives icon. + P_RemoveMobj(actor->tracer); + + if (!newmobj->target + || !newmobj->target->player + || !newmobj->target->skin + || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) + {} // No lives icon for this player, use the default. + else + { // Spawn the lives icon. + mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&livesico->target, newmobj); + P_SetTarget(&newmobj->tracer, livesico); + + livesico->color = newmobj->target->player->mo->color; + livesico->skin = &skins[newmobj->target->player->skin]; + P_SetMobjState(livesico, newmobj->info->seestate); + + // We're using the overlay, so use the overlay 1up sprite (no text) + newmobj->sprite = SPR_TV1P; + } + } +} + +// Function: A_GoldMonitorPop +// +// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know... +// +// var1 = unused +// var2 = unused +// +void A_GoldMonitorPop(mobj_t *actor) +{ + mobjtype_t item = 0; + mobj_t *newmobj; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoldMonitorPop", actor)) + return; +#endif + + // Don't spawn the "pop" explosion, because the monitor isn't broken. + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); + //P_SpawnMobjFromMobj(actor, 0, 0, actor.height/4, MT_EXPLODE); + + // Remove our flags for a bit. + // Players can now stand on top of us. + P_UnsetThingPosition(actor); + actor->flags &= ~(MF_MONITOR|MF_SHOOTABLE); + actor->flags2 |= MF2_STANDONME; + P_SetThingPosition(actor); + + // Don't count this box in statistics. Sorry. + if (actor->target && actor->target->player) + --actor->target->player->numboxes; + actor->fuse = 0; // Don't let the monitor code screw us up. + + if (actor->info->damage == MT_UNKNOWN) + { + // MT_UNKNOWN is random. Because it's unknown to us... get it? + item = P_DoRandomBoxChances(); + + if (item == MT_NULL) + { + CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); + return; + } + } + else + item = actor->info->damage; + + if (item == 0) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_GoldMonitorPop\n"); + return; + } + + // Note: the icon spawns 1 fracunit higher + newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item); + P_SetTarget(&newmobj->target, actor->target); // Transfer target + + if (item == MT_1UP_ICON) + { + if (actor->tracer) // Remove the old lives icon. + P_RemoveMobj(actor->tracer); + + if (!newmobj->target + || !newmobj->target->player + || !newmobj->target->skin + || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) + {} // No lives icon for this player, use the default. + else + { // Spawn the lives icon. + mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&livesico->target, newmobj); + P_SetTarget(&newmobj->tracer, livesico); + + livesico->color = newmobj->target->player->mo->color; + livesico->skin = &skins[newmobj->target->player->skin]; + P_SetMobjState(livesico, newmobj->info->seestate); + + // We're using the overlay, so use the overlay 1up sprite (no text) + newmobj->sprite = SPR_TV1P; + } + } +} + +// Function: A_GoldMonitorRestore +// +// Description: A repeating monitor is coming back to life. Reset monitor flags, etc. +// +// var1 = unused +// var2 = unused +// +void A_GoldMonitorRestore(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoldMonitorRestore", actor)) + return; +#endif + + actor->flags |= MF_MONITOR|MF_SHOOTABLE; + actor->flags2 &= ~MF2_STANDONME; + actor->health = 1; // Just in case. +} + +// Function: A_GoldMonitorSparkle +// +// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it? +// +// var1 = unused +// var2 = unused +// +void A_GoldMonitorSparkle(mobj_t *actor) +{ + fixed_t i, ngangle, xofs, yofs; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoldMonitorSparkle", actor)) + return; +#endif + + ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS); + xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); + yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); + + for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2) + P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false); } // Function: A_Explode @@ -2716,7 +2814,7 @@ void A_BossDeath(mobj_t *mo) // make sure there is a player alive for victory for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (players[i].health > 0 + if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0) || ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0)))) break; @@ -3059,7 +3157,7 @@ void A_Invincibility(mobj_t *actor) S_StopMusic(); if (mariomode) G_GhostAddColor(GHC_INVINCIBLE); - S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", false); + S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); } } @@ -3095,7 +3193,7 @@ void A_SuperSneakers(mobj_t *actor) else { S_StopMusic(); - S_ChangeMusicInternal("shoes", false); + S_ChangeMusicInternal("_shoes", false); } } } @@ -3151,8 +3249,11 @@ void A_ExtraLife(mobj_t *actor) player = actor->target->player; - if (actor->type == MT_1UPICO && !actor->tracer) - actor->frame -= 2; // No lives icon for this player, use the default. + if (actor->type == MT_1UP_ICON && actor->tracer) + { + // We're using the overlay, so use the overlay 1up sprite (no text) + actor->sprite = SPR_TV1P; + } if (ultimatemode) //I don't THINK so! { @@ -3449,7 +3550,7 @@ void A_BubbleSpawn(mobj_t *actor) } actor->flags2 &= ~MF2_DONTDRAW; - if (!(actor->flags & MF_AMBUSH)) + if (!(actor->flags2 & MF2_AMBUSH)) { // Quick! Look through players! // Don't spawn bubbles unless a player is relatively close by (var2). @@ -3497,7 +3598,7 @@ void A_FanBubbleSpawn(mobj_t *actor) if (!(actor->eflags & MFE_UNDERWATER)) return; - if (!(actor->flags & MF_AMBUSH)) + if (!(actor->flags2 & MF2_AMBUSH)) { // Quick! Look through players! // Don't spawn bubbles unless a player is relatively close by (var2). @@ -4064,7 +4165,7 @@ void A_JetChase(mobj_t *actor) return; #endif - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -4957,7 +5058,7 @@ void A_SlingAppear(mobj_t *actor) if (firsttime) { // This is the outermost link in the chain - spawnee->flags |= MF_AMBUSH; + spawnee->flags2 |= MF2_AMBUSH; firsttime = false; } @@ -5940,7 +6041,7 @@ void A_Boss2Chase(mobj_t *actor) { actor->watertop = -actor->watertop; actor->extravalue1 = 18; - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2; actor->extravalue2 = actor->extravalue1; } @@ -5966,7 +6067,7 @@ void A_Boss2Chase(mobj_t *actor) else { // Only speed up if you have the 'Deaf' flag. - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) speedvar = actor->health; else speedvar = actor->info->spawnhealth; @@ -6557,7 +6658,7 @@ void A_BuzzFly(mobj_t *actor) if (LUA_CallAction("A_BuzzFly", actor)) return; #endif - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) return; if (actor->reactiontime) @@ -6697,7 +6798,7 @@ void A_GuardChase(mobj_t *actor) return; // got a new target // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, (actor->flags & MF_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) + if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) { P_NewChaseDir(actor); actor->movecount += 5; // Increase tics before change in direction allowed. @@ -8284,7 +8385,7 @@ void A_RingDrain(mobj_t *actor) } player = actor->target->player; - P_GivePlayerRings(player, -min(locvar1, player->mo->health-1)); + P_GivePlayerRings(player, -min(locvar1, player->rings)); } // Function: A_SplitShot @@ -8592,7 +8693,7 @@ void A_CheckTargetRings(mobj_t *actor) if (!(actor->target) || !(actor->target->player)) return; - if (actor->target->player->health >= locvar1) + if (actor->target->player->rings >= locvar1) P_SetMobjState(actor, locvar2); } @@ -8614,7 +8715,7 @@ void A_CheckRings(mobj_t *actor) #endif for (i = 0; i < MAXPLAYERS; i++) - cntr += players[i].health-1; + cntr += players[i].rings; if (cntr >= locvar1) P_SetMobjState(actor, locvar2); @@ -9186,7 +9287,7 @@ void A_ForceWin(mobj_t *actor) for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && (players[i].health > 0 + if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0) || ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0)))) break; } diff --git a/src/p_inter.c b/src/p_inter.c index 4349be579..6ad04f477 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -221,6 +221,65 @@ void P_DoNightsScore(player_t *player) dummymo->destscale = 2*FRACUNIT; } +// +// P_DoMatchSuper +// +// Checks if you have all 7 pw_emeralds, then turns you "super". =P +// +void P_DoMatchSuper(player_t *player) +{ + UINT16 match_emeralds = player->powers[pw_emeralds]; + boolean doteams = false; + int i; + + // If this gametype has teams, check every player on your team for emeralds. + if (G_GametypeHasTeams()) + { + doteams = true; + for (i = 0; i < MAXPLAYERS; i++) + if (players[i].ctfteam == player->ctfteam) + match_emeralds |= players[i].powers[pw_emeralds]; + } + + if (!ALL7EMERALDS(match_emeralds)) + return; + + // Got 'em all? Turn "super"! + emeraldspawndelay = invulntics + 1; + player->powers[pw_emeralds] = 0; + player->powers[pw_invulnerability] = emeraldspawndelay; + player->powers[pw_sneakers] = emeraldspawndelay; + if (P_IsLocalPlayer(player) && !player->powers[pw_super]) + { + S_StopMusic(); + if (mariomode) + G_GhostAddColor(GHC_INVINCIBLE); + S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); + } + + // Also steal 50 points from every enemy, sealing your victory. + P_StealPlayerScore(player, 50); + + // In a team game? + // Check everyone else on your team for emeralds, and turn those helpful assisting players invincible too. + if (doteams) + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].ctfteam == player->ctfteam + && players[i].powers[pw_emeralds] != 0) + { + players[i].powers[pw_emeralds] = 0; + player->powers[pw_invulnerability] = invulntics + 1; + player->powers[pw_sneakers] = player->powers[pw_invulnerability]; + if (P_IsLocalPlayer(player) && !player->powers[pw_super]) + { + S_StopMusic(); + if (mariomode) + G_GhostAddColor(GHC_INVINCIBLE); + S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); + } + } +} + /** Takes action based on a ::MF_SPECIAL thing touched by a player. * Actually, this just checks a few things (heights, toucher->player, no * objectplace, no dead or disappearing things) @@ -445,7 +504,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { INT32 pindex = special->info->mass - (INT32)pw_infinityring; - player->powers[special->info->mass] += (UINT16)special->info->reactiontime; + player->powers[special->info->mass] += (UINT16)special->reactiontime; player->ringweapons |= 1 << (pindex-1); if (player->powers[special->info->mass] > rw_maximums[pindex]) @@ -532,7 +591,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; if (special->threshold) + { player->powers[pw_emeralds] |= special->info->speed; + P_DoMatchSuper(player); + } else emeralds |= special->info->speed; @@ -553,6 +615,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; player->powers[pw_emeralds] |= special->threshold; + P_DoMatchSuper(player); break; // Secret emblem thingy @@ -814,16 +877,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (G_IsSpecialStage(gamemap) && !player->exiting) { // In special stages, share rings. Everyone gives up theirs to the player who touched the capsule for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (&players[i] != player) && players[i].mo->health > 1) + if (playeringame[i] && (&players[i] != player) && players[i].rings > 0) { - toucher->health += players[i].mo->health-1; - player->health = toucher->health; - players[i].mo->health = 1; - players[i].health = players[i].mo->health; + player->rings += players[i].rings; + players[i].rings = 0; } } - if (!(player->health > 1) || player->exiting) + if (player->rings <= 0 || player->exiting) return; // Mark the player as 'pull into the capsule' @@ -1336,7 +1397,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_SMALLMACECHAIN: case MT_BIGMACECHAIN: // Is this the last link in the chain? - if (toucher->momz > 0 || !(special->flags & MF_AMBUSH) + if (toucher->momz > 0 || !(special->flags2 & MF2_AMBUSH) || (player->powers[pw_carry])) return; @@ -1380,7 +1441,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } if (player->powers[pw_invulnerability] || player->powers[pw_flashing] - || (player->powers[pw_super] && !(ALL7EMERALDS(player->powers[pw_emeralds])))) + || player->powers[pw_super]) return; if (player->powers[pw_shield] || player->bot) //If One-Hit Shield { @@ -1390,11 +1451,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) else { P_PlayRinglossSound(toucher); - if (toucher->health > 10) - toucher->health -= 10; + if (player->rings >= 10) + player->rings -= 10; else - toucher->health = 1; - player->health = toucher->health; + player->rings = 0; } P_DoPlayerPain(player, special, NULL); @@ -1496,6 +1556,9 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour if (!player) return; // Impossible! + if (!player->mo) + return; // Also impossible! + if (player->spectator) return; // No messages for dying (crushed) spectators. @@ -1503,11 +1566,11 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour return; // Presumably it's obvious what's happening in splitscreen. #ifdef HAVE_BLUA - if (LUAh_HurtMsg(player, inflictor, source)) + if (LUAh_HurtMsg(player, inflictor, source, damagetype)) return; #endif - deadtarget = (player->health <= 0); + deadtarget = (player->mo->health <= 0); // Target's name snprintf(targetname, sizeof(targetname), "%s%s%s", @@ -1541,7 +1604,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour else switch (inflictor->type) { case MT_PLAYER: - if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) + if (damagetype == DMG_NUKE) // SH_BOMB, armageddon shield str = M_GetText("%s%s's armageddon blast %s %s.\n"); else if (inflictor->player->powers[pw_invulnerability]) str = M_GetText("%s%s's invincibility aura %s %s.\n"); @@ -1592,8 +1655,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour } else switch (source->type) { - case MT_EGGMANICO: - case MT_EGGMANBOX: + case MT_EGGMAN_ICON: str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n"); break; case MT_SPIKE: @@ -1975,7 +2037,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->health = 0; // This makes it easy to check if something's dead elsewhere. #ifdef HAVE_BLUA - if (LUAh_MobjDeath(target, inflictor, source) || P_MobjWasRemoved(target)) + if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) return; #endif @@ -2105,7 +2167,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (P_IsLocalPlayer(target->player)/* && target->player == &players[consoleplayer] */) { S_StopMusic(); // Stop the Music! Tails 03-14-2000 - S_ChangeMusicInternal("gmover", false); // Yousa dead now, Okieday? Tails 03-14-2000 + S_ChangeMusicInternal("_gover", false); // Yousa dead now, Okieday? Tails 03-14-2000 } } } @@ -2443,8 +2505,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) player_t *player = target->player; tic_t oldnightstime = player->nightstime; - if (!player->powers[pw_flashing] - && !(player->pflags & PF_GODMODE)) + if (!player->powers[pw_flashing]) { angle_t fa; @@ -2494,7 +2555,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) && player->nightstime < 10*TICRATE) { //S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH - S_ChangeMusicInternal("drown",false); + S_ChangeMusicInternal("_drown",false); } } } @@ -2559,27 +2620,18 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } - if (target->health <= 1) // Death + if (player->rings > 0) // Ring loss + { + P_PlayRinglossSound(target); + P_PlayerRingBurst(player, player->rings); + } + else // Death { P_PlayDeathSound(target); P_PlayVictorySound(source); // Killer laughs at you! LAUGHS! BWAHAHAHHAHAA!! } - else if (target->health > 1) // Ring loss - { - P_PlayRinglossSound(target); - P_PlayerRingBurst(player, player->mo->health - 1); - } - - if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - { - player->health -= 10; - if (player->health < 2) - player->health = 2; - target->health = player->health; - } - else - player->health = target->health = 1; + player->rings = 0; return true; } @@ -2630,7 +2682,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) // Burst weapons and emeralds in Match/CTF only if (source && (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF)) { - P_PlayerRingBurst(player, player->health - 1); + P_PlayerRingBurst(player, player->rings); P_PlayerEmeraldBurst(player, false); } @@ -2758,7 +2810,7 @@ void P_RemoveShield(player_t *player) player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK; } -static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) +static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { // Must do pain first to set flashing -- P_RemoveShield can cause damage P_DoPlayerPain(player, source, inflictor); @@ -2767,7 +2819,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes + if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes S_StartSound(player->mo, sfx_spkdth); else S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss. @@ -2792,15 +2844,12 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { - if (!(inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) - { - P_DoPlayerPain(player, source, inflictor); + P_DoPlayerPain(player, source, inflictor); - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); + P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes - S_StartSound(player->mo, sfx_spkdth); - } + if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes + S_StartSound(player->mo, sfx_spkdth); if (source && source->player && !player->powers[pw_super]) //don't score points against super players { @@ -2822,6 +2871,10 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN // Ring loss sound plays despite hitting spikes P_PlayRinglossSound(player->mo); // Ringledingle! + P_PlayerRingBurst(player, damage); + player->rings -= damage; + if (player->rings < 0) + player->rings = 0; } /** Damages an object, which may or may not be a player. @@ -2870,7 +2923,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Everything above here can't be forced. if (!metalrecording) { - UINT8 shouldForce = LUAh_ShouldDamage(target, inflictor, source, damage); + UINT8 shouldForce = LUAh_ShouldDamage(target, inflictor, source, damage, damagetype); if (P_MobjWasRemoved(target)) return (shouldForce == 1); // mobj was removed if (shouldForce == 1) @@ -2899,10 +2952,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!force) { // Special case for team ring boxes - if (target->type == MT_REDRINGBOX && !(source->player->ctfteam == 1)) + if (target->type == MT_RING_REDBOX && !(source->player->ctfteam == 1)) return false; - if (target->type == MT_BLUERINGBOX && !(source->player->ctfteam == 2)) + if (target->type == MT_RING_BLUEBOX && !(source->player->ctfteam == 2)) return false; } @@ -2913,7 +2966,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; #ifdef HAVE_BLUA - if (LUAh_MobjDamage(target, inflictor, source, damage) || P_MobjWasRemoved(target)) + if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) return true; #endif @@ -2941,7 +2994,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; #ifdef HAVE_BLUA - if (LUAh_MobjDamage(target, inflictor, source, damage) || P_MobjWasRemoved(target)) + if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) return true; #endif @@ -2951,7 +3004,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da #ifdef HAVE_BLUA else if (target->flags & MF_ENEMY) { - if (LUAh_MobjDamage(target, inflictor, source, damage) || P_MobjWasRemoved(target)) + if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) return true; } #endif @@ -2965,6 +3018,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player->exiting) return false; + if (player->pflags & PF_GODMODE) + return false; + if (!(target->player->pflags & (PF_NIGHTSMODE|PF_NIGHTSFALL)) && (maptol & TOL_NIGHTS)) return false; @@ -2992,11 +3048,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Don't hit yourself with your own paraloop, baka if (source && source->player && !cv_friendlyfire.value && (gametype == GT_COOP - || (G_GametypeHasTeams() && target->player->ctfteam == source->player->ctfteam))) + || (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam))) return false; // Don't run eachother over in special stages and team games and such } #ifdef HAVE_BLUA - if (LUAh_MobjDamage(target, inflictor, source, damage)) + if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) return true; #endif P_NiGHTSDamage(target, source); // -5s :( @@ -3027,12 +3083,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; } - if (!force && player->pflags & PF_GODMODE) - return false; - // Instant-Death if (damagetype & DMG_DEATHMASK) + { P_KillPlayer(player, source, damage); + player->rings = 0; + } else if (metalrecording) { if (!inflictor) @@ -3046,19 +3102,19 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Metal Sonic walk through flame !! else { // Oh no! Metal Sonic is hit !! - P_ShieldDamage(player, inflictor, source, damage); + P_ShieldDamage(player, inflictor, source, damage, damagetype); return true; } } else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] // ignore bouncing & such in invulnerability - || (player->powers[pw_super] && !(ALL7EMERALDS(player->powers[pw_emeralds]) && inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player)))) + || player->powers[pw_super]) { if (force || (inflictor && (inflictor->flags & MF_MISSILE) && (inflictor->flags2 & MF2_SUPERFIRE) && player->powers[pw_super])) { #ifdef HAVE_BLUA - if (!LUAh_MobjDamage(target, inflictor, source, damage)) + if (!LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) #endif P_SuperDamage(player, inflictor, source, damage); return true; @@ -3067,67 +3123,35 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; } #ifdef HAVE_BLUA - else if (LUAh_MobjDamage(target, inflictor, source, damage)) + else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) return true; #endif - else if (!player->powers[pw_super] && (player->powers[pw_shield] || player->bot)) //If One-Hit Shield + else if (player->powers[pw_shield] || player->bot) //If One-Hit Shield { - P_ShieldDamage(player, inflictor, source, damage); + P_ShieldDamage(player, inflictor, source, damage, damagetype); damage = 0; } - else if (player->mo->health > 1) // No shield but have rings. + else if (player->rings > 0) // No shield but have rings. { - damage = player->mo->health - 1; + damage = player->rings; P_RingDamage(player, inflictor, source, damage, damagetype); + damage = 0; + } + // To reduce griefing potential, don't allow players to be killed + // by friendly fire. Spilling their rings and other items is enough. + else if (!force && G_GametypeHasTeams() + && source && source->player && (source->player->ctfteam == player->ctfteam) + && cv_friendlyfire.value) + { + damage = 0; + P_ShieldDamage(player, inflictor, source, damage, damagetype); } else // No shield, no rings, no invincibility. { - // To reduce griefing potential, don't allow players to be killed - // by friendly fire. Spilling their rings and other items is enough. - if (force || !(G_GametypeHasTeams() - && source && source->player && (source->player->ctfteam == player->ctfteam) - && cv_friendlyfire.value)) - { - damage = 1; - P_KillPlayer(player, source, damage); - } - else - { - damage = 0; - P_ShieldDamage(player, inflictor, source, damage); - } + damage = 1; + P_KillPlayer(player, source, damage); } - if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - { - if (player->powers[pw_shield]) - { - P_RemoveShield(player); - return true; - } - else - { - player->health -= (10 * (1 << (INT32)(player->powers[pw_super] / 10500))); - if (player->health < 2) - player->health = 2; - } - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - P_PlayerFlagBurst(player, false); - } - else if (damagetype & DMG_DEATHMASK) - player->health = 0; - else - { - player->health -= damage; // mirror mobj health here - target->player->powers[pw_flashing] = flashingtics; - if (damage > 0) // don't spill emeralds/ammo/panels for shield damage - P_PlayerRingBurst(player, damage); - } - - if (player->health < 0) - player->health = 0; - P_HitDeathMessages(player, inflictor, source, damagetype); P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); @@ -3139,13 +3163,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da P_DamageMobj(source, target, target, 1, 0); // do the damage - if (player && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]) && inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player)) - { - target->health -= (10 * (1 << (INT32)(player->powers[pw_super] / 10500))); - if (target->health < 2) - target->health = 2; - } - else if (damagetype & DMG_DEATHMASK) + if (damagetype & DMG_DEATHMASK) target->health = 0; else target->health -= damage; @@ -3160,10 +3178,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } if (player) - { - if (!(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) - P_ResetPlayer(target->player); - } + P_ResetPlayer(target->player); else switch (target->type) { @@ -3186,16 +3201,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // if not intent on another player, // chase after this one P_SetTarget(&target->target, source); - if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL) - { - if (player) - { - if (!(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) - P_SetPlayerMobjState(target, target->info->seestate); - } - else - P_SetMobjState(target, target->info->seestate); - } } return true; @@ -3221,7 +3226,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) return; // If no health, don't spawn ring! - if (player->mo->health <= 1) + if (player->rings <= 0) num_rings = 0; if (num_rings > 32 && !(player->pflags & PF_NIGHTSFALL)) @@ -3231,11 +3236,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) P_PlayerEmeraldBurst(player, false); // Spill weapons first - if (player->ringweapons) - P_PlayerWeaponPanelBurst(player); - - // Spill the ammo - P_PlayerWeaponAmmoBurst(player); + P_PlayerWeaponPanelOrAmmoBurst(player); for (i = 0; i < num_rings; i++) { @@ -3492,6 +3493,75 @@ void P_PlayerWeaponAmmoBurst(player_t *player) } } +void P_PlayerWeaponPanelOrAmmoBurst(player_t *player) +{ + mobj_t *mo; + angle_t fa; + fixed_t ns; + INT32 i = 0; + fixed_t z; + + #define SETUP_DROP(thingtype) \ + z = player->mo->z; \ + if (player->mo->eflags & MFE_VERTICALFLIP) \ + z += player->mo->height - mobjinfo[thingtype].height; \ + fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK; \ + ns = FixedMul(3*FRACUNIT, player->mo->scale); \ + + #define DROP_WEAPON(rwflag, pickup, ammo, power) \ + if (player->ringweapons & rwflag) \ + { \ + player->ringweapons &= ~rwflag; \ + SETUP_DROP(pickup) \ + mo = P_SpawnMobj(player->mo->x, player->mo->y, z, pickup); \ + mo->reactiontime = 0; \ + mo->flags2 |= MF2_DONTRESPAWN; \ + mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \ + P_SetTarget(&mo->target, player->mo); \ + mo->fuse = 12*TICRATE; \ + mo->destscale = player->mo->scale; \ + P_SetScale(mo, player->mo->scale); \ + mo->momx = FixedMul(FINECOSINE(fa),ns); \ + if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \ + mo->momy = FixedMul(FINESINE(fa),ns); \ + P_SetObjectMomZ(mo, 4*FRACUNIT, false); \ + if (i & 1) \ + P_SetObjectMomZ(mo, 4*FRACUNIT, true); \ + ++i; \ + } \ + else if (player->powers[power] > 0) \ + { \ + SETUP_DROP(ammo) \ + mo = P_SpawnMobj(player->mo->x, player->mo->y, z, ammo); \ + mo->health = player->powers[power]; \ + mo->flags2 |= MF2_DONTRESPAWN; \ + mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \ + P_SetTarget(&mo->target, player->mo); \ + mo->fuse = 12*TICRATE; \ + mo->destscale = player->mo->scale; \ + P_SetScale(mo, player->mo->scale); \ + mo->momx = FixedMul(FINECOSINE(fa),ns); \ + if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \ + mo->momy = FixedMul(FINESINE(fa),ns); \ + P_SetObjectMomZ(mo, 3*FRACUNIT, false); \ + if (i & 1) \ + P_SetObjectMomZ(mo, 3*FRACUNIT, true); \ + player->powers[power] = 0; \ + ++i; \ + } + + DROP_WEAPON(RW_BOUNCE, MT_BOUNCEPICKUP, MT_BOUNCERING, pw_bouncering); + DROP_WEAPON(RW_RAIL, MT_RAILPICKUP, MT_RAILRING, pw_railring); + DROP_WEAPON(RW_AUTO, MT_AUTOPICKUP, MT_AUTOMATICRING, pw_automaticring); + DROP_WEAPON(RW_EXPLODE, MT_EXPLODEPICKUP, MT_EXPLOSIONRING, pw_explosionring); + DROP_WEAPON(RW_SCATTER, MT_SCATTERPICKUP, MT_SCATTERRING, pw_scatterring); + DROP_WEAPON(RW_GRENADE, MT_GRENADEPICKUP, MT_GRENADERING, pw_grenadering); + DROP_WEAPON(0, 0, MT_INFINITYRING, pw_infinityring); + + #undef DROP_WEAPON + #undef SETUP_DROP +} + // // P_PlayerEmeraldBurst // diff --git a/src/p_local.h b/src/p_local.h index a1cf4892a..8c49e4f18 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -124,6 +124,7 @@ extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; INT32 P_GetPlayerControlDirection(player_t *player); void P_AddPlayerScore(player_t *player, UINT32 amount); +void P_StealPlayerScore(player_t *player, UINT32 amount); void P_ResetCamera(player_t *player, camera_t *thiscam); boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); @@ -211,6 +212,7 @@ void P_PrecipitationEffects(void); void P_RemoveMobj(mobj_t *th); boolean P_MobjWasRemoved(mobj_t *th); void P_RemoveSavegameMobj(mobj_t *th); +UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2); boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state); boolean P_SetMobjState(mobj_t *mobj, statenum_t state); void P_RunShields(void); @@ -241,6 +243,8 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover); +mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type); + mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type); mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type, fixed_t x, fixed_t y, fixed_t z); mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za, mobjtype_t type, fixed_t x, fixed_t y, fixed_t z); @@ -378,7 +382,8 @@ typedef struct BasicFF_s #define DMG_FIRE 2 #define DMG_ELECTRIC 3 #define DMG_SPIKE 4 -//#define DMG_SPECIALSTAGE 5 +#define DMG_NUKE 5 // bomb shield +//#define DMG_SPECIALSTAGE 6 //// Death types - cannot be combined with damage types #define DMG_INSTAKILL 0x80 #define DMG_DROWNED 0x80+1 @@ -397,6 +402,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget void P_PlayerRingBurst(player_t *player, INT32 num_rings); /// \todo better fit in p_user.c void P_PlayerWeaponPanelBurst(player_t *player); void P_PlayerWeaponAmmoBurst(player_t *player); +void P_PlayerWeaponPanelOrAmmoBurst(player_t *player); void P_PlayerEmeraldBurst(player_t *player, boolean toss); void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck); @@ -411,6 +417,7 @@ void P_ResetStarposts(void); boolean P_CanPickupItem(player_t *player, boolean weapon); void P_DoNightsScore(player_t *player); +void P_DoMatchSuper(player_t *player); // // P_SPEC diff --git a/src/p_map.c b/src/p_map.c index 765f88a7d..6ac48a7c8 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -115,6 +115,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) fixed_t offx, offy; fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; + UINT8 jumping, secondjump; if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic return false; @@ -203,25 +204,30 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these. + jumping = object->player->jumping; + secondjump = object->player->secondjump; P_ResetPlayer(object->player); - if (P_MobjFlip(object)*vertispeed > 0) + if (spring->info->painchance) + { + object->player->pflags |= PF_JUMPED; + P_SetPlayerMobjState(object, S_PLAY_JUMP); + } + else if (P_MobjFlip(object)*vertispeed > 0) P_SetPlayerMobjState(object, S_PLAY_SPRING); else if (P_MobjFlip(object)*vertispeed < 0) P_SetPlayerMobjState(object, S_PLAY_FALL); else // horizontal spring { if (pflags & (PF_JUMPED|PF_SPINNING) && (object->player->panim == PA_ROLL || object->player->panim == PA_JUMP || object->player->panim == PA_FALL)) - object->player->pflags = pflags; + { + object->player->pflags |= pflags; + object->player->jumping = jumping; + object->player->secondjump = secondjump; + } else P_SetPlayerMobjState(object, S_PLAY_WALK); } - - if (spring->info->painchance) - { - object->player->pflags |= PF_JUMPED; - P_SetPlayerMobjState(object, S_PLAY_JUMP); - } } return true; } @@ -501,6 +507,74 @@ static boolean PIT_CheckThing(mobj_t *thing) if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) return true; // didn't hit it + if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing. + { + fixed_t cosradius, sinradius; + vertex_t v1, v2; // fake vertexes + line_t junk; // fake linedef + + cosradius = FixedMul(thing->radius, FINECOSINE(thing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(thing->radius, FINESINE(thing->angle>>ANGLETOFINESHIFT)); + + v1.x = thing->x - cosradius; + v1.y = thing->y - sinradius; + v2.x = thing->x + cosradius; + v2.y = thing->y + sinradius; + + junk.v1 = &v1; + junk.v2 = &v2; + junk.dx = v2.x - v1.x; + junk.dy = v2.y - v1.y; + + if (tmthing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues + { + INT32 check1, check2, check3, check4; + cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + check1 = P_PointOnLineSide(tmx - cosradius, tmy - sinradius, &junk); + check2 = P_PointOnLineSide(tmx + cosradius, tmy + sinradius, &junk); + check3 = P_PointOnLineSide(tmx + tmthing->momx - cosradius, tmy + tmthing->momy - sinradius, &junk); + check4 = P_PointOnLineSide(tmx + tmthing->momx + cosradius, tmy + tmthing->momy + sinradius, &junk); + if ((check1 == check2) && (check2 == check3) && (check3 == check4)) + return true; // the line doesn't cross between collider's start or end + } + else + { + if ((P_PointOnLineSide(tmx - tmthing->radius, tmy - tmthing->radius, &junk) + == P_PointOnLineSide(tmx + tmthing->radius, tmy + tmthing->radius, &junk)) + && (P_PointOnLineSide(tmx + tmthing->radius, tmy - tmthing->radius, &junk) + == P_PointOnLineSide(tmx - tmthing->radius, tmy + tmthing->radius, &junk))) + return true; // the line doesn't cross between either pair of opposite corners + } + } + else if (tmthing->flags & MF_PAPERCOLLISION) + { + fixed_t cosradius, sinradius; + vertex_t v1, v2; // fake vertexes + line_t junk; // fake linedef + + cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + + v1.x = tmx - cosradius; + v1.y = tmy - sinradius; + v2.x = tmx + cosradius; + v2.y = tmy + sinradius; + + junk.v1 = &v1; + junk.v2 = &v2; + junk.dx = v2.x - v1.x; + junk.dy = v2.y - v1.y; + + // no need to check whether thing has MF_PAPERCOLLISION, since checked above + + if ((P_PointOnLineSide(thing->x - thing->radius, thing->y - thing->radius, &junk) + == P_PointOnLineSide(thing->x + thing->radius, thing->y + thing->radius, &junk)) + && (P_PointOnLineSide(thing->x + thing->radius, thing->y - thing->radius, &junk) + == P_PointOnLineSide(thing->x - thing->radius, thing->y + thing->radius, &junk))) + return true; // the line doesn't cross between either pair of opposite corners + } + #ifdef HAVE_BLUA { UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type @@ -1015,7 +1089,7 @@ static boolean PIT_CheckThing(mobj_t *thing) || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) || ((tmthing->player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))) - && !((thing->type == MT_REDRINGBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_BLUERINGBOX && tmthing->player->ctfteam != 2))) + && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))) ; // z checking at last // Treat noclip things as non-solid! @@ -1041,18 +1115,24 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - topz = thing->z - FixedMul(FRACUNIT, thing->scale); + topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways // block only when jumping not high enough, // (dont climb max. 24units while already in air) - // if not in air, let P_TryMove() decide if it's not too high + // since return false doesn't handle momentum properly, + // we lie to P_TryMove() so it's always too high if (tmthing->player && tmthing->z + tmthing->height > topz && tmthing->z + tmthing->height < tmthing->ceilingz) - return false; // block while in air - - if (thing->flags & MF_SPRING) + { + tmfloorz = tmceilingz = INT32_MIN; // block while in air +#ifdef ESLOPE + tmceilingslope = NULL; +#endif + tmfloorthing = thing; // needed for side collision + } + else if (thing->flags & MF_SPRING) ; - else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height) + else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height) { tmceilingz = topz; #ifdef ESLOPE @@ -1078,17 +1158,24 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - topz = thing->z + thing->height + FixedMul(FRACUNIT, thing->scale); + topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways // block only when jumping not high enough, // (dont climb max. 24units while already in air) - // if not in air, let P_TryMove() decide if it's not too high - if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz) - return false; // block while in air - - if (thing->flags & MF_SPRING) + // since return false doesn't handle momentum properly, + // we lie to P_TryMove() so it's always too high + if (tmthing->player && tmthing->z < topz + && tmthing->z > tmthing->floorz) + { + tmfloorz = tmceilingz = INT32_MAX; // block while in air +#ifdef ESLOPE + tmfloorslope = NULL; +#endif + tmfloorthing = thing; // needed for side collision + } + else if (thing->flags & MF_SPRING) ; - else if (topz > tmfloorz && tmthing->z >= thing->z) + else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z) { tmfloorz = topz; #ifdef ESLOPE @@ -1179,6 +1266,32 @@ static boolean PIT_CheckLine(line_t *ld) if (P_BoxOnLineSide(tmbbox, ld) != -1) return true; + if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. + { + fixed_t cosradius, sinradius; + cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + if (P_PointOnLineSide(tmx - cosradius, tmy - sinradius, ld) + == P_PointOnLineSide(tmx + cosradius, tmy + sinradius, ld)) + return true; // the line doesn't cross between collider's start or end +#ifdef PAPER_COLLISIONCORRECTION + { + fixed_t dist; + vertex_t result; + angle_t langle; + P_ClosestPointOnLine(tmx, tmy, ld, &result); + langle = R_PointToAngle2(ld->v1->x, ld->v1->y, ld->v2->x, ld->v2->y); + langle += ANGLE_90*(P_PointOnLineSide(tmx, tmy, ld) ? -1 : 1); + dist = abs(FixedMul(tmthing->radius, FINECOSINE((tmthing->angle - langle)>>ANGLETOFINESHIFT))); + cosradius = FixedMul(dist, FINECOSINE(langle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(dist, FINESINE(langle>>ANGLETOFINESHIFT)); + tmthing->flags |= MF_NOCLIP; + P_TeleportMove(tmthing, result.x + cosradius - tmthing->momx, result.y + sinradius - tmthing->momy, tmthing->z); + tmthing->flags &= ~MF_NOCLIP; + } +#endif + } + // A line has been hit // The moving thing's destination position will cross diff --git a/src/p_mobj.c b/src/p_mobj.c index 53812bba6..66041c7dd 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -81,6 +81,41 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum) actioncachehead.prev = newaction; } +// +// P_SetupStateAnimation +// +FUNCINLINE static ATTRINLINE void P_SetupStateAnimation(mobj_t *mobj, state_t *st) +{ + INT32 animlength = (mobj->skin && mobj->sprite == SPR_PLAY) + ? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1 + : st->var1; + + if (!(st->frame & FF_ANIMATE)) + return; + + if (animlength <= 0 || st->var2 == 0) + { + mobj->frame &= ~FF_ANIMATE; + return; // Crash/stupidity prevention + } + + mobj->anim_duration = (UINT16)st->var2; + + if (st->frame & FF_GLOBALANIM) + { + // Attempt to account for the pre-ticker for objects spawned on load + if (!leveltime) return; + + mobj->anim_duration -= (leveltime + 2) % st->var2; // Duration synced to timer + mobj->frame += ((leveltime + 2) / st->var2) % (animlength + 1); // Frame synced to timer (duration taken into account) + } + else if (st->frame & FF_RANDOMANIM) + { + mobj->frame += P_RandomKey(animlength + 1); // Random starting frame + mobj->anim_duration -= P_RandomKey(st->var2); // Random duration for first frame + } +} + // // P_CycleStateAnimation // @@ -89,13 +124,23 @@ FUNCINLINE static ATTRINLINE void P_CycleStateAnimation(mobj_t *mobj) // var2 determines delay between animation frames if (!(mobj->frame & FF_ANIMATE) || --mobj->anim_duration != 0) return; + mobj->anim_duration = (UINT16)mobj->state->var2; - // compare the current sprite frame to the one we started from - // if more than var1 away from it, swap back to the original - // else just advance by one - if (((++mobj->frame) & FF_FRAMEMASK) - (mobj->state->frame & FF_FRAMEMASK) > (UINT32)mobj->state->var1) - mobj->frame = (mobj->state->frame & FF_FRAMEMASK) | (mobj->frame & ~FF_FRAMEMASK); + if (mobj->sprite != SPR_PLAY) + { + // compare the current sprite frame to the one we started from + // if more than var1 away from it, swap back to the original + // else just advance by one + if (((++mobj->frame) & FF_FRAMEMASK) - (mobj->state->frame & FF_FRAMEMASK) > (UINT32)mobj->state->var1) + mobj->frame = (mobj->state->frame & FF_FRAMEMASK) | (mobj->frame & ~FF_FRAMEMASK); + + return; + } + + // sprite2 version of above + if (mobj->skin && (((++mobj->frame) & FF_FRAMEMASK) >= (UINT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes))) + mobj->frame &= ~FF_FRAMEMASK; } // @@ -140,6 +185,215 @@ static void P_CyclePlayerMobjState(mobj_t *mobj) } } +// +// P_GetMobjSprite2 +// + +UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2) +{ + player_t *player = mobj->player; + skin_t *skin = ((skin_t *)mobj->skin); + + if (!skin) + return 0; + + while ((skin->sprites[spr2].numframes <= 0) + && spr2 != SPR2_STND) + { + switch(spr2) + { + case SPR2_PEEL: + spr2 = SPR2_RUN; + break; + case SPR2_RUN: + spr2 = SPR2_WALK; + break; + case SPR2_DRWN: + spr2 = SPR2_DEAD; + break; + case SPR2_DASH: + spr2 = SPR2_SPIN; + break; + case SPR2_GASP: + spr2 = SPR2_SPNG; + break; + case SPR2_JUMP: + spr2 = ((player + ? player->charflags + : skin->flags) + & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_SPIN; + break; + case SPR2_SPNG: // spring + spr2 = SPR2_FALL; + break; + case SPR2_FALL: + spr2 = SPR2_WALK; + break; + case SPR2_RIDE: + spr2 = SPR2_FALL; + break; + + case SPR2_FLY: + spr2 = SPR2_SPNG; + break; + case SPR2_SWIM: + spr2 = SPR2_FLY; + break; + case SPR2_TIRE: + spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; + break; + + case SPR2_GLID: + spr2 = SPR2_FLY; + break; + case SPR2_CLMB: + spr2 = SPR2_SPIN; + break; + case SPR2_CLNG: + spr2 = SPR2_CLMB; + break; + + case SPR2_TWIN: + spr2 = SPR2_SPIN; + break; + + case SPR2_MLEE: + spr2 = SPR2_TWIN; + break; + + // Super sprites fallback to regular sprites + case SPR2_SWLK: + spr2 = SPR2_WALK; + break; + case SPR2_SRUN: + spr2 = SPR2_RUN; + break; + case SPR2_SPEE: + spr2 = SPR2_PEEL; + break; + case SPR2_SPAN: + spr2 = SPR2_PAIN; + break; + case SPR2_SSTN: + spr2 = SPR2_SPAN; + break; + case SPR2_SDTH: + spr2 = SPR2_DEAD; + break; + case SPR2_SDRN: + spr2 = SPR2_DRWN; + break; + case SPR2_SSPN: + spr2 = SPR2_SPIN; + break; + case SPR2_SGSP: + spr2 = SPR2_GASP; + break; + case SPR2_SJMP: + spr2 = ((player + ? player->charflags + : skin->flags) + & SF_NOJUMPSPIN) ? SPR2_SSPG : SPR2_SSPN; + break; + case SPR2_SSPG: + spr2 = SPR2_SPNG; + break; + case SPR2_SFAL: + spr2 = SPR2_FALL; + break; + case SPR2_SEDG: + spr2 = SPR2_EDGE; + break; + case SPR2_SRID: + spr2 = SPR2_RIDE; + break; + case SPR2_SFLT: + spr2 = SPR2_SWLK; + break; + + // NiGHTS sprites. + case SPR2_NTRN: + spr2 = SPR2_TRNS; + break; + case SPR2_NSTD: + spr2 = SPR2_SSTD; + break; + case SPR2_NFLT: + spr2 = (skin->flags & SF_SUPERANIMS) ? SPR2_SFLT : SPR2_FALL; // This is skin-exclusive so the default NiGHTS skin changing system plays nice. + break; + case SPR2_NPUL: + spr2 = SPR2_NFLT; + break; + case SPR2_NPAN: + spr2 = SPR2_NPUL; + break; + case SPR2_NATK: + spr2 = SPR2_SSPN; + break; + /*case SPR2_NGT0: + spr2 = SPR2_STND; + break;*/ + case SPR2_NGT1: + case SPR2_NGT7: + case SPR2_DRL0: + spr2 = SPR2_NGT0; + break; + case SPR2_NGT2: + case SPR2_DRL1: + spr2 = SPR2_NGT1; + break; + case SPR2_NGT3: + case SPR2_DRL2: + spr2 = SPR2_NGT2; + break; + case SPR2_NGT4: + case SPR2_DRL3: + spr2 = SPR2_NGT3; + break; + case SPR2_NGT5: + case SPR2_DRL4: + spr2 = SPR2_NGT4; + break; + case SPR2_NGT6: + case SPR2_DRL5: + spr2 = SPR2_NGT5; + break; + case SPR2_DRL6: + spr2 = SPR2_NGT6; + break; + case SPR2_NGT8: + case SPR2_DRL7: + spr2 = SPR2_NGT7; + break; + case SPR2_NGT9: + case SPR2_DRL8: + spr2 = SPR2_NGT8; + break; + case SPR2_NGTA: + case SPR2_DRL9: + spr2 = SPR2_NGT9; + break; + case SPR2_NGTB: + case SPR2_DRLA: + spr2 = SPR2_NGTA; + break; + case SPR2_NGTC: + case SPR2_DRLB: + spr2 = SPR2_NGTB; + break; + case SPR2_DRLC: + spr2 = SPR2_NGTC; + break; + + // Dunno? Just go to standing then. + default: + spr2 = SPR2_STND; + break; + } + } + return spr2; +} + // // P_SetPlayerMobjState // Returns true if the mobj is still present. @@ -366,216 +620,18 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) } } - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set - // Player animations if (st->sprite == SPR_PLAY) { skin_t *skin = ((skin_t *)mobj->skin); - boolean noalt = false; - UINT8 spr2 = st->frame & FF_FRAMEMASK; UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1; UINT8 numframes; - while (skin && ((numframes = skin->sprites[spr2].numframes) <= 0) - && spr2 != SPR2_STND) - { - switch(spr2) - { - case SPR2_PEEL: - spr2 = SPR2_RUN; - break; - case SPR2_RUN: - spr2 = SPR2_WALK; - break; - case SPR2_DRWN: - spr2 = SPR2_DEAD; - break; - case SPR2_DASH: - spr2 = SPR2_SPIN; - break; - case SPR2_GASP: - spr2 = SPR2_SPNG; - break; - case SPR2_JUMP: - spr2 = (player->charflags & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_SPIN; - break; - case SPR2_SPNG: // spring - spr2 = SPR2_FALL; - break; - case SPR2_FALL: - spr2 = SPR2_WALK; - break; - case SPR2_RIDE: - spr2 = SPR2_FALL; - break; + UINT8 spr2 = P_GetMobjSprite2(mobj, st->frame & FF_FRAMEMASK); - case SPR2_FLY: - spr2 = SPR2_SPNG; - break; - case SPR2_SWIM: - spr2 = SPR2_FLY; - break; - case SPR2_TIRE: - spr2 = (player->charability == CA_FLY) ? SPR2_FLY : SPR2_SWIM; - break; - - case SPR2_GLID: - spr2 = SPR2_FLY; - break; - case SPR2_CLMB: - spr2 = SPR2_SPIN; - break; - case SPR2_CLNG: - spr2 = SPR2_CLMB; - break; - - case SPR2_TWIN: - spr2 = SPR2_SPIN; - break; - - case SPR2_MLEE: - spr2 = SPR2_TWIN; - break; - - // Super sprites fallback to regular sprites - case SPR2_SWLK: - spr2 = SPR2_WALK; - break; - case SPR2_SRUN: - spr2 = SPR2_RUN; - break; - case SPR2_SPEE: - spr2 = SPR2_PEEL; - break; - case SPR2_SPAN: - spr2 = SPR2_PAIN; - break; - case SPR2_SSTN: - spr2 = SPR2_SPAN; - break; - case SPR2_SDTH: - spr2 = SPR2_DEAD; - break; - case SPR2_SDRN: - spr2 = SPR2_DRWN; - break; - case SPR2_SSPN: - spr2 = SPR2_SPIN; - break; - case SPR2_SGSP: - spr2 = SPR2_GASP; - break; - case SPR2_SJMP: - spr2 = (player->charflags & SF_NOJUMPSPIN) ? SPR2_SSPG : SPR2_SSPN; - break; - case SPR2_SSPG: - spr2 = SPR2_SPNG; - break; - case SPR2_SFAL: - spr2 = SPR2_FALL; - break; - case SPR2_SEDG: - spr2 = SPR2_EDGE; - break; - case SPR2_SRID: - spr2 = SPR2_RIDE; - break; - case SPR2_SFLT: - spr2 = SPR2_SWLK; - break; - - // NiGHTS sprites. - case SPR2_NTRN: - spr2 = SPR2_TRNS; - break; - case SPR2_NSTD: - spr2 = SPR2_SSTD; - break; - case SPR2_NFLT: - spr2 = (skin->flags & SF_SUPERANIMS) ? SPR2_SFLT : SPR2_FALL; // This is skin-exclusive so the default NiGHTS skin changing system plays nice. - break; - case SPR2_NPUL: - spr2 = SPR2_NFLT; - break; - case SPR2_NPAN: - spr2 = SPR2_NPUL; - break; - case SPR2_NATK: - spr2 = SPR2_SSPN; - break; - /*case SPR2_NGT0: - spr2 = SPR2_STND; - break;*/ - case SPR2_NGT1: - case SPR2_NGT7: - case SPR2_DRL0: - spr2 = SPR2_NGT0; - break; - case SPR2_NGT2: - case SPR2_DRL1: - spr2 = SPR2_NGT1; - break; - case SPR2_NGT3: - case SPR2_DRL2: - spr2 = SPR2_NGT2; - break; - case SPR2_NGT4: - case SPR2_DRL3: - spr2 = SPR2_NGT3; - break; - case SPR2_NGT5: - case SPR2_DRL4: - spr2 = SPR2_NGT4; - break; - case SPR2_NGT6: - case SPR2_DRL5: - spr2 = SPR2_NGT5; - break; - case SPR2_DRL6: - spr2 = SPR2_NGT6; - break; - case SPR2_NGT8: - case SPR2_DRL7: - spr2 = SPR2_NGT7; - break; - case SPR2_NGT9: - case SPR2_DRL8: - spr2 = SPR2_NGT8; - break; - case SPR2_NGTA: - case SPR2_DRL9: - spr2 = SPR2_NGT9; - break; - case SPR2_NGTB: - case SPR2_DRLA: - spr2 = SPR2_NGTA; - break; - case SPR2_NGTC: - case SPR2_DRLB: - spr2 = SPR2_NGTB; - break; - case SPR2_DRLC: - spr2 = SPR2_NGTC; - break; - - - // Sprites for non-player objects? There's nothing we can do. - case SPR2_SIGN: - case SPR2_LIFE: - noalt = true; - break; - - // Dunno? Just go to standing then. - default: - spr2 = SPR2_STND; - break; - } - if (noalt) - break; - } - - if (!skin) + if (skin) + numframes = skin->sprites[spr2].numframes; + else { frame = 0; numframes = 0; @@ -588,7 +644,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) } else if (mobj->sprite2 != spr2) { - if ((st->frame & FF_MIDDLESTARTCHANCE) && numframes && P_RandomChance(FRACUNIT/2)) + if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2)) frame = numframes/2; else frame = 0; @@ -598,7 +654,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) { if (st->frame & FF_SPR2ENDSTATE) // no frame advancement { - if (st->var1 == S_NULL) + if (st->var1 == mobj->state-states) frame--; else { @@ -621,10 +677,10 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) { mobj->sprite = st->sprite; mobj->frame = st->frame; - if ((st->frame & (FF_ANIMATE|FF_MIDDLESTARTCHANCE)) == (FF_ANIMATE|FF_MIDDLESTARTCHANCE)) - mobj->frame += P_RandomKey(st->var1+1); } + P_SetupStateAnimation(mobj, st); + // Modified handling. // Call action functions when the state is set @@ -689,16 +745,16 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) st = &states[state]; mobj->state = st; mobj->tics = st->tics; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set // Player animations if (st->sprite == SPR_PLAY) { skin_t *skin = ((skin_t *)mobj->skin); - UINT8 spr2 = st->frame & FF_FRAMEMASK; UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1; UINT8 numframes; + UINT8 spr2 = P_GetMobjSprite2(mobj, st->frame & FF_FRAMEMASK); + if (skin) numframes = skin->sprites[spr2].numframes; else @@ -714,7 +770,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) } else if (mobj->sprite2 != spr2) { - if ((st->frame & FF_MIDDLESTARTCHANCE) && numframes && P_RandomChance(FRACUNIT/2)) + if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2)) frame = numframes/2; else frame = 0; @@ -722,8 +778,17 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) if (frame >= numframes) { - if (st->frame & FF_SPR2ENDSTATE) - return P_SetPlayerMobjState(mobj, st->var1); // Differs from P_SetPlayerMobjState - allows object to be removed via S_NULL + if (st->frame & FF_SPR2ENDSTATE) // no frame advancement + { + if (st->var1 == mobj->state-states) + frame--; + else + { + if (mobj->frame & FF_FRAMEMASK) + mobj->frame--; + return P_SetMobjState(mobj, st->var1); + } + } else frame = 0; } @@ -736,10 +801,10 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) { mobj->sprite = st->sprite; mobj->frame = st->frame; - if ((st->frame & (FF_ANIMATE|FF_MIDDLESTARTCHANCE)) == (FF_ANIMATE|FF_MIDDLESTARTCHANCE)) - mobj->frame += P_RandomKey(st->var1+1); } + P_SetupStateAnimation(mobj, st); + // Modified handling. // Call action functions when the state is set @@ -792,7 +857,7 @@ boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation(mobj, st); return true; } @@ -811,7 +876,7 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation((mobj_t*)mobj, st); return true; } @@ -1019,14 +1084,12 @@ void P_EmeraldManager(void) else break; - if (leveltime < TICRATE) // Start of map - spawnpoints[j]->threshold = 60*TICRATE + P_RandomByte() * (TICRATE/5); - else - spawnpoints[j]->threshold = P_RandomByte() * (TICRATE/5); - + spawnpoints[j]->threshold = emeraldspawndelay + P_RandomByte() * (TICRATE/5); break; } } + + emeraldspawndelay = 0; } // @@ -1856,7 +1919,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) mo->momx = player->cmomx; mo->momy = player->cmomy; } - else + else if (!(mo->eflags & MFE_SPRUNG)) { if (oldx == mo->x && oldy == mo->y) // didn't go anywhere { @@ -2385,13 +2448,13 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp if (topheight > mo->floorz && abs(delta1) < abs(delta2) && (rover->flags & FF_SOLID) // Non-FF_SOLID Mario blocks are only solid from bottom && !(rover->flags & FF_REVERSEPLATFORM) - && ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference) + && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference) { mo->floorz = topheight; } if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) && !(rover->flags & FF_PLATFORM) - && ((P_MobjFlip(mo)*mo->momz > 0) || ((rover->flags & FF_SOLID) && !(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below + && ((P_MobjFlip(mo)*mo->momz >= 0) || ((rover->flags & FF_SOLID) && !(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below { mo->ceilingz = bottomheight; } @@ -2828,7 +2891,7 @@ static boolean P_ZMovement(mobj_t *mo) && abs(mom.y) < FixedMul(STOPSPEED, mo->scale) && abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) { - if (mo->flags & MF_AMBUSH) + if (mo->flags2 & MF2_AMBUSH) { // If deafed, give the tumbleweed another random kick if it runs out of steam. mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); @@ -4135,17 +4198,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) } animonly: - // cycle through states, - // calling action functions at transitions - if (mobj->tics != -1) - { - mobj->tics--; - - // you can cycle through multiple states in a tic - if (!mobj->tics) - if (!P_SetPlayerMobjState(mobj, mobj->state->nextstate)) - return; // freed itself - } + P_CyclePlayerMobjState(mobj); } static void CalculatePrecipFloor(precipmobj_t *mobj) @@ -4316,15 +4369,15 @@ boolean P_BossTargetPlayer(mobj_t *actor, boolean closest) player = &players[actor->lastlook]; - if (player->health <= 0) - continue; // dead - if (player->pflags & PF_INVIS || player->bot || player->spectator) continue; // ignore notarget if (!player->mo || P_MobjWasRemoved(player->mo)) continue; + if (player->mo->health <= 0) + continue; //dead + if (!P_CheckSight(actor, player->mo)) continue; // out of sight @@ -4354,15 +4407,15 @@ boolean P_SupermanLook4Players(mobj_t *actor) { if (playeringame[c]) { - if (players[c].health <= 0) - continue; // dead - if (players[c].pflags & PF_INVIS) continue; // ignore notarget if (!players[c].mo || players[c].bot) continue; + if (players[c].mo->health <= 0) + continue; // dead + playersinthegame[stop] = &players[c]; stop++; } @@ -6429,6 +6482,8 @@ void P_RunOverlays(void) P_UnsetThingPosition(mo); mo->x = destx; mo->y = desty; + mo->radius = mo->target->radius; + mo->height = mo->target->height; if (mo->eflags & MFE_VERTICALFLIP) mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs; else @@ -6766,7 +6821,7 @@ void P_MobjThinker(mobj_t *mobj) flame->angle = mobj->angle; - if (mobj->flags & MF_AMBUSH) // Wave up and down instead of side-to-side + if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side flame->momz = mobj->fuse << (FRACBITS-2); else flame->angle += FixedAngle(mobj->fuse*FRACUNIT); @@ -6801,7 +6856,7 @@ void P_MobjThinker(mobj_t *mobj) strength -= ((20*FRACUNIT)/16)*mobj->movedir; // If deaf'd, the object spawns on the ceiling. - if (mobj->flags & MF_AMBUSH) + if (mobj->flags2 & MF2_AMBUSH) { mobj->z = mobj->ceilingz-mobj->height; flame->momz = -strength; @@ -7133,7 +7188,7 @@ void P_MobjThinker(mobj_t *mobj) P_SetTarget(&mobj->target, NULL); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo - && players[i].mare == mobj->threshold && players[i].health > 1) + && players[i].mare == mobj->threshold && players[i].rings > 0) { fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); if (dist < shortest) @@ -7594,9 +7649,51 @@ void P_MobjThinker(mobj_t *mobj) mobj_t *flagmo, *newmobj; #ifdef HAVE_BLUA - if (!LUAh_MobjFuse(mobj) && !P_MobjWasRemoved(mobj)) + if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj)) + ; + else #endif - switch (mobj->type) + if (mobj->info->flags & MF_MONITOR) + { + // Special case for ALL monitors. + // If a box's speed is nonzero, it's allowed to respawn as a WRM/SRM. + if (mobj->info->speed != 0 && (mobj->flags2 & (MF2_AMBUSH|MF2_STRONGBOX))) + { + mobjtype_t spawnchance[64]; + INT32 numchoices = 0, i = 0; + +// This define should make it a lot easier to organize and change monitor weights +#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ +for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type + + // Type SRM WRM + SETMONITORCHANCES(MT_SNEAKERS_BOX, 0, 10); // Super Sneakers + SETMONITORCHANCES(MT_INVULN_BOX, 2, 0); // Invincibility + SETMONITORCHANCES(MT_WHIRLWIND_BOX, 3, 8); // Whirlwind Shield + SETMONITORCHANCES(MT_ELEMENTAL_BOX, 3, 8); // Elemental Shield + SETMONITORCHANCES(MT_ATTRACT_BOX, 2, 0); // Attraction Shield + SETMONITORCHANCES(MT_FORCE_BOX, 3, 3); // Force Shield + SETMONITORCHANCES(MT_ARMAGEDDON_BOX, 2, 0); // Armageddon Shield + SETMONITORCHANCES(MT_MIXUP_BOX, 0, 1); // Teleporters + SETMONITORCHANCES(MT_RECYCLER_BOX, 0, 1); // Recycler + SETMONITORCHANCES(MT_1UP_BOX, 1, 1); // 1-Up + // ======================================= + // Total 16 32 + +#undef SETMONITORCHANCES + + i = P_RandomKey(numchoices); // Gotta love those random numbers! + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); + } + else + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); + + // Transfer flags2 (ambush, strongbox, objectflip) + newmobj->flags2 = mobj->flags2; + P_RemoveMobj(mobj); // make sure they disappear + return; + } + else switch (mobj->type) { // gargoyle and snowman handled in P_PushableThinker, not here case MT_THROWNGRENADE: @@ -7655,68 +7752,6 @@ void P_MobjThinker(mobj_t *mobj) } P_RemoveMobj(mobj); return; - case MT_YELLOWTV: // Ring shield box - case MT_BLUETV: // Force shield box - case MT_GREENTV: // Water shield box - case MT_BLACKTV: // Bomb shield box - case MT_WHITETV: // Jump shield box - case MT_SNEAKERTV: // Super Sneaker box - case MT_SUPERRINGBOX: // 10-Ring box - case MT_REDRINGBOX: // Red Team 10-Ring box - case MT_BLUERINGBOX: // Blue Team 10-Ring box - case MT_INV: // Invincibility box - case MT_MIXUPBOX: // Teleporter Mixup box - case MT_RECYCLETV: // Recycler box - case MT_SCORETVSMALL: - case MT_SCORETVLARGE: - case MT_PRUP: // 1up! - case MT_EGGMANBOX: // Eggman box - case MT_GRAVITYBOX: // Gravity box - case MT_QUESTIONBOX: - if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) - { - mobjtype_t spawnchance[64]; - INT32 numchoices = 0, i = 0; - -// This define should make it a lot easier to organize and change monitor weights -#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ -for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type - - // Type SRM WRM - SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers - SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility - SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield - SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield - SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield - SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield - SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield - SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters - SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler - SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up - // ====================================== - // Total 16 32 - -#undef SETMONITORCHANCES - - i = P_RandomKey(numchoices); // Gotta love those random numbers! - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); - - // If the monitor respawns randomly, transfer the flag. - if (mobj->flags & MF_AMBUSH) - newmobj->flags |= MF_AMBUSH; - - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = mobj->flags2; - } - else - { - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); - - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = mobj->flags2; - } - P_RemoveMobj(mobj); // make sure they disappear - return; case MT_METALSONIC_BATTLE: break; // don't remove case MT_SPIKE: @@ -7733,6 +7768,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s default: P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. break; + // Looking for monitors? They moved to a special condition above. } if (P_MobjWasRemoved(mobj)) return; @@ -8025,7 +8061,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation(mobj, st); mobj->friction = ORIG_FRICTION; @@ -8251,7 +8287,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation((mobj_t*)mobj, st); // set subsector and/or block links P_SetPrecipitationThingPosition(mobj); @@ -8816,8 +8852,10 @@ void P_SpawnPlayer(INT32 playernum) // (usefulness: when body mobj is detached from player (who respawns), // the dead body mobj retains the skin through the 'spritedef' override). mobj->skin = &skins[p->skin]; + P_SetupStateAnimation(mobj, mobj->state); - mobj->health = p->health; + mobj->health = 1; + p->rings = 0; p->playerstate = PST_LIVE; p->bonustime = false; @@ -9183,36 +9221,37 @@ void P_SpawnMapThing(mapthing_t *mthing) if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) return; - // Set powerup boxes to user settings for competition. - if (gametype == GT_COMPETITION) + // Altering monitor spawns via cvars + // If MF_GRENADEBOUNCE is set in the monitor's info, + // skip this step. (Used for gold monitors) + // Yeah, this is a dirty hack. + if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR) { - if ((mobjinfo[i].flags & MF_MONITOR) && cv_competitionboxes.value) // not Normal + if (gametype == GT_COMPETITION) { + // Set powerup boxes to user settings for competition. if (cv_competitionboxes.value == 1) // Random - i = MT_QUESTIONBOX; + i = MT_MYSTERY_BOX; else if (cv_competitionboxes.value == 2) // Teleports - i = MT_MIXUPBOX; + i = MT_MIXUP_BOX; else if (cv_competitionboxes.value == 3) // None return; // Don't spawn! + // default case: normal } - } - - // Set powerup boxes to user settings for other netplay modes - else if (gametype != GT_COOP) - { - if ((mobjinfo[i].flags & MF_MONITOR) && cv_matchboxes.value) // not Normal + // Set powerup boxes to user settings for other netplay modes + else if (gametype != GT_COOP) { if (cv_matchboxes.value == 1) // Random - i = MT_QUESTIONBOX; - else if (cv_matchboxes.value == 3) // Don't spawn - return; - else // cv_matchboxes.value == 2, Non-Random + i = MT_MYSTERY_BOX; + else if (cv_matchboxes.value == 2) // Non-Random { - if (i == MT_QUESTIONBOX) + if (i == MT_MYSTERY_BOX) return; // don't spawn in Non-Random - mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! } + else if (cv_matchboxes.value == 3) // Don't spawn + return; + // default case: normal } } @@ -9220,8 +9259,8 @@ void P_SpawnMapThing(mapthing_t *mthing) { if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING) i = MT_RING; - else if (i == MT_BLUERINGBOX || i == MT_REDRINGBOX) - i = MT_SUPERRINGBOX; + else if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX) + i = MT_RING_BOX; else if (i == MT_BLUEFLAG || i == MT_REDFLAG) return; // No flags in non-CTF modes! } @@ -9248,23 +9287,27 @@ void P_SpawnMapThing(mapthing_t *mthing) return; /// \todo // 1UPs -->> Score TVs - else if (i == MT_PRUP) // 1UP + else if (i == MT_1UP_BOX) // 1UP { // Either or, doesn't matter which. if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) - i = MT_SCORETVLARGE; // 10,000 + i = MT_SCORE10K_BOX; // 10,000 else - i = MT_SCORETVSMALL; // 1,000 + i = MT_SCORE1K_BOX; // 1,000 } } if (ultimatemode) { - if (i == MT_PITYTV || i == MT_GREENTV || i == MT_YELLOWTV || i == MT_BLUETV || i == MT_BLACKTV || i == MT_WHITETV) + if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX + || i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX) return; // No shields in Ultimate mode - if (i == MT_SUPERRINGBOX && !G_IsSpecialStage(gamemap)) + if (i == MT_RING_BOX && !G_IsSpecialStage(gamemap)) return; // No rings in Ultimate mode (except special stages) + + // Don't include the gold repeating boxes here please. + // They're likely facets of the level's design and therefore required to progress. } if (i == MT_EMMY && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++))) @@ -9526,7 +9569,7 @@ ML_NOCLIMB : Direction not controllable if (firsttime) { // This is the outermost link in the chain - spawnee->flags |= MF_AMBUSH; + spawnee->flags2 |= MF2_AMBUSH; firsttime = false; } @@ -9677,7 +9720,7 @@ ML_NOCLIMB : Direction not controllable { // Inverted if uppermost bit is set if (mthing->angle & 16384) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; if (mthing->angle > 0) mobj->radius = (mthing->angle & 16383)*FRACUNIT; @@ -9766,7 +9809,7 @@ ML_NOCLIMB : Direction not controllable } //count 10 ring boxes into the number of rings equation too. - if (i == MT_SUPERRINGBOX) + if (i == MT_RING_BOX) nummaprings += 10; if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED) @@ -9845,16 +9888,11 @@ ML_NOCLIMB : Direction not controllable mobj->flags2 |= MF2_STANDONME; } - if (mobj->flags & MF_MONITOR) + if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) { // flag for strong/weak random boxes - if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum || - mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum || - mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum || - mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || - mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum || - mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum) - mobj->flags |= MF_AMBUSH; + // any monitor with nonzero speed is allowed to respawn like this + mobj->flags2 |= MF2_AMBUSH; } else if (mthing->type != mobjinfo[MT_AXIS].doomednum && @@ -9862,19 +9900,17 @@ ML_NOCLIMB : Direction not controllable mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum && mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum && mthing->type != mobjinfo[MT_STARPOST].doomednum) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } if (mthing->options & MTF_OBJECTSPECIAL) { - // flag for strong/weak random boxes - if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum || - mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum || - mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum || - mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || - mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum || - mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum) - mobj->flags2 |= MF2_STRONGBOX; + if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) + { + // flag for strong/weak random boxes + // any monitor with nonzero speed is allowed to respawn like this + mobj->flags2 |= MF2_STRONGBOX; + } // Requires you to be in bonus time to activate if (mobj->flags & MF_NIGHTSITEM) @@ -10201,7 +10237,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) P_SetMobjState(mobj, mobj->info->seestate); mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; mthing->mobj = mobj; } // All manners of rings and coins @@ -10275,7 +10311,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; mthing->mobj = mobj; } // *** @@ -10331,7 +10367,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if (mthing->options & MTF_AMBUSH) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } } // Diagonal rings (handles both types) @@ -10389,7 +10425,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if (mthing->options & MTF_AMBUSH) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } } // Rings of items (all six of them) @@ -10798,7 +10834,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai { mobj_t *th; angle_t an; - fixed_t x, y, z, slope = 0; + fixed_t x, y, z, slope = 0, speed; // angle at which you fire, is player angle an = angle; @@ -10830,9 +10866,13 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai P_SetTarget(&th->target, source); + speed = th->info->speed; + if (source->player && source->player->charability == CA_FLY) + speed = FixedMul(speed, 3*FRACUNIT/2); + th->angle = an; - th->momx = FixedMul(th->info->speed, FINECOSINE(an>>ANGLETOFINESHIFT)); - th->momy = FixedMul(th->info->speed, FINESINE(an>>ANGLETOFINESHIFT)); + th->momx = FixedMul(speed, FINECOSINE(an>>ANGLETOFINESHIFT)); + th->momy = FixedMul(speed, FINESINE(an>>ANGLETOFINESHIFT)); if (allowaim) { @@ -10840,7 +10880,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai th->momy = FixedMul(th->momy,FINECOSINE(source->player->aiming>>ANGLETOFINESHIFT)); } - th->momz = FixedMul(th->info->speed, slope); + th->momz = FixedMul(speed, slope); //scaling done here so it doesn't clutter up the code above th->momx = FixedMul(th->momx, th->scale); @@ -10863,3 +10903,34 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration) pl->flashcount = duration; pl->flashpal = type; } + +// +// P_SpawnMobjFromMobj +// Spawns an object with offsets relative to the position of another object. +// Scale, gravity flip, etc. is taken into account automatically. +// +mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type) +{ + mobj_t *newmobj; + + xofs = FixedMul(xofs, mobj->scale); + yofs = FixedMul(yofs, mobj->scale); + zofs = FixedMul(zofs, mobj->scale); + + newmobj = P_SpawnMobj(mobj->x + xofs, mobj->y + yofs, mobj->z + zofs, type); + if (!newmobj) + return NULL; + + if (mobj->eflags & MFE_VERTICALFLIP) + { + fixed_t elementheight = FixedMul(newmobj->info->height, mobj->scale); + + newmobj->eflags |= MFE_VERTICALFLIP; + newmobj->flags2 |= MF2_OBJECTFLIP; + newmobj->z = mobj->z + mobj->height - zofs - elementheight; + } + + newmobj->destscale = mobj->destscale; + P_SetScale(newmobj, mobj->scale); + return newmobj; +} diff --git a/src/p_mobj.h b/src/p_mobj.h index b6592cb3d..a8ec27f1a 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -107,8 +107,8 @@ typedef enum MF_NOSECTOR = 1<<3, // Don't use the blocklinks (inert but displayable) MF_NOBLOCKMAP = 1<<4, - // Not to be activated by sound, deaf monster. - MF_AMBUSH = 1<<5, + // Thin, paper-like collision bound (for visual equivalent, see FF_PAPERSPRITE) + MF_PAPERCOLLISION = 1<<5, // You can push this object. It can activate switches and things by pushing it on top. MF_PUSHABLE = 1<<6, // Object is a boss. @@ -151,10 +151,9 @@ typedef enum MF_PAIN = 1<<24, // This mobj will stick to any surface or solid object it touches. MF_STICKY = 1<<25, - // NiGHTS hidden item. Goes to seestate and turns MF_SPECIAL when paralooped. + // NiGHTS hidden item. Goes to seestate and turns MF_SPECIAL when paralooped. MF_NIGHTSITEM = 1<<26, // for chase camera, don't be blocked by things (partial clipping) - // (need comma at end of this for SOC editor) MF_NOCLIPTHING = 1<<27, // Missile bounces like a grenade. MF_GRENADEBOUNCE = 1<<28, @@ -192,6 +191,8 @@ typedef enum MF2_BOSSNOTRAP = 1<<24, // No Egg Trap after boss MF2_BOSSFLEE = 1<<25, // Boss is fleeing! MF2_BOSSDEAD = 1<<26, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) + MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH + MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) // free: to and including 1<<31 } mobjflag2_t; @@ -452,5 +453,6 @@ void P_EmeraldManager(void); extern mapthing_t *huntemeralds[MAXHUNTEMERALDS]; extern INT32 numhuntemeralds; extern boolean runemeraldmanager; +extern UINT16 emeraldspawndelay; extern INT32 numstarposts; #endif diff --git a/src/p_pspr.h b/src/p_pspr.h index 9420796ff..97d7adb94 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -37,14 +37,12 @@ /// \brief Frame flags: only the frame number - 0 to 511 (Frames from 0 to 63, Sprite2 number uses full range) #define FF_FRAMEMASK 0x1ff -/// \brief Frame flags: A change of state at the end of Sprite2 animation + +/// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation #define FF_SPR2ENDSTATE 0x1000 -/// \brief Frame flags: 50% of starting in middle of animation (Sprite2 and FF_ANIMATE) -#define FF_MIDDLESTARTCHANCE 0x2000 -/// \brief Frame flags: Simple stateless animation -#define FF_ANIMATE 0x4000 -/// \brief Frame flags: frame always appears full bright -#define FF_FULLBRIGHT 0x8000 +/// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation +#define FF_SPR2MIDSTART 0x2000 + /// \brief Frame flags: 0 = no trans(opaque), 1-15 = transl. table #define FF_TRANSMASK 0xf0000 /// \brief shift for FF_TRANSMASK @@ -60,6 +58,20 @@ #define FF_TRANS80 (tr_trans80<palette); - CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette); - - // now part of level loading since in future each level may have - // its own anim texture sequences, switches etc. - P_InitPicAnims(); + CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); @@ -3005,6 +3002,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) else R_FlushTextureCache(); // just reload it from file + // Reload ANIMATED / ANIMDEFS + P_InitPicAnims(); + // Flush and reload HUD graphics ST_UnloadGraphics(); HU_LoadGraphics(); diff --git a/src/p_spec.c b/src/p_spec.c index 09ffd50b4..760bf2363 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -224,8 +224,8 @@ static animdef_t harddefs[] = static animdef_t *animdefs = NULL; // A prototype; here instead of p_spec.h, so they're "private" -void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i); -void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i); +void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum); +void P_ParseAnimationDefintion(SINT8 istexture); /** Sets up texture and flat animations. * @@ -235,24 +235,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i); * Issues an error if any animation cycles are invalid. * * \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims - * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs) + * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_) */ void P_InitPicAnims(void) { // Init animation - INT32 i; // Position in the animdefs array INT32 w; // WAD - UINT8 *wadAnimdefs; // not to be confused with animdefs, the combined total of every ANIMATED lump in every WAD, or ANIMDEFS, the ZDoom lump I intend to implement later + UINT8 *animatedLump; UINT8 *currentPos; + size_t i; + + I_Assert(animdefs == NULL); if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR) { - if (animdefs) - { - Z_Free(animdefs); - animdefs = NULL; - } - for (w = 0, i = 0, maxanims = 0; w < numwadfiles; w++) + for (w = numwadfiles-1, maxanims = 0; w >= 0; w--) { UINT16 animatedLumpNum; UINT16 animdefsLumpNum; @@ -261,20 +258,20 @@ void P_InitPicAnims(void) animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0); if (animatedLumpNum != INT16_MAX) { - wadAnimdefs = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC); + animatedLump = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC); // Get the number of animations in the file - for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; maxanims++, currentPos+=23); + i = maxanims; + for (currentPos = animatedLump; *currentPos != UINT8_MAX; maxanims++, currentPos+=23); // Resize animdefs (or if it hasn't been created, create it) animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); // Sanity check it - if (!animdefs) { + if (!animdefs) I_Error("Not enough free memory for ANIMATED data"); - } // Populate the new array - for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; i++, currentPos+=23) + for (currentPos = animatedLump; *currentPos != UINT8_MAX; i++, currentPos+=23) { M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes @@ -282,15 +279,13 @@ void P_InitPicAnims(void) M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes } - Z_Free(wadAnimdefs); + Z_Free(animatedLump); } // Now find ANIMDEFS animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0); if (animdefsLumpNum != INT16_MAX) - { - P_ParseANIMDEFSLump(w, animdefsLumpNum, &i); - } + P_ParseANIMDEFSLump(w, animdefsLumpNum); } // Define the last one animdefs[maxanims].istexture = -1; @@ -350,16 +345,20 @@ void P_InitPicAnims(void) lastanim->istexture = -1; R_ClearTextureNumCache(false); + // Clear animdefs now that we're done with it. + // We'll only be using anims from now on. if (animdefs != harddefs) - Z_ChangeTag(animdefs, PU_CACHE); + Z_Free(animdefs); + animdefs = NULL; } -void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i) +void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum) { char *animdefsLump; size_t animdefsLumpLength; char *animdefsText; char *animdefsToken; + char *p; // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll // need to make a space of memory where I can ensure that it will terminate @@ -379,18 +378,19 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i) Z_Free(animdefsLump); // Now, let's start parsing this thing - animdefsToken = M_GetToken(animdefsText); + p = animdefsText; + animdefsToken = M_GetToken(p); while (animdefsToken != NULL) { if (stricmp(animdefsToken, "TEXTURE") == 0) { Z_Free(animdefsToken); - P_ParseAnimationDefintion(1, i); + P_ParseAnimationDefintion(1); } else if (stricmp(animdefsToken, "FLAT") == 0) { Z_Free(animdefsToken); - P_ParseAnimationDefintion(0, i); + P_ParseAnimationDefintion(0); } else if (stricmp(animdefsToken, "OSCILLATE") == 0) { @@ -401,23 +401,22 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i) { I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken); } - animdefsToken = M_GetToken(NULL); + // parse next line + while (*p != '\0' && *p != '\n') ++p; + if (*p == '\n') ++p; + animdefsToken = M_GetToken(p); } Z_Free(animdefsToken); Z_Free((void *)animdefsText); } -void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) +void P_ParseAnimationDefintion(SINT8 istexture) { char *animdefsToken; size_t animdefsTokenLength; char *endPos; INT32 animSpeed; - - // Increase the size to make room for the new animation definition - maxanims++; - animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); - animdefs[*i].istexture = istexture; + size_t i; // Startname animdefsToken = M_GetToken(NULL); @@ -451,14 +450,39 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) { I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); } - strncpy(animdefs[*i].startname, animdefsToken, 9); + + // Search for existing animdef + for (i = 0; i < maxanims; i++) + if (stricmp(animdefsToken, animdefs[i].startname) == 0) + { + //CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken); + + // If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found. + // Instead, we're just going to skip parsing the rest of this line entirely. + Z_Free(animdefsToken); + return; + } + + // Not found + if (i == maxanims) + { + // Increase the size to make room for the new animation definition + maxanims++; + animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); + strncpy(animdefs[i].startname, animdefsToken, 9); + } + + // animdefs[i].startname is now set to animdefsToken either way. Z_Free(animdefsToken); + // set texture type + animdefs[i].istexture = istexture; + // "RANGE" animdefsToken = M_GetToken(NULL); if (animdefsToken == NULL) { - I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[*i].startname); + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname); } if (stricmp(animdefsToken, "ALLOWDECALS") == 0) { @@ -473,7 +497,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) } if (stricmp(animdefsToken, "RANGE") != 0) { - I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[*i].startname, animdefsToken); + I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken); } Z_Free(animdefsToken); @@ -481,21 +505,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) animdefsToken = M_GetToken(NULL); if (animdefsToken == NULL) { - I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[*i].startname); + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname); } animdefsTokenLength = strlen(animdefsToken); if (animdefsTokenLength>8) { I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); } - strncpy(animdefs[*i].endname, animdefsToken, 9); + strncpy(animdefs[i].endname, animdefsToken, 9); Z_Free(animdefsToken); // "TICS" animdefsToken = M_GetToken(NULL); if (animdefsToken == NULL) { - I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[*i].startname); + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname); } if (stricmp(animdefsToken, "RAND") == 0) { @@ -504,7 +528,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) } if (stricmp(animdefsToken, "TICS") != 0) { - I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[*i].startname, animdefsToken); + I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken); } Z_Free(animdefsToken); @@ -512,7 +536,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) animdefsToken = M_GetToken(NULL); if (animdefsToken == NULL) { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname); + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname); } endPos = NULL; #ifndef AVOID_ERRNO @@ -526,13 +550,10 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) #endif || animSpeed < 0) // Number is not positive { - I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken); + I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken); } - animdefs[*i].speed = animSpeed; + animdefs[i].speed = animSpeed; Z_Free(animdefsToken); - - // Increment i before we go, so this doesn't cause issues later - (*i)++; } @@ -1603,10 +1624,10 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!playeringame[i] || players[i].spectator) continue; - if (!players[i].mo || players[i].mo->health < 1) + if (!players[i].mo || players[i].rings <= 0) continue; - rings += players[i].mo->health-1; + rings += players[i].rings; } } else @@ -1614,7 +1635,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!(actor && actor->player)) return false; // no player to count rings from here, sorry - rings = actor->health-1; + rings = actor->player->rings; } if (triggerline->flags & ML_NOCLIMB) @@ -3530,10 +3551,9 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers break; case 9: // Ring Drainer (Floor Touch) case 10: // Ring Drainer (No Floor Touch) - if (leveltime % (TICRATE/2) == 0 && player->mo->health > 1) + if (leveltime % (TICRATE/2) == 0 && player->rings > 0) { - player->mo->health--; - player->health--; + player->rings--; S_StartSound(player->mo, sfx_itemup); } break; @@ -3541,7 +3561,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super] || player->exiting || player->bot) break; - if (!(player->powers[pw_shield] || player->mo->health > 1)) // Don't do anything if no shield or rings anyway + if (!(player->powers[pw_shield] || player->rings > 0)) // Don't do anything if no shield or rings anyway break; if (player->powers[pw_shield]) @@ -3549,14 +3569,13 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers P_RemoveShield(player); S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss. } - else if (player->mo->health > 1) + else if (player->rings > 0) { P_PlayRinglossSound(player->mo); - if (player->mo->health > 10) - player->mo->health -= 10; + if (player->rings >= 10) + player->rings -= 10; else - player->mo->health = 1; - player->health = player->mo->health; + player->rings = 0; } P_DoPlayerPain(player, NULL, NULL); // this does basically everything that was here before @@ -6750,31 +6769,6 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3 P_AddThinker(&s->thinker); } -/** Adds a wall scroller. - * Scroll amount is rotated with respect to wall's linedef first, so that - * scrolling towards the wall in a perpendicular direction is translated into - * vertical motion, while scrolling along the wall in a parallel direction is - * translated into horizontal motion. - * - * \param dx x speed of scrolling or its acceleration. - * \param dy y speed of scrolling or its acceleration. - * \param l Line whose front side will scroll. - * \param control Sector whose heights control this scroller's effect - * remotely, or -1 if there is no control sector. - * \param accel Nonzero for an accelerative effect. - * \sa Add_Scroller, P_SpawnScrollers - */ -static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l, INT32 control, INT32 accel) -{ - fixed_t x = abs(l->dx), y = abs(l->dy), d; - if (y > x) - d = x, x = y, y = d; - d = FixedDiv(x, FINESINE((tantoangle[FixedDiv(y, x) >> DBITS] + ANGLE_90) >> ANGLETOFINESHIFT)); - x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); - y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); - Add_Scroller(sc_side, x, y, control, *l->sidenum, accel, 0); -} - /** Initializes the scrollers. * * \todo Get rid of all the magic numbers. @@ -6857,7 +6851,7 @@ static void P_SpawnScrollers(void) case 502: for (s = -1; (s = P_FindLineFromLineTag(l, s)) >= 0 ;) if (s != (INT32)i) - Add_WallScroller(dx, dy, lines+s, control, accel); + Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0); break; case 505: @@ -7446,7 +7440,7 @@ void T_Pusher(pusher_t *p) } else { - if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1))) + if (top < thing->z || bottom > (thing->z + (thing->height >> 1))) continue; if (thing->z + thing->height > top) touching = true; diff --git a/src/p_tick.c b/src/p_tick.c index 55df9ca28..5235a1a03 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -469,7 +469,7 @@ static inline void P_DoSpecialStageStuff(void) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { - ssrings += (players[i].mo->health-1); + ssrings += players[i].rings; // If in water, deplete timer 6x as fast. if ((players[i].mo->eflags & MFE_TOUCHWATER) diff --git a/src/p_user.c b/src/p_user.c index d615151a4..5b8523c0c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -625,7 +625,7 @@ static void P_DeNightserizePlayer(player_t *player) if (!(mo2->type == MT_NIGHTSDRONE)) continue; - if (mo2->flags & MF_AMBUSH) + if (mo2->flags2 & MF2_AMBUSH) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); break; @@ -697,7 +697,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) { for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]/* && players[i].pflags & PF_NIGHTSMODE*/) - total_rings += players[i].health-1; + total_rings += players[i].rings; } for (i = 0; i < MAXPLAYERS; i++) @@ -715,8 +715,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) } else { - players[i].finishedrings = (INT16)(players[i].health - 1); - P_AddPlayerScore(&players[i], (players[i].health - 1) * 50); + players[i].finishedrings = (INT16)(players[i].rings); + P_AddPlayerScore(&players[i], (players[i].rings) * 50); } // Add score to leaderboards now @@ -727,7 +727,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) players[i].lastmarescore = players[i].marescore; players[i].marescore = 0; - players[i].mo->health = players[i].health = 1; + players[i].rings = 0; P_DoPlayerExit(&players[i]); } } @@ -735,12 +735,12 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) { /// \todo Handle multi-mare special stages. // Ring bonus - P_AddPlayerScore(player, (player->health - 1) * 50); + P_AddPlayerScore(player, (player->rings) * 50); player->lastmare = (UINT8)oldmare; player->texttimer = 4*TICRATE; player->textvar = 4; // Score and grades - player->finishedrings = (INT16)(player->health - 1); + player->finishedrings = (INT16)(player->rings); // Add score to temp leaderboards if (!(netgame||multiplayer) && P_IsLocalPlayer(player)) @@ -751,7 +751,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->marescore = 0; player->marebegunat = leveltime; - player->mo->health = player->health = 1; + player->rings = 0; } else { @@ -895,30 +895,23 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) if (!player->mo) return; - player->mo->health += num_rings; - player->health += num_rings; + player->rings += num_rings; if (!G_IsSpecialStage(gamemap) || !useNightsSS) player->totalring += num_rings; // Can only get up to 9999 rings, sorry! - if (player->mo->health > 10000) - { - player->mo->health = 10000; - player->health = 10000; - } - else if (player->mo->health < 1) - { - player->mo->health = 1; - player->health = 1; - } + if (player->rings > 9999) + player->rings = 9999; + else if (player->rings < 0) + player->rings = 0; // Now extra life bonuses are handled here instead of in P_MovePlayer, since why not? if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives()) { INT32 gainlives = 0; - while (player->xtralife < maxXtraLife && player->health > 100 * (player->xtralife+1)) + while (player->xtralife < maxXtraLife && player->rings >= 100 * (player->xtralife+1)) { ++gainlives; ++player->xtralife; @@ -958,7 +951,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings) if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player)) { S_StopMusic(); - S_ChangeMusicInternal("supers", true); + S_ChangeMusicInternal("_super", true); } S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi @@ -969,10 +962,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings) player->mo->momx = player->mo->momy = player->mo->momz = 0; if (giverings) - { - player->mo->health = 51; - player->health = player->mo->health; - } + player->rings = 50; // Just in case. if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC)) @@ -991,6 +981,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings) P_PlayerFlagBurst(player, false); } + // Adds to the player's score void P_AddPlayerScore(player_t *player, UINT32 amount) { @@ -1077,6 +1068,42 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) } } +// Steals from every enemy's score. +void P_StealPlayerScore(player_t *player, UINT32 amount) +{ + boolean teams = G_GametypeHasTeams(); + UINT32 stolen = 0; + int i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (&players[i] == player + || (teams && players[i].ctfteam == player->ctfteam)) + continue; + if (players[i].score >= amount) + { + stolen += amount; + players[i].score -= amount; + } + else + { + stolen += players[i].score; + players[i].score = 0; + } + } + if (stolen > 0) + { + // In team match, all stolen points are removed from the enemy team's running score. + if (gametype == GT_TEAMMATCH) + { + if (player->ctfteam == 1) + bluescore -= amount; + else if (player->ctfteam == 2) + redscore -= amount; + } + P_AddPlayerScore(player, stolen); + } +} + // // P_PlayLivesJingle // @@ -1094,7 +1121,7 @@ void P_PlayLivesJingle(player_t *player) if (player) player->powers[pw_extralife] = extralifetics + 1; S_StopMusic(); // otherwise it won't restart if this is done twice in a row - S_ChangeMusicInternal("xtlife", false); + S_ChangeMusicInternal("_1up", false); } } @@ -1112,9 +1139,9 @@ void P_RestoreMusic(player_t *player) return; S_SpeedMusic(1.0f); if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC)) - S_ChangeMusicInternal("supers", true); + S_ChangeMusicInternal("_super", true); else if (player->powers[pw_invulnerability] > 1) - S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", false); + S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super]) { if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC) @@ -1123,7 +1150,7 @@ void P_RestoreMusic(player_t *player) S_ChangeMusic(mapmusname, mapmusflags, true); } else - S_ChangeMusicInternal("shoes", true); + S_ChangeMusicInternal("_shoes", true); } else S_ChangeMusic(mapmusname, mapmusflags, true); @@ -2054,7 +2081,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) && player == &players[consoleplayer]) { S_StopMusic(); - S_ChangeMusicInternal("drown", false); + S_ChangeMusicInternal("_drown", false); } } @@ -2262,14 +2289,13 @@ static void P_DoClimbing(player_t *player) fixed_t platy; subsector_t *glidesector; boolean climb = true; - boolean onesided = ((player->lastsidehit != -1 && player->lastlinehit != -1) && !(lines[player->lastlinehit].backsector)); platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); + glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy); - if (onesided || glidesector->sector != player->mo->subsector->sector) + if (!glidesector || glidesector->sector != player->mo->subsector->sector) { boolean floorclimb = false; boolean thrust = false; @@ -2277,7 +2303,7 @@ static void P_DoClimbing(player_t *player) boolean skyclimber = false; fixed_t floorheight, ceilingheight; // ESLOPE - if (onesided) + if (!glidesector) floorclimb = true; else { @@ -3130,72 +3156,61 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) mobj_t *mo = NULL; player->pflags |= PF_ATTACKDOWN; + #define TAKE_AMMO(player, power) \ + player->powers[power]--; \ + if (player->rings < 1) \ + { \ + if (player->powers[power] > 0) \ + player->powers[power]--; \ + } \ + else \ + player->rings--; + if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring. goto firenormal; //code repetition sucks. // Bounce ring else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering]) { - if (player->health <= 1) - return; + TAKE_AMMO(player, pw_bouncering); P_SetWeaponDelay(player, TICRATE/4); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING); if (mo) mo->fuse = 3*TICRATE; // Bounce Ring time - - player->powers[pw_bouncering]--; - player->mo->health--; - player->health--; } // Rail ring else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring]) { - if (player->health <= 1) - return; + TAKE_AMMO(player, pw_railring); P_SetWeaponDelay(player, (3*TICRATE)/2); mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW); // Rail has no unique thrown object, therefore its sound plays here. S_StartSound(player->mo, sfx_rail1); - - player->powers[pw_railring]--; - player->mo->health--; - player->health--; } // Automatic else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring]) { - if (player->health <= 1) - return; + TAKE_AMMO(player, pw_automaticring); player->pflags &= ~PF_ATTACKDOWN; P_SetWeaponDelay(player, 2); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNAUTOMATIC, MF2_AUTOMATIC); - - player->powers[pw_automaticring]--; - player->mo->health--; - player->health--; } // Explosion else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring]) { - if (player->health <= 1) - return; + TAKE_AMMO(player, pw_explosionring); P_SetWeaponDelay(player, (3*TICRATE)/2); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION); - - player->powers[pw_explosionring]--; - player->mo->health--; - player->health--; } // Grenade else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering]) { - if (player->health <= 1) - return; + TAKE_AMMO(player, pw_grenadering); P_SetWeaponDelay(player, TICRATE/3); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION); @@ -3205,10 +3220,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) //P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale)); mo->fuse = mo->info->mass; } - - player->powers[pw_grenadering]--; - player->mo->health--; - player->health--; } // Scatter // Note: Ignores MF2_RAILRING @@ -3218,8 +3229,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) angle_t shotangle = player->mo->angle; angle_t oldaiming = player->aiming; - if (player->health <= 1) - return; + TAKE_AMMO(player, pw_scatterring); P_SetWeaponDelay(player, (2*TICRATE)/3); // Center @@ -3245,10 +3255,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) player->mo->z = oldz; player->aiming = oldaiming; - - player->powers[pw_scatterring]--; - player->mo->health--; - player->health--; return; } // No powers, just a regular ring. @@ -3272,7 +3278,7 @@ firenormal: // Red Ring else { - if (player->health <= 1) + if (player->rings <= 0) return; P_SetWeaponDelay(player, TICRATE/4); @@ -3281,11 +3287,12 @@ firenormal: if (mo) P_ColorTeamMissile(mo, player); - player->mo->health--; - player->health--; + player->rings--; } } + #undef TAKE_AMMO + if (mo) { if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING) @@ -3336,7 +3343,7 @@ static void P_DoSuperStuff(player_t *player) return; // NiGHTS Super doesn't mix with normal super // Does player have all emeralds? If so, flag the "Ready For Super!" - if ((ALL7EMERALDS(emeralds) || ALL7EMERALDS(player->powers[pw_emeralds])) && player->health > 50) + if (ALL7EMERALDS(emeralds) && player->rings >= 50) player->pflags |= PF_SUPERREADY; else player->pflags &= ~PF_SUPERREADY; @@ -3344,7 +3351,7 @@ static void P_DoSuperStuff(player_t *player) if (player->powers[pw_super]) { // If you're super and not Sonic, de-superize! - if (!((ALL7EMERALDS(emeralds)) && (player->charflags & SF_SUPER)) && !(ALL7EMERALDS(player->powers[pw_emeralds]))) + if (!(ALL7EMERALDS(emeralds) && player->charflags & SF_SUPER)) { player->powers[pw_super] = 0; P_SetPlayerMobjState(player->mo, S_PLAY_STND); @@ -3374,10 +3381,7 @@ static void P_DoSuperStuff(player_t *player) // Deplete one ring every second while super if ((leveltime % TICRATE == 0) && !(player->exiting)) - { - player->health--; - player->mo->health--; - } + player->rings--; player->mo->color = (player->pflags & PF_GODMODE && cv_debug == 0) ? (SKINCOLOR_SUPERSILVER1 + 5*((leveltime >> 1) % 7)) // A wholesome easter egg. @@ -3394,7 +3398,7 @@ static void P_DoSuperStuff(player_t *player) G_GhostAddColor(GHC_SUPER); // Ran out of rings while super! - if (player->health <= 1 || player->exiting) + if (player->rings <= 0 || player->exiting) { player->powers[pw_emeralds] = 0; // lost the power stones P_SpawnGhostMobj(player->mo); @@ -3451,12 +3455,6 @@ static void P_DoSuperStuff(player_t *player) P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); break; } - - if (!player->exiting) - { - player->health = 1; - player->mo->health = 1; - } } // Inform the netgame that the champion has fallen in the heat of battle. @@ -3484,12 +3482,12 @@ static void P_DoSuperStuff(player_t *player) // boolean P_SuperReady(player_t *player) { - if ((player->pflags & PF_SUPERREADY) && !player->powers[pw_super] && !player->powers[pw_tailsfly] + if (player->pflags & PF_SUPERREADY && !player->powers[pw_super] && !player->powers[pw_tailsfly] && !(player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_invulnerability] && !(maptol & TOL_NIGHTS) // don't turn 'regular super' in nights levels && player->pflags & PF_JUMPED - && ((player->charflags & SF_SUPER) || ALL7EMERALDS(player->powers[pw_emeralds]))) + && player->charflags & SF_SUPER) return true; return false; @@ -4086,13 +4084,6 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags |= PF_GLIDING|PF_THOKKED; player->glidetime = 0; - if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - { - // Glide at double speed while super. - glidespeed *= 2; - player->pflags &= ~PF_THOKKED; - } - P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); P_InstaThrust(player->mo, player->mo->angle, FixedMul(glidespeed, player->mo->scale)); player->pflags &= ~(PF_SPINNING|PF_STARTDASH); @@ -4217,8 +4208,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_JUMPDOWN; // Repeat abilities, but not double jump! - if ((player->charability2 == CA2_MULTIABILITY && player->charability != CA_DOUBLEJUMP) - || (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) + if (player->charability2 == CA2_MULTIABILITY && player->charability != CA_DOUBLEJUMP) player->secondjump = 0; else if (player->charability == CA_FLOAT && player->secondjump == 1) player->secondjump = 2; @@ -4462,9 +4452,6 @@ static void P_2dMovement(player_t *player) if (cmd->forwardmove != 0) P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT,10*FRACUNIT), false); - if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - player->mo->momz *= 2; - player->mo->momx = 0; } else if (cmd->sidemove != 0 && !(player->pflags & PF_GLIDING || player->exiting @@ -4665,11 +4652,7 @@ static void P_3dMovement(player_t *player) if (player->climbing) { if (cmd->forwardmove) - { P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT, 10*FRACUNIT), false); - if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - player->mo->momz *= 2; - } } else if (!analogmove && cmd->forwardmove != 0 && !(player->pflags & PF_GLIDING || player->exiting @@ -4703,12 +4686,7 @@ static void P_3dMovement(player_t *player) } // Sideways movement if (player->climbing) - { - if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FixedMul(FixedDiv(cmd->sidemove*FRACUNIT, 5*FRACUNIT), player->mo->scale)); - else - P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FixedMul(FixedDiv(cmd->sidemove*FRACUNIT, 10*FRACUNIT), player->mo->scale)); - } + P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FixedMul(FixedDiv(cmd->sidemove*FRACUNIT, 10*FRACUNIT), player->mo->scale)); // Analog movement control else if (analogmove) { @@ -5006,7 +4984,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad boolean transfer1last = false; boolean transfer2last = false; vertex_t vertices[4]; - fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags & MF_AMBUSH ? -1 : 1); + fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags2 & MF2_AMBUSH ? -1 : 1); // Find next waypoint for (th = thinkercap.next; th != &thinkercap; th = th->next) @@ -5437,12 +5415,10 @@ static void P_DoNiGHTSCapsule(player_t *player) if (G_IsSpecialStage(gamemap)) { // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here! for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (&players[i] != player) && players[i].mo->health > 1) + if (playeringame[i] && (&players[i] != player) && players[i].rings > 0) { - player->mo->health += players[i].mo->health-1; - player->health = player->mo->health; - players[i].mo->health = 1; - players[i].health = players[i].mo->health; + player->rings += players[i].rings; + players[i].rings = 0; } } @@ -5451,10 +5427,9 @@ static void P_DoNiGHTSCapsule(player_t *player) && player->mo->y == player->capsule->y && player->mo->z == player->capsule->z+(player->capsule->height/3)) { - if (player->mo->health > 1) + if (player->rings > 0) { - player->mo->health--; - player->health--; + player->rings--; player->capsule->health--; player->capsule->extravalue1++; @@ -5624,7 +5599,7 @@ static void P_NiGHTSMovement(player_t *player) } else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE) // S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH - S_ChangeMusicInternal("drown",false); + S_ChangeMusicInternal("_drown",false); if (player->mo->z < player->mo->floorz) @@ -5683,7 +5658,7 @@ static void P_NiGHTSMovement(player_t *player) // The 'ambush' flag says you should rotate // the other way around the axis. - if (player->mo->target->flags & MF_AMBUSH) + if (player->mo->target->flags2 & MF2_AMBUSH) backwardaxis = true; player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); @@ -6146,7 +6121,7 @@ static void P_PlayerDropWeapon(player_t *player) if (mo) { - player->mo->health--; + player->rings--; P_InstaThrust(mo, player->mo->angle-ANGLE_180, 8*FRACUNIT); P_SetObjectMomZ(mo, 4*FRACUNIT, false); mo->flags2 |= MF2_DONTRESPAWN; @@ -6452,7 +6427,7 @@ static void P_MovePlayer(player_t *player) if (playeringame[i]) players[i].exiting = (14*TICRATE)/5 + 1; } - else if (player->health > 1) + else if (player->rings > 0) P_DamageMobj(player->mo, NULL, NULL, 1, 0); player->pflags &= ~PF_NIGHTSFALL; } @@ -6610,8 +6585,8 @@ static void P_MovePlayer(player_t *player) P_ResetPlayer(player); // down, stop gliding. if (onground) P_SetPlayerMobjState(player->mo, S_PLAY_WALK); - else if ((player->charability2 == CA2_MULTIABILITY) - || (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]) && player->charability == CA_GLIDEANDCLIMB)) + else if (player->charability2 == CA2_MULTIABILITY + && player->charability == CA_GLIDEANDCLIMB) { player->pflags |= PF_JUMPED; P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); @@ -6864,11 +6839,6 @@ static void P_MovePlayer(player_t *player) { if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) P_DoJumpShield(player); - else if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]) && player->charability == CA_FLY) - { - P_DoJumpShield(player); - player->mo->momz *= 2; - } } // Bomb shield activation if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) @@ -7465,12 +7435,12 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) mo->flags |= MF_SPECIAL|MF_SHOOTABLE; if (mo->type == MT_EGGGUARD && mo->tracer) //nuke Egg Guard's shield! - P_KillMobj(mo->tracer, inflictor, source, 0); + P_KillMobj(mo->tracer, inflictor, source, DMG_NUKE); if (mo->flags & MF_BOSS || mo->type == MT_PLAYER) //don't OHKO bosses nor players! - P_DamageMobj(mo, inflictor, source, 1, 0); + P_DamageMobj(mo, inflictor, source, 1, DMG_NUKE); else - P_DamageMobj(mo, inflictor, source, 1000, 0); + P_DamageMobj(mo, inflictor, source, 1000, DMG_NUKE); } } @@ -7978,7 +7948,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else if (player->mo->target) { - if (player->mo->target->flags & MF_AMBUSH) + if (player->mo->target->flags2 & MF2_AMBUSH) angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); else angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y); @@ -8634,7 +8604,7 @@ void P_DoPityCheck(player_t *player) if ((player->pity >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE) { if (player->pity > 0) - S_StartSound(player->mo, mobjinfo[MT_PITYSHIELDICO].seesound); + S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound); player->pity = 0; player->powers[pw_shield] = SH_PITY; @@ -8659,7 +8629,7 @@ void P_PlayerThink(player_t *player) #endif // todo: Figure out what is actually causing these problems in the first place... - if ((player->health <= 0 || player->mo->health <= 0) && player->playerstate == PST_LIVE) //you should be DEAD! + if (player->mo->health <= 0 && player->playerstate == PST_LIVE) //you should be DEAD! { CONS_Debug(DBG_GAMELOGIC, "P_PlayerThink: Player %s in PST_LIVE with 0 health. (\"Zombie bug\")\n", sizeu1(playeri)); player->playerstate = PST_DEAD; @@ -8752,14 +8722,14 @@ void P_PlayerThink(player_t *player) if (countdown == 11*TICRATE - 1) { if (P_IsLocalPlayer(player)) - S_ChangeMusicInternal("drown", false); + S_ChangeMusicInternal("_drown", false); } // If you've hit the countdown and you haven't made // it to the exit, you're a goner! else if (countdown == 1 && !player->exiting && player->lives > 0) { - if (netgame && player->health > 0) + if (netgame && player->mo->health > 0) CONS_Printf(M_GetText("%s ran out of time.\n"), player_names[player-players]); player->pflags |= PF_TIMEOVER; @@ -8848,7 +8818,7 @@ void P_PlayerThink(player_t *player) { player->score = 0; player->mo->health = 1; - player->health = 1; + player->rings = 0; } if ((netgame || multiplayer) && player->lives <= 0) @@ -9021,7 +8991,7 @@ void P_PlayerThink(player_t *player) if (player->powers[pw_flashing] && player->powers[pw_flashing] < UINT16_MAX && ((player->pflags & PF_NIGHTSMODE) || player->powers[pw_flashing] < flashingtics)) player->powers[pw_flashing]--; - if (player->powers[pw_tailsfly] && player->powers[pw_tailsfly] < UINT16_MAX && player->charability != CA_SWIM && !(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) // tails fly counter + if (player->powers[pw_tailsfly] && player->powers[pw_tailsfly] < UINT16_MAX && player->charability != CA_SWIM) // tails fly counter player->powers[pw_tailsfly]--; if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)) @@ -9337,10 +9307,6 @@ void P_PlayerAfterThink(player_t *player) if (player->currentweapon == WEP_RAIL && (!(player->ringweapons & RW_RAIL) || !player->powers[pw_railring])) player->currentweapon = 0; - // If you're out of rings, but have Infinity Rings left, switch to that. - if (player->currentweapon != 0 && player->health <= 1 && player->powers[pw_infinityring]) - player->currentweapon = 0; - if (P_IsLocalPlayer(player) && (player->pflags & PF_WPNDOWN) && player->currentweapon != oldweapon) S_StartSound(NULL, sfx_wepchg); diff --git a/src/r_data.c b/src/r_data.c index cb5cf3591..b92d88f19 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -263,7 +263,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) texturememory += blocksize; block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); - memset(block, 0xF7, blocksize+1); // Transparency hack + memset(block, 0xFF, blocksize+1); // Transparency hack // columns lookup table colofs = (UINT32 *)(void *)block; @@ -1499,6 +1499,9 @@ void R_InitData(void) CONS_Printf("R_LoadTextures()...\n"); R_LoadTextures(); + CONS_Printf("P_InitPicAnims()...\n"); + P_InitPicAnims(); + CONS_Printf("R_InitSprites()...\n"); R_InitSpriteLumps(); R_InitSprites(); diff --git a/src/r_main.c b/src/r_main.c index 79ee803e1..b05e37b53 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -771,7 +771,7 @@ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y) } // -// R_IsPointInSubsector, same as above but returns 0 if not in subsector - this does not work in opengl because of polyvertex_t +// R_IsPointInSubsector, same as above but returns 0 if not in subsector // subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) { @@ -795,7 +795,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) ret = &subsectors[nodenum & ~NF_SUBSECTOR]; for (i = 0; i < ret->numlines; i++) - if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) + //if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers + if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side) return 0; return ret; diff --git a/src/r_plane.c b/src/r_plane.c index ad30f4247..e21e15d1a 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -709,6 +709,7 @@ void R_DrawPlanes(void) if (dc_yl <= dc_yh) { angle = (pl->viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; + dc_iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); dc_x = x; dc_source = R_GetColumn(texturetranslation[skytexture], diff --git a/src/r_segs.c b/src/r_segs.c index cb78743b6..257be2989 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -728,6 +728,12 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) // Render FOF sides kinda like normal sides, with the frac and step and everything // NOTE: INT64 instead of fixed_t because overflow concerns INT64 top_frac, top_step, bottom_frac, bottom_step; + // skew FOF walls with slopes? + boolean slopeskew = false; + fixed_t ffloortextureslide = 0; + INT32 oldx = -1; + fixed_t left_top, left_bottom; // needed here for slope skewing + pslope_t *skewslope = NULL; #endif void (*colfunc_2s) (column_t *); @@ -951,21 +957,71 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) mceilingclip = ds->sprtopclip; dc_texheight = textureheight[texnum]>>FRACBITS; +#ifdef ESLOPE + // calculate both left ends + if (*pfloor->t_slope) + left_top = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) - viewz; + else + left_top = *pfloor->topheight - viewz; + + if (*pfloor->b_slope) + left_bottom = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) - viewz; + else + left_bottom = *pfloor->bottomheight - viewz; + skewslope = *pfloor->t_slope; // skew using top slope by default + if (newline) + { + if (newline->flags & ML_DONTPEGTOP) + slopeskew = true; + } + else if (pfloor->master->flags & ML_DONTPEGTOP) + slopeskew = true; + + if (slopeskew) + dc_texturemid = left_top; + else +#endif dc_texturemid = *pfloor->topheight - viewz; if (newline) { offsetvalue = sides[newline->sidenum[0]].rowoffset; if (newline->flags & ML_DONTPEGBOTTOM) + { +#ifdef ESLOPE + skewslope = *pfloor->b_slope; // skew using bottom slope + if (slopeskew) + dc_texturemid = left_bottom; + else +#endif offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; + } } else { offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset; if (curline->linedef->flags & ML_DONTPEGBOTTOM) + { +#ifdef ESLOPE + skewslope = *pfloor->b_slope; // skew using bottom slope + if (slopeskew) + dc_texturemid = left_bottom; + else +#endif offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; + } } +#ifdef ESLOPE + if (slopeskew) + { + angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); + + if (skewslope) + ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT)); + } +#endif + dc_texturemid += offsetvalue; //faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures @@ -981,23 +1037,18 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) #ifdef ESLOPE // Set heights according to plane, or slope, whichever { - fixed_t left_top, right_top, left_bottom, right_bottom; + fixed_t right_top, right_bottom; + // calculate right ends now if (*pfloor->t_slope) - { - left_top = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) - viewz; right_top = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) - viewz; - } else - left_top = right_top = *pfloor->topheight - viewz; + right_top = *pfloor->topheight - viewz; if (*pfloor->b_slope) - { - left_bottom = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) - viewz; right_bottom = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) - viewz; - } else - left_bottom = right_bottom = *pfloor->bottomheight - viewz; + right_bottom = *pfloor->bottomheight - viewz; // using INT64 to avoid 32bit overflow top_frac = (INT64)centeryfrac - (((INT64)left_top * ds->scale1) >> FRACBITS); @@ -1021,6 +1072,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { if (maskedtexturecol[dc_x] != INT16_MAX) { +#ifdef ESLOPE + if (ffloortextureslide) { // skew FOF walls + if (oldx != -1) + dc_texturemid += FixedMul(ffloortextureslide, (maskedtexturecol[oldx]-maskedtexturecol[dc_x])<>= 4; #endif - topstep = -FixedMul (rw_scalestep, worldtop); - topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); + if (linedef->special == 41) { // HORIZON LINES + topstep = bottomstep = 0; + topfrac = bottomfrac = (centeryfrac>>4); + } else { + topstep = -FixedMul (rw_scalestep, worldtop); + topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); - bottomstep = -FixedMul (rw_scalestep,worldbottom); - bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); + bottomstep = -FixedMul (rw_scalestep,worldbottom); + bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); #ifdef ESLOPE - if (frontsector->c_slope) { - fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); - topstep = (topfracend-topfrac)/(range); - } - if (frontsector->f_slope) { - fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); - bottomstep = (bottomfracend-bottomfrac)/(range); - } + if (frontsector->c_slope) { + fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); + topstep = (topfracend-topfrac)/(range); + } + if (frontsector->f_slope) { + fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); + bottomstep = (bottomfracend-bottomfrac)/(range); + } #endif + } dc_numlights = 0; diff --git a/src/r_things.c b/src/r_things.c index f9f0f756c..9f6cad529 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -808,11 +808,18 @@ static void R_DrawVisSprite(vissprite_t *vis) if (overflow_test < 0) overflow_test = -overflow_test; if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow + if (vis->scalestep) // handles right edge too + { + overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*(vis->scale + (vis->scalestep*(vis->x2 - vis->x1))))>>FRACBITS); + if (overflow_test < 0) overflow_test = -overflow_test; + if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto + } + colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { - // translate green skin to another color + // translate certain pixels to white colfunc = transcolfunc; if (vis->mobj->type == MT_CYBRAKDEMON) dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); @@ -868,13 +875,10 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!dc_colormap) dc_colormap = colormaps; - dc_iscale = FixedDiv(FRACUNIT, vis->scale); dc_texturemid = vis->texturemid; dc_texheight = 0; frac = vis->startfrac; - spryscale = vis->scale; - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); windowtop = windowbottom = sprbotscreen = INT32_MAX; if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) @@ -886,28 +890,29 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!vis->isScaled) { vis->scale = FixedMul(vis->scale, this_scale); - spryscale = vis->scale; - dc_iscale = FixedDiv(FRACUNIT, vis->scale); + vis->scalestep = FixedMul(vis->scalestep, this_scale); vis->xiscale = FixedDiv(vis->xiscale,this_scale); vis->isScaled = true; } dc_texturemid = FixedDiv(dc_texturemid,this_scale); + } - //Oh lordy, mercy me. Don't freak out if sprites go offscreen! - /*if (vis->xiscale > 0) - frac = FixedDiv(frac, this_scale); - else if (vis->x1 <= 0) - frac = (vis->x1 - vis->x2) * vis->xiscale;*/ + spryscale = vis->scale; + if (!(vis->scalestep)) + { sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - //dc_hires = 1; + dc_iscale = FixedDiv(FRACUNIT, vis->scale); } x1 = vis->x1; x2 = vis->x2; if (vis->x1 < 0) + { + spryscale += vis->scalestep*(-vis->x1); vis->x1 = 0; + } if (vis->x2 >= vid.width) vis->x2 = vid.width-1; @@ -915,6 +920,7 @@ static void R_DrawVisSprite(vissprite_t *vis) for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { #ifdef RANGECHECK + texturecolumn = frac>>FRACBITS; if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) @@ -923,10 +929,16 @@ static void R_DrawVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); #endif + if (vis->scalestep) + { + sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); + dc_iscale = (0xffffffffu / (unsigned)spryscale); + } if (vis->vflip) R_DrawFlippedMaskedColumn(column, patch->height); else R_DrawMaskedColumn(column); + spryscale += vis->scalestep; } colfunc = basecolfunc; @@ -1021,7 +1033,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) if (testheight <= sprite->gz) return; - cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->scale))>>FRACBITS); + cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->sortscale))>>FRACBITS); if (cutfrac < 0) continue; if (cutfrac > viewheight) @@ -1094,7 +1106,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t tr_x, tr_y; fixed_t gxt, gyt; fixed_t tx, tz; - fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t xscale, yscale, sortscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! INT32 x1, x2; @@ -1104,13 +1116,19 @@ static void R_ProjectSprite(mobj_t *thing) size_t rot; UINT8 flip; + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); INT32 lindex; vissprite_t *vis; - angle_t ang; + angle_t ang = 0; // compiler complaints fixed_t iscale; + fixed_t scalestep; + fixed_t offset, offset2; + boolean papersprite = !!(thing->frame & FF_PAPERSPRITE); + + INT32 dispoffset = thing->info->dispoffset; //SoM: 3/17/2000 fixed_t gz, gzt; @@ -1118,6 +1136,8 @@ static void R_ProjectSprite(mobj_t *thing) INT32 light = 0; fixed_t this_scale = thing->scale; + fixed_t ang_scale = FRACUNIT; + // transform the origin point tr_x = thing->x - viewx; tr_y = thing->y - viewy; @@ -1128,7 +1148,7 @@ static void R_ProjectSprite(mobj_t *thing) tz = gxt-gyt; // thing is behind view plane? - if (tz < FixedMul(MINZ, this_scale)) + if (!(papersprite) && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later return; gxt = -FixedMul(tr_x, viewsin); @@ -1141,7 +1161,7 @@ static void R_ProjectSprite(mobj_t *thing) // aspect ratio stuff xscale = FixedDiv(projection, tz); - yscale = FixedDiv(projectiony, tz); + sortscale = FixedDiv(projectiony, tz); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -1188,6 +1208,13 @@ static void R_ProjectSprite(mobj_t *thing) I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite); #endif + if (sprframe->rotate != SRF_SINGLE || papersprite) + { + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + if (papersprite) + ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT)); + } + if (sprframe->rotate == SRF_SINGLE) { // use single rotation for all views @@ -1198,7 +1225,7 @@ static void R_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + //ang = R_PointToAngle (thing->x, thing->y) - thing->angle; if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right rot = 6; // F7 slot @@ -1219,22 +1246,112 @@ static void R_ProjectSprite(mobj_t *thing) // calculate edges of the shape if (flip) - tx -= FixedMul(spritecachedinfo[lump].width-spritecachedinfo[lump].offset, this_scale); + offset = spritecachedinfo[lump].offset - spritecachedinfo[lump].width; else - tx -= FixedMul(spritecachedinfo[lump].offset, this_scale); + offset = -spritecachedinfo[lump].offset; + offset = FixedMul(offset, this_scale); + tx += FixedMul(offset, ang_scale); x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS; // off the right side? if (x1 > viewwidth) return; - tx += FixedMul(spritecachedinfo[lump].width, this_scale); + offset2 = FixedMul(spritecachedinfo[lump].width, this_scale); + tx += FixedMul(offset2, ang_scale); x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1; // off the left side if (x2 < 0) return; + if (papersprite) + { + fixed_t yscale2, cosmul, sinmul, tz2; + INT32 range; + + if (ang >= ANGLE_180) + { + offset *= -1; + offset2 *= -1; + } + + cosmul = FINECOSINE(thing->angle>>ANGLETOFINESHIFT); + sinmul = FINESINE(thing->angle>>ANGLETOFINESHIFT); + + tr_x += FixedMul(offset, cosmul); + tr_y += FixedMul(offset, sinmul); + gxt = FixedMul(tr_x, viewcos); + gyt = -FixedMul(tr_y, viewsin); + tz = gxt-gyt; + yscale = FixedDiv(projectiony, tz); + if (yscale < 64) return; // Fix some funky visuals + + tr_x += FixedMul(offset2, cosmul); + tr_y += FixedMul(offset2, sinmul); + gxt = FixedMul(tr_x, viewcos); + gyt = -FixedMul(tr_y, viewsin); + tz2 = gxt-gyt; + yscale2 = FixedDiv(projectiony, tz2); + if (yscale2 < 64) return; // ditto + + if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier + return; + + if (x2 > x1) + range = (x2 - x1); + else + range = 1; + + scalestep = (yscale2 - yscale)/range; + + // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? + // sortscale = max(yscale, yscale2); + // sortscale = min(yscale, yscale2); + } + else + { + scalestep = 0; + yscale = sortscale; + } + + xscale = FixedMul(xscale, ang_scale); + + if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) + { + fixed_t linkscale; +#if 0 // support for chains of linkdraw - probably not network safe to modify mobjs during rendering + mobj_t *link, *link2; + + for (link = thing->tracer; (link->tracer && (link->flags2 & MF2_LINKDRAW)); link = link->tracer) + link->flags2 &= ~MF2_LINKDRAW; // to prevent infinite loops, otherwise would just be a ; + + for (link2 = thing->tracer; (link2->tracer && (link2 != link)); link2 = link2->tracer) + link->flags2 |= MF2_LINKDRAW; // only needed for correction of the above + + if (link->flags2 & MF2_LINKDRAW) + link->flags2 &= ~MF2_LINKDRAW; // let's try and make sure this doesn't happen again... + + tr_x = link->x - viewx; + tr_y = link->y - viewy; +#else + tr_x = thing->tracer->x - viewx; + tr_y = thing->tracer->y - viewy; +#endif + gxt = FixedMul(tr_x, viewcos); + gyt = -FixedMul(tr_y, viewsin); + tz = gxt-gyt; + linkscale = FixedDiv(projectiony, tz); + + if (tz < FixedMul(MINZ, this_scale)) + return; + + if (sortscale < linkscale) + dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0) + + sortscale = linkscale; // now make sure it's linked + } + // PORTAL SPRITE CLIPPING if (portalrender) { @@ -1246,7 +1363,7 @@ static void R_ProjectSprite(mobj_t *thing) } //SoM: 3/17/2000: Disregard sprites that are out of view.. - if (thing->eflags & MFE_VERTICALFLIP) + if (vflip) { // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. @@ -1316,7 +1433,8 @@ static void R_ProjectSprite(mobj_t *thing) vis->heightsec = heightsec; //SoM: 3/17/2000 vis->mobjflags = thing->flags; vis->scale = yscale; //<dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15 + vis->sortscale = sortscale; + vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15 vis->gx = thing->x; vis->gy = thing->y; vis->gz = gz; @@ -1325,6 +1443,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->pz = thing->z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; + vis->scalestep = scalestep; vis->mobj = thing; // Easy access! Tails 06-07-2002 @@ -1342,8 +1461,8 @@ static void R_ProjectSprite(mobj_t *thing) vis->xscale = xscale; //SoM: 4/17/2000 vis->sector = thing->subsector->sector; - vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); - vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS); + vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); + vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); vis->cut = SC_NONE; if (thing->subsector->sector->numlights) vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap; @@ -1364,7 +1483,10 @@ static void R_ProjectSprite(mobj_t *thing) } if (vis->x1 > x1) + { vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1); + vis->scale += scalestep*(vis->x1 - x1); + } //Fab: lumppat is the lump number of the patch to use, this is different // than lumpid for sprites-in-pwad : the graphics are patched @@ -1402,10 +1524,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->precip = false; - if (thing->eflags & MFE_VERTICALFLIP) - vis->vflip = true; - else - vis->vflip = false; + vis->vflip = vflip; vis->isScaled = false; @@ -1523,7 +1642,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // store information in a vissprite vis = R_NewVisSprite(); - vis->scale = yscale; //<scale = vis->sortscale = yscale; //<dispoffset = 0; // Monster Iestyn: 23/11/15 vis->gx = thing->x; vis->gy = thing->y; @@ -1533,6 +1652,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->pz = thing->z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; + vis->scalestep = 0; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; @@ -1711,14 +1831,14 @@ void R_SortVisSprites(void) bestscale = bestdispoffset = INT32_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) { - if (ds->scale < bestscale) + if (ds->sortscale < bestscale) { - bestscale = ds->scale; + bestscale = ds->sortscale; bestdispoffset = ds->dispoffset; best = ds; } // order visprites of same scale by dispoffset, smallest first - else if (ds->scale == bestscale && ds->dispoffset < bestdispoffset) + else if (ds->sortscale == bestscale && ds->dispoffset < bestdispoffset) { bestdispoffset = ds->dispoffset; best = ds; @@ -1880,7 +2000,7 @@ static void R_CreateDrawNodes(void) for (i = x1; i <= x2; i++) { - if (r2->seg->frontscale[i] > rover->scale) + if (r2->seg->frontscale[i] > rover->sortscale) break; } if (i > x2) @@ -1899,10 +2019,10 @@ static void R_CreateDrawNodes(void) continue; scale = r2->thickseg->scale1 > r2->thickseg->scale2 ? r2->thickseg->scale1 : r2->thickseg->scale2; - if (scale <= rover->scale) + if (scale <= rover->sortscale) continue; scale = r2->thickseg->scale1 + (r2->thickseg->scalestep * (sintersect - r2->thickseg->x1)); - if (scale <= rover->scale) + if (scale <= rover->sortscale) continue; #ifdef ESLOPE @@ -1952,11 +2072,11 @@ static void R_CreateDrawNodes(void) continue; scale = r2->seg->scale1 > r2->seg->scale2 ? r2->seg->scale1 : r2->seg->scale2; - if (scale <= rover->scale) + if (scale <= rover->sortscale) continue; scale = r2->seg->scale1 + (r2->seg->scalestep * (sintersect - r2->seg->x1)); - if (rover->scale < scale) + if (rover->sortscale < scale) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -1972,8 +2092,8 @@ static void R_CreateDrawNodes(void) if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) continue; - if (r2->sprite->scale > rover->scale - || (r2->sprite->scale == rover->scale && r2->sprite->dispoffset > rover->dispoffset)) + if (r2->sprite->sortscale > rover->sortscale + || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset)) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2126,8 +2246,8 @@ void R_ClipSprites(void) scale = ds->scale2; } - if (scale < spr->scale || - (lowscale < spr->scale && + if (scale < spr->sortscale || + (lowscale < spr->sortscale && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) { // masked mid texture? @@ -2178,7 +2298,7 @@ void R_ClipSprites(void) fixed_t mh, h; INT32 phs = viewplayer->mo->subsector->sector->heightsec; if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && - (h = centeryfrac - FixedMul(mh -= viewz, spr->scale)) >= 0 && + (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && (h >>= FRACBITS) < viewheight) { if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) @@ -2196,7 +2316,7 @@ void R_ClipSprites(void) } if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && - (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && + (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && (h >>= FRACBITS) < viewheight) { if (phs != -1 && viewz >= sectors[phs].ceilingheight) diff --git a/src/r_things.h b/src/r_things.h index ffe34e293..20dd25abf 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -149,7 +149,8 @@ typedef struct vissprite_s fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors fixed_t startfrac; // horizontal position of x1 - fixed_t scale; + fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW + fixed_t scalestep; // only for paper sprites, 0 otherwise fixed_t xiscale; // negative if flipped fixed_t texturemid; diff --git a/src/screen.c b/src/screen.c index 376586c5d..d00155785 100644 --- a/src/screen.c +++ b/src/screen.c @@ -411,6 +411,7 @@ void SCR_DisplayTicRate(void) tic_t ontic = I_GetTime(); tic_t totaltics = 0; INT32 ticcntcolor = 0; + INT32 offs = (cv_debug ? 8 : 0); for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i) fpsgraph[i % TICRATE] = false; @@ -424,9 +425,9 @@ void SCR_DisplayTicRate(void) if (totaltics <= TICRATE/2) ticcntcolor = V_REDMAP; else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP; - V_DrawString(vid.width-(24*vid.dupx), vid.height-(16*vid.dupy), + V_DrawString(vid.width-((24+(6*offs))*vid.dupx), vid.height-((16-offs)*vid.dupy), V_YELLOWMAP|V_NOSCALESTART, "FPS"); - V_DrawString(vid.width-(40*vid.dupx), vid.height-( 8*vid.dupy), + V_DrawString(vid.width-(40*vid.dupx), vid.height-(8*vid.dupy), ticcntcolor|V_NOSCALESTART, va("%02d/%02u", totaltics, TICRATE)); lasttic = ontic; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index ea8ade8c1..71ee3f794 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2647,6 +2647,47 @@ INT32 I_PutEnv(char *variable) #endif } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + char storage[256]; + if (size > 255) + size = 255; + memcpy(storage, data, size); + storage[size] = 0; + + if (SDL_SetClipboardText(storage)) + return 0; + return -1; +} + +const char *I_ClipboardPaste(void) +{ + static char clipboard_modified[256]; + char *clipboard_contents, *i = clipboard_modified; + + if (!SDL_HasClipboardText()) + return NULL; + clipboard_contents = SDL_GetClipboardText(); + memcpy(clipboard_modified, clipboard_contents, 255); + SDL_free(clipboard_contents); + clipboard_modified[255] = 0; + + while (*i) + { + if (*i == '\n' || *i == '\r') + { // End on newline + *i = 0; + break; + } + else if (*i == '\t') + *i = ' '; // Tabs become spaces + else if (*i < 32 || (unsigned)*i > 127) + *i = '?'; // Nonprintable chars become question marks + ++i; + } + return (const char *)&clipboard_modified; +} + /** \brief The isWadPathOk function \param path string path to check diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 4a46813c1..88bbadd20 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -220,7 +220,7 @@ static Mix_Chunk *ds2chunk(void *stream) break; default: // convert arbitrary hz to 44100. step = 0; - frac = ((UINT32)freq << FRACBITS) / 44100; + frac = ((UINT32)freq << FRACBITS) / 44100 + 1; //Add 1 to counter truncation. while (i < samples) { o = (INT16)(*s+0x80)<<8; // changed signedness and shift up to 16 bits diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h index 7e144644c..2d6209f2b 100644 --- a/src/sdl/ogl_sdl.h +++ b/src/sdl/ogl_sdl.h @@ -24,7 +24,6 @@ boolean OglSdlSurface(INT32 w, INT32 h); void OglSdlFinishUpdate(boolean vidwait); -extern SDL_Window *window; extern SDL_Renderer *renderer; extern SDL_GLContext sdlglcontext; extern Uint16 realwidth; diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index 7ac32f4b3..fea1e1648 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -71,4 +71,7 @@ void I_GetConsoleEvents(void); void SDLforceUngrabMouse(void); +// Needed for some WIN32 functions +extern SDL_Window *window; + #endif diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 888a6a507..ed0db653d 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -2666,6 +2666,18 @@ INT32 I_PutEnv(char *variable) #endif } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + /** \brief The isWadPathOk function \param path string path to check diff --git a/src/sounds.c b/src/sounds.c index 8ad42ac9f..75ee1358c 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -159,6 +159,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"lvpass", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"mindig", false, 8, 64, -1, NULL, 0, -1, -1, LUMPERROR}, {"mixup", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"monton", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"pogo" , false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"pop" , false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"rail1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, diff --git a/src/sounds.h b/src/sounds.h index 565d41b56..532c61da6 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -222,6 +222,7 @@ typedef enum sfx_lvpass, sfx_mindig, sfx_mixup, + sfx_monton, sfx_pogo, sfx_pop, sfx_rail1, diff --git a/src/st_stuff.c b/src/st_stuff.c index 43d2bd176..9a7f64986 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -288,15 +288,15 @@ void ST_LoadGraphics(void) scatterring = W_CachePatchName("SCATIND", PU_HUDGFX); grenadering = W_CachePatchName("GRENIND", PU_HUDGFX); railring = W_CachePatchName("RAILIND", PU_HUDGFX); - jumpshield = W_CachePatchName("WHTVB0", PU_HUDGFX); - forceshield = W_CachePatchName("BLTVB0", PU_HUDGFX); - ringshield = W_CachePatchName("YLTVB0", PU_HUDGFX); - watershield = W_CachePatchName("ELTVB0", PU_HUDGFX); - bombshield = W_CachePatchName("BKTVB0", PU_HUDGFX); - pityshield = W_CachePatchName("GRTVB0", PU_HUDGFX); - invincibility = W_CachePatchName("PINVB0", PU_HUDGFX); - sneakers = W_CachePatchName("SHTVB0", PU_HUDGFX); - gravboots = W_CachePatchName("GBTVB0", PU_HUDGFX); + jumpshield = W_CachePatchName("TVWWC0", PU_HUDGFX); + forceshield = W_CachePatchName("TVFOC0", PU_HUDGFX); + ringshield = W_CachePatchName("TVATC0", PU_HUDGFX); + watershield = W_CachePatchName("TVELC0", PU_HUDGFX); + bombshield = W_CachePatchName("TVARC0", PU_HUDGFX); + pityshield = W_CachePatchName("TVPIC0", PU_HUDGFX); + invincibility = W_CachePatchName("TVIVC0", PU_HUDGFX); + sneakers = W_CachePatchName("TVSSC0", PU_HUDGFX); + gravboots = W_CachePatchName("TVGVC0", PU_HUDGFX); tagico = W_CachePatchName("TAGICO", PU_HUDGFX); rflagico = W_CachePatchName("RFLAGICO", PU_HUDGFX); @@ -546,19 +546,26 @@ static void ST_DrawNightsOverlayNum(INT32 x /* right border */, INT32 y, INT32 a static void ST_drawDebugInfo(void) { INT32 height = 192; + INT32 dist = 8; - if (!stplyr->mo) + if (!(stplyr->mo && cv_debug)) return; + if (cv_ticrate.value) + { + height -= 12; + dist >>= 1; + } + if (cv_debug & DBG_BASIC) { const fixed_t d = AngleFixed(stplyr->mo->angle); - V_DrawRightAlignedString(320, 168, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); - V_DrawRightAlignedString(320, 176, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); - V_DrawRightAlignedString(320, 184, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); - V_DrawRightAlignedString(320, 192, V_MONOSPACE, va("A: %6d", FixedInt(d))); + V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); + V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); + V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); + V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d))); - height = 152; + height -= (32+dist); } if (cv_debug & DBG_DETAILED) @@ -569,11 +576,12 @@ static void ST_drawDebugInfo(void) V_DrawRightAlignedString(320, height - 80, V_MONOSPACE, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime])); // Flags - V_DrawRightAlignedString(304-64, height - 72, V_MONOSPACE, "Flags:"); - V_DrawString(304-60, height - 72, (stplyr->jumping) ? V_GREENMAP : V_REDMAP, "JM"); - V_DrawString(304-40, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD"); - V_DrawString(304-20, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP"); - V_DrawString(304, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST"); + V_DrawRightAlignedString(304-74, height - 72, V_MONOSPACE, "PF:"); + V_DrawString(304-72, height - 72, (stplyr->jumping) ? V_GREENMAP : V_REDMAP, "JM"); + V_DrawString(304-54, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD"); + V_DrawString(304-36, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP"); + V_DrawString(304-18, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST"); + V_DrawString(304, height - 72, (stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP, "TH"); V_DrawRightAlignedString(320, height - 64, V_MONOSPACE, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS)); V_DrawRightAlignedString(320, height - 56, V_MONOSPACE, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS)); @@ -587,7 +595,7 @@ static void ST_drawDebugInfo(void) V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS)); V_DrawRightAlignedString(320, height, V_MONOSPACE, va("SPEED: %6d", stplyr->speed>>FRACBITS)); - height -= 120; + height -= (112+dist); } if (cv_debug & DBG_RANDOMIZER) // randomizer testing @@ -600,12 +608,12 @@ static void ST_drawDebugInfo(void) V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Seed: %08x", P_GetRandSeed())); V_DrawRightAlignedString(320, height, V_MONOSPACE, va("== : .%04d", peekres)); - height -= 32; + height -= (24+dist); } if (cv_debug & DBG_MEMORY) { - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); + V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } } @@ -664,9 +672,9 @@ static void ST_drawTime(void) static inline void ST_drawRings(void) { - INT32 ringnum = max(stplyr->health-1, 0); + INT32 ringnum = max(stplyr->rings, 0); - ST_DrawPatchFromHudWS(HUD_RINGS, ((stplyr->health <= 1 && leveltime/5 & 1) ? rrings : sborings)); + ST_DrawPatchFromHudWS(HUD_RINGS, ((stplyr->rings <= 0 && leveltime/5 & 1) ? rrings : sborings)); if (objectplacing) ringnum = op_currentdoomednum; @@ -675,8 +683,8 @@ static inline void ST_drawRings(void) INT32 i; ringnum = 0; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].mo->health > 1) - ringnum += players[i].mo->health - 1; + if (playeringame[i] && players[i].mo && players[i].rings > 0) + ringnum += players[i].rings; } ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum); @@ -1145,11 +1153,11 @@ static void ST_drawNiGHTSHUD(void) INT32 i; total_ringcount = 0; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] /*&& players[i].pflags & PF_NIGHTSMODE*/ && players[i].health) - total_ringcount += players[i].health - 1; + if (playeringame[i] /*&& players[i].pflags & PF_NIGHTSMODE*/ && players[i].rings) + total_ringcount += players[i].rings; } else - total_ringcount = stplyr->health-1; + total_ringcount = stplyr->rings; if (stplyr->capsule) { @@ -1361,7 +1369,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I txtflags |= V_YELLOWMAP; if (weapon == pw_infinityring - || (stplyr->ringweapons & rwflag && stplyr->health > 1)) + || (stplyr->ringweapons & rwflag)) txtflags |= V_20TRANS; else { @@ -1399,7 +1407,7 @@ static void ST_drawMatchHUD(void) if (stplyr->powers[pw_infinityring]) ST_drawWeaponRing(pw_infinityring, 0, 0, offset, infinityring); - else if (stplyr->health > 1) + else if (stplyr->rings > 0) V_DrawScaledPatch(8 + offset, STRINGY(162), V_SNAPTOLEFT, normring); else V_DrawTranslucentPatch(8 + offset, STRINGY(162), V_SNAPTOLEFT|V_80TRANS, normring); diff --git a/src/v_video.c b/src/v_video.c index 91d730513..e8d3cdec6 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -774,43 +774,51 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (!screens[0]) return; - if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) - { // 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) + if (c & V_NOSCALESTART) { - // Center it if necessary - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // 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; + dest = screens[0] + y*vid.width + x; + deststop = screens[0] + vid.rowbytes * vid.height; + } + else + { + if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) + { // 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; } - 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 - if (c & V_SNAPTOBOTTOM) - dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(c & V_SNAPTOTOP)) - dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; + // Center it if necessary + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // 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. -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 if (rendermode != render_soft && rendermode != render_none) { UINT32 hwcolor; - switch (pcolor) + switch (cons_backcolor.value) { - case 0: hwcolor = 0xffffff00; break; //white - case 1: hwcolor = 0xff800000; break; //orange - case 2: hwcolor = 0x0000ff00; break; //blue - case 3: hwcolor = 0x00800000; break; //green - case 4: hwcolor = 0x80808000; break; //gray - case 5: hwcolor = 0xff000000; break; //red - default: hwcolor = 0x00800000; break; //green + case 0: hwcolor = 0xffffff00; break; // White + case 1: hwcolor = 0x80808000; break; // Gray + case 2: hwcolor = 0x40201000; break; // Brown + case 3: hwcolor = 0xff000000; break; // Red + case 4: hwcolor = 0xff800000; break; // Orange + case 5: hwcolor = 0x80800000; break; // Yellow + 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); return; } #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, // just the stop position deststop = screens[0] + vid.rowbytes * min(plines, vid.height); for (buf = screens[0]; buf < deststop; ++buf) - *buf = colormap[*buf]; + *buf = consolebgmap[*buf]; } // Gets string colormap, used for 0x80 color codes diff --git a/src/v_video.h b/src/v_video.h index 70255d0ef..353f84c1d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -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 void V_DrawFadeScreen(void); -void V_DrawFadeConsBack(INT32 plines, INT32 pcolor); +void V_DrawFadeConsBack(INT32 plines); // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 0331080c8..80b89a6e6 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -3598,6 +3598,18 @@ INT32 I_PutEnv(char *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); const CPUInfoFlags *I_CPUInfo(void) diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c index 88764ef73..3b6a47258 100644 --- a/src/win32ce/win_sys.c +++ b/src/win32ce/win_sys.c @@ -3470,6 +3470,18 @@ INT32 I_PutEnv(char *variable) return putenv(variable); } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + typedef BOOL (WINAPI *MyFunc3) (DWORD); const CPUInfoFlags *I_CPUInfo(void) diff --git a/src/y_inter.c b/src/y_inter.c index b2e1cdf9f..3b14f2837 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -679,7 +679,7 @@ void Y_Ticker(void) boolean anybonuses = false; if (!intertic) // first time only - S_ChangeMusicInternal("lclear", false); // don't loop it + S_ChangeMusicInternal("_clear", false); // don't loop it if (intertic < TICRATE) // one second pause before tally begins return; @@ -740,7 +740,7 @@ void Y_Ticker(void) if (!intertic) // first time only { - S_ChangeMusicInternal("lclear", false); // don't loop it + S_ChangeMusicInternal("_clear", false); // don't loop it tallydonetic = 0; } @@ -801,7 +801,7 @@ void Y_Ticker(void) else if (intertype == int_match || intertype == int_ctf || intertype == int_teammatch) // match { if (!intertic) // first time only - S_ChangeMusicInternal("racent", true); // loop it + S_ChangeMusicInternal("_inter", true); // loop it // If a player has left or joined, recalculate scores. if (data.match.numplayers != D_NumPlayers()) @@ -810,7 +810,7 @@ void Y_Ticker(void) else if (intertype == int_race || intertype == int_classicrace) // race { if (!intertic) // first time only - S_ChangeMusicInternal("racent", true); // loop it + S_ChangeMusicInternal("_inter", true); // loop it // Don't bother recalcing for race. It doesn't make as much sense. } @@ -839,13 +839,13 @@ static void Y_UpdateRecordReplays(void) if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time)) mainrecords[gamemap-1]->time = players[consoleplayer].realtime; - if ((UINT16)(players[consoleplayer].health - 1) > mainrecords[gamemap-1]->rings) - mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].health - 1); + if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings) + mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); // Save demo! bestdemo[255] = '\0'; lastdemo[255] = '\0'; - G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].health-1)); + G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].rings)); G_CheckDemoStatus(); I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); @@ -1435,7 +1435,7 @@ static void Y_CalculateCompetitionWinners(void) bestat[j] = true; times[i] = players[i].realtime; - rings[i] = (UINT32)max(players[i].health-1, 0); + rings[i] = (UINT32)max(players[i].rings, 0); maxrings[i] = (UINT32)players[i].totalring; monitors[i] = (UINT32)players[i].numboxes; scores[i] = (UINT32)min(players[i].score, 99999990); @@ -1450,7 +1450,7 @@ static void Y_CalculateCompetitionWinners(void) else bestat[0] = false; - if (max(players[i].health-1, 0) >= max(players[j].health-1, 0)) + if (max(players[i].rings, 0) >= max(players[j].rings, 0)) points[i]++; else bestat[1] = false; @@ -1573,7 +1573,7 @@ static void Y_SetRingBonus(player_t *player, y_bonus_t *bstruct) { strncpy(bstruct->patch, "YB_RING", sizeof(bstruct->patch)); bstruct->display = true; - bstruct->points = max(0, (player->health-1) * 100); + bstruct->points = max(0, (player->rings) * 100); } // @@ -1621,7 +1621,7 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct) for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; - sharedringtotal += players[i].health - 1; + sharedringtotal += players[i].rings; } if (!sharedringtotal || sharedringtotal < nummaprings) data.coop.gotperfbonus = 0;