diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index bc7a673b7..5f1d3e74f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3617,9 +3617,9 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) { - const fixed_t thingxpos = thing->x + thing->sprxoff; - const fixed_t thingypos = thing->y + thing->spryoff; - const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t thingxpos = thing->x + thing->sprxoff; + fixed_t thingypos = thing->y + thing->spryoff; + fixed_t thingzpos = thing->z + thing->sprzoff; GLPatch_t *gpatch; FOutVector shadowVerts[4]; @@ -3637,6 +3637,21 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) fixed_t slopez; pslope_t *groundslope; + // hitlag vibrating + if (thing->hitlag > 0) + { + fixed_t mul = thing->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(thing->momx, mul); + thingypos += FixedMul(thing->momy, mul); + thingzpos += FixedMul(thing->momz, mul); + } + groundz = R_GetShadowZ(thing, &groundslope); floordiff = abs((flip < 0 ? thing->height : 0) + thingzpos - groundz); @@ -4867,9 +4882,9 @@ static void HWR_AddSprites(sector_t *sec) // BP why not use xtoviexangle/viewangletox like in bsp ?.... static void HWR_ProjectSprite(mobj_t *thing) { - const fixed_t thingxpos = thing->x + thing->sprxoff; - const fixed_t thingypos = thing->y + thing->spryoff; - const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t thingxpos = thing->x + thing->sprxoff; + fixed_t thingypos = thing->y + thing->spryoff; + fixed_t thingzpos = thing->z + thing->sprzoff; gl_vissprite_t *vis; float tr_x, tr_y; @@ -4907,6 +4922,21 @@ static void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; + // hitlag vibrating + if (thing->hitlag > 0) + { + fixed_t mul = thing->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(thing->momx, mul); + thingypos += FixedMul(thing->momy, mul); + thingzpos += FixedMul(thing->momz, mul); + } + dispoffset = thing->info->dispoffset; this_scale = FIXED_TO_FLOAT(thing->scale); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9896eb458..f68771a1b 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1340,9 +1340,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // Look at HWR_ProjectSprite for more { - const fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff; - const fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff; - const fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff; + fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff; + fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff; + fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff; GLPatch_t *gpatch; INT32 durs = spr->mobj->state->tics; @@ -1358,6 +1358,21 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) INT32 mod; float finalscale; + // hitlag vibrating + if (spr->mobj->hitlag > 0) + { + fixed_t mul = spr->mobj->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(spr->mobj->momx, mul); + thingypos += FixedMul(spr->mobj->momy, mul); + thingzpos += FixedMul(spr->mobj->momz, mul); + } + // Apparently people don't like jump frames like that, so back it goes //if (tics > durs) //durs = tics; diff --git a/src/k_collide.c b/src/k_collide.c index 56747a47f..7fbe17603 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -30,7 +30,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing] + if ((t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) && !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ || t1->type == MT_JAWZ_DUD)) return true; @@ -58,11 +58,6 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) || t2->type == MT_BALLHOG) { // Other Item Damage - if (t2->eflags & MFE_VERTICALFLIP) - t2->z -= t2->height; - else - t2->z += t2->height; - S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); @@ -94,11 +89,6 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) if (damageitem) { // This Item Damage - if (t1->eflags & MFE_VERTICALFLIP) - t1->z -= t1->height; - else - t1->z += t1->height; - S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); @@ -133,7 +123,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; // Banana snipe! @@ -147,7 +137,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) } else { - // Player Damage P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); } @@ -159,11 +148,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) || t2->type == MT_BALLHOG) { // Other Item Damage - if (t2->eflags & MFE_VERTICALFLIP) - t2->z -= t2->height; - else - t2->z += t2->height; - S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); @@ -184,11 +168,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (damageitem) { // This Item Damage - if (t1->eflags & MFE_VERTICALFLIP) - t1->z -= t1->height; - else - t1->z += t1->height; - S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); @@ -283,15 +262,19 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; // Bomb punting if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4]) || (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_DEPLOY13])) + { P_KillMobj(t1, t2, t2, DMG_NORMAL); + } else + { K_PuntMine(t1, t2); + } } else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) @@ -300,11 +283,6 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) P_KillMobj(t1, t2, t2, DMG_NORMAL); // Other Item Damage - if (t2->eflags & MFE_VERTICALFLIP) - t2->z -= t2->height; - else - t2->z += t2->height; - S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); @@ -326,10 +304,17 @@ boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2) { if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; - P_DamageMobj(t2, t1, t1->target, 1, (t1->state == &states[S_MINEEXPLOSION1]) ? DMG_EXPLODE : DMG_NORMAL); + if (t1->state == &states[S_MINEEXPLOSION1]) + { + P_DamageMobj(t2, t1, t1->target, 1, DMG_EXPLODE); + } + else + { + P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); + } } else if (t2->flags & MF_SHOOTABLE) { @@ -347,14 +332,16 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; S_StartSound(NULL, sfx_bsnipe); // let all players hear it. + HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[t2->player-players])); I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[t2->player-players]); + P_DamageMobj(t2, t1, t1->target, 1, DMG_INSTAKILL); P_KillMobj(t1, t2, t2, DMG_NORMAL); } diff --git a/src/k_kart.c b/src/k_kart.c index ddbab8fe1..e35b9ff56 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1457,8 +1457,8 @@ static void K_UpdateDraft(player_t *player) continue; #ifndef EASYDRAFTTEST - yourangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - theirangle = R_PointToAngle2(0, 0, players[i].mo->momx, players[i].mo->momy); + yourangle = K_MomentumAngle(player->mo); + theirangle = K_MomentumAngle(players[i].mo); diff = R_PointToAngle2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y) - yourangle; if (diff > ANGLE_180) @@ -2015,7 +2015,7 @@ void K_PlayPowerGloatSound(mobj_t *source) void K_MomentumToFacing(player_t *player) { - angle_t dangle = player->mo->angle - R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + angle_t dangle = player->mo->angle - K_MomentumAngle(player->mo); if (dangle > ANGLE_180) dangle = InvAngle(dangle); @@ -2362,6 +2362,83 @@ fixed_t K_3dKartMovement(player_t *player) return finalspeed; } +angle_t K_MomentumAngle(mobj_t *mo) +{ + if (mo->momx || mo->momy) + { + return R_PointToAngle2(0, 0, mo->momx, mo->momy); + } + else + { + return mo->angle; // default to facing angle, rather than 0 + } +} + +void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics) +{ + boolean mo1valid = (mo1 && !P_MobjWasRemoved(mo1)); + boolean mo2valid = (mo2 && !P_MobjWasRemoved(mo2)); + + INT32 tics1 = tics; + INT32 tics2 = tics; + + if (mo1valid == true && mo2valid == true) + { + const fixed_t ticaddfactor = mapobjectscale * 8; + const INT32 mintics = tics; + + const fixed_t mo1speed = FixedHypot(FixedHypot(mo1->momx, mo1->momy), mo1->momz); + const fixed_t mo2speed = FixedHypot(FixedHypot(mo2->momx, mo2->momy), mo2->momz); + const fixed_t speeddiff = mo2speed - mo1speed; + + const fixed_t scalediff = mo2->scale - mo1->scale; + + const angle_t mo1angle = K_MomentumAngle(mo1); + const angle_t mo2angle = K_MomentumAngle(mo2); + + angle_t anglediff = mo1angle - mo2angle; + fixed_t anglemul = FRACUNIT; + + if (anglediff > ANGLE_180) + { + anglediff = InvAngle(anglediff); + } + + anglemul = FRACUNIT + (AngleFixed(anglediff) / 180); // x1.0 at 0, x1.5 at 90, x2.0 at 180 + + /* + CONS_Printf("anglemul: %f\n", FIXED_TO_FLOAT(anglemul)); + CONS_Printf("speeddiff: %f\n", FIXED_TO_FLOAT(speeddiff)); + CONS_Printf("scalediff: %f\n", FIXED_TO_FLOAT(scalediff)); + */ + + tics1 += FixedMul(speeddiff, FixedMul(anglemul, FRACUNIT + scalediff)) / ticaddfactor; + tics2 += FixedMul(-speeddiff, FixedMul(anglemul, FRACUNIT - scalediff)) / ticaddfactor; + + if (tics1 < mintics) + { + tics1 = mintics; + } + + if (tics2 < mintics) + { + tics2 = mintics; + } + } + + //CONS_Printf("tics1: %d, tics2: %d\n", tics1, tics2); + + if (mo1valid == true) + { + mo1->hitlag += tics1; + } + + if (mo2valid == true) + { + mo2->hitlag += tics2; + } +} + void K_DoInstashield(player_t *player) { mobj_t *layera; @@ -2738,7 +2815,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) if (!bombflashtimer && P_CheckSight(p->mo, source)) { bombflashtimer = TICRATE*2; - P_FlashPal(p, 1, 1); + P_FlashPal(p, PAL_WHITE, 1); } break; // we can break right now because quakes are global to all split players somehow. } @@ -3131,7 +3208,7 @@ static void K_SpawnAIZDust(player_t *player) if (player->speed <= K_GetKartSpeed(player, false)) return; - travelangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + travelangle = K_MomentumAngle(player->mo); //S_StartSound(player->mo, sfx_s3k47); { @@ -3175,7 +3252,7 @@ void K_SpawnBoostTrail(player_t *player) if (player->kartstuff[k_drift] != 0) travelangle = player->mo->angle; else - travelangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); + travelangle = K_MomentumAngle(player->mo); for (i = 0; i < 2; i++) { @@ -3267,7 +3344,7 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) mo->z, MT_WIPEOUTTRAIL); P_SetTarget(&dust->target, mo); - dust->angle = R_PointToAngle2(0,0,mo->momx,mo->momy); + dust->angle = K_MomentumAngle(mo); dust->destscale = mo->scale; P_SetScale(dust, mo->scale); K_FlipFromObject(dust, mo); @@ -3400,7 +3477,7 @@ void K_DriftDustHandling(mobj_t *spawner) if (P_AproxDistance(spawner->momx, spawner->momy) < 5*spawner->scale) return; - anglediff = abs((signed)(spawner->angle - R_PointToAngle2(0, 0, spawner->momx, spawner->momy))); + anglediff = abs((signed)(spawner->angle - K_MomentumAngle(spawner))); } if (anglediff > ANGLE_180) @@ -3702,7 +3779,7 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map void K_PuntMine(mobj_t *thismine, mobj_t *punter) { - angle_t fa = R_PointToAngle2(0, 0, punter->momx, punter->momy) >> ANGLETOFINESHIFT; + angle_t fa = K_MomentumAngle(punter) >> ANGLETOFINESHIFT; fixed_t z = 30*mapobjectscale + punter->momz; fixed_t spd; mobj_t *mine; @@ -3739,6 +3816,9 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter) if (!mine || P_MobjWasRemoved(mine)) return; + if (mine->threshold > 0 || mine->hitlag > 0) + return; + spd = (82 + ((gamespeed-1) * 14))*mapobjectscale; // Avg Speed is 41 in Normal mine->flags |= MF_NOCLIPTHING; @@ -3748,6 +3828,8 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter) mine->extravalue1 = 0; mine->reactiontime = mine->info->reactiontime; + K_SetHitLagForObjects(punter, mine, 5); + mine->momx = punter->momx + FixedMul(FINECOSINE(fa), spd); mine->momy = punter->momy + FixedMul(FINESINE(fa), spd); mine->momz = P_MobjFlip(mine) * z; @@ -5372,7 +5454,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) MT_FASTLINE); P_SetTarget(&fast->target, player->mo); - fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + fast->angle = K_MomentumAngle(player->mo); fast->momx = 3*player->mo->momx/4; fast->momy = 3*player->mo->momy/4; fast->momz = 3*player->mo->momz/4; @@ -5913,18 +5995,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) { boolean finishlinehack = false; angle_t playerangle = player->mo->angle; - angle_t momangle = player->mo->angle; + angle_t momangle = K_MomentumAngle(player->mo); angle_t angletowaypoint = R_PointToAngle2(player->mo->x, player->mo->y, waypoint->mobj->x, waypoint->mobj->y); angle_t angledelta = ANGLE_MAX; angle_t momdelta = ANGLE_MAX; - if (player->mo->momx != 0 || player->mo->momy != 0) - { - // Defaults to facing angle if you're not moving. - momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - } - angledelta = playerangle - angletowaypoint; if (angledelta > ANGLE_180) { @@ -6425,7 +6501,7 @@ static void K_KartDrift(player_t *player, boolean onground) { if (player->kartstuff[k_driftcharge] < 0 || player->kartstuff[k_driftcharge] >= dsone) { - angle_t pushdir = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + angle_t pushdir = K_MomentumAngle(player->mo); S_StartSound(player->mo, sfx_s23c); //K_SpawnDashDustRelease(player); @@ -6863,7 +6939,7 @@ static void K_KartSpindash(player_t *player) mobj_t *grease; grease = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_TIREGREASE); P_SetTarget(&grease->target, player->mo); - grease->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + grease->angle = K_MomentumAngle(player->mo); grease->extravalue1 = i; } } @@ -7528,7 +7604,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (!onground) { P_Thrust( - player->mo, R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), + player->mo, K_MomentumAngle(player->mo), FixedMul(player->mo->scale, K_GetKartGameSpeedScalar(gamespeed)) ); } diff --git a/src/k_kart.h b/src/k_kart.h index 6fcf7690d..408ed3303 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -39,6 +39,8 @@ void K_KartMoveAnimation(player_t *player); void K_KartPlayerHUDUpdate(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); +angle_t K_MomentumAngle(mobj_t *mo); +void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics); void K_DoInstashield(player_t *player); void K_BattleHitPlayer(player_t *player, player_t *victim, UINT8 points, boolean reducewanted); void K_RemoveBumper(player_t *player, mobj_t *inflictor, mobj_t *source); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index f37fb93dc..a299f9c83 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -95,7 +95,8 @@ enum mobj_e { mobj_whiteshadow, mobj_sprxoff, mobj_spryoff, - mobj_sprzoff + mobj_sprzoff, + mobj_hitlag }; static const char *const mobj_opt[] = { @@ -170,6 +171,7 @@ static const char *const mobj_opt[] = { "sprxoff", "spryoff", "sprzoff", + "hitlag", NULL}; #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) @@ -430,6 +432,9 @@ static int mobj_get(lua_State *L) case mobj_sprzoff: lua_pushfixed(L, mo->sprzoff); break; + case mobj_hitlag: + lua_pushinteger(L, mo->hitlag); + break; default: // extra custom variables in Lua memory lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); @@ -787,6 +792,9 @@ static int mobj_set(lua_State *L) case mobj_sprzoff: mo->sprzoff = luaL_checkfixed(L, 3); break; + case mobj_hitlag: + mo->hitlag = luaL_checkinteger(L, 3); + break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); diff --git a/src/p_enemy.c b/src/p_enemy.c index d018af9c5..bc925d4aa 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4457,6 +4457,9 @@ void A_GrenadeRing(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; + if (actor->hitlag > 0) + return; + if (actor->state == &states[S_SSMINE_DEPLOY8]) explodedist = (3*explodedist)/2; @@ -4524,6 +4527,9 @@ void A_SSMineExplode(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; + if (actor->hitlag > 0) + return; + type = (mobjtype_t)locvar1; // Use blockmap to check for nearby shootables @@ -8757,7 +8763,7 @@ void A_JawzChase(mobj_t *actor) if (!actor->tracer) { - actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + actor->angle = K_MomentumAngle(actor); } P_Thrust(actor, actor->angle, thrustamount); @@ -8887,7 +8893,7 @@ static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir) if (mo->eflags & MFE_VERTICALFLIP) sz = mo->ceilingz; - travelangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + travelangle = K_MomentumAngle(mo); if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) { newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); @@ -8917,7 +8923,7 @@ static void SpawnSPBSpeedLines(mobj_t *actor) MT_FASTLINE); P_SetTarget(&fast->target, actor); - fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + fast->angle = K_MomentumAngle(actor); fast->color = SKINCOLOR_RED; fast->colorized = true; K_MatchGenericExtraFlags(fast, actor); diff --git a/src/p_inter.c b/src/p_inter.c index b0dd45156..efa3d3eaa 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1075,6 +1075,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) return; + //K_SetHitLagForObjects(target, inflictor, 15); + // SRB2kart // I wish I knew a better way to do this if (target->target && target->target->player && target->target->player->mo) @@ -1646,8 +1648,10 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } -static boolean P_KillPlayer(player_t *player, UINT8 type) +static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type) { + (void)source; + if (player->exiting) { player->mo->destscale = 1; @@ -1668,6 +1672,8 @@ static boolean P_KillPlayer(player_t *player, UINT8 type) break; } + K_SetHitLagForObjects(player->mo, inflictor, 15); + player->pflags &= ~PF_SLIDING; player->powers[pw_carry] = CR_NONE; @@ -1753,6 +1759,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player_t *player; boolean force = false; + INT32 laglength = 10; + if (objectplacing) return false; @@ -1760,13 +1768,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Spectator handling - if (multiplayer) - { - if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator) - return false; + if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator) + return false; - if (source && source->player && source->player->spectator) - return false; + if (source && source->player && source->player->spectator) + return false; + + if (((damagetype & DMG_TYPEMASK) == DMG_STING) + || ((inflictor && !P_MobjWasRemoved(inflictor)) && inflictor->type == MT_BANANA && inflictor->health <= 1)) + { + laglength = 5; } // Everything above here can't be forced. @@ -1830,7 +1841,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Instant-Death if ((damagetype & DMG_DEATHMASK)) { - if (!P_KillPlayer(player, damagetype)) + if (!P_KillPlayer(player, inflictor, source, damagetype)) return false; } else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) @@ -1941,6 +1952,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } player->kartstuff[k_instashield] = 15; + K_SetHitLagForObjects(target, inflictor, laglength); return true; } } @@ -1962,12 +1974,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (source && source->player && target) G_GhostAddHit((INT32) (source->player - players), target); + K_SetHitLagForObjects(target, inflictor, laglength); + if (target->health <= 0) { P_KillMobj(target, inflictor, source, damagetype); return true; } + //K_SetHitLagForObjects(target, inflictor, laglength); + if (player) P_ResetPlayer(target->player); else diff --git a/src/p_map.c b/src/p_map.c index b8d9820dd..48e274ebb 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -357,7 +357,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) mobj_t *grease; grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE); P_SetTarget(&grease->target, object); - grease->angle = R_PointToAngle2(0, 0, object->momx, object->momy); + grease->angle = K_MomentumAngle(object); grease->extravalue1 = i; } } @@ -1217,19 +1217,31 @@ static boolean PIT_CheckThing(mobj_t *thing) if (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam) { if (tmthing->scale > thing->scale + (mapobjectscale/8)) // SRB2kart - Handle squishes first! + { P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SQUISH); + } else if (thing->scale > tmthing->scale + (mapobjectscale/8)) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_SQUISH); + } else if (tmthing->player->kartstuff[k_invincibilitytimer] && !thing->player->kartstuff[k_invincibilitytimer]) // SRB2kart - Then invincibility! + { P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT); + } else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer]) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); + } else if ((tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) && !(thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) // SRB2kart - Then flame shield! + { P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT); + } else if ((thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) && !(tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); + } } } @@ -2472,6 +2484,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (radius < mapobjectscale) radius = mapobjectscale; + if (thing->hitlag > 0) + { + // Do not move during hitlag + return false; + } + do { if (thing->flags & MF_NOCLIP) { tryx = x; diff --git a/src/p_mobj.c b/src/p_mobj.c index bcbfaf2e7..ae09c87e1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1620,8 +1620,10 @@ void P_XYMovement(mobj_t *mo) relation = transferslope->xydirection - R_PointToAngle2(0, 0, mo->momx, mo->momy); else // Give it for free, I guess. relation = ANGLE_90; + transfermomz = FixedMul(transfermomz, abs(FINESINE((relation >> ANGLETOFINESHIFT) & FINEMASK))); + if (P_MobjFlip(mo)*(transfermomz - mo->momz) > 2*FRACUNIT) // Do the actual launch! { mo->momz = transfermomz; @@ -1696,7 +1698,7 @@ void P_XYMovement(mobj_t *mo) if (oldslope != mo->standingslope) { // First, compare different slopes angle_t oldangle, newangle; - angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + angle_t moveangle = K_MomentumAngle(mo); oldangle = FixedMul((signed)oldslope->zangle, FINECOSINE((moveangle - oldslope->xydirection) >> ANGLETOFINESHIFT)); @@ -1728,7 +1730,7 @@ void P_XYMovement(mobj_t *mo) P_SlopeLaunch(mo); } } else if (moved && mo->standingslope && predictedz) { - angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + angle_t moveangle = K_MomentumAngle(mo); angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); /*CONS_Printf("flat to angle %f - predicted z of %f\n", @@ -4881,8 +4883,6 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj) mobj->angle += mobj->movedir; } - - mobj->angle += (angle_t)mobj->movecount; } return true; @@ -6142,7 +6142,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) frictionsafety = FRACUNIT; } - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + mobj->angle = K_MomentumAngle(mobj); if (mobj->health <= 5) { INT32 i; @@ -6244,7 +6244,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) thrustamount = beatfriction + FixedDiv(mobj->movefactor - currentspeed, frictionsafety); } - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + mobj->angle = K_MomentumAngle(mobj); P_Thrust(mobj, mobj->angle, thrustamount); if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true)) @@ -6407,7 +6407,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) //mobj->angle = mobj->target->angle; { - angle_t angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); + angle_t angle = K_MomentumAngle(mobj->target); fixed_t nudge; mobj->angle = angle; @@ -6675,7 +6675,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { const angle_t off = FixedAngle(40*FRACUNIT); - angle_t ang = mobj->target->angle; + angle_t ang = K_MomentumAngle(mobj->target); fixed_t z; UINT8 trans = (mobj->target->player->kartstuff[k_tiregrease] * (NUMTRANSMAPS+1)) / greasetics; @@ -6688,9 +6688,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->eflags & MFE_VERTICALFLIP) z += mobj->target->height; - if (mobj->target->momx || mobj->target->momy) - ang = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); - if (mobj->extravalue1) ang = (signed)(ang - off); else @@ -6985,10 +6982,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } P_TeleportMove(mobj, destx, desty, mobj->target->z); - if (mobj->target->momx || mobj->target->momy) - mobj->angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); - else - mobj->angle = mobj->target->angle; + mobj->angle = K_MomentumAngle(mobj->target); if (underlayst != S_NULL) { @@ -7865,7 +7859,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->momx = (23*mobj->momx)/24; mobj->momy = (23*mobj->momy)/24; - mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); + mobj->angle = K_MomentumAngle(mobj); if ((mobj->z - mobj->floorz) < (24*mobj->scale) && (leveltime % 3 != 0)) { @@ -8419,6 +8413,13 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) P_SetTarget(&mobj->hprev, NULL); + // Don't run any thinker code while in hitlag + if (mobj->hitlag > 0) + { + mobj->hitlag--; + return; + } + mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL); tmfloorthing = tmhitthing = NULL; @@ -9020,6 +9021,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->colorized = false; + mobj->hitlag = 0; + // Set shadowscale here, before spawn hook so that Lua can change it P_DefaultMobjShadowScale(mobj); diff --git a/src/p_mobj.h b/src/p_mobj.h index 6ffa393aa..96d929041 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -420,6 +420,8 @@ typedef struct mobj_s fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision + INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls + // WARNING: New fields must be added separately to savegame and Lua. } mobj_t; diff --git a/src/p_saveg.c b/src/p_saveg.c index 0b083e42c..e8309f8d5 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1369,9 +1369,10 @@ typedef enum MD2_ROLLANGLE = 1<<14, MD2_SHADOWSCALE = 1<<15, MD2_DRAWFLAGS = 1<<16, - MD2_WAYPOINTCAP = 1<<17, - MD2_KITEMCAP = 1<<18, - MD2_ITNEXT = 1<<19, + MD2_HITLAG = 1<<17, + MD2_WAYPOINTCAP = 1<<18, + MD2_KITEMCAP = 1<<19, + MD2_ITNEXT = 1<<20, } mobj_diff2_t; typedef enum @@ -1586,6 +1587,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_SHADOWSCALE; if (mobj->drawflags) diff2 |= MD2_DRAWFLAGS; + if (mobj->hitlag) + diff2 |= MD2_HITLAG; if (mobj == waypointcap) diff2 |= MD2_WAYPOINTCAP; if (mobj == kitemcap) @@ -1750,6 +1753,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT16(save_p, df); } + if (diff2 & MD2_HITLAG) + WRITEINT32(save_p, mobj->hitlag); WRITEUINT32(save_p, mobj->mobjnum); } @@ -2814,6 +2819,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) } if (diff2 & MD2_DRAWFLAGS) mobj->drawflags = READUINT16(save_p); + if (diff2 & MD2_HITLAG) + mobj->hitlag = READINT32(save_p); if (diff & MD_REDFLAG) { diff --git a/src/p_spec.c b/src/p_spec.c index a86c54c07..3d0eddd2e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4602,8 +4602,7 @@ DoneSection2: { const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); const fixed_t minspeed = 24*hscale; - angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; - // if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0 + angle_t pushangle = K_MomentumAngle(player->mo); if (player->mo->eflags & MFE_SPRUNG) break; @@ -4625,8 +4624,7 @@ DoneSection2: const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); const fixed_t minspeed = 24*hscale; const fixed_t maxspeed = 28*hscale; - angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; - // if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0 + angle_t pushangle = K_MomentumAngle(player->mo); if (player->mo->eflags & MFE_SPRUNG) break; @@ -4673,7 +4671,7 @@ DoneSection2: } lineangle = K_ReflectAngle( - R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), lineangle, + K_MomentumAngle(player->mo), lineangle, playerspeed, linespeed ); diff --git a/src/p_user.c b/src/p_user.c index 073cb8bbf..6c6c0578a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2271,7 +2271,7 @@ void P_MovePlayer(player_t *player) if (trailScale > 0) { - const angle_t forwardangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + const angle_t forwardangle = K_MomentumAngle(player->mo); const fixed_t playerVisualRadius = player->mo->radius + 8*FRACUNIT; const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); @@ -4071,7 +4071,7 @@ static void P_HandleFollower(player_t *player) player->follower->drawflags |= MFD_DONTDRAW; if (player->speed && (player->follower->momx || player->follower->momy)) - player->follower->angle = R_PointToAngle2(0, 0, player->follower->momx, player->follower->momy); + player->follower->angle = K_MomentumAngle(player->follower); // if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward. // Make sure the follower itself is also moving however, otherwise we'll be facing angle 0 @@ -4217,6 +4217,11 @@ void P_PlayerThink(player_t *player) } #endif + if (player->mo->hitlag > 0) + { + return; + } + if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj)) { P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid diff --git a/src/r_things.c b/src/r_things.c index df1946ba6..9788d916b 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1403,9 +1403,9 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, // static void R_ProjectSprite(mobj_t *thing) { - const fixed_t thingxpos = thing->x + thing->sprxoff; - const fixed_t thingypos = thing->y + thing->spryoff; - const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t thingxpos = thing->x + thing->sprxoff; + fixed_t thingypos = thing->y + thing->spryoff; + fixed_t thingzpos = thing->z + thing->sprzoff; mobj_t *oldthing = thing; @@ -1464,6 +1464,21 @@ static void R_ProjectSprite(mobj_t *thing) INT32 rollangle = 0; #endif + // hitlag vibrating + if (thing->hitlag > 0) + { + fixed_t mul = thing->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(thing->momx, mul); + thingypos += FixedMul(thing->momy, mul); + thingzpos += FixedMul(thing->momz, mul); + } + // transform the origin point tr_x = thingxpos - viewx; tr_y = thingypos - viewy;