diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index 7490b8d68eacdda6c1e11464881fbc1f81b64ab8..c91ab7a8794c6f45b698ea9c1b71637b799f13cc 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -4105,16 +4105,16 @@ thingtypes { title = "Egg Mobile"; sprite = "EGGMA1"; - width = 24; - height = 76; + width = 36; + height = 84; flags4text = "[4] End level on death"; } 201 { title = "Egg Slimer"; sprite = "EGGNA1"; - width = 24; - height = 76; + width = 36; + height = 84; flags4text = "[4] End level on death"; flags8text = "[8] Speed up when hit"; } @@ -4122,7 +4122,7 @@ thingtypes { title = "Sea Egg"; sprite = "EGGOA1"; - width = 32; + width = 36; height = 116; flags4text = "[4] End level on death"; } @@ -4130,8 +4130,8 @@ thingtypes { title = "Egg Colosseum"; sprite = "EGGPA1"; - width = 24; - height = 76; + width = 36; + height = 84; flags4text = "[4] End level on death"; } 204 diff --git a/src/b_bot.c b/src/b_bot.c index bf2dbbb68586aab8390557568622d2e9e6f89e0a..82075eb8efebe09aad15d75573a02b09c56addb6 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -17,6 +17,7 @@ #include "p_local.h" #include "b_bot.h" #include "lua_hook.h" +#include "i_system.h" // I_BaseTiccmd void B_UpdateBotleader(player_t *player) { @@ -132,17 +133,17 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) // Update catchup_tics if (mem->thinkstate == AI_SPINFOLLOW) { - mem-> catchup_tics = 0; + mem->catchup_tics = 0; } else if (dist > followmax || zdist > comfortheight || stalled) { - mem-> catchup_tics = min(mem-> catchup_tics + 2, 70); - if (mem-> catchup_tics >= 70) + mem->catchup_tics = min(mem->catchup_tics + 2, 70); + if (mem->catchup_tics >= 70) mem->thinkstate = AI_CATCHUP; } else { - mem-> catchup_tics = max(mem-> catchup_tics - 1, 0); + mem->catchup_tics = max(mem->catchup_tics - 1, 0); if (mem->thinkstate == AI_CATCHUP) mem->thinkstate = AI_FOLLOW; } @@ -317,7 +318,6 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { // Copy inputs cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT - bot->drawangle = ang; cmd->forwardmove = 8 * pcmd->forwardmove / 10; cmd->sidemove = 8 * pcmd->sidemove / 10; } @@ -344,7 +344,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) else if (!jump_last && !(bot->pflags & PF_JUMPED) //&& !(player->pflags & PF_SPINNING) && ((zdist > 32*scale && player->pflags & PF_JUMPED) // Following || (zdist > 64*scale && mem->thinkstate == AI_CATCHUP) // Vertical catch-up - || (stalled && mem-> catchup_tics > 20 && bot->powers[pw_carry] == CR_NONE) + || (stalled && mem->catchup_tics > 20 && bot->powers[pw_carry] == CR_NONE) //|| (bmom < scale>>3 && dist > followthres && !(bot->powers[pw_carry])) // Stopped & not in carry state || (bot->pflags & PF_SPINNING && !(bot->pflags & PF_JUMPED)))) // Spinning jump = true; @@ -371,6 +371,8 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) { + G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver + // Can't build a ticcmd if we aren't spawned... if (!player->mo) return; @@ -390,7 +392,7 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) return; // Make sure we have a valid main character to follow - B_UpdateBotleader(player); + B_UpdateBotleader(player); if (!player->botleader) return; @@ -403,7 +405,7 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward { player_t *player = mo->player; // don't try to do stuff if your sonic is in a minecart or something - if (&player->botleader && player->botleader->powers[pw_carry] && player->botleader->powers[pw_carry] != CR_PLAYER) + if (player->botleader && player->botleader->powers[pw_carry] && player->botleader->powers[pw_carry] != CR_PLAYER) return; // Turn the virtual keypresses into ticcmd_t. if (twodlevel || mo->flags2 & MF2_TWOD) { @@ -593,25 +595,43 @@ void B_HandleFlightIndicator(player_t *player) { mobj_t *tails = player->mo; botmem_t *mem = &player->botmem; + boolean shouldExist; + if (!tails) return; - if (mem->thinkstate == AI_THINKFLY && player->bot == BOT_2PAI && tails->health) + shouldExist = (mem->thinkstate == AI_THINKFLY) && player->botleader + && player->bot == BOT_2PAI && player->playerstate == PST_LIVE; + + // check whether the indicator doesn't exist + if (P_MobjWasRemoved(tails->hnext)) { - if (!tails->hnext) - { - P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); - if (tails->hnext) - { - P_SetTarget(&tails->hnext->target, tails); - P_SetTarget(&tails->hnext->hprev, tails); - P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); - } - } + // if it shouldn't exist, everything is fine + if (!shouldExist) + return; + + // otherwise, spawn it + P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); + P_SetTarget(&tails->hnext->target, tails); + P_SetTarget(&tails->hnext->hprev, tails); + P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); } - else if (tails->hnext && tails->hnext->type == MT_OVERLAY && tails->hnext->state == states+S_FLIGHTINDICATOR) + + // if the mobj isn't a flight indicator, let's not mess with it + if (tails->hnext->type != MT_OVERLAY || (tails->hnext->state != states+S_FLIGHTINDICATOR)) + return; + + // if it shouldn't exist, remove it + if (!shouldExist) { P_RemoveMobj(tails->hnext); P_SetTarget(&tails->hnext, NULL); + return; } + + // otherwise, update its visibility + if (P_IsLocalPlayer(player->botleader)) + tails->hnext->flags2 &= ~MF2_DONTDRAW; + else + tails->hnext->flags2 |= MF2_DONTDRAW; } diff --git a/src/byteptr.h b/src/byteptr.h index 4c8414fae29c7d3498a9a085f607243d261c3af9..ee16bc13f78bbe120cf484338680ac7dac10b208 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -150,26 +150,78 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #undef DEALIGNED -#define WRITESTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} while (0) -#define WRITESTRING(p,s) do { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} while (0) -#define WRITEMEM(p,s,n) do { memcpy(p, s, n); p += n; } while (0) - -#define SKIPSTRING(p) while (READCHAR(p) != '\0') - -#define READSTRINGN(p,s,n) ({ size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';}) -#define READSTRING(p,s) ({ size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';}) -#define READMEM(p,s,n) ({ memcpy(s, p, n); p += n; }) - -#if 0 // old names -#define WRITEBYTE(p,b) WRITEUINT8(p,b) -#define WRITESHORT(p,b) WRITEINT16(p,b) -#define WRITEUSHORT(p,b) WRITEUINT16(p,b) -#define WRITELONG(p,b) WRITEINT32(p,b) -#define WRITEULONG(p,b) WRITEUINT32(p,b) - -#define READBYTE(p) READUINT8(p) -#define READSHORT(p) READINT16(p) -#define READUSHORT(p) READUINT16(p) -#define READLONG(p) READINT32(p) -#define READULONG(p) READUINT32(p) -#endif +#define WRITESTRINGN(p, s, n) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + if (tmp_i < n) \ + WRITECHAR(p, '\0'); \ +}) + +#define WRITESTRINGL(p, s, n) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; tmp_i < n - 1 && s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + WRITECHAR(p, '\0'); \ +}) + +#define WRITESTRING(p, s) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + WRITECHAR(p, '\0'); \ +}) + +#define WRITEMEM(p, s, n) ({ \ + memcpy(p, s, n); \ + p += n; \ +}) + +#define SKIPSTRING(p) while (READCHAR(p) != '\0') + +#define SKIPSTRINGN(p, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n && READCHAR(p) != '\0') \ + tmp_i++; \ +}) + +#define SKIPSTRINGL(p, n) SKIPSTRINGN(p, n) + +#define READSTRINGN(p, s, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READSTRINGL(p, s, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n - 1 && (s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READSTRING(p, s) ({ \ + size_t tmp_i = 0; \ + \ + while ((s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READMEM(p, s, n) ({ \ + memcpy(s, p, n); \ + p += n; \ +}) diff --git a/src/d_net.c b/src/d_net.c index 3a4746002eb87efe8dd57e45729cefc96943bdca..fc029f9675389f0ec9b6de44d54a096917906ab6 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -1144,8 +1144,9 @@ boolean HGetPacket(void) if (netbuffer->checksum != NetbufferChecksum()) { DEBFILE("Bad packet checksum\n"); - //Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode); - Net_CloseConnection(doomcom->remotenode); + // Do not disconnect or anything, just ignore the packet. + // Bad checksums with UDP tend to happen very scarcely + // so they are not normally an issue. continue; } diff --git a/src/deh_tables.c b/src/deh_tables.c index 23d307abf7a7b78123b93d951303392646ad0a62..983d4710b7b43eace42d4f8d4efdf705723893ab 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3549,6 +3549,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi // because sadly no one remembers this place while searching for full state names. const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity testing later. "MT_NULL", + "MT_RAY", "MT_UNKNOWN", "MT_THOK", // Thok! mobj diff --git a/src/g_game.c b/src/g_game.c index 44860bbbc5a19190e5ef705dff024d70dc6d1445..fa0900b02ff0602c3ac0a7af095769026db85cdd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1411,7 +1411,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) newtarget = P_SpawnMobj(ticcmd_ztargetfocus[forplayer]->x, ticcmd_ztargetfocus[forplayer]->y, ticcmd_ztargetfocus[forplayer]->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]); - if (P_AproxDistance( + if (player->mo && P_AproxDistance( player->mo->x - ticcmd_ztargetfocus[forplayer]->x, player->mo->y - ticcmd_ztargetfocus[forplayer]->y ) > 50*player->mo->scale) @@ -1547,12 +1547,17 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) cmd->sidemove = (SINT8)(cmd->sidemove + side); // Note: Majority of botstuffs are handled in G_Ticker now. - if (player->bot == BOT_2PHUMAN) //Player-controlled bot + if (player->bot == BOT_2PAI + && !player->powers[pw_tailsfly] + && (cmd->forwardmove || cmd->sidemove || cmd->buttons)) { - // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Strafe - cmd->angleturn = (INT16)((localangle - *myangle) >> 16); + player->bot = BOT_2PHUMAN; // A player-controlled bot. Returns to AI when it respawns. + CV_SetValue(&cv_analog[1], true); } + if (player->bot == BOT_2PHUMAN) + cmd->angleturn = (INT16)((localangle - *myangle) >> 16); + *myangle += (cmd->angleturn<<16); if (controlstyle == CS_LMAOGALOG) { @@ -2307,65 +2312,44 @@ void G_Ticker(boolean run) buf = gametic % BACKUPTICS; + // Generate ticcmds for bots FIRST, then copy received ticcmds for players. + // This emulates pre-2.2.10 behaviour where the bot referenced their leader's last copied ticcmd, + // which is desirable because P_PlayerThink can override inputs (e.g. while PF_STASIS is applied or in a waterslide), + // and the bot AI needs to respect that. +#define ISHUMAN (players[i].bot == BOT_NONE || players[i].bot == BOT_2PHUMAN) for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i]) + if (playeringame[i] && !ISHUMAN) // Less work is required if we're building a bot ticcmd. { - INT16 received; - // Save last frame's button readings - players[i].lastbuttons = players[i].cmd.buttons; + players[i].lastbuttons = players[i].cmd.buttons; // Save last frame's button readings + B_BuildTiccmd(&players[i], &players[i].cmd); + + // Since bot TicCmd is pre-determined for both the client and server, the latency and packet checks are simplified. + players[i].cmd.latency = 0; + P_SetPlayerAngle(&players[i], players[i].cmd.angleturn << 16); + } + } + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && ISHUMAN) + { + players[i].lastbuttons = players[i].cmd.buttons; // Save last frame's button readings G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); - // Bot ticcmd handling - // Yes, ordinarily this would be handled in G_BuildTiccmd... - // ...however, bot players won't have a corresponding consoleplayer or splitscreen player 2 to send that information. - // Therefore, this has to be done after ticcmd sends are received. - if (players[i].bot == BOT_2PAI) { // Tailsbot for P2 - if (!players[i].powers[pw_tailsfly] && (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons)) - { - players[i].bot = BOT_2PHUMAN; // A player-controlled bot. Returns to AI when it respawns. - CV_SetValue(&cv_analog[1], true); - } - else - { - B_BuildTiccmd(&players[i], &players[i].cmd); - } - B_HandleFlightIndicator(&players[i]); - } - else if (players[i].bot == BOT_MPAI) { - B_BuildTiccmd(&players[i], &players[i].cmd); - } + + // Use the leveltime sent in the player's ticcmd to determine control lag + players[i].cmd.latency = min(((leveltime & 0xFF) - players[i].cmd.latency) & 0xFF, MAXPREDICTTICS-1); // Do angle adjustments. - if (players[i].bot == BOT_NONE || players[i].bot == BOT_2PHUMAN) - { - received = (players[i].cmd.angleturn & TICCMD_RECEIVED); - players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn; - players[i].oldrelangleturn = players[i].cmd.angleturn; - if (P_ControlStyle(&players[i]) == CS_LMAOGALOG) - P_ForceLocalAngle(&players[i], players[i].angleturn << 16); - else - players[i].cmd.angleturn = players[i].angleturn; - if (P_ControlStyle(&players[i]) == CS_LMAOGALOG) - P_ForceLocalAngle(&players[i], players[i].angleturn << 16); - else - players[i].cmd.angleturn = players[i].angleturn; - - players[i].cmd.angleturn &= ~TICCMD_RECEIVED; - // Use the leveltime sent in the player's ticcmd to determine control lag - players[i].cmd.latency = min(((leveltime & 0xFF) - players[i].cmd.latency) & 0xFF, MAXPREDICTTICS-1); - } - else // Less work is required if we're building a bot ticcmd. - { - // Since bot TicCmd is pre-determined for both the client and server, the latency and packet checks are simplified. - received = 1; - players[i].cmd.latency = 0; - players[i].angleturn = players[i].cmd.angleturn; - players[i].oldrelangleturn = players[i].cmd.angleturn; - } - players[i].cmd.angleturn |= received; + players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn; + players[i].oldrelangleturn = players[i].cmd.angleturn; + if (P_ControlStyle(&players[i]) == CS_LMAOGALOG) + P_ForceLocalAngle(&players[i], players[i].angleturn << 16); + else + players[i].cmd.angleturn = (players[i].angleturn & ~TICCMD_RECEIVED) | (players[i].cmd.angleturn & TICCMD_RECEIVED); } } +#undef ISHUMAN // do main actions switch (gamestate) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index e02dbea5b6fbab58944c13cba4d232f95d5271ea..02697789ebe9f2ba8e43282476002fc85e0e6707 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -347,19 +347,16 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p v[2].t = v[3].t = hwrPatch->max_t; // clip it since it is used for bunny scroll in doom I - if (blendmode) - flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; - else - flags = PF_Translucent|PF_NoDepthTest; + flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; if (alphalevel) { FSurfaceInfo Surf; Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; - if (alphalevel == 10) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; - else if (alphalevel == 11) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; - else if (alphalevel == 12) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + if (alphalevel == 10) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; // V_HUDTRANSHALF + else if (alphalevel == 11) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; // V_HUDTRANS + else if (alphalevel == 12) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; // V_HUDTRANSDOUBLE else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); @@ -644,19 +641,16 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, } // clip it since it is used for bunny scroll in doom I - if (blendmode) - flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; - else - flags = PF_Translucent|PF_NoDepthTest; + flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; if (alphalevel) { FSurfaceInfo Surf; Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; - if (alphalevel == 10) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; - else if (alphalevel == 11) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; - else if (alphalevel == 12) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + if (alphalevel == 10) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; // V_HUDTRANSHALF + else if (alphalevel == 11) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; // V_HUDTRANS + else if (alphalevel == 12) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; // V_HUDTRANSDOUBLE else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index cf7118fbe0694c206a2d26497196f2cc81d5787f..39ad1d9ed987a268728bceb061e91315cb21a6c1 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -76,7 +76,7 @@ patch_t *nto_font[NT_FONTSIZE]; static player_t *plr; boolean chat_on; // entering a chat message? -static char w_chat[HU_MAXMSGLEN]; +static char w_chat[HU_MAXMSGLEN + 1]; static size_t c_input = 0; // let's try to make the chat input less shitty. static boolean headsupactive = false; boolean hu_showscores; // draw rankings @@ -461,7 +461,7 @@ void HU_AddChatText(const char *text, boolean playsound) static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) { - char buf[254]; + char buf[2 + HU_MAXMSGLEN + 1]; size_t numwords, ix; char *msg = &buf[2]; const size_t msgspace = sizeof buf - 2; @@ -537,7 +537,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) } buf[0] = target; newmsg = msg+5+spc; - strlcpy(msg, newmsg, 252); + strlcpy(msg, newmsg, HU_MAXMSGLEN + 1); } SendNetXCmd(XD_SAY, buf, strlen(msg) + 1 + msg-buf); @@ -644,7 +644,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); msg = (char *)*p; - SKIPSTRING(*p); + SKIPSTRINGL(*p, HU_MAXMSGLEN + 1); if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum))) { @@ -858,72 +858,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) #endif } -// Handles key input and string input -// -static inline boolean HU_keyInChatString(char *s, char ch) -{ - size_t l; - - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) - || ch == ' ') // Allow spaces, of course - { - l = strlen(s); - if (l < HU_MAXMSGLEN - 1) - { - if (c_input >= strlen(s)) // don't do anything complicated - { - s[l++] = ch; - s[l]=0; - } - else - { - - // move everything past c_input for new characters: - size_t m = HU_MAXMSGLEN-1; - while (m>=c_input) - { - if (s[m]) - s[m+1] = (s[m]); - if (m == 0) // prevent overflow - break; - m--; - } - s[c_input] = ch; // and replace this. - } - c_input++; - return true; - } - return false; - } - else if (ch == KEY_BACKSPACE) - { - size_t i = c_input; - - if (c_input <= 0) - return false; - - if (!s[i-1]) - return false; - - if (i >= strlen(s)-1) - { - s[strlen(s)-1] = 0; - c_input--; - return false; - } - - for (; (i < HU_MAXMSGLEN); i++) - { - s[i-1] = s[i]; - } - c_input--; - } - else if (ch != KEY_ENTER) - return false; // did not eat key - - return true; // ate the key -} - #endif // @@ -945,151 +879,123 @@ void HU_Ticker(void) #ifndef NONET static boolean teamtalk = false; +static boolean justscrolleddown; +static boolean justscrolledup; +static INT16 typelines = 1; // number of drawfill lines we need when drawing the chat. it's some weird hack and might be one frame off but I'm lazy to make another loop. +// It's up here since it has to be reset when we open the chat. -// Clear spaces so we don't end up with messages only made out of emptiness -static boolean HU_clearChatSpaces(void) +static boolean HU_chatboxContainsOnlySpaces(void) { - size_t i = 0; // Used to just check our message - char c; // current character we're iterating. - boolean nothingbutspaces = true; + size_t i; - for (; i < strlen(w_chat); i++) // iterate through message and eradicate all spaces that don't belong. - { - c = w_chat[i]; - if (!c) - break; // if there's nothing, it's safe to assume our message has ended, so let's not waste any more time here. + for (i = 0; w_chat[i]; i++) + if (w_chat[i] != ' ') + return false; - if (c != ' ') // Isn't a space - { - nothingbutspaces = false; - } - } - return nothingbutspaces; + return true; } -// -// -static void HU_queueChatChar(char c) +static void HU_sendChatMessage(void) { - // send automaticly the message (no more chat char) - if (c == KEY_ENTER) + char buf[2 + HU_MAXMSGLEN + 1]; + char *msg = &buf[2]; + size_t ci; + INT32 target = 0; + + // if our message was nothing but spaces, don't send it. + if (HU_chatboxContainsOnlySpaces()) + return; + + // copy printable characters and terminating '\0' only. + for (ci = 2; w_chat[ci-2]; ci++) { - char buf[2+256]; - char *msg = &buf[2]; - size_t i = 0; - size_t ci = 2; - INT32 target = 0; + char c = w_chat[ci-2]; + if (c >= ' ' && !(c & 0x80)) + buf[ci] = c; + }; + buf[ci] = '\0'; - if (HU_clearChatSpaces()) // Avoids being able to send empty messages, or something. - return; // If this returns true, that means our message was NOTHING but spaces, so don't send it period. + memset(w_chat, '\0', sizeof(w_chat)); + c_input = 0; - do { - c = w_chat[-2+ci++]; - if (!c || (c >= ' ' && !(c & 0x80))) // copy printable characters and terminating '\0' only. - buf[ci-1]=c; - } while (c); + // last minute mute check + if (CHAT_MUTE) + { + HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); + return; + } - for (;(i<HU_MAXMSGLEN);i++) - w_chat[i] = 0; // reset this. + if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm + { + INT32 spc = 1; // used if playernum[1] is a space. + char playernum[3]; + const char *newmsg; - c_input = 0; + // what we're gonna do now is check if the player exists + // with that logic, characters 4 and 5 are our numbers: - // last minute mute check - if (CHAT_MUTE) + // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. + if (teamtalk) { - HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); + HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); return; } - if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm + strncpy(playernum, msg+3, 3); + // check for undesirable characters in our "number" + if (!(isdigit(playernum[0]) && isdigit(playernum[1]))) { - INT32 spc = 1; // used if playernum[1] is a space. - char playernum[3]; - const char *newmsg; - - // what we're gonna do now is check if the player exists - // with that logic, characters 4 and 5 are our numbers: - - // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. - if (teamtalk) - { - HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); - return; - } - - strncpy(playernum, msg+3, 3); - // check for undesirable characters in our "number" - if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9'))) - { - // check if playernum[1] is a space - if (playernum[1] == ' ') - spc = 0; - // let it slide - else - { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<player num> \'.", false); - return; - } - } - // I'm very bad at C, I swear I am, additional checks eww! - if (spc != 0) - { - if (msg[5] != ' ') - { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<player num> \'.", false); - return; - } - } - - target = atoi(playernum); // turn that into a number - //CONS_Printf("%d\n", target); - - // check for target player, if it doesn't exist then we can't send the message! - if (target < MAXPLAYERS && playeringame[target]) // player exists - target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! + // check if playernum[1] is a space + if (playernum[1] == ' ') + spc = 0; + // let it slide else { - HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<player num> \'.", false); return; } - - // we need to get rid of the /pm<player num> - newmsg = msg+5+spc; - strlcpy(msg, newmsg, 255); } - if (ci > 3) // don't send target+flags+empty message. + // I'm very bad at C, I swear I am, additional checks eww! + if (spc != 0 && msg[5] != ' ') { - if (teamtalk) - buf[0] = -1; // target - else - buf[0] = target; + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<player num> \'.", false); + return; + } - buf[1] = 0; // flags - SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); + target = atoi(playernum); // turn that into a number + + // check for target player, if it doesn't exist then we can't send the message! + if (target < MAXPLAYERS && playeringame[target]) // player exists + target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! + else + { + HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same + return; } - return; + + // we need to get rid of the /pm<player num> + newmsg = msg+5+spc; + strlcpy(msg, newmsg, HU_MAXMSGLEN + 1); + } + if (ci > 2) // don't send target+flags+empty message. + { + buf[0] = teamtalk ? -1 : target; // target + buf[1] = 0; // flags + SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); } } + #endif void HU_clearChatChars(void) { - size_t i = 0; - for (;i<HU_MAXMSGLEN;i++) - w_chat[i] = 0; // reset this. + memset(w_chat, '\0', sizeof(w_chat)); chat_on = false; c_input = 0; I_UpdateMouseGrab(); } -#ifndef NONET -static boolean justscrolleddown; -static boolean justscrolledup; -static INT16 typelines = 1; // number of drawfill lines we need when drawing the chat. it's some weird hack and might be one frame off but I'm lazy to make another loop. -// It's up here since it has to be reset when we open the chat. -#endif - // // Returns true if key eaten // @@ -1171,21 +1077,23 @@ boolean HU_Responder(event_t *ev) if (shiftdown ^ capslock) c = shiftxform[c]; } - else // if we're holding shift we should still shift non letter symbols + else // if we're holding shift we should still shift non letter symbols { if (shiftdown) c = shiftxform[c]; } // pasting. pasting is cool. chat is a bit limited, though :( - if (((c == 'v' || c == 'V') && ctrldown) && !CHAT_MUTE) + if ((c == 'v' || c == 'V') && ctrldown) { - const char *paste = I_ClipboardPaste(); + const char *paste; size_t chatlen; size_t pastelen; - // create a dummy string real quickly + if (CHAT_MUTE) + return true; + paste = I_ClipboardPaste(); if (paste == NULL) return true; @@ -1194,40 +1102,16 @@ boolean HU_Responder(event_t *ev) if (chatlen+pastelen > HU_MAXMSGLEN) return true; // we can't paste this!! - if (c_input >= strlen(w_chat)) // add it at the end of the string. - { - memcpy(&w_chat[chatlen], paste, pastelen); // copy all of that. - c_input += pastelen; - /*size_t i = 0; - for (;i<pastelen;i++) - { - HU_queueChatChar(paste[i]); // queue it so that it's actually sent. (this chat write thing is REALLY messy.) - }*/ - return true; - } - else // otherwise, we need to shift everything and make space, etc etc - { - size_t i = HU_MAXMSGLEN-1; - while (i >= c_input) - { - if (w_chat[i]) - w_chat[i+pastelen] = w_chat[i]; - if (i == 0) // prevent overflow - break; - i--; - } - memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. - c_input += pastelen; - return true; - } - } - - if (!CHAT_MUTE && HU_keyInChatString(w_chat,c)) - { - HU_queueChatChar(c); + memmove(&w_chat[c_input + pastelen], &w_chat[c_input], pastelen); + memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. + c_input += pastelen; + return true; } - if (c == KEY_ENTER) + else if (c == KEY_ENTER) { + if (!CHAT_MUTE) + HU_sendChatMessage(); + chat_on = false; c_input = 0; // reset input cursor chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :) @@ -1268,6 +1152,32 @@ boolean HU_Responder(event_t *ev) else c_input++; } + else if ((c >= HU_FONTSTART && c <= HU_FONTEND && hu_font[c-HU_FONTSTART]) + || c == ' ') // Allow spaces, of course + { + if (CHAT_MUTE || strlen(w_chat) >= HU_MAXMSGLEN) + return true; + + memmove(&w_chat[c_input + 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); + w_chat[c_input] = c; + c_input++; + } + else if (c == KEY_BACKSPACE) + { + if (CHAT_MUTE || c_input <= 0) + return true; + + memmove(&w_chat[c_input - 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); + c_input--; + } + else if (c == KEY_DEL) + { + if (CHAT_MUTE || c_input >= strlen(w_chat)) + return true; + + memmove(&w_chat[c_input], &w_chat[c_input + 1], strlen(w_chat) - c_input); + } + return true; } #endif @@ -1863,64 +1773,25 @@ static void HU_DrawChat_Old(void) } #endif -// draw the Crosshair, at the exact center of the view. -// +// Draw crosshairs at the exact center of the view. +// In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them. // Crosshairs are pre-cached at HU_Init -static inline void HU_DrawCrosshair(void) +static inline void HU_DrawCrosshairs(void) { - INT32 i, y, dupz; + INT32 cross1 = cv_crosshair.value & 3; + INT32 cross2 = cv_crosshair2.value & 3; - i = cv_crosshair.value & 3; - if (!i) + if (automapactive || demoplayback) return; - if ((netgame || multiplayer) && players[displayplayer].spectator) - return; - -#ifdef HWRENDER - if (rendermode != render_soft) - y = (INT32)gl_basewindowcentery; - else -#endif - y = viewwindowy + (viewheight>>1); + stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); + if (!players[displayplayer].spectator && (!camera.chase || ticcmd_ztargetfocus[0]) && cross1) + V_DrawStretchyFixedPatch((BASEVIDWIDTH/2)<<FRACBITS, (BASEVIDHEIGHT/2)<<FRACBITS, FRACUNIT, splitscreen ? 2*FRACUNIT : FRACUNIT, V_TRANSLUCENT|V_PERPLAYER, crosshair[cross1 - 1], NULL); - dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - - V_DrawFixedPatch(vid.width<<(FRACBITS-1), y<<FRACBITS, FRACUNIT/dupz, V_TRANSLUCENT, crosshair[i - 1], NULL); -} - -static inline void HU_DrawCrosshair2(void) -{ - INT32 i, y, dupz; - - i = cv_crosshair2.value & 3; - if (!i) - return; - - if ((netgame || multiplayer) && players[secondarydisplayplayer].spectator) - return; - -#ifdef HWRENDER - if (rendermode != render_soft) - y = (INT32)gl_basewindowcentery; - else -#endif - y = viewwindowy + (viewheight>>1); - - if (!splitscreen) - return; - - #ifdef HWRENDER - if (rendermode != render_soft) - y += (INT32)gl_viewheight; - else - #endif - y += viewheight; - - dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - - V_DrawFixedPatch(vid.width<<(FRACBITS-1), y<<FRACBITS, FRACUNIT/dupz, V_TRANSLUCENT, crosshair[i - 1], NULL); + stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); + if (!players[secondarydisplayplayer].spectator && (!camera2.chase || ticcmd_ztargetfocus[1]) && cross2 && splitscreen) + V_DrawStretchyFixedPatch((BASEVIDWIDTH/2)<<FRACBITS, (BASEVIDHEIGHT/2)<<FRACBITS, FRACUNIT, 2*FRACUNIT, V_TRANSLUCENT|V_PERPLAYER, crosshair[cross2 - 1], NULL); } static void HU_DrawCEcho(void) @@ -2114,19 +1985,9 @@ void HU_Drawer(void) if (gamestate != GS_LEVEL) return; - // draw the crosshair, not when viewing demos nor with chasecam + // draw the crosshair if (LUA_HudEnabled(hud_crosshair)) - { - if (!automapactive && cv_crosshair.value && !demoplayback && - (!camera.chase || ticcmd_ztargetfocus[0]) - && !players[displayplayer].spectator) - HU_DrawCrosshair(); - - if (!automapactive && cv_crosshair2.value && !demoplayback && - (!camera2.chase || ticcmd_ztargetfocus[1]) - && !players[secondarydisplayplayer].spectator) - HU_DrawCrosshair2(); - } + HU_DrawCrosshairs(); // draw desynch text if (hu_redownloadinggamestate) diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 9b7cee2d3053cb63138a08d32dcfb75565ee537e..bb1a59e69fd9474c6ea8f2f4e8aebcc3c59627b4 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -62,7 +62,7 @@ typedef struct //------------------------------------ // chat stuff //------------------------------------ -#define HU_MAXMSGLEN 224 +#define HU_MAXMSGLEN 223 #define CHAT_BUFSIZE 64 // that's enough messages, right? We'll delete the older ones when that gets out of hand. #ifdef NETSPLITSCREEN #define OLDCHAT (cv_consolechat.value == 1 || dedicated || vid.width < 640) diff --git a/src/info.c b/src/info.c index 87dc4d272dc21987b81ba57317ec5ccada40c656..63a39861835dd101ea5172a8712dc854d5443ea6 100644 --- a/src/info.c +++ b/src/info.c @@ -3797,7 +3797,7 @@ state_t states[NUMSTATES] = {SPR_NTPN, 3, 4, {NULL}, 0, 0, S_PIAN5}, // S_PIAN4 {SPR_NTPN, 2, 4, {NULL}, 0, 0, S_PIAN6}, // S_PIAN5 {SPR_NTPN, 1, 4, {NULL}, 0, 0, S_PIAN1}, // S_PIAN6 - {SPR_NTPN, 5|FF_ANIMATE, 4, {NULL}, 1, 4, S_PIAN1}, // S_PIANSING + {SPR_NTPN, 4|FF_ANIMATE, 24, {NULL}, 1, 4, S_PIAN1}, // S_PIANSING // Shleep {SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2}, // S_SHLEEP1 @@ -4018,6 +4018,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_RAY + -1, // doomednum + S_NULL, // spawnstate + 0, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 0, // radius + 0, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_UNKNOWN -1, // doomednum S_UNKNOWN, // spawnstate @@ -5655,8 +5682,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE_FLEE1, // xdeathstate sfx_s3kb4, // deathsound 4, // speed - 24*FRACUNIT, // radius - 76*FRACUNIT, // height + 36*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset sfx_None, // mass 3, // damage @@ -5790,8 +5817,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE2_FLEE1,// xdeathstate sfx_s3kb4, // deathsound 2*FRACUNIT, // speed - 24*FRACUNIT, // radius - 76*FRACUNIT, // height + 36*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset 0, // mass 3, // damage @@ -5898,7 +5925,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE3_FLEE1, // xdeathstate sfx_s3kb4, // deathsound 8*FRACUNIT, // speed - 32*FRACUNIT, // radius + 36*FRACUNIT, // radius 116*FRACUNIT, // height 0, // display offset MT_FAKEMOBILE, // mass @@ -5925,7 +5952,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_mswarp, // deathsound 8*FRACUNIT, // speed - 32*FRACUNIT, // radius + 36*FRACUNIT, // radius 116*FRACUNIT, // height 0, // display offset 0, // mass @@ -5979,8 +6006,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE4_FLEE1,// xdeathstate sfx_s3kb4, // deathsound 0, // speed - 24*FRACUNIT, // radius - 76*FRACUNIT, // height + 36*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset 0, // mass 3, // damage @@ -8031,7 +8058,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -8058,7 +8085,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_NOGRAVITY|MF_SCENERY|MF_PAPERCOLLISION, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION, // flags S_NULL // raisestate }, @@ -8085,7 +8112,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIP|MF_NOCLIPTHING, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING, // flags S_NULL // raisestate }, @@ -20013,8 +20040,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // painstate 200, // painchance sfx_None, // painsound - S_PIANSING, // meleestate - S_NULL, // missilestate + S_NULL, // meleestate + S_PIANSING, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound @@ -20025,7 +20052,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index 067028dfeaa7bb7090325274d29ff54de539c97d..58c41f9be08086449852b34d68bcf80a461af3a5 100644 --- a/src/info.h +++ b/src/info.h @@ -4376,6 +4376,7 @@ extern playersprite_t free_spr2; typedef enum mobj_type { MT_NULL, + MT_RAY, // General purpose mobj MT_UNKNOWN, MT_THOK, // Thok! mobj diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d64f8abd2fa71beb473a0b673145df39a538ae81..becd12b59dc050435f062f682a9fc47e15e54863 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3458,7 +3458,7 @@ static int lib_gAddPlayer(lua_State *L) lua_pushnil(L); return 1; } - + newplayernum = i; @@ -3489,15 +3489,15 @@ static int lib_gAddPlayer(lua_State *L) // Read the bot name, if given if (!lua_isnoneornil(L, 3)) - strcpy(player_names[newplayernum], luaL_checkstring(L, 3)); - + strlcpy(player_names[newplayernum], luaL_checkstring(L, 3), sizeof(*player_names)); + bot = luaL_optinteger(L, 4, 3); newplayer->bot = (bot >= BOT_NONE && bot <= BOT_MPAI) ? bot : BOT_MPAI; - + // If our bot is a 2P type, we'll need to set its leader so it can spawn if (newplayer->bot == BOT_2PAI || newplayer->bot == BOT_2PHUMAN) B_UpdateBotleader(newplayer); - + // Set the skin (can't do this until AFTER bot type is set!) SetPlayerSkinByNum(newplayernum, skinnum); @@ -3510,7 +3510,7 @@ static int lib_gAddPlayer(lua_State *L) strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum)); HU_AddChatText(joinmsg, false); } - + LUA_PushUserdata(L, newplayer, META_PLAYER); return 1; } diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 287a185bc36b06b5d04cc18d5667b9e869047452..d5f1cf25e5976bf708e22de5398e4fa8638ef631 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -347,6 +347,10 @@ static boolean prepare_mobj_hook int hook_type, mobjtype_t mobj_type ){ +#ifdef PARANOIA + if (mobj_type == MT_NULL) + I_Error("MT_NULL has been passed to a mobj hook\n"); +#endif return init_hook_type(hook, default_status, hook_type, mobj_type, NULL, mobj_hook_available(hook_type, mobj_type)); diff --git a/src/mserv.c b/src/mserv.c index f64c7bea91b6487efca07f01ba7bb41ad786358c..ff62f2cdc6de170c79e3583cbf25cfccdab53995 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -98,6 +98,7 @@ void AddMServCommands(void) CV_RegisterVar(&cv_servername); #ifdef MASTERSERVER COM_AddCommand("listserv", Command_Listserv_f); + COM_AddCommand("masterserver_update", Update_parameters); // allows people to updates manually in case you were delisted by accident #endif #endif } diff --git a/src/p_enemy.c b/src/p_enemy.c index 8409ea9b9ac71333f1fe9ab11638a067696d2ab5..13d667badd0abdd99ca63ffd78cb5ba723d5199a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2659,7 +2659,7 @@ void A_LobShot(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2 >> 16; - mobj_t *shot, *hitspot; + mobj_t *shot; angle_t an; fixed_t z; fixed_t dist; @@ -2698,11 +2698,6 @@ void A_LobShot(mobj_t *actor) P_SetScale(shot, actor->scale); } - // Keep track of where it's going to land - hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL); - hitspot->tics = airtime; - P_SetTarget(&shot->tracer, hitspot); - P_SetTarget(&shot->target, actor); // where it came from shot->angle = an = actor->angle; @@ -3338,20 +3333,18 @@ void A_SkullAttack(mobj_t *actor) actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90; else if (locvar1 == 3) { - statenum_t oldspawnstate = mobjinfo[MT_NULL].spawnstate; - UINT32 oldflags = mobjinfo[MT_NULL].flags; - fixed_t oldradius = mobjinfo[MT_NULL].radius; - fixed_t oldheight = mobjinfo[MT_NULL].height; - mobj_t *check; + statenum_t oldspawnstate = mobjinfo[MT_RAY].spawnstate; + UINT32 oldflags = mobjinfo[MT_RAY].flags; + fixed_t oldradius = mobjinfo[MT_RAY].radius; + fixed_t oldheight = mobjinfo[MT_RAY].height; INT32 i, j; static INT32 k;/* static for (at least) GCC 9.1 weirdness */ - boolean allow; angle_t testang = 0; - mobjinfo[MT_NULL].spawnstate = S_INVISIBLE; - mobjinfo[MT_NULL].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP; - mobjinfo[MT_NULL].radius = mobjinfo[actor->type].radius; - mobjinfo[MT_NULL].height = mobjinfo[actor->type].height; + mobjinfo[MT_RAY].spawnstate = S_INVISIBLE; + mobjinfo[MT_RAY].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP; + mobjinfo[MT_RAY].radius = mobjinfo[actor->type].radius; + mobjinfo[MT_RAY].height = mobjinfo[actor->type].height; if (P_RandomChance(FRACUNIT/2)) // port priority 1? { @@ -3364,15 +3357,12 @@ void A_SkullAttack(mobj_t *actor) j = 9; } -#define dostuff(q) check = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_NULL);\ +#define dostuff(q) \ testang = actor->angle + ((i+(q))*ANG10);\ - allow = (P_TryMove(check,\ - P_ReturnThrustX(check, testang, dist + 2*actor->radius),\ - P_ReturnThrustY(check, testang, dist + 2*actor->radius),\ - true));\ - P_RemoveMobj(check);\ - if (allow)\ - break; + if (P_CheckMove(actor,\ + P_ReturnThrustX(actor, testang, dist + 2*actor->radius),\ + P_ReturnThrustY(actor, testang, dist + 2*actor->radius),\ + true)) break; if (P_RandomChance(FRACUNIT/2)) // port priority 2? { @@ -3398,10 +3388,10 @@ void A_SkullAttack(mobj_t *actor) #undef dostuff - mobjinfo[MT_NULL].spawnstate = oldspawnstate; - mobjinfo[MT_NULL].flags = oldflags; - mobjinfo[MT_NULL].radius = oldradius; - mobjinfo[MT_NULL].height = oldheight; + mobjinfo[MT_RAY].spawnstate = oldspawnstate; + mobjinfo[MT_RAY].flags = oldflags; + mobjinfo[MT_RAY].radius = oldradius; + mobjinfo[MT_RAY].height = oldheight; } an = actor->angle >> ANGLETOFINESHIFT; @@ -4205,7 +4195,6 @@ void A_CustomPower(mobj_t *actor) player_t *player; INT32 locvar1 = var1; INT32 locvar2 = var2; - boolean spawnshield = false; if (LUA_CallAction(A_CUSTOMPOWER, actor)) return; @@ -4224,15 +4213,10 @@ void A_CustomPower(mobj_t *actor) player = actor->target->player; - if (locvar1 == pw_shield && player->powers[pw_shield] != locvar2) - spawnshield = true; + P_SetPower(player, locvar1, locvar2); - player->powers[locvar1] = (UINT16)locvar2; if (actor->info->seesound) S_StartSound(player->mo, actor->info->seesound); - - if (spawnshield) //workaround for a bug - P_SpawnShieldOrb(player); } // Function: A_GiveWeapon @@ -6548,7 +6532,7 @@ void A_OldRingExplode(mobj_t *actor) { { const angle_t fa = (i*FINEANGLES/16) & FINEMASK; - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points mo->momx = FixedMul(FINECOSINE(fa),ns); @@ -6574,7 +6558,7 @@ void A_OldRingExplode(mobj_t *actor) { } } - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); P_SetTarget(&mo->target, actor->target); mo->momz = ns; @@ -6589,7 +6573,7 @@ void A_OldRingExplode(mobj_t *actor) { mo->color = skincolor_bluering; } - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); P_SetTarget(&mo->target, actor->target); mo->momz = -ns; diff --git a/src/p_local.h b/src/p_local.h index 7390137e97c5a560da5ba864e4e507df941afc31..0c5a70fe9ece762ec1888708c5b1c88a67623463 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -154,6 +154,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff); void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); +void P_SetPower(player_t *player, powertype_t power, UINT16 value); void P_SpawnShieldOrb(player_t *player); void P_SwitchShield(player_t *player, UINT16 shieldtype); mobj_t *P_SpawnGhostMobj(mobj_t *mobj); @@ -409,6 +410,7 @@ void P_SetUnderlayPosition(mobj_t *thing); boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y); boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam); +boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_Move(mobj_t *actor, fixed_t speed); boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); diff --git a/src/p_map.c b/src/p_map.c index 5d90399d5cd3743ade20eb3d43fb77f315bdfc8e..d4a85b9e426bd18b324b5a4a9fd87a097d3c010f 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1465,6 +1465,86 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + // Sprite Spikes! + // Do not return because solidity code comes below. + if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID && thing->player) // moving spike rams into player?! + { + if (tmthing->eflags & MFE_VERTICALFLIP) + { + if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz + && !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && thing->eflags & MFE_VERTICALFLIP)) + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); + } + else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz + && !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && !(thing->eflags & MFE_VERTICALFLIP))) + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); + } + else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?! + { + if (thing->eflags & MFE_VERTICALFLIP) + { + if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) + && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale) + && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && tmthing->eflags & MFE_VERTICALFLIP)) + P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); + } + else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) + && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) + && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && !(tmthing->eflags & MFE_VERTICALFLIP))) + P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); + } + + if (tmthing->type == MT_WALLSPIKE && tmthing->flags & MF_SOLID && thing->player) // wall spike impales player + { + fixed_t bottomz, topz; + bottomz = tmthing->z; + topz = tmthing->z + tmthing->height; + if (tmthing->eflags & MFE_VERTICALFLIP) + bottomz -= FixedMul(FRACUNIT, tmthing->scale); + else + topz += FixedMul(FRACUNIT, tmthing->scale); + + if (thing->z + thing->height > bottomz // above bottom + && thing->z < topz) // below top + // don't check angle, the player was clearly in the way in this case + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); + } + else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tmthing->player) + { + fixed_t bottomz, topz; + angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); + + if (P_PlayerInPain(tmthing->player) && (tmthing->momx || tmthing->momy)) + { + angle_t playerangle = R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle; + if (playerangle > ANGLE_180) + playerangle = InvAngle(playerangle); + if (playerangle < ANGLE_90) + return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. + } + + bottomz = thing->z; + topz = thing->z + thing->height; + + if (thing->eflags & MFE_VERTICALFLIP) + bottomz -= FixedMul(FRACUNIT, thing->scale); + else + topz += FixedMul(FRACUNIT, thing->scale); + + if (tmthing->z + tmthing->height > bottomz // above bottom + && tmthing->z < topz // below top + && !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer + { // use base as a reference point to determine what angle you touched the spike at + touchangle = thing->angle - touchangle; + if (touchangle > ANGLE_180) + touchangle = InvAngle(touchangle); + if (touchangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked! + P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); + } + } + if (thing->flags & MF_PUSHABLE) { if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM) @@ -1543,22 +1623,6 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->player) { - if (tmthing->type == MT_WALLSPIKE && (tmthing->flags & MF_SOLID)) // wall spike impales player - { - fixed_t bottomz, topz; - bottomz = tmthing->z; - topz = tmthing->z + tmthing->height; - if (tmthing->eflags & MFE_VERTICALFLIP) - bottomz -= FixedMul(FRACUNIT, tmthing->scale); - else - topz += FixedMul(FRACUNIT, tmthing->scale); - - if (thing->z + thing->height > bottomz // above bottom - && thing->z < topz) // below top - // don't check angle, the player was clearly in the way in this case - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); - } - // Doesn't matter what gravity player's following! Just do your stuff in YOUR direction only if (tmthing->eflags & MFE_VERTICALFLIP && (tmthing->z + tmthing->height + tmthing->momz < thing->z @@ -1593,55 +1657,6 @@ static boolean PIT_CheckThing(mobj_t *thing) if (!tmthing->health) return true; - if (thing->type == MT_SPIKE && (thing->flags & MF_SOLID)) // unfortunate player falls into spike?! - { - if (thing->eflags & MFE_VERTICALFLIP) - { - if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) - && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale) - && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && tmthing->eflags & MFE_VERTICALFLIP)) - P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); - } - else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) - && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) - && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && !(tmthing->eflags & MFE_VERTICALFLIP))) - P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); - } - - if (thing->type == MT_WALLSPIKE && (thing->flags & MF_SOLID)) - { - fixed_t bottomz, topz; - angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); - - if (P_PlayerInPain(tmthing->player) && (tmthing->momx || tmthing->momy)) - { - angle_t playerangle = R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle; - if (playerangle > ANGLE_180) - playerangle = InvAngle(playerangle); - if (playerangle < ANGLE_90) - return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. - } - - bottomz = thing->z; - topz = thing->z + thing->height; - - if (thing->eflags & MFE_VERTICALFLIP) - bottomz -= FixedMul(FRACUNIT, thing->scale); - else - topz += FixedMul(FRACUNIT, thing->scale); - - if (tmthing->z + tmthing->height > bottomz // above bottom - && tmthing->z < topz // below top - && !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer - { // use base as a reference point to determine what angle you touched the spike at - touchangle = thing->angle - touchangle; - if (touchangle > ANGLE_180) - touchangle = InvAngle(touchangle); - if (touchangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked! - P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); - } - } - if (thing->type == MT_FAN || thing->type == MT_STEAM) P_DoFanAndGasJet(thing, tmthing); else if (thing->flags & MF_SPRING && tmthing->player->powers[pw_carry] != CR_MINECART) @@ -1706,8 +1721,8 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - if ((thing->player) && (tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM)) - ; // springs and gas jets should never be able to step up onto a player + if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player)) + ; // springs, gas jets and springs should never be able to step up onto a player // z checking at last // Treat noclip things as non-solid! else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID @@ -1715,9 +1730,6 @@ static boolean PIT_CheckThing(mobj_t *thing) { fixed_t topz, tmtopz; - if (tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) // do not run height checks if you are a spike - return true; - if (tmthing->eflags & MFE_VERTICALFLIP) { // pass under @@ -2654,17 +2666,17 @@ boolean PIT_PushableMoved(mobj_t *thing) return true; } -// -// P_TryMove -// Attempt to move to a new position. -// -boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +static boolean +increment_move +( mobj_t * thing, + fixed_t x, + fixed_t y, + boolean allowdropoff) { fixed_t tryx = thing->x; fixed_t tryy = thing->y; fixed_t radius = thing->radius; fixed_t thingtop; - fixed_t startingonground = P_IsObjectOnGround(thing); floatok = false; if (radius < MAXRADIUS/2) @@ -2802,7 +2814,38 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } } while (tryx != x || tryy != y); + return true; +} + +// +// P_CheckMove +// Check if a P_TryMove would be successful. +// +boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +{ + boolean moveok; + mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY); + + hack->radius = thing->radius; + hack->height = thing->height; + + moveok = increment_move(hack, x, y, allowdropoff); + P_RemoveMobj(hack); + + return moveok; +} + +// +// P_TryMove +// Attempt to move to a new position. +// +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +{ + fixed_t startingonground = P_IsObjectOnGround(thing); + // The move is ok! + if (!increment_move(thing, x, y, allowdropoff)) + return false; // If it's a pushable object, check if anything is // standing on top and move it, too. diff --git a/src/p_mobj.c b/src/p_mobj.c index 9056f5a3f7c0f839fed32c5a509bec2f8797d008..8cb275a4f62ff2b79a3b0e47a29ddcc37fe250c4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7861,36 +7861,6 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (P_MobjFlip(mobj)*mobj->momz < mobj->info->speed) mobj->momz = P_MobjFlip(mobj)*mobj->info->speed; break; - case MT_SPIKE: - case MT_WALLSPIKE: - if (mobj->fuse) - { - mobj->fuse--; - break; - } - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->spawnpoint ? mobj->spawnpoint->args[0] : mobj->info->speed; - break; - case MT_WALLSPIKEBASE: - if (!mobj->target) - { - P_RemoveMobj(mobj); - return; - } - mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); -#if 0 - if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle - { - mobj_t* target = mobj->target; // shortcut - const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); - P_UnsetThingPosition(mobj); - mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); - mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); - P_SetThingPosition(mobj); - mobj->angle = target->angle + ANGLE_90; - } -#endif - break; case MT_ROCKCRUMBLE1: case MT_ROCKCRUMBLE2: case MT_ROCKCRUMBLE3: @@ -9399,6 +9369,26 @@ static boolean P_MobjRegularThink(mobj_t *mobj) switch (mobj->type) { + case MT_WALLSPIKEBASE: + if (!mobj->target) + { + P_RemoveMobj(mobj); + return false; + } + mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); +#if 0 + if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle + { + mobj_t* target = mobj->target; // shortcut + const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); + P_UnsetThingPosition(mobj); + mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); + mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); + P_SetThingPosition(mobj); + mobj->angle = target->angle + ANGLE_90; + } +#endif + break; case MT_FALLINGROCK: // Despawn rocks here in case zmovement code can't do so (blame slopes) if (!mobj->momx && !mobj->momy && !mobj->momz @@ -10083,6 +10073,11 @@ static boolean P_FuseThink(mobj_t *mobj) break; case MT_METALSONIC_BATTLE: break; // don't remove + case MT_SPIKE: + case MT_WALLSPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->spawnpoint ? mobj->spawnpoint->args[0] : mobj->info->speed; + break; case MT_NIGHTSCORE: P_RemoveMobj(mobj); return false; @@ -10572,7 +10567,17 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) const mobjinfo_t *info = &mobjinfo[type]; SINT8 sc = -1; state_t *st; - mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); + mobj_t *mobj; + + if (type == MT_NULL) + { +#ifdef PARANOIA + I_Error("Tried to spawn MT_NULL\n"); +#endif + return NULL; + } + + mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); // this is officially a mobj, declared as soon as possible. mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; @@ -13041,34 +13046,36 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean case MT_SPIKE: // Pop up spikes! if (mthing->args[0]) + { + mobj->flags &= ~MF_SCENERY; mobj->fuse = mthing->args[1]; - else - mobj->flags |= MF_NOTHINK; + } if (mthing->args[2] & TMSF_RETRACTED) P_SetMobjState(mobj, mobj->info->meleestate); - // no collision for spikes if the intangible flag is checked - if ((mthing->args[2] & TMSF_INTANGIBLE) || metalrecording) + // Use per-thing collision for spikes unless the intangible flag is checked. + if (!(mthing->args[2] & TMSF_INTANGIBLE) && !metalrecording) { P_UnsetThingPosition(mobj); - mobj->flags |= (MF_NOBLOCKMAP|MF_NOCLIPHEIGHT); - mobj->flags &= ~MF_SOLID; + mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT); + mobj->flags |= MF_SOLID; P_SetThingPosition(mobj); } break; case MT_WALLSPIKE: // Pop up spikes! if (mthing->args[0]) + { + mobj->flags &= ~MF_SCENERY; mobj->fuse = mthing->args[1]; - else - mobj->flags |= MF_NOTHINK; + } if (mthing->args[2] & TMSF_RETRACTED) P_SetMobjState(mobj, mobj->info->meleestate); - // no collision for spikes if the intangible flag is checked - if ((mthing->args[2] & TMSF_INTANGIBLE) || metalrecording) + // Use per-thing collision for spikes unless the intangible flag is checked. + if (!(mthing->args[2] & TMSF_INTANGIBLE) && !metalrecording) { P_UnsetThingPosition(mobj); - mobj->flags |= (MF_NOBLOCKMAP|MF_NOCLIPHEIGHT); - mobj->flags &= ~MF_SOLID; + mobj->flags &= ~(MF_NOBLOCKMAP | MF_NOCLIPHEIGHT); + mobj->flags |= MF_SOLID; P_SetThingPosition(mobj); } // spawn base @@ -13084,8 +13091,6 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean P_SetScale(base, mobj->scale); P_SetTarget(&base->target, mobj); P_SetTarget(&mobj->tracer, base); - if (!mthing->args[0]) - base->flags |= MF_NOTHINK; } break; case MT_RING_BOX: diff --git a/src/p_setup.c b/src/p_setup.c index 89e7175bc5e1866016dddf9a7b9259b2100998bc..94ae3257c16ec9ee0cf080b4437202ccd24fad32 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2533,7 +2533,10 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype P_InitializeSeg(seg); seg->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); if (seg->linedef) - segs[i].offset = FixedHypot(v1->x - seg->linedef->v1->x, v1->y - seg->linedef->v1->y); + { + vertex_t *v = (seg->side == 1) ? seg->linedef->v2 : seg->linedef->v1; + segs[i].offset = FixedHypot(v1->x - v->x, v1->y - v->y); + } seg->length = P_SegLength(seg); #ifdef HWRENDER seg->flength = (rendermode == render_opengl) ? P_SegLengthFloat(seg) : 0; @@ -6415,7 +6418,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // internal game map maplumpname = G_BuildMapName(gamemap); - lastloadedmaplumpnum = W_CheckNumForName(maplumpname); + lastloadedmaplumpnum = W_CheckNumForMap(maplumpname); if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); diff --git a/src/p_spec.c b/src/p_spec.c index e4d2c449d402767c337bebea02247efcf6d37916..2be0414161676c61ca445e4446cedaa32255b391 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2778,21 +2778,15 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 434: // Custom Power if (mo && mo->player) { - mobj_t *dummy = P_SpawnMobj(mo->x, mo->y, mo->z, MT_NULL); + powertype_t power = line->stringargs[0] ? get_number(line->stringargs[0]) : 0; + INT32 value = line->stringargs[1] ? get_number(line->stringargs[1]) : 0; + if (value == -1) // 'Infinite' + value = UINT16_MAX; - var1 = line->stringargs[0] ? get_number(line->stringargs[0]) : 0; - var2 = line->stringargs[1] ? get_number(line->stringargs[1]) : 0; - if (var2 == -1) // 'Infinite' - var2 = UINT16_MAX; + P_SetPower(mo->player, power, value); - P_SetTarget(&dummy->target, mo); - A_CustomPower(dummy); - - if (bot) { - P_SetTarget(&dummy->target, bot); - A_CustomPower(dummy); - } - P_RemoveMobj(dummy); + if (bot) + P_SetPower(bot->player, power, value); } break; diff --git a/src/p_user.c b/src/p_user.c index 29dd6b9026d4709224131030afc455dc8f4358ec..6c34b40a888c2011a34cf389e6cc41796c1f2779 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1043,7 +1043,8 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale); } - player->drawangle = ang + ANGLE_180; + if (player->pflags & PF_DIRECTIONCHAR) + player->drawangle = ang + ANGLE_180; P_InstaThrust(player->mo, ang, fallbackspeed); } @@ -1922,6 +1923,24 @@ void P_SwitchShield(player_t *player, UINT16 shieldtype) } } +// +// P_SetPower +// +// Sets a power and spawns a shield orb if required. +// +void P_SetPower(player_t *player, powertype_t power, UINT16 value) +{ + boolean spawnshield = false; + + if (power == pw_shield && player->powers[pw_shield] != value) + spawnshield = true; + + player->powers[power] = value; + + if (spawnshield) //workaround for a bug + P_SpawnShieldOrb(player); +} + // // P_SpawnGhostMobj // @@ -6197,18 +6216,11 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad if (player->exiting) return; + if (!P_CheckMove(player->mo, + player->mo->x + player->mo->momx, + player->mo->y + player->mo->momy, true)) { - boolean notallowed; - mobj_t *hack = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_NULL); - hack->flags = MF_NOGRAVITY; - hack->radius = player->mo->radius; - hack->height = player->mo->height; - hack->z = player->mo->z; - P_SetThingPosition(hack); - notallowed = (!(P_TryMove(hack, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, true))); - P_RemoveMobj(hack); - if (notallowed) - return; + return; } { @@ -11357,6 +11369,8 @@ void P_PlayerThink(player_t *player) { if (B_CheckRespawn(player)) player->playerstate = PST_REBORN; + else + B_HandleFlightIndicator(player); } if (player->playerstate == PST_REBORN) { diff --git a/src/r_draw.h b/src/r_draw.h index 2173c7a5a36e5c9b92063657aa833dbb5b457726..2576e1577a5147e5572f464146f06f886b56b34a 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -170,6 +170,7 @@ void R_DrawViewBorder(void); void R_DrawColumn_8(void); void R_DrawShadeColumn_8(void); void R_DrawTranslucentColumn_8(void); +void R_DrawDropShadowColumn_8(void); void R_DrawTranslatedColumn_8(void); void R_DrawTranslatedTranslucentColumn_8(void); void R_Draw2sMultiPatchColumn_8(void); diff --git a/src/r_draw8.c b/src/r_draw8.c index b8a63d5c042d7ce49f8480bac269b763c43f5dd6..182182574c488841c39b4e6d2a43704db03c90a4 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -416,6 +416,39 @@ void R_DrawTranslucentColumn_8(void) } } +// Hack: A cut-down copy of R_DrawTranslucentColumn_8 that does not read texture +// data since something about calculating the texture reading address for drop shadows is broken. +// dc_texturemid and dc_iscale get wrong values for drop shadows, however those are not strictly +// needed for the current design of the shadows, so this function bypasses the issue +// by not using those variables at all. +void R_DrawDropShadowColumn_8(void) +{ + register INT32 count; + register UINT8 *dest; + + count = dc_yh - dc_yl + 1; + + if (count <= 0) // Zero length, column does not exceed a pixel. + return; + + dest = &topleft[dc_yl*vid.width + dc_x]; + + { +#define DSCOLOR 31 // palette index for the color of the shadow + register const UINT8 *transmap_offset = dc_transmap + (dc_colormap[DSCOLOR] << 8); +#undef DSCOLOR + while ((count -= 2) >= 0) + { + *dest = *(transmap_offset + (*dest)); + dest += vid.width; + *dest = *(transmap_offset + (*dest)); + dest += vid.width; + } + if (count & 1) + *dest = *(transmap_offset + (*dest)); + } +} + /** \brief The R_DrawTranslatedTranslucentColumn_8 function Spiffy function. Not only does it colormap a sprite, but does translucency as well. Uber-kudos to Cyan Helkaraxe diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index 2433cb4024295401017fae6b08394a7db7d0d0df..90201c771b8498a26628438c5a219b742cde0ca0 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -992,6 +992,9 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); @@ -1033,12 +1036,13 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1065,12 +1069,13 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1101,12 +1106,13 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1142,6 +1148,9 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); @@ -1183,12 +1192,13 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1215,12 +1225,13 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1251,12 +1262,13 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) diff --git a/src/r_main.c b/src/r_main.c index 8729b5dcb36ccedb8aed999dbf3afcb60e0faf04..0d6a74a3b07d71b355f9417bdb57631b2576cb8c 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1450,7 +1450,7 @@ static void Mask_Post (maskcount_t* m) void R_RenderPlayerView(player_t *player) { - UINT8 nummasks = 1; + INT32 nummasks = 1; maskcount_t* masks = malloc(sizeof(maskcount_t)); if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1 diff --git a/src/r_portal.c b/src/r_portal.c index 3026f4e4c0a99ea9cde1503eb90952e06b49a26b..cba98db051eed2a7b6830761771b561b3ce7fdee 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -132,6 +132,7 @@ static portal_t* Portal_Add (const INT16 x1, const INT16 x2) void Portal_Remove (portal_t* portal) { + portalcullsector = NULL; portal_base = portal->next; Z_Free(portal->ceilingclip); Z_Free(portal->floorclip); diff --git a/src/r_splats.c b/src/r_splats.c index c554e9b1f002937671e19b1e043460d3168c3e2e..21048c46d0795e257c7a83f60e229b85447c0dc8 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -482,7 +482,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr continue; for (i = x1; i <= x2; i++) - cliptab[i] = (y >= mfloorclip[i]); + cliptab[i] = (y >= mfloorclip[i] || y <= mceilingclip[i]); // clip left while (cliptab[x1]) diff --git a/src/r_things.c b/src/r_things.c index accd1e2b3cd16795a27700d23f128d25e3c99fbb..34a2dd33616d7092b853a61f0c3ee6065be47c07 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -837,6 +837,12 @@ static void R_DrawVisSprite(vissprite_t *vis) else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. colfunc = colfuncs[COLDRAWFUNC_TRANS]; + // Hack: Use a special column function for drop shadows that bypasses + // invalid memory access crashes caused by R_ProjectDropShadow putting wrong values + // in dc_texturemid and dc_iscale when the shadow is sloped. + if (vis->cut & SC_SHADOW) + colfunc = R_DrawDropShadowColumn_8; + if (vis->extra_colormap && !(vis->renderflags & RF_NOCOLORMAPS)) { if (!dc_colormap) @@ -3001,13 +3007,25 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p if (portal) { - for (x = x1; x <= x2; x++) + INT32 start_index = max(portal->start, x1); + INT32 end_index = min(portal->start + portal->end - portal->start, x2); + for (x = x1; x < start_index; x++) + { + spr->clipbot[x] = -1; + spr->cliptop[x] = -1; + } + for (x = start_index; x <= end_index; x++) { if (spr->clipbot[x] > portal->floorclip[x - portal->start]) spr->clipbot[x] = portal->floorclip[x - portal->start]; if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) spr->cliptop[x] = portal->ceilingclip[x - portal->start]; } + for (x = end_index + 1; x <= x2; x++) + { + spr->clipbot[x] = -1; + spr->cliptop[x] = -1; + } } } @@ -3168,10 +3186,10 @@ static void R_DrawMaskedList (drawnode_t* head) } } -void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) +void R_DrawMasked(maskcount_t* masks, INT32 nummasks) { drawnode_t *heads; /**< Drawnode lists; as many as number of views/portals. */ - SINT8 i; + INT32 i; heads = calloc(nummasks, sizeof(drawnode_t)); diff --git a/src/r_things.h b/src/r_things.h index b1ff32b1ee4a3e723bb020f27a397c71e3f91297..b4676fbbd08aea02d3459eaaf41577571b4c88cb 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -100,7 +100,7 @@ typedef struct sector_t* viewsector; } maskcount_t; -void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); +void R_DrawMasked(maskcount_t* masks, INT32 nummasks); // ---------- // VISSPRITES diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index ccec37093698edbcc7865702fea0138db5996749..ab63be946fd15c9792b99b95d340469cfb64b973 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -358,9 +358,10 @@ static void I_ReportSignal(int num, int coredumped) I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Process killed by signal", - sigmsg, NULL); + if (!M_CheckParm("-dedicated")) + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "Process killed by signal", + sigmsg, NULL); } #ifndef NEWSIGNALHANDLER @@ -2202,9 +2203,10 @@ static void newsignalhandler_Warn(const char *pr) I_OutputMsg("%s\n", text); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Startup error", - text, NULL); + if (!M_CheckParm("-dedicated")) + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "Startup error", + text, NULL); I_ShutdownConsole(); exit(-1); @@ -2405,9 +2407,10 @@ void I_Error(const char *error, ...) // Implement message box with SDL_ShowSimpleMessageBox, // which should fail gracefully if it can't put a message box up // on the target system - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "SRB2 "VERSIONSTRING" Recursive Error", - buffer, NULL); + if (!M_CheckParm("-dedicated")) + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "SRB2 "VERSIONSTRING" Recursive Error", + buffer, NULL); W_Shutdown(); exit(-1); // recursive errors detected @@ -2449,9 +2452,10 @@ void I_Error(const char *error, ...) // Implement message box with SDL_ShowSimpleMessageBox, // which should fail gracefully if it can't put a message box up // on the target system - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "SRB2 "VERSIONSTRING" Error", - buffer, NULL); + if (!M_CheckParm("-dedicated")) + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "SRB2 "VERSIONSTRING" Error", + buffer, NULL); // Note that SDL_ShowSimpleMessageBox does *not* require SDL to be // initialized at the time, so calling it after SDL_Quit() is // perfectly okay! In addition, we do this on purpose so the diff --git a/src/v_video.c b/src/v_video.c index 12588f9c2fc2bebda04d6292e137778dff504d63..4e17a44971dd97e9c7e8445baf19889dcee45662 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -539,25 +539,21 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca patchdrawfunc = standardpdraw; v_translevel = NULL; - if (alphalevel) + if (alphalevel || blendmode) { - if (alphalevel == 10) + if (alphalevel == 10) // V_HUDTRANSHALF alphalevel = hudminusalpha[st_translucency]; - else if (alphalevel == 11) + else if (alphalevel == 11) // V_HUDTRANS alphalevel = 10 - st_translucency; - else if (alphalevel == 12) + else if (alphalevel == 12) // V_HUDTRANSDOUBLE alphalevel = hudplusalpha[st_translucency]; if (alphalevel >= 10) return; // invis - if (alphalevel) + if (alphalevel || blendmode) { - if (blendmode) - v_translevel = R_GetBlendTable(blendmode+1, alphalevel); - else - v_translevel = R_GetTranslucencyTable(alphalevel); - + v_translevel = R_GetBlendTable(blendmode+1, alphalevel); patchdrawfunc = translucentpdraw; } } @@ -833,25 +829,21 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN patchdrawfunc = standardpdraw; v_translevel = NULL; - if (alphalevel) + if (alphalevel || blendmode) { - if (alphalevel == 10) + if (alphalevel == 10) // V_HUDTRANSHALF alphalevel = hudminusalpha[st_translucency]; - else if (alphalevel == 11) + else if (alphalevel == 11) // V_HUDTRANS alphalevel = 10 - st_translucency; - else if (alphalevel == 12) + else if (alphalevel == 12) // V_HUDTRANSDOUBLE alphalevel = hudplusalpha[st_translucency]; if (alphalevel >= 10) return; // invis - if (alphalevel) + if (alphalevel || blendmode) { - if (blendmode) - v_translevel = R_GetBlendTable(blendmode+1, alphalevel); - else - v_translevel = R_GetTranslucencyTable(alphalevel); - + v_translevel = R_GetBlendTable(blendmode+1, alphalevel); patchdrawfunc = translucentpdraw; } } @@ -1410,11 +1402,11 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT))) { - if (alphalevel == 10) + if (alphalevel == 10) // V_HUDTRANSHALF alphalevel = hudminusalpha[st_translucency]; - else if (alphalevel == 11) + else if (alphalevel == 11) // V_HUDTRANS alphalevel = 10 - st_translucency; - else if (alphalevel == 12) + else if (alphalevel == 12) // V_HUDTRANSDOUBLE alphalevel = hudplusalpha[st_translucency]; if (alphalevel >= 10) diff --git a/src/w_wad.c b/src/w_wad.c index e49e0ce82f9ffe24c06d757b61b2a69bbc10ee2a..b594912f1b881f7f48417afd9c34d9899ffcb28a 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1463,8 +1463,14 @@ lumpnum_t W_CheckNumForMap(const char *name) continue; // Now look for the specified map. for (; lumpNum < end; lumpNum++) - if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) - return (i<<16) + lumpNum; + { + if (!strnicmp(name, wadfiles[i]->lumpinfo[lumpNum].name, 8)) + { + const char *extension = strrchr(wadfiles[i]->lumpinfo[lumpNum].fullname, '.'); + if (!(extension && stricmp(extension, ".wad"))) + return (i<<16) + lumpNum; + } + } } } return LUMPERROR;