diff --git a/src/d_main.cpp b/src/d_main.cpp index 75bfe8216..7d8b07fca 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -94,7 +94,7 @@ #define ASSET_HASH_TEXTURES_KART 0xb4211b2f32b6a291 #define ASSET_HASH_CHARS_KART 0x1e68a3e01aa5c68b #define ASSET_HASH_MAPS_KART 0x38558ed00da41ce9 -#define ASSET_HASH_MAIN_PK3 0xfea5cf465c3a62d1 +#define ASSET_HASH_MAIN_PK3 0x82f7ac8f6266e9e3 #define ASSET_HASH_MAPPATCH_PK3 0x5928d3af98c18214 #define ASSET_HASH_BONUSCHARS_KART 0x60e6f13d822a7461 #ifdef USE_PATCH_FILE diff --git a/src/info/actions.h b/src/info/actions.h index f32aa3438..55aab4bbd 100644 --- a/src/info/actions.h +++ b/src/info/actions.h @@ -213,6 +213,7 @@ _(A_SSMineExplode, SSMINEEXPLODE) _(A_SSMineSearch, GRENADERING) _(A_SSMineExplode, MINEEXPLODE) _(A_LandMineExplode, LANDMINEEXPLODE) +_(A_EggMinePop, EGGMINEPOP) _(A_BallhogExplode, BALLHOGEXPLODE) _(A_LightningFollowPlayer, LIGHTNINGFOLLOWPLAYER) _(A_FZBoomFlash, FZBOOMFLASH) diff --git a/src/info/mobjs.h b/src/info/mobjs.h index f7e5bc3ef..a45912f63 100644 --- a/src/info/mobjs.h +++ b/src/info/mobjs.h @@ -605,8 +605,8 @@ _(BOOMPARTICLE) // Land Mine _(LANDMINE) // Egg Mine -// _(EGGMINE_CAPSULE) -// _(EGGMINE_SHIELD) +_(EGGMINE) +_(EGGMINE_SHIELD) _(BALLHOG) // Ballhog _(BALLHOGBOOM) diff --git a/src/info/states.h b/src/info/states.h index e824bfce6..c58c239e9 100644 --- a/src/info/states.h +++ b/src/info/states.h @@ -2817,9 +2817,9 @@ _(LANDMINE) _(LANDMINE_EXPLODE) // Egg mine -// _(EGGMINE) -// _(EGGMINE_POP) -// _(EGGMINE_SHIELD) +_(EGGMINE) +_(EGGMINE_OVERLAY) +_(EGGMINE_POP) // Ballhog _(BALLHOG1) diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index 21b9ca3d1..8916cc795 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -1234,7 +1234,7 @@ void K_BotItemUsage(botdata_t *bd, const player_t *player) { K_BotItemEggmanExplosion(bd, player); } - else if (player->itemflags & IF_EGGMANOUT) + else if ((!K_IsKartItemAlternate(KITEM_EGGMAN)) && (player->itemflags & IF_EGGMANOUT)) { K_BotItemEggman(bd, player); } @@ -1291,7 +1291,22 @@ void K_BotItemUsage(botdata_t *bd, const player_t *player) } break; case KITEM_EGGMAN: - K_BotItemEggmanShield(bd, player); + if (K_IsKartItemAlternate(KITEM_EGGMAN)) + { + if (!(player->itemflags & IF_ITEMOUT)) + { + K_BotItemGenericOrbitShield(bd, player); + } + else if (player->position != 1) // Hold onto orbiting items when in 1st :) + { + // about the same usage (?), maybe a dedicated usage function one day + K_BotItemMine(bd, player); + } + } + else + { + K_BotItemEggmanShield(bd, player); + } break; case KITEM_ORBINAUT: if (!(player->itemflags & IF_ITEMOUT)) diff --git a/src/k_collide.c b/src/k_collide.c index d1e4c4e7f..a0fcf0ee5 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -296,6 +296,122 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) return true; } +void K_EggMineBounce(mobj_t *t1, mobj_t *t2) +{ + fixed_t zimpulse; + fixed_t impulse = min(max(FixedMul(R_PointToDist2(0, 0, t2->momx, t2->momy), 115*FRACUNIT/100), 15*mapobjectscale), 45*mapobjectscale); + fixed_t pointx = (t1->x + t2->x)/2; + fixed_t pointy = (t1->y + t2->y)/2; + fixed_t localspacex = t1->x - pointx; + fixed_t localspacey = t1->y - pointy; + angle_t impulseangle = R_PointToAngle2(0, 0, (localspacex + t2->momx)/2, (localspacey + t2->momy)/2); + P_InstaThrust(t1, impulseangle, impulse); + zimpulse = (P_MobjFlip(t1) * min((P_AproxDistance(t2->momx, t2->momy) + P_AproxDistance(t1->momx, t1->momy)), 28*mapobjectscale)) + t2->momz/2; + + if (t2->type == MT_EGGMINE) + { + fixed_t zdiff = (t1->z + (t1->height*P_MobjFlip(t1)/2)) - (t2->z + (t2->height*P_MobjFlip(t2))/2); + zimpulse /= 2; + if (zdiff < 0) + { + zimpulse *= -1; + } + } + // doesn't this look familiar + t1->momz = zimpulse; + t1->z += t1->momz; + + if (t1->extravalue1 == 0) + { + + K_SpawnEggMineBumpEffect(t1); + t1->extravalue1 = 6; + } +} + +boolean K_EggMineCollide(mobj_t *t1, mobj_t *t2) +{ + boolean sprung; + + if (t1->health <= 0 || t2->health <= 0) + return true; + + if (t2->player || t2->type == MT_EGGMINE || t2->type == MT_EGGMINE_SHIELD) + { + if ((t2 == t1->target || t2->target == t1->target) && t1->threshold > 0) + { + return true; + } + + if (t2->player && t2->player->flamestore && (K_GetShieldFromPlayer(t2->player) == KSHIELD_FLAME)) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + return true; + } + + if (t2->type == MT_PLAYER && t1->health > 1) + { + if (t1->health > 2) + { + K_DoEggMineStrip(t2, t1, t1->target); + S_StartSound(t2, sfx_bsnipe); + P_DamageMobj(t2, t1, t1->target, 1, DMG_FLIPOVER); + P_RemoveMobj(t1); + return true; + } + else if (P_IsObjectOnGround(t2)) + { + S_StartSound(t2, sfx_cdfm37); + t2->momz = 3*t1->scale*P_MobjFlip(t2); + K_SpawnEggMineBumpEffect(t1); + t1->extravalue1 = 6; + return true; + } + } + K_EggMineBounce(t1, t2); + } + else if (t2->flags & MF_SPRING) + { + // Let thrown items hit springs! + sprung = P_DoSpring(t2, t1); + } + else if (K_IsMissileOrKartItem(t2)) + { + // eggmines don't kill eachother + if (!(t2->type == MT_SPB || t2->type == MT_EGGMINE || t2->type == MT_EGGMINE_SHIELD)) + { + P_KillMobj(t2, t1, t1->target, DMG_INSTAKILL); + } + P_KillMobj(t1, t2, t2->target, DMG_INSTAKILL); + } + + if (sprung) + { + return false; + } + return true; +} + +boolean K_EggMineShieldCollide(mobj_t *t1, mobj_t *t2) +{ + if (t1->health <= 0 || t2->health <= 0) + return true; + + if (K_IsMissileOrKartItem(t2)) + { + // eggmines don't kill eachother + if (!(t2->type == MT_SPB || t2->type == MT_EGGMINE || t2->type == MT_EGGMINE_SHIELD)) + { + P_KillMobj(t2, t1, t1->target, DMG_INSTAKILL); + } + P_KillMobj(t1, t2, t2->target, DMG_INSTAKILL); + return true; + } + + return true; +} + 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))) @@ -396,6 +512,8 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) } else { + // these can only come from eggmines now + K_DoEggMineStrip(t2, t1, t1->target); // Player Damage P_DamageMobj(t2, t1, t1->target, 1, DMG_FLIPOVER); } @@ -554,8 +672,8 @@ static void K_BubbleShieldCollideDrain(player_t *player, mobj_t *bubble, INT16 d static boolean K_BubbleReflectingTrapItem(const mobj_t *t) { return t->type == MT_BANANA || (t->type == MT_ORBINAUT && t->flags2 & MF2_AMBUSH) || t->type == MT_JAWZ_DUD || - t->type == MT_EGGMANITEM || t->type == MT_SSMINE || t->type == MT_SSMINE_SHIELD || t->type == MT_LANDMINE;// || - // t->type == MT_EGGMINE_CAPSULE || t->type == MT_EGGMINE_SHIELD; + t->type == MT_EGGMANITEM || t->type == MT_SSMINE || t->type == MT_SSMINE_SHIELD || t->type == MT_LANDMINE || + t->type == MT_EGGMINE; } static boolean K_StrongPlayerBump(const player_t *player) @@ -618,7 +736,7 @@ boolean K_BubbleShieldCanReflect(mobj_t *t) { return (t->type == MT_ORBINAUT || t->type == MT_JAWZ || t->type == MT_JAWZ_DUD || t->type == MT_BANANA || t->type == MT_EGGMANITEM || t->type == MT_BALLHOG - || t->type == MT_SSMINE || t->type == MT_LANDMINE || t->type == MT_SINK //|| t->type == MT_EGGMINE_CAPSULE + || t->type == MT_SSMINE || t->type == MT_LANDMINE || t->type == MT_SINK || t->type == MT_EGGMINE || t->type == MT_KART_LEFTOVER || t->type == MT_PLAYER); } @@ -638,7 +756,7 @@ static INT16 K_GetBubbleDamage(mobj_t* itm) { case MT_EGGMANITEM: case MT_BALLHOG: - // case MT_EGGMINE_CAPSULE: + case MT_EGGMINE: // Experiment: Let Bubble Shields hard-counter Ballhogs and Eggboxes. dmg = 0; break; @@ -776,7 +894,8 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2) if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD || t2->type == MT_EGGMANITEM || t2->type == MT_EGGMANITEM_SHIELD || t2->type == MT_SSMINE || t2->type == MT_SSMINE_SHIELD - || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) + || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD + || t2->type == MT_EGGMINE_SHIELD) return false; if (t1->health) diff --git a/src/k_collide.h b/src/k_collide.h index 8eeb20a4b..958f3f410 100644 --- a/src/k_collide.h +++ b/src/k_collide.h @@ -13,6 +13,9 @@ void K_ItemDamage(mobj_t *t1, mobj_t *t2, boolean clash); 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_EggMineBounce(mobj_t *t1, mobj_t *t2); +boolean K_EggMineCollide(mobj_t *t1, mobj_t *t2); +boolean K_EggMineShieldCollide(mobj_t *t1, mobj_t *t2); 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); diff --git a/src/k_items.c b/src/k_items.c index 69a208da6..6f1155148 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -2028,24 +2028,93 @@ void K_PlayerItemThink(player_t *player, boolean onground) } break; case KITEM_EGGMAN: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + if (K_IsKartItemAlternate(KITEM_EGGMAN)) { - mobj_t *mo; - player->itemamount--; - K_SetItemOut(player, KITEM_EGGMAN, IF_EGGMANOUT); - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); - if (mo) + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { - K_FlipFromObject(mo, player->mo); - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); + angle_t newangle; + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + K_SetItemOut(player, KITEM_EGGMAN, IF_ITEMOUT); + S_StartSound(player->mo, sfx_s3k3a); + + for (moloop = 0; moloop < player->itemamount; moloop++) + { + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->itemamount) * moloop) << FRACBITS) + ANGLE_90; + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMINE_SHIELD); + if (!mo) + { + player->itemamount = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->angle = newangle; + mo->movecount = player->itemamount; + mo->movedir = mo->lastlook = moloop+1; + + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + K_BotResetItemConfirm(player, false); + } + else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Egg Mine Thrown + { + mobj_t *mo; + player->itemamount -= 1; + + if (player->throwdir == 1) + { + mo = K_ThrowKartItem(player, false, MT_EGGMINE, 1, 0); + mo->health = 3; + mo->whiteshadow = true; + mo->lastlook = 1; + } + else + { + mo = K_ThrowKartItem(player, true, MT_EGGMINE, 4, 0); + if (player->throwdir == 0) + { + mo->health = 2; + mo->whiteshadow = true; + } + else + { + + mo->health = 1; + mo->whiteshadow = false; + } + mo->lastlook = 1; + } + K_UpdateHnextList(player, false); + K_PlayAttackTaunt(player->mo); + } + } + else + { + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->itemamount--; + K_SetItemOut(player, KITEM_EGGMAN, IF_EGGMANOUT); + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); + if (mo) + { + K_FlipFromObject(mo, player->mo); + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + K_BotResetItemConfirm(player, false); } - K_BotResetItemConfirm(player, false); } break; case KITEM_ORBINAUT: @@ -2458,3 +2527,38 @@ void K_AltShrinkPityIncrease(player_t *player) player->growshrinktimer = ((INT16)shrinktime) * -1; } + +#undef PITY_SHRINKINCREASE_BASE +#undef PITY_SHRINKINCREASE + +void K_SpawnEggMineBumpEffect(mobj_t *mo) +{ + mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); + if (mo->eflags & MFE_VERTICALFLIP) + { + fx->eflags |= MFE_VERTICALFLIP; + } + else + { + fx->eflags |= ~MFE_VERTICALFLIP; + } + fx->scale = mo->scale; + S_StartSound(mo, sfx_cdfm15); +} + +void K_DoEggMineStrip(mobj_t *tmo, mobj_t *inflictor, mobj_t *source) +{ + if (inflictor && (inflictor->type == MT_LANDMINE || inflictor->type == MT_EGGMINE)) + { + if (tmo->player) + { + S_StartSound(tmo, sfx_bewar3); + K_DropItems(tmo->player); + tmo->player->itemtype = MAXKARTITEMS; // aka KITEM_SAD + tmo->player->itemamount = 1; + tmo->player->itemblink = TICRATE; + tmo->player->itemblinkmode = KITEMBLINK_MASHED; + K_SetPlayerItemCooldown(tmo->player, TICRATE, false); + } + } +} \ No newline at end of file diff --git a/src/k_items.h b/src/k_items.h index 511cf1054..9098661a6 100644 --- a/src/k_items.h +++ b/src/k_items.h @@ -220,6 +220,9 @@ INT16 K_GetShrinkTime(const player_t *player); boolean K_IsAltShrunk(const player_t *player); void K_AltShrinkPityIncrease(player_t *player); +void K_SpawnEggMineBumpEffect(mobj_t *mo); +void K_DoEggMineStrip(mobj_t *tmo, mobj_t *inflictor, mobj_t *source); + void K_PlayerItemThink(player_t *player, boolean onground); #ifdef __cplusplus diff --git a/src/k_kart.c b/src/k_kart.c index 05d04ba52..f64a75c4e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3828,9 +3828,10 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed) { - mobj_t *th; + mobj_t *missile; fixed_t x, y, z; fixed_t finalspeed = speed; + fixed_t spawndist; mobj_t *throwmo; if (source->player && source->player->speed > K_GetKartSpeed(source->player, false, false)) @@ -3855,82 +3856,101 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I z = source->z+source->height - mobjinfo[type].height; } - th = P_SpawnMobj(x, y, z, type); + missile = P_SpawnMobj(x, y, z, type); - th->flags2 |= flags2; + missile->flags2 |= flags2; if (source->flags2 & MF2_WATERRUN) { // Allow certain items to run on water as well! - if (K_ItemMobjAllowedtoWaterRun(th)) + if (K_ItemMobjAllowedtoWaterRun(missile)) { - th->flags2 |= MF2_WATERRUN; + missile->flags2 |= MF2_WATERRUN; } } - th->threshold = 10; + missile->threshold = 10; - if (th->info->seesound) - S_StartSound(source, th->info->seesound); + if (missile->info->seesound) + S_StartSound(source, missile->info->seesound); - P_SetTarget(&th->target, source); + P_SetTarget(&missile->target, source); - if (P_IsObjectOnGround(source)) + if ((type != MT_EGGMINE) && P_IsObjectOnGround(source)) { // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn // This should set it for FOFs - P_SetOrigin(th, th->x, th->y, th->z); + P_SetOrigin(missile, missile->x, missile->y, missile->z); // spawn on the ground if the player is on the ground if (P_MobjFlip(source) < 0) { - th->z = th->ceilingz - th->height; - th->eflags |= MFE_VERTICALFLIP; + missile->z = missile->ceilingz - missile->height; + missile->eflags |= MFE_VERTICALFLIP; } else - th->z = th->floorz; + missile->z = missile->floorz; } - th->angle = an; + missile->angle = an; - th->momx = FixedMul(finalspeed, FINECOSINE(an>>ANGLETOFINESHIFT)); - th->momy = FixedMul(finalspeed, FINESINE(an>>ANGLETOFINESHIFT)); + missile->momx = FixedMul(finalspeed, FINECOSINE(an>>ANGLETOFINESHIFT)); + missile->momy = FixedMul(finalspeed, FINESINE(an>>ANGLETOFINESHIFT)); switch (type) { case MT_ORBINAUT: if (source && source->player) - th->color = source->player->skincolor; + missile->color = source->player->skincolor; else - th->color = SKINCOLOR_GREY; - th->movefactor = finalspeed; + missile->color = SKINCOLOR_GREY; + missile->movefactor = finalspeed; break; case MT_JAWZ: if (source && source->player) { INT32 lasttarg = source->player->lastjawztarget; - th->cvmem = source->player->skincolor; + missile->cvmem = source->player->skincolor; if ((lasttarg >= 0 && lasttarg < MAXPLAYERS) && playeringame[lasttarg] && !players[lasttarg].spectator && players[lasttarg].mo) { - P_SetTarget(&th->tracer, players[lasttarg].mo); + P_SetTarget(&missile->tracer, players[lasttarg].mo); } } else - th->cvmem = SKINCOLOR_KETCHUP; + missile->cvmem = SKINCOLOR_KETCHUP; /* FALLTHRU */ case MT_JAWZ_DUD: - S_StartSound(th, th->info->activesound); + S_StartSound(missile, missile->info->activesound); /* FALLTHRU */ case MT_SPB: - th->movefactor = finalspeed; + missile->movefactor = finalspeed; break; case MT_BUBBLESHIELDTRAP: - P_SetScale(th, ((5*th->destscale)>>2)*4); - th->destscale = (5*th->destscale)>>2; - S_StartSound(th, sfx_s3kbfl); - S_StartSound(th, sfx_cdfm35); + P_SetScale(missile, ((5*missile->destscale)>>2)*4); + missile->destscale = (5*missile->destscale)>>2; + S_StartSound(missile, sfx_s3kbfl); + S_StartSound(missile, sfx_cdfm35); + break; + case MT_EGGMINE: + // eggmines should spawn closer to the source + P_SetOrigin(missile, + source->x + FixedMul(source->radius + mobjinfo[type].radius, FINECOSINE(an>>ANGLETOFINESHIFT)), + source->y + FixedMul(source->radius + mobjinfo[type].radius, FINESINE(an>>ANGLETOFINESHIFT)), + missile->z + ); + // spawn on the ground if the player is on the ground + if (P_IsObjectOnGround(source)) + { + if (P_MobjFlip(source) < 0) + { + missile->z = missile->ceilingz - missile->height; + missile->eflags |= MFE_VERTICALFLIP; + } + else + missile->z = missile->floorz; + } break; default: break; @@ -3938,15 +3958,15 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I if (type != MT_BUBBLESHIELDTRAP) { - x = x + P_ReturnThrustX(source, an, source->radius + th->radius); - y = y + P_ReturnThrustY(source, an, source->radius + th->radius); + x = x + P_ReturnThrustX(source, an, source->radius + missile->radius); + y = y + P_ReturnThrustY(source, an, source->radius + missile->radius); throwmo = P_SpawnMobj(x, y, z, MT_FIREDITEM); throwmo->movecount = 1; throwmo->movedir = source->angle - an; P_SetTarget(&throwmo->target, source); } - return th; + return missile; } UINT16 K_DriftSparkColor(player_t *player, INT32 charge) @@ -5065,6 +5085,13 @@ void K_DropHnextList(player_t *player) orbit = false; type = MT_EGGMANITEM; break; + case MT_EGGMINE_SHIELD: + orbit = false; + dropall = true; + type = MT_EGGMINE; + + work->lastlook = 0; + break; // intentionally do nothing case MT_ROCKETSNEAKER: case MT_SINK_SHIELD: @@ -5385,7 +5412,7 @@ void K_DropItems(player_t *player) { K_DropHnextList(player); - if (player->mo && !P_MobjWasRemoved(player->mo) && player->itemamount > 0) + if (player->mo && !P_MobjWasRemoved(player->mo) && player->itemamount > 0 && player->itemtype != MAXKARTITEMS) // don't drop KITEM_SAD { mobj_t *drop = K_CreatePaperItem( player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, diff --git a/src/p_enemy.c b/src/p_enemy.c index 4c37a2d1f..37d3d5ceb 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -11472,6 +11472,39 @@ void A_LandMineExplode(void *thing) } } +void A_EggMinePop(void *thing) +{ + mobj_t *actor = thing; + mobj_t *poof; + mobj_t *landMine; + player_t *player; + + if (LUA_CallAction(A_EGGMINEPOP, actor)) + return; + + if (actor->lastlook == 0) return; + + poof = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EXPLODE); + S_StartSound(poof, actor->info->deathsound); + + if (!(actor->target && actor->target->player)) return; + + player = actor->target->player; + + landMine = P_SpawnMobj(actor->x, actor->y, actor->z + actor->height/2, MT_LANDMINE); + K_FlipFromObject(landMine, actor); + landMine->threshold = 10; + landMine->target = player->mo; + + landMine->destscale = mapobjectscale; + P_SetScale(landMine, 3*actor->scale/4); + + landMine->angle = actor->angle; + + landMine->momz = (28 * mapobjectscale * P_MobjFlip(actor)); + landMine->color = player->skincolor; +} + void A_BallhogExplode(void *thing) { mobj_t *actor = thing; diff --git a/src/p_inter.c b/src/p_inter.c index 5b25a2d34..f4e492c5a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1432,7 +1432,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->target->player->itemamount--; } else if ((target->type == MT_ORBINAUT_SHIELD && target->target->player->itemtype == KITEM_ORBINAUT) // orbit items - || (target->type == MT_JAWZ_SHIELD && target->target->player->itemtype == KITEM_JAWZ)) + || (target->type == MT_JAWZ_SHIELD && target->target->player->itemtype == KITEM_JAWZ) + || (target->type == MT_EGGMINE_SHIELD && target->target->player->itemtype == KITEM_EGGMAN && K_IsKartItemAlternate(KITEM_EGGMAN))) { if (target->target->player->itemamount) target->target->player->itemamount--; @@ -1443,7 +1444,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } if (!target->target->player->itemamount) - target->target->player->itemflags &= ~IF_ITEMOUT; + { + K_UnsetItemOut(target->target->player); + // target->target->player->itemflags &= ~IF_ITEMOUT; + } if (target->target->hnext == target) P_SetTarget(&target->target->hnext, NULL); diff --git a/src/p_map.c b/src/p_map.c index a6fdd39cd..2a683add0 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -772,6 +772,48 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return K_EggItemCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } + if (g_tm.thing->type == MT_EGGMINE) + { + // see if it went over / under + if (g_tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (g_tm.thing->z + g_tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + return K_EggMineCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + else if (thing->type == MT_EGGMINE) + { + // see if it went over / under + if (g_tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (g_tm.thing->z + g_tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + return K_EggMineCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + + if (g_tm.thing->type == MT_EGGMINE_SHIELD) + { + // see if it went over / under + if (g_tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (g_tm.thing->z + g_tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + return K_EggMineShieldCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + else if (thing->type == MT_EGGMINE_SHIELD) + { + // see if it went over / under + if (g_tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (g_tm.thing->z + g_tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + return K_EggMineShieldCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + if (g_tm.thing->type == MT_RANDOMITEM) return BMIT_CONTINUE; @@ -3771,6 +3813,11 @@ void P_BounceMove(mobj_t *mo, TryMoveResult_t *result) tmxmove = FixedMul(mmomx, (FRACUNIT - (FRACUNIT>>6) - (FRACUNIT>>5))); tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>6) - (FRACUNIT>>5))); } + else if (mo->type == MT_EGGMINE) + { + tmxmove = mmomx/3; + tmymove = mmomy/3; + } else if (mo->type == MT_THROWNGRENADE || mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE) { // Quickly decay speed as it bounces diff --git a/src/p_mobj.c b/src/p_mobj.c index 3d0eaf2d0..9561f6ea8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1241,7 +1241,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_EGGMANITEM: case MT_SSMINE: case MT_LANDMINE: - // case MT_EGGMINE_CAPSULE: + case MT_EGGMINE: case MT_SINK: if (mo->extravalue2 > 0) { @@ -1799,6 +1799,10 @@ void P_XYMovement(mobj_t *mo) fx->eflags &= ~MFE_VERTICALFLIP; fx->scale = mo->scale; } + else if (mo->type == MT_EGGMINE) + { + K_SpawnEggMineBumpEffect(mo); + } switch (mo->type) { @@ -6508,7 +6512,7 @@ boolean P_IsKartFieldItem(INT32 type) case MT_JAWZ_DUD: case MT_SSMINE: case MT_LANDMINE: - // case MT_EGGMINE_CAPSULE: + case MT_EGGMINE: case MT_BALLHOG: case MT_BUBBLESHIELDTRAP: case MT_SINK: @@ -6529,6 +6533,7 @@ boolean P_IsKartItem(INT32 type) case MT_JAWZ_SHIELD: case MT_SSMINE_SHIELD: case MT_SINK_SHIELD: + case MT_EGGMINE_SHIELD: return true; // Primarily for minimap data, handle with care @@ -7398,6 +7403,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) case MT_BANANA_SHIELD: case MT_SSMINE_SHIELD: case MT_EGGMANITEM_SHIELD: + case MT_EGGMINE_SHIELD: case MT_SINK_SHIELD: if ((mobj->health > 0 && (!mobj->target || !mobj->target->player || mobj->target->health <= 0 || mobj->target->player->spectator)) @@ -8012,7 +8018,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj) case MT_BANANA: case MT_EGGMANITEM: case MT_LANDMINE: - // case MT_EGGMINE_CAPSULE: + case MT_EGGMINE: case MT_SPB: if (P_IsObjectOnGround(mobj)) { @@ -8021,6 +8027,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj) } /* FALLTHRU */ case MT_ORBINAUT_SHIELD: + case MT_EGGMINE_SHIELD: case MT_BANANA_SHIELD: case MT_EGGMANITEM_SHIELD: mobj->renderflags ^= RF_DONTDRAW; @@ -8796,10 +8803,50 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->threshold > 0) mobj->threshold--; break; - // case MT_EGGMINE_CAPSULE: - // todo - // decrement fuse while on ground - // when fuse runs out pop open and spawn a land mine + case MT_EGGMINE: + mobj->friction = 95*ORIG_FRICTION/100; + if (mobj->momx || mobj->momy) + { + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + } + + if (P_IsObjectOnGround(mobj)) + { + if (mobj->health > 1 && mobj->threshold == 0) + { + S_StartSound(mobj, mobj->info->activesound); + mobj->health = 1; + mobj->whiteshadow = false; + } + if (!S_SoundPlaying(mobj, sfx_s3kd2l)) + { + S_StartSound(mobj, sfx_s3kd2l); + } + mobj->movefactor -= 1; + if (mobj->movefactor <= 0) + { + P_KillMobj(mobj, mobj, NULL, DMG_INSTAKILL); + } + } + else if (S_SoundPlaying(mobj, sfx_s3kd2l)) + { + S_StopSoundByID(mobj, sfx_s3kd2l); + } + + if (mobj->threshold > 0) + { + mobj->threshold -= 1; + } + if (mobj->extravalue1 > 0) + { + mobj->extravalue1 -= 1; + } break; case MT_SPBEXPLOSION: mobj->health--; @@ -10897,8 +10944,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_SSMINE: case MT_SSMINE_SHIELD: case MT_LANDMINE: - // case MT_EGGMINE_CAPSULE: - // case MT_EGGMINE_SHIELD: + case MT_EGGMINE: + case MT_EGGMINE_SHIELD: case MT_BALLHOG: case MT_SINK: case MT_ROCKETSNEAKER: @@ -11318,6 +11365,22 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) nummaprings++; break; // SRB2Kart + case MT_EGGMINE: + case MT_EGGMINE_SHIELD: + { + mobj_t *overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + P_SetMobjState(overlay, S_EGGMINE_OVERLAY); + overlay->destscale = mobj->scale; + P_SetScale(overlay, mobj->scale); + P_SetTarget(&overlay->target, mobj); + P_SetTarget(&overlay->tracer, mobj); + overlay->flags2 |= MF2_LINKDRAW; + overlay->dispoffset = -1; + + mobj->movefactor = TICRATE; + mobj->threshold = 6; + break; + } case MT_BUBBLESHIELD: { // Spawn in the damage overlay