diff --git a/src/deh_tables.c b/src/deh_tables.c index ab0ef138b..5f026fe39 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -313,6 +313,7 @@ actionpointer_t actionpointers[] = {{A_JawzExplode}, "A_JAWZEXPLODE"}, {{A_SSMineSearch}, "A_SSMINESEARCH"}, {{A_SSMineExplode}, "A_SSMINEEXPLODE"}, + {{A_SSMineFlash}, "A_SSMINEFLASH"}, {{A_LandMineExplode}, "A_LANDMINEEXPLODE"}, {{A_BallhogExplode}, "A_BALLHOGEXPLODE"}, {{A_LightningFollowPlayer}, "A_LIGHTNINGFOLLOWPLAYER"}, @@ -4529,6 +4530,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_JANKSPARK2", "S_JANKSPARK3", "S_JANKSPARK4", + + // Broly Ki Orb + "S_BROLY1", + "S_BROLY2", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", diff --git a/src/info.c b/src/info.c index 3c6612ac4..345069d54 100644 --- a/src/info.c +++ b/src/info.c @@ -495,6 +495,7 @@ char sprnames[NUMSPRITES + 1][5] = "BOM3", // Boss Explosion 2 "BOM4", // Underwater Explosion "BMNB", // Mine Explosion + "LSSJ", // My ki is overflowing!! // Crumbly rocks "ROIA", @@ -5141,6 +5142,10 @@ state_t states[NUMSTATES] = {SPR_JANK, FF_PAPERSPRITE|FF_FULLBRIGHT|FF_ANIMATE, 4, {NULL}, 3, 1, S_JANKSPARK3}, // S_JANKSPARK2 {SPR_JANK, 0, 0, {A_SetCustomValue}, -1, 5, S_JANKSPARK4}, // S_JANKSPARK3 {SPR_JANK, 0, 0, {A_ChangeAngleRelative}, 180, 180, S_JANKSPARK2}, // S_JANKSPARK4 + + // Broly Ki Orb + {SPR_LSSJ, FF_REVERSESUBTRACT|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_BROLY2}, // S_BROLY1 + {SPR_NULL, 0, 1, {A_SSMineFlash}, 0, 0, S_NULL}, // S_BROLY2 }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = diff --git a/src/info.h b/src/info.h index 35a050011..e4c96915c 100644 --- a/src/info.h +++ b/src/info.h @@ -549,6 +549,7 @@ void A_ItemPop(); void A_JawzExplode(); void A_SSMineSearch(); void A_SSMineExplode(); +void A_SSMineFlash(); void A_LandMineExplode(); void A_LandMineExplode(); void A_BallhogExplode(); @@ -1041,6 +1042,7 @@ typedef enum sprite SPR_BOM3, // Boss Explosion 2 SPR_BOM4, // Underwater Explosion SPR_BMNB, // Mine Explosion + SPR_LSSJ, // My ki is overflowing!! // Crumbly rocks SPR_ROIA, @@ -5563,6 +5565,10 @@ typedef enum state S_JANKSPARK3, S_JANKSPARK4, + // Broly Ki Orb + S_BROLY1, + S_BROLY2, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES diff --git a/src/k_collide.c b/src/k_collide.c index dac44b5f7..64f460a61 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -206,6 +206,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) static mobj_t *grenade; static fixed_t explodedist; static boolean explodespin; +static tic_t minehitlag; static inline boolean PIT_SSMineChecks(mobj_t *thing) { @@ -284,17 +285,22 @@ static inline BlockItReturn_t PIT_SSMineExplode(mobj_t *thing) if (PIT_SSMineChecks(thing) == true) return BMIT_CONTINUE; - P_DamageMobj(thing, grenade, grenade->target, 1, (explodespin ? DMG_NORMAL : DMG_EXPLODE)); + if (P_DamageMobj(thing, grenade, grenade->target, 1, (explodespin ? DMG_NORMAL : DMG_EXPLODE))) + { + minehitlag = thing->hitlag; + } + return BMIT_CONTINUE; } -void K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin) +tic_t 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; + minehitlag = 0; // Use blockmap to check for nearby shootables yh = (unsigned)(actor->y + explodedist - bmaporgy)>>MAPBLOCKSHIFT; @@ -310,6 +316,15 @@ void K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin) // Set this flag to ensure that the inital action won't be triggered twice. actor->flags2 |= MF2_DEBRIS; + + if (!spin) + { + K_SpawnBrolyKi(actor, minehitlag); + + return minehitlag; + } + + return 0; } boolean K_MineCollide(mobj_t *t1, mobj_t *t2) @@ -396,6 +411,7 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) P_DamageMobj(t2, t1, t1->target, 1, DMG_TUMBLE); } + t1->reactiontime = t2->hitlag; P_KillMobj(t1, t2, t2, DMG_NORMAL); } else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD @@ -419,6 +435,7 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); + t1->reactiontime = t2->hitlag; P_KillMobj(t1, t2, t2, DMG_NORMAL); } else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE || t2->type == MT_LANDMINE) @@ -431,6 +448,8 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) { // Shootable damage P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); + + t1->reactiontime = t2->hitlag; P_KillMobj(t1, t2, t2, DMG_NORMAL); } diff --git a/src/k_collide.h b/src/k_collide.h index a498241ca..e8700a097 100644 --- a/src/k_collide.h +++ b/src/k_collide.h @@ -10,7 +10,7 @@ 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); +tic_t K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin); boolean K_MineCollide(mobj_t *t1, mobj_t *t2); boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2); diff --git a/src/k_kart.c b/src/k_kart.c index d3fd17661..05decab06 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5122,7 +5122,7 @@ void K_MineFlashScreen(mobj_t *source) } // Spawns the purely visual explosion -void K_SpawnMineExplosion(mobj_t *source, UINT8 color) +void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay) { INT32 i, radius, height; mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING); @@ -5130,10 +5130,9 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) mobj_t *truc; INT32 speed, speed2; - K_MineFlashScreen(source); - K_MatchGenericExtraFlags(smoldering, source); smoldering->tics = TICRATE*3; + smoldering->hitlag += delay; radius = source->radius>>FRACBITS; height = source->height>>FRACBITS; @@ -5151,6 +5150,8 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust->destscale = source->scale*10; dust->scalespeed = source->scale/12; P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale)); + dust->hitlag += delay; + dust->renderflags |= RF_DONTDRAW; truc = P_SpawnMobj(source->x + P_RandomRange(PR_EXPLOSION, -radius, radius)*FRACUNIT, source->y + P_RandomRange(PR_EXPLOSION, -radius, radius)*FRACUNIT, @@ -5167,6 +5168,8 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) if (truc->eflags & MFE_UNDERWATER) truc->momz = (117 * truc->momz) / 200; truc->color = color; + truc->hitlag += delay; + truc->renderflags |= RF_DONTDRAW; } for (i = 0; i < 16; i++) @@ -5180,6 +5183,8 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust->scalespeed = source->scale/12; dust->tics = 30; dust->momz = P_RandomRange(PR_EXPLOSION, FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT; + dust->hitlag += delay; + dust->renderflags |= RF_DONTDRAW; truc = P_SpawnMobj(source->x + P_RandomRange(PR_EXPLOSION, -radius, radius)*FRACUNIT, source->y + P_RandomRange(PR_EXPLOSION, -radius, radius)*FRACUNIT, @@ -5200,9 +5205,40 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) truc->momz = (117 * truc->momz) / 200; truc->tics = TICRATE*2; truc->color = color; + truc->hitlag += delay; + truc->renderflags |= RF_DONTDRAW; } } +void K_SpawnBrolyKi(mobj_t *source, tic_t duration) +{ + mobj_t *x; + + if (duration == 0) + { + return; + } + + x = P_SpawnMobjFromMobj(source, 0, 0, 0, MT_THOK); + + // Shrink into center of source object. + x->z = (source->z + source->height / 2); + x->height = 0; + + P_SetMobjState(x, S_BROLY1); + x->hitlag = 0; // do not copy source hitlag + + P_SetScale(x, 64 * mapobjectscale); + x->scalespeed = x->scale / duration; + + // The last tic doesn't actually get rendered so in order + // to show scale = destscale, add one buffer tic. + x->tics = (duration + 1); + x->destscale = 1; // 0 also doesn't work + + K_ReduceVFX(x, NULL); +} + #undef MINEQUAKEDIST fixed_t K_ItemScaleForPlayer(player_t *player) diff --git a/src/k_kart.h b/src/k_kart.h index cddf3d503..87f3e1998 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -106,7 +106,8 @@ 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_MineFlashScreen(mobj_t *source); -void K_SpawnMineExplosion(mobj_t *source, UINT8 color); +void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay); +void K_SpawnBrolyKi(mobj_t *source, tic_t duration); void K_RunFinishLineBeam(void); 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 06fbb789c..8c88c5155 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3601,10 +3601,11 @@ static int lib_kSpawnMineExplosion(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); UINT8 color = (UINT8)luaL_optinteger(L, 2, SKINCOLOR_KETCHUP); + tic_t delay = (tic_t)luaL_optinteger(L, 3, 0); NOHUD if (!source) return LUA_ErrInvalid(L, "mobj_t"); - K_SpawnMineExplosion(source, color); + K_SpawnMineExplosion(source, color, delay); return 0; } diff --git a/src/p_enemy.c b/src/p_enemy.c index 131e92bf7..afe17b5bc 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -315,6 +315,7 @@ void A_ItemPop(mobj_t *actor); void A_JawzExplode(mobj_t *actor); void A_SSMineSearch(mobj_t *actor); void A_SSMineExplode(mobj_t *actor); +void A_SSMineFlash(mobj_t *actor); void A_LandMineExplode(mobj_t *actor); void A_BallhogExplode(mobj_t *actor); void A_LightningFollowPlayer(mobj_t *actor); @@ -13117,14 +13118,21 @@ void A_SSMineExplode(mobj_t *actor) { INT32 locvar1 = var1; + tic_t delay; + if (LUA_CallAction(A_SSMINEEXPLODE, actor)) return; if (actor->flags2 & MF2_DEBRIS) return; - K_SpawnMineExplosion(actor, (actor->target && actor->target->player) ? actor->target->player->skincolor : SKINCOLOR_KETCHUP); - K_MineExplodeAttack(actor, (3*actor->info->painchance)>>1, (boolean)locvar1); + delay = K_MineExplodeAttack(actor, (3*actor->info->painchance)>>1, (boolean)locvar1); + K_SpawnMineExplosion(actor, (actor->target && actor->target->player) ? actor->target->player->skincolor : SKINCOLOR_KETCHUP, delay); +} + +void A_SSMineFlash(mobj_t *actor) +{ + K_MineFlashScreen(actor); } void A_LandMineExplode(mobj_t *actor) @@ -13135,21 +13143,27 @@ void A_LandMineExplode(mobj_t *actor) INT32 i; mobj_t *smoldering; + tic_t delay = actor->reactiontime; + if (LUA_CallAction(A_LANDMINEEXPLODE, actor)) return; + if (delay == 0) + { + delay = 8; + } + // we'll base the explosion "timer" off of some stupid variable like uh... cvmem! // Yeah let's use cvmem since nobody uses that if (actor->target && !P_MobjWasRemoved(actor->target)) colour = actor->target->color; - K_MineFlashScreen(actor); - // Spawn smoke remains: smoldering = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOLDERING); P_SetScale(smoldering, actor->scale); smoldering->tics = TICRATE*3; + smoldering->hitlag = delay; actor->fuse = actor->tics; // disappear when this state ends. @@ -13159,6 +13173,8 @@ void A_LandMineExplode(mobj_t *actor) expl = P_SpawnMobj(actor->x, actor->y, actor->z + actor->scale, MT_BOOMEXPLODE); expl->color = colour; expl->tics = (i+1); + expl->hitlag = delay; + expl->renderflags |= RF_DONTDRAW; //K_MatchGenericExtraFlags(expl, actor); P_SetScale(expl, actor->scale*4); @@ -13169,6 +13185,8 @@ void A_LandMineExplode(mobj_t *actor) // 100/45 = 2.22 fu/t expl->momz = ((i+1)*actor->scale*5/2)*P_MobjFlip(expl); } + + K_SpawnBrolyKi(actor, delay); } void A_BallhogExplode(mobj_t *actor) diff --git a/src/p_mobj.c b/src/p_mobj.c index 340e40e52..ce526659d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5889,6 +5889,10 @@ static void P_MobjSceneryThink(mobj_t *mobj) smoke->momz = P_RandomRange(PR_SMOLDERING, 4, 9)*mobj->scale*P_MobjFlip(smoke); } break; + case MT_SMOKE: + case MT_BOOMEXPLODE: + mobj->renderflags &= ~(RF_DONTDRAW); + break; case MT_BOOMPARTICLE: { fixed_t x = P_RandomRange(PR_EXPLOSION, -16, 16)*mobj->scale;