From 9584982685bc8514a0ce0f52fb9336bab5870da5 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 29 Apr 2025 18:02:58 -0400 Subject: [PATCH] Revert Rewrite mines As much as this pains me, this might be needed for lua compat. This reverts commit 1381a56077d924681caa502019f3d474f57debf4. --- src/deh_tables.c | 2 +- src/doomdef.h | 1 + src/info/actions.h | 4 +- src/info/mobjs.h | 4 +- src/info/states.h | 5 +- src/k_collide.c | 136 ++++++---------------------- src/k_collide.h | 13 +-- src/k_kart.c | 86 +++++++++++++++++- src/k_kart.h | 1 + src/lua_baselib.c | 20 +++++ src/p_enemy.c | 215 ++++++++++++++++++++++++++------------------- src/p_map.c | 21 +++++ src/p_mobj.c | 45 +++++++--- 13 files changed, 318 insertions(+), 235 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 8e94269d4..0a35ee43c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1472,7 +1472,7 @@ struct int_const_s const INT_CONST[] = { {"PRECIPFX_THUNDER",PRECIPFX_THUNDER}, {"PRECIPFX_LIGHTNING",PRECIPFX_LIGHTNING}, {"PRECIPFX_WATERPARTICLES",PRECIPFX_WATERPARTICLES}, - + // followermode_t {"FOLLOWERMODE_FLOAT",FOLLOWERMODE_FLOAT}, {"FOLLOWERMODE_GROUND",FOLLOWERMODE_GROUND}, diff --git a/src/doomdef.h b/src/doomdef.h index dcd763376..44cdfe7e1 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -102,6 +102,7 @@ extern "C" { #endif #define NOMD5 +#define NOFILEHASH // Uncheck this to compile debugging code //#define RANGECHECK diff --git a/src/info/actions.h b/src/info/actions.h index d52e430d6..365385077 100644 --- a/src/info/actions.h +++ b/src/info/actions.h @@ -191,8 +191,6 @@ _(A_FlickyHeightCheck, FLICKYHEIGHTCHECK) _(A_FlickyFlutter, FLICKYFLUTTER) _(A_FlameParticle, FLAMEPARTICLE) _(A_FadeOverlay, FADEOVERLAY) -_(A_MineExplode, MINEEXPLODE) -_(A_MineRange, MINERANGE) _(A_ConnectToGround, CONNECTTOGROUND) _(A_SpawnParticleRelative, SPAWNPARTICLERELATIVE) _(A_ParticleSpawn, PARTICLESPAWN) @@ -212,6 +210,8 @@ _(A_JawzExplode, JAWZEXPLODE) _(A_SPBChase, SPBCHASE) _(A_SSMineSearch, SSMINESEARCH) _(A_SSMineExplode, SSMINEEXPLODE) +_(A_SSMineSearch, GRENADERING) +_(A_SSMineExplode, MINEEXPLODE) _(A_LandMineExplode, LANDMINEEXPLODE) _(A_BallhogExplode, BALLHOGEXPLODE) _(A_LightningFollowPlayer, LIGHTNINGFOLLOWPLAYER) diff --git a/src/info/mobjs.h b/src/info/mobjs.h index c525fb2b7..660814b21 100644 --- a/src/info/mobjs.h +++ b/src/info/mobjs.h @@ -595,8 +595,8 @@ _(PLAYERRETICULE) // Jawz reticule _(SSMINE) // Mine stuff _(SSMINE_SHIELD) - -_(MINEEXPLOSION) // to keep compatmode scripts happy +_(MINEEXPLOSION) +_(MINEEXPLOSIONSOUND) _(SMOLDERING) // New explosion _(BOOMEXPLODE) diff --git a/src/info/states.h b/src/info/states.h index 90134581e..c55459214 100644 --- a/src/info/states.h +++ b/src/info/states.h @@ -2784,7 +2784,9 @@ _(SSMINE_DEPLOY11) _(SSMINE_DEPLOY12) _(SSMINE_DEPLOY13) _(SSMINE_EXPLODE) -_(SSMINE_EXPLODE2) +_(MINEEXPLOSION1) +_(MINEEXPLOSION2) + // New explosion _(QUICKBOOM1) @@ -3476,7 +3478,6 @@ _(EBARREL15) _(EBARREL16) _(EBARREL17) _(EBARREL18) -_(EBARREL19) _(MERRYHORSE) diff --git a/src/k_collide.c b/src/k_collide.c index 768b2191c..e24950cde 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -286,115 +286,6 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) return true; } -static mobj_t *grenade; -static fixed_t explodedist; -static boolean explodespin; - -static inline boolean PIT_SSMineChecks(mobj_t *thing) -{ - if (thing == grenade) // Don't explode yourself! Endless loop! - return true; - - if (thing->health <= 0) - return true; - - if (!(thing->flags & MF_SHOOTABLE) || (thing->flags & MF_SCENERY)) - return true; - - if (thing->player && thing->player->spectator) - return true; - - if (P_AproxDistance(P_AproxDistance(thing->x - grenade->x, thing->y - grenade->y), thing->z - grenade->z) > explodedist) - return true; // Too far away - - if (P_CheckSight(grenade, thing) == false) - return true; // Not in sight - - return false; -} - -static inline BlockItReturn_t PIT_SSMineSearch(mobj_t *thing) -{ - if (grenade == NULL || P_MobjWasRemoved(grenade)) - return BMIT_ABORT; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot - - if (grenade->flags2 & MF2_DEBRIS) // don't explode twice - return BMIT_ABORT; - - if (thing->type != MT_PLAYER) // Don't explode for anything but an actual player. - return BMIT_CONTINUE; - - if (thing == grenade->target && grenade->threshold != 0) // Don't blow up at your owner instantly. - return BMIT_CONTINUE; - - if (PIT_SSMineChecks(thing) == true) - return BMIT_CONTINUE; - - // Explode! - P_SetMobjState(grenade, grenade->info->deathstate); - return BMIT_ABORT; -} - -void K_DoMineSearch(mobj_t *actor, fixed_t size) -{ - INT32 bx, by, xl, xh, yl, yh; - - explodedist = FixedMul(size, actor->scale); - grenade = actor; - - yh = (unsigned)(actor->y + (explodedist + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT; - yl = (unsigned)(actor->y - (explodedist + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT; - xh = (unsigned)(actor->x + (explodedist + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT; - xl = (unsigned)(actor->x - (explodedist + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT; - - BMBOUNDFIX (xl, xh, yl, yh); - - for (by = yl; by <= yh; by++) - for (bx = xl; bx <= xh; bx++) - P_BlockThingsIterator(bx, by, PIT_SSMineSearch); -} - -static inline BlockItReturn_t PIT_SSMineExplode(mobj_t *thing) -{ - if (grenade == NULL || P_MobjWasRemoved(grenade)) - return BMIT_ABORT; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot - -#if 0 - if (grenade->flags2 & MF2_DEBRIS) // don't explode twice - return BMIT_ABORT; -#endif - - if (PIT_SSMineChecks(thing) == true) - return BMIT_CONTINUE; - - P_DamageMobj(thing, grenade, grenade->target, 1, (explodespin ? DMG_NORMAL : DMG_EXPLODE)); - return BMIT_CONTINUE; -} - -void K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin) -{ - INT32 bx, by, xl, xh, yl, yh; - - explodespin = spin; - explodedist = FixedMul(size, actor->scale); - grenade = actor; - - // Use blockmap to check for nearby shootables - yh = (unsigned)(actor->y + explodedist - bmaporgy)>>MAPBLOCKSHIFT; - yl = (unsigned)(actor->y - explodedist - bmaporgy)>>MAPBLOCKSHIFT; - xh = (unsigned)(actor->x + explodedist - bmaporgx)>>MAPBLOCKSHIFT; - xl = (unsigned)(actor->x - explodedist - bmaporgx)>>MAPBLOCKSHIFT; - - BMBOUNDFIX (xl, xh, yl, yh); - - for (by = yl; by <= yh; by++) - for (bx = xl; bx <= xh; bx++) - P_BlockThingsIterator(bx, by, PIT_SSMineExplode); - - // Set this flag to ensure that the inital action won't be triggered twice. - actor->flags2 |= MF2_DEBRIS; -} - boolean K_MineCollide(mobj_t *t1, mobj_t *t2) { if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) @@ -410,7 +301,7 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) // Bomb punting if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4]) - || (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_EXPLODE2])) + || (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_DEPLOY13])) { P_KillMobj(t1, t2, t2, DMG_NORMAL); } @@ -445,6 +336,31 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) return true; } +boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2) +{ + if (t2->player) + { + if (t2->player->flashing > 0) + return true; + + 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) + { + // Shootable damage + P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); + } + + return true; +} + boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) { if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) diff --git a/src/k_collide.h b/src/k_collide.h index 2032582d0..22670b016 100644 --- a/src/k_collide.h +++ b/src/k_collide.h @@ -9,31 +9,22 @@ extern "C" { #endif angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2); - boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2); - boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2); boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2); - -void K_DoMineSearch(mobj_t *actor, fixed_t size); -void K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin); boolean K_MineCollide(mobj_t *t1, mobj_t *t2); - +boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2); boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2); - boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2); - void K_ThunderShieldAttack(mobj_t *actor, fixed_t size); boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2); boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2); + boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2); - boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2); - boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2); boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2); - boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2); #ifdef __cplusplus diff --git a/src/k_kart.c b/src/k_kart.c index abb508d56..96df5e0d3 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4257,6 +4257,90 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) K_HandleBumperChanges(victim, oldVictimBumpers); } +// source is the mobj that originally threw the bomb that exploded etc. +// Spawns the sphere around the explosion that handles spinout +void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source) +{ + mobj_t *mobj; + mobj_t *ghost = NULL; + INT32 i; + TVector v; + TVector *res; + fixed_t finalx, finaly, finalz, dist; + //mobj_t hoopcenter; + angle_t degrees, fa, closestangle; + fixed_t mobjx, mobjy, mobjz; + + //hoopcenter.x = x; + //hoopcenter.y = y; + //hoopcenter.z = z; + + //hoopcenter.z = z - mobjinfo[type].height/2; + + degrees = FINEANGLES/number; + + closestangle = 0; + + // Create the hoop! + for (i = 0; i < number; i++) + { + fa = (i*degrees); + v[0] = FixedMul(FINECOSINE(fa),radius); + v[1] = 0; + v[2] = FixedMul(FINESINE(fa),radius); + v[3] = FRACUNIT; + + res = VectorMatrixMultiply(v, *RotateXMatrix(rotangle)); + M_Memcpy(&v, res, sizeof (v)); + res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); + M_Memcpy(&v, res, sizeof (v)); + + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; + + mobj = P_SpawnMobj(finalx, finaly, finalz, type); + + mobj->z -= mobj->height>>1; + + // change angle + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, x, y); + + // change slope + dist = P_AproxDistance(P_AproxDistance(x - mobj->x, y - mobj->y), z - mobj->z); + + if (dist < 1) + dist = 1; + + mobjx = mobj->x; + mobjy = mobj->y; + mobjz = mobj->z; + + if (ghostit) + { + ghost = P_SpawnGhostMobj(mobj); + P_SetMobjState(mobj, S_NULL); + mobj = ghost; + } + + if (spawncenter) + { + mobj->x = x; + mobj->y = y; + mobj->z = z; + } + + mobj->momx = FixedMul(FixedDiv(mobjx - x, dist), FixedDiv(dist, 6*FRACUNIT)); + mobj->momy = FixedMul(FixedDiv(mobjy - y, dist), FixedDiv(dist, 6*FRACUNIT)); + mobj->momz = FixedMul(FixedDiv(mobjz - z, dist), FixedDiv(dist, 6*FRACUNIT)); + + if (source && !P_MobjWasRemoved(source)) + P_SetTarget(&mobj->target, source); + } +} + +#define MINEQUAKEDIST 4096 + // Spawns the purely visual explosion void K_SpawnMineExplosion(mobj_t *source, UINT8 color) { @@ -4271,8 +4355,6 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) radius = source->radius>>FRACBITS; height = source->height>>FRACBITS; - S_StartSound(smoldering, sfx_s3k4e); - if (!color) color = SKINCOLOR_KETCHUP; diff --git a/src/k_kart.h b/src/k_kart.h index f4f3d3f2e..2579a53f6 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -154,6 +154,7 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers); void K_DestroyBumpers(player_t *player, UINT8 amount); void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount); +void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source); void K_SpawnMineExplosion(mobj_t *source, UINT8 color); UINT16 K_DriftSparkColor(player_t *player, INT32 charge); void K_SpawnBoostTrail(player_t *player); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 3380da3ef..c2dfe08e7 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3692,6 +3692,25 @@ static int lib_kTakeBumpersFromPlayer(lua_State *L) return 0; } +static int lib_kSpawnKartExplosion(lua_State *L) +{ + fixed_t x = luaL_checkfixed(L, 1); + fixed_t y = luaL_checkfixed(L, 2); + fixed_t z = luaL_checkfixed(L, 3); + fixed_t radius = (fixed_t)luaL_optinteger(L, 4, 32*FRACUNIT); + INT32 number = (INT32)luaL_optinteger(L, 5, 32); + mobjtype_t type = luaL_optinteger(L, 6, MT_MINEEXPLOSION); + angle_t rotangle = luaL_optinteger(L, 7, 0); + boolean spawncenter = lua_opttrueboolean(L, 8); + boolean ghostit = lua_optboolean(L, 9); + mobj_t *source = NULL; + NOHUD + if (!lua_isnone(L, 10) && lua_isuserdata(L, 10)) + source = *((mobj_t **)luaL_checkudata(L, 10, META_MOBJ)); + K_SpawnKartExplosion(x, y, z, radius, number, type, rotangle, spawncenter, ghostit, source); + return 0; +} + static int lib_kSpawnMineExplosion(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -4467,6 +4486,7 @@ static luaL_Reg lib[] = { {"K_SpinPlayer",lib_kSpinPlayer}, {"K_ExplodePlayer",lib_kExplodePlayer}, {"K_TakeBumpersFromPlayer",lib_kTakeBumpersFromPlayer}, + {"K_SpawnKartExplosion",lib_kSpawnKartExplosion}, {"K_SpawnMineExplosion",lib_kSpawnMineExplosion}, {"K_SpawnBoostTrail",lib_kSpawnBoostTrail}, {"K_SpawnSparkleTrail",lib_kSpawnSparkleTrail}, diff --git a/src/p_enemy.c b/src/p_enemy.c index 3c9d2e223..f9901218f 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -26,9 +26,7 @@ #include "i_video.h" #include "z_zone.h" #include "lua_hook.h" - -// SRB2kart -#include "k_kart.h" +#include "k_kart.h" // SRB2kart #include "k_waypoint.h" #include "k_battle.h" #include "k_collide.h" @@ -10149,84 +10147,6 @@ void A_FadeOverlay(mobj_t *actor) P_SetTarget(&actor->tracer, fade); } -// Function: A_MineExplode -// Description: Handles the explosion of a DSZ mine. -// -// var1 = unused -// var2 = unused -// -void A_MineExplode(mobj_t *actor) -{ - // INT32 locvar1 = var1; - // INT32 locvar2 = var2; - - if (LUA_CallAction(A_MINEEXPLODE, actor)) - return; - - A_Scream(actor); - actor->flags = MF_NOGRAVITY|MF_NOCLIP; - - /* - quake.epicenter = NULL; - quake.radius = 512*FRACUNIT; - quake.intensity = 8*FRACUNIT; - quake.time = TICRATE/3; - */ - P_StartQuake(8<tracer, 192*FRACUNIT, 0, true); - P_MobjCheckWater(actor); - - { -#define dist 64 - UINT8 i; - mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_SONIC3KBOSSEXPLODE); - S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e)); - P_SpawnMobj(actor->x, actor->y, actor->z, type); - for (i = 0; i < 16; i++) - { - mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT, - actor->y+P_RandomRange(-dist, dist)*FRACUNIT, - actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT, - type); - fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z; - fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx)); - b->momx = FixedDiv(dx, dm)*3; - b->momy = FixedDiv(dy, dm)*3; - b->momz = FixedDiv(dz, dm)*3; - if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop)) - b->flags &= ~MF_NOGRAVITY; - } -#undef dist - - if (actor->watertop != INT32_MAX) - P_SpawnMobj(actor->x, actor->y, actor->watertop, (actor->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH); - } -} - -// Function: A_MineRange -// Description: If the target gets too close, change the state to meleestate. -// -// var1 = Distance to alert at -// var2 = unused -// -void A_MineRange(mobj_t *actor) -{ - fixed_t dm; - INT32 locvar1 = var1; - // INT32 locvar2 = var2; - - if (LUA_CallAction(A_MINERANGE, actor)) - return; - - if (!actor->target) - return; - - dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x)); - if ((dm>>FRACBITS) < locvar1) - P_SetMobjState(actor, actor->info->meleestate); -} - // Function: A_ConnectToGround // Description: Create a palm tree trunk/mine chain. // @@ -11081,9 +11001,55 @@ void A_SPBChase(mobj_t *actor) return; } +static mobj_t *grenade; +static fixed_t explodedist; + +static inline BlockItReturn_t PIT_SSMineSearch(mobj_t *thing) +{ + if (!grenade) + return BMIT_ABORT; + + if (grenade->flags2 & MF2_DEBRIS) + return BMIT_ABORT; + + if (thing->type != MT_PLAYER) // Don't explode for anything but an actual player. + return BMIT_CONTINUE; + + if (!(thing->flags & MF_SHOOTABLE)) + { + // didn't do any damage + return BMIT_CONTINUE; + } + + if (netgame && thing->player && thing->player->spectator) + return BMIT_CONTINUE; + + if (thing == grenade->target && grenade->threshold != 0) // Don't blow up at your owner. + return BMIT_CONTINUE; + + if (thing->player && (thing->player->hyudorotimer + || ((gametyperules & GTR_BUMPERS) && thing->player && thing->player->bumper <= 0 && thing->player->karmadelay))) + return BMIT_CONTINUE; + + // see if it went over / under + if (grenade->z - explodedist > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (grenade->z + grenade->height + explodedist < thing->z) + return BMIT_CONTINUE; // underneath + + if (P_AproxDistance(P_AproxDistance(thing->x - grenade->x, thing->y - grenade->y), + thing->z - grenade->z) > explodedist) + return BMIT_CONTINUE; // Too far away + + // Explode! + P_SetMobjState(grenade, grenade->info->deathstate); + return BMIT_ABORT; +} + void A_SSMineSearch(mobj_t *actor) { - fixed_t dis = INT32_MAX; + INT32 bx, by, xl, xh, yl, yh; + explodedist = FixedMul(actor->info->painchance, mapobjectscale); if (LUA_CallAction(A_SSMINESEARCH, actor)) return; @@ -11091,19 +11057,66 @@ void A_SSMineSearch(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; + if (actor->state == &states[S_SSMINE_DEPLOY8]) + explodedist = (3*explodedist)/2; + if (leveltime % 35 == 0) S_StartSound(actor, actor->info->activesound); - dis = actor->info->painchance; - if (actor->state == &states[S_SSMINE_DEPLOY8]) - dis = (3*dis)>>1; + // Use blockmap to check for nearby shootables + yh = (unsigned)(actor->y + explodedist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (unsigned)(actor->y - explodedist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (unsigned)(actor->x + explodedist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (unsigned)(actor->x - explodedist - bmaporgx)>>MAPBLOCKSHIFT; - K_DoMineSearch(actor, dis); + grenade = actor; + + for (by = yl; by <= yh; by++) + for (bx = xl; bx <= xh; bx++) + P_BlockThingsIterator(bx, by, PIT_SSMineSearch); +} + +static inline BlockItReturn_t PIT_MineExplode(mobj_t *thing) +{ + if (!grenade || P_MobjWasRemoved(grenade)) + return BMIT_ABORT; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot + + if (grenade->flags2 & MF2_DEBRIS) // don't explode twice + return BMIT_ABORT; + + if (thing == grenade || thing->type == MT_MINEEXPLOSIONSOUND) // Don't explode yourself! Endless loop! + return BMIT_CONTINUE; + + if (!(thing->flags & MF_SHOOTABLE) || (thing->flags & MF_SCENERY)) + return BMIT_CONTINUE; + + if (netgame && thing->player && thing->player->spectator) + return BMIT_CONTINUE; + + if ((gametyperules & GTR_BUMPERS) && grenade->target && grenade->target->player && grenade->target->player->bumper <= 0 && thing == grenade->target) + return BMIT_CONTINUE; + + // see if it went over / under + if (grenade->z - explodedist > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (grenade->z + grenade->height + explodedist < thing->z) + return BMIT_CONTINUE; // underneath + + if (P_AproxDistance(P_AproxDistance(thing->x - grenade->x, thing->y - grenade->y), + thing->z - grenade->z) > explodedist) + return BMIT_CONTINUE; // Too far away + + P_DamageMobj(thing, grenade, grenade->target, 1, DMG_EXPLODE); + return BMIT_CONTINUE; } void A_SSMineExplode(mobj_t *actor) { + INT32 bx, by, xl, xh, yl, yh; + INT32 d; INT32 locvar1 = var1; + mobjtype_t type; + explodedist = FixedMul((3*actor->info->painchance)/2, actor->scale); if (LUA_CallAction(A_SSMINEEXPLODE, actor)) return; @@ -11111,13 +11124,33 @@ void A_SSMineExplode(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; - K_MineExplodeAttack(actor, (3*actor->info->painchance)>>1, (boolean)locvar1); + type = (mobjtype_t)locvar1; - skincolornum_t color = SKINCOLOR_KETCHUP; - if (!P_MobjWasRemoved(actor->target) && actor->target->player) - color = actor->target->player->skincolor; + // Use blockmap to check for nearby shootables + yh = (unsigned)(actor->y + explodedist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (unsigned)(actor->y - explodedist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (unsigned)(actor->x + explodedist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (unsigned)(actor->x - explodedist - bmaporgx)>>MAPBLOCKSHIFT; - K_SpawnMineExplosion(actor, color); + BMBOUNDFIX (xl, xh, yl, yh); + + grenade = actor; + + for (by = yl; by <= yh; by++) + for (bx = xl; bx <= xh; bx++) + P_BlockThingsIterator(bx, by, PIT_MineExplode); + + for (d = 0; d < 16; d++) + K_SpawnKartExplosion(actor->x, actor->y, actor->z, explodedist + 32*mapobjectscale, 32, type, d*(ANGLE_45/4), true, false, actor->target); // 32 <-> 64 + + if (actor->target && actor->target->player) + K_SpawnMineExplosion(actor, actor->target->player->skincolor); + else + K_SpawnMineExplosion(actor, SKINCOLOR_KETCHUP); + + P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINEEXPLOSIONSOUND); + + actor->flags2 |= MF2_DEBRIS; // Set this flag to ensure that the explosion won't be effective more than 1 frame. } void A_LandMineExplode(mobj_t *actor) diff --git a/src/p_map.c b/src/p_map.c index 2933a8dd3..c01c57e6d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -812,6 +812,27 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return K_MineCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } + if (g_tm.thing->type == MT_MINEEXPLOSION) + { + // see if it went over / under + if (g_tm.thing->z > thing->z + thing->height) + return true; // overhead + if (g_tm.thing->z + g_tm.thing->height < thing->z) + return true; // underneath + + return K_MineExplosionCollide(g_tm.thing, thing); + } + else if (thing->type == MT_MINEEXPLOSION) + { + // see if it went over / under + if (g_tm.thing->z > thing->z + thing->height) + return true; // overhead + if (g_tm.thing->z + g_tm.thing->height < thing->z) + return true; // underneath + + return K_MineExplosionCollide(thing, g_tm.thing); + } + if (g_tm.thing->type == MT_LANDMINE) { // see if it went over / under diff --git a/src/p_mobj.c b/src/p_mobj.c index 9f381fd3a..1b8978a74 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7833,6 +7833,9 @@ static boolean P_MobjDeadThink(mobj_t *mobj) return false; } break; + case MT_MINEEXPLOSIONSOUND: + P_RemoveMobj(mobj); + return false; case MT_CDUFO: if (mobj->fuse > TICRATE) mobj->renderflags ^= RF_DONTDRAW; // only by good fortune does this end with it having RF_DONTDRAW... don't touch! @@ -8624,6 +8627,34 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_SPBEXPLOSION: mobj->health--; break; + case MT_MINEEXPLOSION: + if ((mobj->z < mobj->floorz - mobj->height) || (mobj->z > mobj->ceilingz + mobj->height)) + { + P_KillMobj(mobj, NULL, NULL, DMG_NORMAL); + break; + } + + if (mobj->tics != -1) + { + mobj->tics--; + + // you can cycle through multiple states in a tic + if (!mobj->tics) + if (!P_SetMobjState(mobj, mobj->state->nextstate)) + return false; // freed itself + } + + P_UnsetThingPosition(mobj); + mobj->x += mobj->momx; + mobj->y += mobj->momy; + mobj->z += mobj->momz; + P_SetThingPosition(mobj); + return false; + case MT_MINEEXPLOSIONSOUND: + if (mobj->health == 100) + S_StartSound(mobj, sfx_s3k4e); + mobj->health--; + break; case MT_BOOSTFLAME: if (!mobj->target || !mobj->target->health) { @@ -9987,17 +10018,6 @@ static void P_FiringThink(mobj_t *mobj) mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); } -static void K_MineExplodeThink(mobj_t *mobj) -{ - if (mobj->state->action.acp1 == (actionf_p1)A_SSMineExplode) - { - if (mobj->state->tics > 1) - { - K_MineExplodeAttack(mobj, mobj->info->painchance, (boolean)mobj->state->var1); - } - } -} - static void P_MonitorFuseThink(mobj_t *mobj) { mobj_t *newmobj; @@ -10302,9 +10322,6 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags2 & MF2_FIRING) P_FiringThink(mobj); - if (mobj->flags2 & MF2_DEBRIS) - K_MineExplodeThink(mobj); - if (mobj->flags & MF_AMBIENT) { if (leveltime % mobj->health)