diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c43137d2c..6f544ec25 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -513,6 +513,10 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->currentweapon = LONG(players[i].currentweapon); rsp->ringweapons = LONG(players[i].ringweapons); + rsp->ammoremoval = (UINT16)SHORT(players[i].ammoremoval); + rsp->ammoremovaltimer = (tic_t)LONG(players[i].ammoremovaltimer); + rsp->ammoremovalweapon = LONG(players[i].ammoremovalweapon); + for (j = 0; j < NUMPOWERS; ++j) rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); @@ -644,6 +648,10 @@ static void resynch_read_player(resynch_pak *rsp) players[i].currentweapon = LONG(rsp->currentweapon); players[i].ringweapons = LONG(rsp->ringweapons); + players[i].ammoremoval = (UINT16)SHORT(rsp->ammoremoval); + players[i].ammoremovaltimer = (tic_t)LONG(rsp->ammoremovaltimer); + players[i].ammoremovalweapon = LONG(rsp->ammoremovalweapon); + for (j = 0; j < NUMPOWERS; ++j) players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a6783fb3d..a2f140f33 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -164,6 +164,9 @@ typedef struct angle_t aiming; INT32 currentweapon; INT32 ringweapons; + UINT16 ammoremoval; + tic_t ammoremovaltimer; + INT32 ammoremovalweapon; UINT16 powers[NUMPOWERS]; // Score is resynched in the confirm resync packet diff --git a/src/d_player.h b/src/d_player.h index c133af703..5860cf1de 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -333,6 +333,10 @@ typedef struct player_s INT32 currentweapon; // current weapon selected. INT32 ringweapons; // weapons currently obtained. + UINT16 ammoremoval; // amount of ammo removed for the current weapon. + tic_t ammoremovaltimer; // flashing counter for ammo used. + INT32 ammoremovalweapon; // weapon from which the ammo was removed. + // Power ups. invinc and invis are tic counters. UINT16 powers[NUMPOWERS]; diff --git a/src/dehacked.c b/src/dehacked.c index 04ac2ef4b..5db61a5b5 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3347,6 +3347,10 @@ static void readmaincfg(MYFILE *f) { gameovertics = get_number(word2); } + else if (fastcmp(word, "AMMOREMOVALTICS")) + { + ammoremovaltics = get_number(word2); + } else if (fastcmp(word, "INTROTOPLAY")) { introtoplay = (UINT8)get_number(word2); diff --git a/src/g_game.c b/src/g_game.c index 81eb5d1a2..d5d992f4e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -217,6 +217,8 @@ UINT16 nightslinktics = 2*TICRATE; INT32 gameovertics = 15*TICRATE; +UINT8 ammoremovaltics = 2*TICRATE; + UINT8 use1upSound = 0; UINT8 maxXtraLife = 2; // Max extra lives from rings diff --git a/src/g_game.h b/src/g_game.h index 6f4079ccc..4a1719494 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -52,6 +52,7 @@ extern tic_t levelstarttic; // for modding? extern INT16 prevmap, nextmap; extern INT32 gameovertics; +extern UINT8 ammoremovaltics; extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) extern INT16 rw_maximums[NUM_WEAPONS]; extern INT32 pausedelay; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index b7bdaa1be..addd707e1 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -136,6 +136,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->currentweapon); else if (fastcmp(field,"ringweapons")) lua_pushinteger(L, plr->ringweapons); + else if (fastcmp(field,"ammoremoval")) + lua_pushinteger(L, plr->ammoremoval); + else if (fastcmp(field,"ammoremovaltimer")) + lua_pushinteger(L, plr->ammoremovaltimer); + else if (fastcmp(field,"ammoremovalweapon")) + lua_pushinteger(L, plr->ammoremovalweapon); else if (fastcmp(field,"powers")) LUA_PushUserdata(L, plr->powers, META_POWERS); else if (fastcmp(field,"pflags")) @@ -428,6 +434,12 @@ static int player_set(lua_State *L) plr->currentweapon = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"ringweapons")) plr->ringweapons = (INT32)luaL_checkinteger(L, 3); + else if (fastcmp(field,"ammoremoval")) + plr->ammoremoval = (UINT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"ammoremovaltimer")) + plr->ammoremovaltimer = (tic_t)luaL_checkinteger(L, 3); + else if (fastcmp(field,"ammoremovalweapon")) + plr->ammoremovalweapon = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"powers")) return NOSET; else if (fastcmp(field,"pflags")) diff --git a/src/p_map.c b/src/p_map.c index cc9209ea8..15fa97c8f 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -285,6 +285,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (spring->info->painchance != 2) { + if (object->player) + object->player->pflags &= ~PF_APPLYAUTOBRAKE; + if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA { object->momx = object->momy = 0; diff --git a/src/p_saveg.c b/src/p_saveg.c index ea998b445..7c073b151 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -125,6 +125,10 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].currentweapon); WRITEINT32(save_p, players[i].ringweapons); + WRITEUINT16(save_p, players[i].ammoremoval); + WRITEUINT32(save_p, players[i].ammoremovaltimer); + WRITEINT32(save_p, players[i].ammoremovaltimer); + for (j = 0; j < NUMPOWERS; j++) WRITEUINT16(save_p, players[i].powers[j]); @@ -329,6 +333,10 @@ static void P_NetUnArchivePlayers(void) players[i].currentweapon = READINT32(save_p); players[i].ringweapons = READINT32(save_p); + players[i].ammoremoval = READUINT16(save_p); + players[i].ammoremovaltimer = READUINT32(save_p); + players[i].ammoremovalweapon = READINT32(save_p); + for (j = 0; j < NUMPOWERS; j++) players[i].powers[j] = READUINT16(save_p); diff --git a/src/p_user.c b/src/p_user.c index 65f93a11c..a69bd5b93 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3900,6 +3900,33 @@ static void P_SetWeaponDelay(player_t *player, INT32 delay) } } +// +// P_DrainWeaponAmmo +// +// Reduces rings and weapon ammo. Also penalizes the player +// for using weapon rings with no normal rings! >:V +// +static void P_DrainWeaponAmmo (player_t *player, INT32 power) +{ + player->powers[power]--; + + if (player->rings < 1) + { + player->ammoremovalweapon = player->currentweapon; + player->ammoremovaltimer = ammoremovaltics; + + if (player->powers[power] > 0) // can't take a ring that doesn't exist + { + player->powers[power]--; + player->ammoremoval = 2; + } + else + player->ammoremoval = 1; + } + else + player->rings--; +} + // // P_DoFiring() // @@ -3938,22 +3965,12 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) 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]) { - TAKE_AMMO(player, pw_bouncering); + P_DrainWeaponAmmo(player, pw_bouncering); P_SetWeaponDelay(player, TICRATE/4); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING); @@ -3964,7 +3981,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Rail ring else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring]) { - TAKE_AMMO(player, pw_railring); + P_DrainWeaponAmmo(player, pw_railring); P_SetWeaponDelay(player, (3*TICRATE)/2); mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW); @@ -3975,7 +3992,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Automatic else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring]) { - TAKE_AMMO(player, pw_automaticring); + P_DrainWeaponAmmo(player, pw_automaticring); player->pflags &= ~PF_ATTACKDOWN; P_SetWeaponDelay(player, 2); @@ -3984,7 +4001,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Explosion else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring]) { - TAKE_AMMO(player, pw_explosionring); + P_DrainWeaponAmmo(player, pw_explosionring); P_SetWeaponDelay(player, (3*TICRATE)/2); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION); @@ -3992,7 +4009,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Grenade else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering]) { - TAKE_AMMO(player, pw_grenadering); + P_DrainWeaponAmmo(player, pw_grenadering); P_SetWeaponDelay(player, TICRATE/3); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION); @@ -4011,7 +4028,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) angle_t shotangle = player->mo->angle; angle_t oldaiming = player->aiming; - TAKE_AMMO(player, pw_scatterring); + P_DrainWeaponAmmo(player, pw_scatterring); P_SetWeaponDelay(player, (2*TICRATE)/3); // Center @@ -4073,8 +4090,6 @@ firenormal: } } - #undef TAKE_AMMO - if (mo) { if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING) @@ -11248,6 +11263,16 @@ void P_PlayerThink(player_t *player) if (!currentlyonground) acceleration /= 2; + // fake skidding! see P_SkidStuff for reference on conditionals + else if (!player->skidtime && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID) && P_AproxDistance(player->mo->momx, player->mo->momy) >= FixedMul(player->runspeed/2, player->mo->scale)) + { + if (player->mo->state-states != S_PLAY_SKID) + P_SetPlayerMobjState(player->mo, S_PLAY_SKID); + player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; + + if (P_IsLocalPlayer(player)) // the sound happens way more frequently now, so give co-op players' ears a brake... + S_StartSound(player->mo, sfx_skid); + } if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... acceleration = FixedMul(acceleration<mo->movefactor)>>FRACBITS; @@ -11332,6 +11357,12 @@ void P_PlayerThink(player_t *player) // Counters, time dependent power ups. // Time Bonus & Ring Bonus count settings + if (player->ammoremovaltimer) + { + if (--player->ammoremovaltimer == 0) + player->ammoremoval = 0; + } + // Strength counts up to diminish fade. if (player->powers[pw_sneakers] && player->powers[pw_sneakers] < UINT16_MAX) player->powers[pw_sneakers]--; diff --git a/src/st_stuff.c b/src/st_stuff.c index aefb4c53c..142cd3e61 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1960,6 +1960,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I static void ST_drawMatchHUD(void) { + char penaltystr[5]; const INT32 y = 176; // HUD_LIVES INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; @@ -1986,18 +1987,20 @@ static void ST_drawMatchHUD(void) ST_drawWeaponSelect(offset, y); } - offset += 20; - ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); - offset += 20; - ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, y, bouncering); - offset += 20; - ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, y, scatterring); - offset += 20; - ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, y, grenadering); - offset += 20; - ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, y, explosionring); - offset += 20; - ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, y, railring); + ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset + 20, y, autoring); + ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset + 40, y, bouncering); + ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset + 60, y, scatterring); + ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset + 80, y, grenadering); + ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset + 100, y, explosionring); + ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset + 120, y, railring); + + if (stplyr->ammoremovaltimer && leveltime % 8 < 4) + { + sprintf(penaltystr, "-%d", stplyr->ammoremoval); + V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y, + V_REDMAP, penaltystr); + } + } }