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_collide.c b/src/k_collide.c index d1e4c4e7f..be7bc8579 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -296,6 +296,72 @@ 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; + } + } + t1->momz = zimpulse; + + if (t1->extravalue1 == 0) + { + + K_SpawnEggMineBumpEffect(t1); + t1->extravalue1 = 6; + } +} + +boolean K_EggMineCollide(mobj_t *t1, mobj_t *t2) +{ + 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->type == MT_PLAYER && t1->health > 1) + { + if (t1->health > 2) + { + 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); + } + 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))) @@ -618,7 +684,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 +704,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; diff --git a/src/k_items.c b/src/k_items.c index 69a208da6..98fd900cf 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -2028,24 +2028,96 @@ 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; + } + K_EggMineSetup(mo); + 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); + K_EggMineSetup(mo); + mo->health = 3; + mo->whiteshadow = true; + mo->lastlook = 1; + } + else + { + mo = K_ThrowKartItem(player, true, MT_EGGMINE, 4, 0); + K_EggMineSetup(mo); + 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 +2530,80 @@ 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->itemblink = TICRATE/2; + tmo->player->itemblinkmode = KITEMBLINK_MASHED; + K_SetPlayerItemCooldown(tmo->player, TICRATE, false); + } + } +} + +void K_EggMinePop(mobj_t *mo) +{ + mobj_t *poof; + mobj_t *landMine; + player_t *player; + + if (mo->lastlook == 0) return; + + poof = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); + S_StartSound(poof, mo->info->deathsound); + + if (!(mo->target && mo->target->player)) return; + + player = mo->target->player; + + landMine = P_SpawnMobj(mo->x, mo->y, mo->z + mo->height/2, MT_LANDMINE); + K_FlipFromObject(landMine, mo); + landMine->threshold = 10; + landMine->target = player->mo; + + P_SetScale(landMine, 3*mo->scale/4); + landMine->destscale = mo->destscale; + + landMine->angle = mo->angle; + + landMine->momz = (28 * mapobjectscale * P_MobjFlip(mo)); + landMine->color = player->skincolor; +} + +void K_EggMineSetup(mobj_t *mo) +{ + mobj_t *overlay; + + mo->movefactor = TICRATE; + mo->threshold = 6; + + overlay = P_SpawnMobj(mo->x, mo->y, mo->z, MT_OVERLAY); + overlay->target = mo; + overlay->tracer = mo; + overlay->state = S_EGGMINE_OVERLAY; + overlay->flags2 |= MF2_LINKDRAW; + overlay->dispoffset = -1; +} \ No newline at end of file diff --git a/src/p_map.c b/src/p_map.c index a6fdd39cd..3a664cc80 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -772,6 +772,27 @@ 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_RANDOMITEM) return BMIT_CONTINUE; diff --git a/src/p_mobj.c b/src/p_mobj.c index 3d0eaf2d0..501b9e539 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) { @@ -6508,7 +6508,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: @@ -8012,7 +8012,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)) { @@ -8796,10 +8796,52 @@ 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) + { + K_EggMinePop(mobj); + 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 +10939,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: