diff --git a/src/dehacked.c b/src/dehacked.c index 11ad022ca..d844097b6 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7319,6 +7319,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_NIGHTSEXTRATIME", "MT_NIGHTSLINKFREEZE", "MT_EGGCAPSULE", + "MT_IDEYAANCHOR", "MT_NIGHTOPIANHELPER", // the actual helper object that orbits you "MT_PIAN", // decorative singing friend "MT_SHLEEP", // almost-decorative sleeping enemy diff --git a/src/info.c b/src/info.c index 45d7438b9..769d27e88 100644 --- a/src/info.c +++ b/src/info.c @@ -17190,6 +17190,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_IDEYAANCHOR + 1714, // doomednum + S_INVISIBLE, // spawnstate + 0, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 1*FRACUNIT, // radius + 2*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_NIGHTOPIANHELPER -1, // doomednum S_NIGHTOPIANHELPER1, // spawnstate diff --git a/src/info.h b/src/info.h index e3af600a3..8baafbd87 100644 --- a/src/info.h +++ b/src/info.h @@ -4275,6 +4275,7 @@ typedef enum mobj_type MT_NIGHTSEXTRATIME, MT_NIGHTSLINKFREEZE, MT_EGGCAPSULE, + MT_IDEYAANCHOR, MT_NIGHTOPIANHELPER, // the actual helper object that orbits you MT_PIAN, // decorative singing friend MT_SHLEEP, // almost-decorative sleeping enemy diff --git a/src/p_enemy.c b/src/p_enemy.c index d9fc26082..f4fffc5d6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8554,20 +8554,42 @@ void A_ToggleFlameJet(mobj_t* actor) // // var1 = Angle adjustment (aka orbit speed) // var2: -// Lower 16 bits: height offset -// Bits 17-20: set if object is Nightopian Helper -// Bits 21-24: set to not sync scale to player +// Bits 1-10: height offset, max 1023 +// Bits 11-16: X radius factor (max 63, default 20) +// Bit 17: set if object is Nightopian Helper +// Bit 18: set to define X/Y/Z rotation factor +// Bits 19-20: Unused +// Bits 21-26: Y radius factor (max 63, default 32) +// Bits 27-32: Z radius factor (max 63, default 32) // +// If MF_GRENADEBOUNCE is flagged on mobj, use actor->threshold to define X/Y/Z radius factor, max 1023 each: +// Bits 1-10: X factor +// Bits 11-20: Y factor +// Bits 21-30: Z factor void A_OrbitNights(mobj_t* actor) { - INT32 ofs = (var2 & 0xFFFF); - boolean ishelper = (var2 & 0xF0000); - boolean donotrescale = (var2 & 0xF00000); + INT32 ofs = (var2 & 0x3FF); + boolean ishelper = (var2 & 0x10000); + boolean donotrescale = (var2 & 0x40000); + INT32 xfactor = 32, yfactor = 32, zfactor = 20; #ifdef HAVE_BLUA if (LUA_CallAction("A_OrbitNights", actor)) return; #endif + if (actor->flags & MF_GRENADEBOUNCE) + { + xfactor = (actor->threshold & 0x3FF); + yfactor = (actor->threshold & 0xFFC00) >> 10; + zfactor = (actor->threshold & 0x3FF00000) >> 20; + } + else if (var2 & 0x20000) + { + xfactor = (var2 & 0xFC00) >> 10; + yfactor = (var2 & 0x3F00000) >> 20; + zfactor = (var2 & 0xFC000000) >> 26; + } + if (!actor->target || (actor->target->player && // if NiGHTS special stage and not NiGHTSmode. @@ -8586,9 +8608,9 @@ void A_OrbitNights(mobj_t* actor) const angle_t fa = (angle_t)actor->extravalue1 >> ANGLETOFINESHIFT; const angle_t ofa = ((angle_t)actor->extravalue1 + (ofs*ANG1)) >> ANGLETOFINESHIFT; - const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(32*FRACUNIT, actor->scale)); - const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(20*FRACUNIT, actor->scale)); - const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(32*FRACUNIT, actor->scale)); + const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(xfactor*FRACUNIT, actor->scale)); + const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(zfactor*FRACUNIT, actor->scale)); + const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(yfactor*FRACUNIT, actor->scale)); actor->x = actor->target->x + fc; actor->y = actor->target->y + fs; diff --git a/src/p_inter.c b/src/p_inter.c index b007de030..5f2875252 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -797,17 +797,54 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_NightserizePlayer(player, special->health); // Transform! if (!spec) { - if (toucher->tracer) // Move the ideya over to the drone! + if (toucher->tracer) // Move the Ideya to an anchor! { mobj_t *orbittarget = special->target ? special->target : special; - mobj_t *hnext = orbittarget->hnext; + mobj_t *hnext = orbittarget->hnext, *anchorpoint = NULL, *anchorpoint2 = NULL; + mobj_t *mo2; + thinker_t *th; + + // The player might have two Ideyas: toucher->tracer and toucher->tracer->hnext + // so handle their anchorpoints accordingly. + // scan the thinkers to find the corresponding anchorpoint + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == MT_IDEYAANCHOR) + { + if (mo2->health == toucher->tracer->health) // do ideya numberes match? + anchorpoint = mo2; + else if (toucher->tracer->hnext && mo2->health == toucher->tracer->hnext->health) + anchorpoint2 = mo2; + + if ((!toucher->tracer->hnext && anchorpoint) + || (toucher->tracer->hnext && anchorpoint && anchorpoint2)) + break; + } + } + + if (anchorpoint) + { + toucher->tracer->flags |= MF_GRENADEBOUNCE; // custom radius factors + toucher->tracer->threshold = 8 << 20; // X factor 0, Y factor 0, Z factor 8 + } + + if (anchorpoint2) + { + toucher->tracer->hnext->flags |= MF_GRENADEBOUNCE; // custom radius factors + toucher->tracer->hnext->threshold = 8 << 20; // X factor 0, Y factor 0, Z factor 8 + } P_SetTarget(&orbittarget->hnext, toucher->tracer); if (!orbittarget->hnext->hnext) P_SetTarget(&orbittarget->hnext->hnext, hnext); // Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo. else - P_SetTarget(&orbittarget->hnext->hnext->target, orbittarget); - P_SetTarget(&orbittarget->hnext->target, orbittarget); + P_SetTarget(&orbittarget->hnext->hnext->target, anchorpoint2 ? anchorpoint2 : orbittarget); + P_SetTarget(&orbittarget->hnext->target, anchorpoint ? anchorpoint : orbittarget); P_SetTarget(&toucher->tracer, NULL); if (hnext) @@ -821,7 +858,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { mobj_t *hnext = special->target ? special->target : special; // goalpost while ((hnext = hnext->hnext)) + { + hnext->flags &= ~MF_GRENADEBOUNCE; + hnext->threshold = 0; P_SetTarget(&hnext->target, toucher); + } } return; } diff --git a/src/p_mobj.c b/src/p_mobj.c index f3d3de5ec..7f871064a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10792,6 +10792,9 @@ ML_EFFECT4 : Don't clip inside the ground mobj->health = mthing->angle & 255; mobj->threshold = mthing->angle >> 8; break; + case MT_IDEYAANCHOR: + mobj->health = mthing->extrainfo; + break; case MT_NIGHTSDRONE: { boolean flip = mthing->options & MTF_OBJECTFLIP;