diff --git a/src/deh_tables.c b/src/deh_tables.c index 7fbf62af3..b29e08394 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4791,6 +4791,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_MEGABARRIER1", "S_MEGABARRIER2", "S_MEGABARRIER3", + + "S_GPZ_TREETHING_B", + "S_GPZ_TREETHING_M", + "S_GPZ_TREETHING_S", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -5971,9 +5975,6 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_DLZ_HOVER", "MT_DLZ_ROCKET", - "MT_DLZ_SEASAW_SPAWN", - "MT_DLZ_SEASAW_HITBOX", - "MT_DLZ_SEASAW_VISUAL", "MT_DLZ_RINGVACCUM", "MT_DLZ_SUCKEDRING", @@ -5999,6 +6000,16 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BLENDEYE_PUYO_DUST", "MT_BLENDEYE_PUYO_DUST_COFFEE", "MT_MEGABARRIER", + + "MT_SEASAW_VISUAL", + "MT_DLZ_SEASAW_SPAWN", + "MT_DLZ_SEASAW_HITBOX", + "MT_GPZ_SEASAW_SPAWN", + "MT_GPZ_SEASAW_HITBOX", + + "MT_GPZ_TREETHING_B", + "MT_GPZ_TREETHING_M", + "MT_GPZ_TREETHING_S", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 49ca2f610..74d760f2f 100644 --- a/src/info.c +++ b/src/info.c @@ -968,6 +968,15 @@ char sprnames[NUMSPRITES + 1][5] = "MGSH", // Mega Barrier + // GPZ Seasaw + "GPPS", + "GPZS", + + // Gust Planet Trees + "GPTB", + "GPTM", + "GPTS", + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5619,6 +5628,10 @@ state_t states[NUMSTATES] = {SPR_MGSH, 2|FF_PAPERSPRITE|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MEGABARRIER1, {SPR_MGSH, 1|FF_PAPERSPRITE|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MEGABARRIER2, {SPR_MGSH, 0|FF_PAPERSPRITE|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MEGABARRIER3, + + {SPR_GPTB, 0, -1, {A_SetScale}, 4*FRACUNIT, 0, S_NULL}, // S_GPZ_TREETHING_B, + {SPR_GPTM, 0, -1, {A_SetScale}, 4*FRACUNIT, 0, S_NULL}, // S_GPZ_TREETHING_M, + {SPR_GPTS, 0, -1, {A_SetScale}, 4*FRACUNIT, 0, S_NULL}, // S_GPZ_TREETHING_S, }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -31124,87 +31137,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_DLZ_SEASAW_SPAWN, - 3432, // doomednum - S_INVISIBLE, // spawnstate - 1000, // 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 - 32*FRACUNIT, // radius - 32*FRACUNIT, // height - 0, // display offset - 0, // mass - 0, // damage - sfx_None, // activesound - 0, // flags - S_NULL // raisestate - }, - - { // MT_DLZ_SEASAW_HITBOX, - -1, // doomednum - S_INVISIBLE, // spawnstate - 1000, // 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 - 8*FRACUNIT, // radius - 40*FRACUNIT, // height - 0, // display offset - 0, // mass - 0, // damage - sfx_None, // activesound - MF_SOLID, // flags - S_NULL // raisestate - }, - - { // MT_DLZ_SEASAW_VISUAL, - -1, // doomednum - S_INVISIBLE, // spawnstate - 1000, // 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 - 40*FRACUNIT, // radius - 64*FRACUNIT, // height - 0, // display offset - 0, // mass - 0, // damage - sfx_None, // activesound - MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate - }, - { // MT_DLZ_RINGVACCUM, 3433, // doomednum S_INVISIBLE, // spawnstate @@ -31770,7 +31702,223 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOSQUISH, // flags S_NULL // raisestate - } + }, + + { // MT_SEASAW_VISUAL, + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // 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 + 40*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_DLZ_SEASAW_SPAWN, + 3432, // doomednum + S_INVISIBLE, // spawnstate + 1000, // 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 + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_DLZ_SEASAW_HITBOX, + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // 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 + 8*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_GPZ_SEASAW_SPAWN, + 3435, // doomednum + S_INVISIBLE, // spawnstate + 1000, // 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 + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_GPZ_SEASAW_HITBOX, + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // 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 + 8*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_GPZ_TREETHING_B, + 3436, // doomednum + S_GPZ_TREETHING_B, // spawnstate + 1000, // 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 + 64*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_GPZ_TREETHING_M, + 3437, // doomednum + S_GPZ_TREETHING_M, // spawnstate + 1000, // 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 + 64*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_GPZ_TREETHING_S, + 3438, // doomednum + S_GPZ_TREETHING_M, // spawnstate + 1000, // 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 + 64*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, }; diff --git a/src/info.h b/src/info.h index 90f80efcf..53a9e62fd 100644 --- a/src/info.h +++ b/src/info.h @@ -1522,6 +1522,15 @@ typedef enum sprite SPR_MGSH, // Mega Barrier + // GPZ Seasaw + SPR_GPPS, + SPR_GPZS, + + // Gust Planet Trees + SPR_GPTB, + SPR_GPTM, + SPR_GPTS, + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -6044,6 +6053,10 @@ typedef enum state S_MEGABARRIER2, S_MEGABARRIER3, + S_GPZ_TREETHING_B, + S_GPZ_TREETHING_M, + S_GPZ_TREETHING_S, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -7242,9 +7255,6 @@ typedef enum mobj_type MT_DLZ_HOVER, MT_DLZ_ROCKET, - MT_DLZ_SEASAW_SPAWN, - MT_DLZ_SEASAW_HITBOX, - MT_DLZ_SEASAW_VISUAL, MT_DLZ_RINGVACCUM, MT_DLZ_SUCKEDRING, @@ -7272,6 +7282,16 @@ typedef enum mobj_type MT_MEGABARRIER, + MT_SEASAW_VISUAL, + MT_DLZ_SEASAW_SPAWN, + MT_DLZ_SEASAW_HITBOX, + MT_GPZ_SEASAW_SPAWN, + MT_GPZ_SEASAW_HITBOX, + + MT_GPZ_TREETHING_B, + MT_GPZ_TREETHING_M, + MT_GPZ_TREETHING_S, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_objects.h b/src/k_objects.h index 8a95e414d..a116b96ea 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -261,11 +261,6 @@ void Obj_DLZRocketSpecial(mobj_t *mo, player_t *p); // touch activation void Obj_playerDLZRocket(player_t *p); // player looping thinker void Obj_DLZRocketDismount(player_t *p); // used in p_map.c to get off the rocket when we cross transfer lines. -/* DLZ Seasaw */ -void Obj_DLZSeasawSpawn(mobj_t *mo); -void Obj_DLZSeasawThink(mobj_t *mo); -void Obj_DLZSeasawCollide(mobj_t *mo, mobj_t *mo2); - /* DLZ Hover */ void Obj_DLZHoverSpawn(mobj_t *mo); void Obj_DLZHoverCollide(mobj_t *mo, mobj_t *mo2); @@ -298,6 +293,16 @@ void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source); void Obj_SpawnMegaBarrier(player_t *player); boolean Obj_MegaBarrierThink(mobj_t *mobj); +/* DLZ Seasaw */ +void Obj_DLZSeasawSpawn(mobj_t *mo); +void Obj_DLZSeasawThink(mobj_t *mo); +void Obj_DLZSeasawCollide(mobj_t *mo, mobj_t *mo2); + +/* GPZ Seasaw */ +void Obj_GPZSeasawSpawn(mobj_t *mo); +void Obj_GPZSeasawThink(mobj_t *mo); +void Obj_GPZSeasawCollide(mobj_t *mo, mobj_t *mo2); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 2bd4a38b3..96182b5ea 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -34,6 +34,7 @@ target_sources(SRB2SDL2 PRIVATE eggball.c dlzrocket.c dlzseasaw.c + gpzseasaw.c dlzothers.c wpzturbine.c wpzothers.c diff --git a/src/objects/dlzseasaw.c b/src/objects/dlzseasaw.c index 14550eddb..ede154e13 100644 --- a/src/objects/dlzseasaw.c +++ b/src/objects/dlzseasaw.c @@ -43,7 +43,7 @@ static void Obj_DLZSeasawUpdate(mobj_t *mo, boolean ghostme) if (mo->eflags & MFE_VERTICALFLIP) { mo->tracer->eflags |= MFE_VERTICALFLIP; - mo->tracer->eflags |= MF2_OBJECTFLIP; + mo->tracer->flags2 |= MF2_OBJECTFLIP; } } @@ -151,7 +151,7 @@ void Obj_DLZSeasawSpawn(mobj_t *mo) { // right now we don't care if the objects are positionned properly. - mobj_t *vis = P_SpawnMobj(mo->x, mo->y, mo->z + 8*mapobjectscale*P_MobjFlip(mo), MT_DLZ_SEASAW_VISUAL); + mobj_t *vis = P_SpawnMobj(mo->x, mo->y, mo->z + 8*mapobjectscale*P_MobjFlip(mo), MT_SEASAW_VISUAL); vis->sprite = SPR_DLZS; vis->frame = (j+1)|FF_PAPERSPRITE; vis->tics = -1; diff --git a/src/objects/gpzseasaw.c b/src/objects/gpzseasaw.c new file mode 100644 index 000000000..d20061f08 --- /dev/null +++ b/src/objects/gpzseasaw.c @@ -0,0 +1,355 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2022 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file gpzseasaw.c +/// \brief Gust Planet Zone seasaw. Similar to Dead Line version, but with notable differences. + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../s_sound.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../k_waypoint.h" +#include "../k_respawn.h" +#include "../k_collide.h" + +// updates the seasaw's visuals and hitboxes using the hnext/hprev list. +static void Obj_GPZSeasawUpdate(mobj_t *mo, boolean ghostme) +{ + + mobj_t *ptr = mo; + mobj_t *ptrp = mo; + UINT8 j; + angle_t visan = (angle_t)mo->extravalue1 + ANGLE_90; + + if (mo->tracer && !P_MobjWasRemoved(mo->tracer)) + { + mo->tracer->tics = 3; + P_MoveOrigin(mo->tracer, mo->x, mo->y, mo->z); + P_SetScale(mo->tracer, mo->scale); + + if (mo->eflags & MFE_VERTICALFLIP) + { + mo->tracer->eflags |= MFE_VERTICALFLIP; + mo->tracer->flags2 |= MF2_OBJECTFLIP; + } + + } + + fixed_t cx = mo->x + FixedMul(mo->scale, 96*FINECOSINE(visan>>ANGLETOFINESHIFT)); + fixed_t cy = mo->y + FixedMul(mo->scale, 96*FINESINE(visan>>ANGLETOFINESHIFT)); + + INT32 hdist = 64; // hitbox dist + + angle_t tun_an = visan; + + // visuals + for (j = 0; j < 4; j++) + { + // get our mobj. + if (ptr && !P_MobjWasRemoved(ptr) && ptr->hnext && !P_MobjWasRemoved(ptr->hnext)) + { + tun_an += ANGLE_90; + + fixed_t x = cx + FixedMul(mo->scale, 32*FINECOSINE(tun_an>>ANGLETOFINESHIFT)); + fixed_t y = cy + FixedMul(mo->scale, 32*FINESINE(tun_an>>ANGLETOFINESHIFT)); + ptr = ptr->hnext; + + P_MoveOrigin(ptr, x, y, mo->z + 8*mapobjectscale*P_MobjFlip(mo)); + ptr->angle = tun_an + ANGLE_90; + ptr->tics = 3; + P_SetScale(ptr, 2 * mo->scale); + + if (mo->eflags & MFE_VERTICALFLIP) + { + ptr->eflags |= MFE_VERTICALFLIP; + ptr->flags2 |= MF2_OBJECTFLIP; + } + + if (ghostme && leveltime&1) + { + mobj_t *g = P_SpawnGhostMobj(ptr); + g->colorized = true; + g->color = mo->color; + g->fuse = 3; + } + } + + // get our mobj. + if (ptrp && !P_MobjWasRemoved(ptrp) && ptrp->hprev && !P_MobjWasRemoved(ptrp->hprev)) + { + + fixed_t x = mo->x + FixedMul(mo->scale, hdist*FINECOSINE(visan>>ANGLETOFINESHIFT)); + fixed_t y = mo->y + FixedMul(mo->scale, hdist*FINESINE(visan>>ANGLETOFINESHIFT)); + + ptrp = ptrp->hprev; + + P_SetOrigin(ptrp, x, y, mo->z + 8*mapobjectscale*P_MobjFlip(mo)); // it's invisible so nobody cares about interpolating it. + ptrp->angle = visan; + ptrp->tics = 3; + + + if (mo->eflags & MFE_VERTICALFLIP) + { + ptrp->eflags |= MFE_VERTICALFLIP; + ptrp->flags2 |= MF2_OBJECTFLIP; + } + + hdist += 16; + } + } + + // center thingy + ptr = ptr->hnext; + + P_MoveOrigin(ptr, cx, cy, mo->z + 8*mapobjectscale*P_MobjFlip(mo)); + ptr->angle = visan + ANGLE_90; + ptr->tics = 3; + P_SetScale(ptr, 2 * mo->scale); + + if (mo->eflags & MFE_VERTICALFLIP) + { + ptr->eflags |= MFE_VERTICALFLIP; + ptr->flags2 |= MF2_OBJECTFLIP; + } + + if (ghostme && leveltime&1) + { + mobj_t *g = P_SpawnGhostMobj(ptr); + g->colorized = true; + g->color = mo->color; + g->fuse = 3; + } +} + +// sets up seasaw spawn objects to update each frame later +void Obj_GPZSeasawSpawn(mobj_t *mo) +{ + mobj_t *pole; + mobj_t *ptr = mo; + mobj_t *ptrp = mo; + UINT8 j; + + P_SetScale(mo, 2*mapobjectscale); + mo->destscale = 2*mapobjectscale; + + // setup vars + mo->extravalue1 = (INT32)mo->angle; + + // center pole: + pole = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK); + pole->tics = -1; + pole->sprite = SPR_GPPS; + pole->frame = 0; + P_SetTarget(&pole->target, mo); + P_SetTarget(&mo->tracer, pole); + + if (mo->eflags & MFE_VERTICALFLIP) + pole->eflags |= MFE_VERTICALFLIP; + + int frame_lookup[4] = {0, 3, 1, 3}; // A D B D + // spawn visuals / hitboxes. + for (j = 0; j < 4; j++) // spawn both ends of the "tunnel" and the sides! + { + // right now we don't care if the objects are positionned properly. + + mobj_t *vis = P_SpawnMobj(mo->x, mo->y, mo->z + 8*mapobjectscale*P_MobjFlip(mo), MT_SEASAW_VISUAL); + vis->sprite = SPR_GPZS; + vis->frame = frame_lookup[j]|FF_PAPERSPRITE; + vis->tics = -1; + + if (mo->eflags & MFE_VERTICALFLIP) + { + vis->eflags |= MFE_VERTICALFLIP; + vis->flags2 |= MF2_OBJECTFLIP; + } + + P_SetTarget(&vis->target, mo); + P_SetTarget(&ptr->hnext, vis); // save in an hnext list for updating later. + ptr = vis; + + // --- + + mobj_t *h = P_SpawnMobj(mo->x, mo->y, mo->z + 8*mapobjectscale*P_MobjFlip(mo), MT_GPZ_SEASAW_HITBOX); + h->tics = -1; + + if (mo->eflags & MFE_VERTICALFLIP) + { + h->eflags |= MFE_VERTICALFLIP; + h->flags2 |= MF2_OBJECTFLIP; + } + + P_SetTarget(&h->target, mo); + P_SetTarget(&ptrp->hprev, h); // save in an hprev list for updating later. + ptrp = h; + } + + // finally, spawn the last thingy at the center: + mobj_t *vis = P_SpawnMobj(mo->x, mo->y, mo->z + 8*mapobjectscale*P_MobjFlip(mo), MT_SEASAW_VISUAL); + vis->sprite = SPR_GPZS; + vis->frame = 2|FF_PAPERSPRITE; // C + vis->tics = -1; + + if (mo->eflags & MFE_VERTICALFLIP) + { + vis->eflags |= MFE_VERTICALFLIP; + vis->flags2 |= MF2_OBJECTFLIP; + } + + P_SetTarget(&vis->target, mo); + P_SetTarget(&ptr->hnext, vis); // save in an hnext list for updating later. + ptr = vis; + + // update after spawning the objects so that they appear in the right spot when the map loads. + Obj_GPZSeasawUpdate(mo, false); +} + +static void Obj_GPZSeasawReset(mobj_t *mo) +{ + mo->extravalue1 = (INT32)mo->angle; + P_SetTarget(&mo->target, NULL); + Obj_GPZSeasawUpdate(mo, false); +} + +// main seasaw thinker. +void Obj_GPZSeasawThink(mobj_t *mo) +{ + boolean ghost = false; + SINT8 rot = 1; + fixed_t px, py; + + if (mo->target && !P_MobjWasRemoved(mo->target)) + { + mobj_t *t = mo->target; + player_t *p = t->player; // our target should always be a player, do NOT porceed if it isn't. + + if (!p) // untarget this instantly. + { + Obj_GPZSeasawReset(mo); + return; + } + + if (!mo->extravalue2) + rot = -1; + + INT32 angleadd = ANG1*max(4, (3*mo->movefactor/4)/(mapobjectscale*2)) * rot; + + p->seasawcooldown = TICRATE/2; + + mo->extravalue1 += angleadd; + p->seasawangle += angleadd; + + p->seasawangleadd += max(4, (3*mo->movefactor/4)/(mapobjectscale*2)); + P_SetPlayerAngle(p, (angle_t)(p->seasawangle + ANGLE_90*rot)); + //t->angle = p->seasawangle + ANGLE_90*rot; + + p->seasawdist = (184 * mapobjectscale) / FRACUNIT; + + if (p->seasawangleadd >= 360) // we did a full turn! + { + // reset everything and send the player zooming + Obj_GPZSeasawReset(mo); + + angle_t thrust_angle = mo->threshold ? mo->angle + ANGLE_180 : mo->angle; + P_SetPlayerAngle(p, thrust_angle); + P_MoveOrigin(t, t->x, t->y, t->z); // miscall that to set the position properly. + P_InstaThrust(t, thrust_angle, mo->movefactor*3); // send the player flying at triple the speed they came at us with. + S_StartSound(t, sfx_s3kb6); + + p->seasawangleadd = 0; + p->seasawangle = 0; + p->seasawmoreangle = 0; + p->seasaw = false; + + Obj_GPZSeasawUpdate(mo, true); + return; + } + // update the player + px = mo->x + p->seasawdist*FINECOSINE((angle_t)p->seasawangle>>ANGLETOFINESHIFT); + py = mo->y + p->seasawdist*FINESINE((angle_t)p->seasawangle>>ANGLETOFINESHIFT); + + P_MoveOrigin(t, px, py, mo->z + mapobjectscale*8); + } + else + Obj_GPZSeasawReset(mo); + + // finally, update the visuals. + Obj_GPZSeasawUpdate(mo, ghost); +} + +// ported just for convenience of not needing to rewrite the code to account for UINT32 angles... +// the precision loss hardly matters whatsoever. +static INT32 angtoint(angle_t a) +{ + return a/ANG1; +} + +// to use in mobjcollide and movemobjcollide just like the lua, woo. +// mo is the player's mo, mo2 is the seasaw hitbox. +void Obj_GPZSeasawCollide(mobj_t *mo, mobj_t *mo2) +{ + player_t *p = mo->player; + INT32 momangle; + + // cooldown / respawning + if (p->seasawcooldown || p->respawn.timer) + return; + + // other wacko state that'd do very weird shit if we overwrote it. + if (K_isPlayerInSpecialState(p)) + return; + + // another player is already using the seasar + if (mo2->target && !P_MobjWasRemoved(mo2->target) && mo2->target->target && !P_MobjWasRemoved(mo2->target->target)) + return; + + // height checks + if (mo->z + mo->height < mo2->z) + return; + + if (mo->z > mo2->z + mo2->height) + return; + + // too slow. + if (p->speed < K_GetKartSpeed(p, false, false)/3) + return; + + + momangle = angtoint(R_PointToAngle2(0, 0, mo->momx, mo->momy)); + + //CONS_Printf("%d / %d -> %d\n", momangle, angtoint(mo2->target->angle), (abs(((momangle - angtoint(mo2->target->angle) +180) % 360) - 180))); + + int side = mo2->target->spawnpoint && (mo2->target->spawnpoint->options & 1); + + // this depends on the side we hit the thing from. + mo2->target->threshold = (abs(((momangle - angtoint(mo2->target->angle) +180) % 360) - 180) > 60); + + mo2->target->movefactor = p->speed; // keep the speed the player was going at. + mo2->target->extravalue2 = side ^ mo2->target->threshold; // which side of the pole are we on? + + P_SetTarget(&mo2->target->target, mo); + mo2->target->cvmem = 0; + + // set player vars now: + p->seasawdist = (128 * mapobjectscale) / FRACUNIT; + p->seasawangle = mo2->target->angle + (side ? ANGLE_270 : ANGLE_90); + p->seasawangleadd = 0; + p->seasawdir = false; + p->seasaw = true; + p->pflags |= PF_STASIS; + p->seasawcooldown = TICRATE/2; + + S_StartSound(mo, sfx_s3k3c); +} diff --git a/src/p_map.c b/src/p_map.c index 5e68afc21..954aca720 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -724,6 +724,14 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; } + if (thing->type == MT_GPZ_SEASAW_HITBOX) + { + if (tm.thing->type == MT_PLAYER) + Obj_GPZSeasawCollide(tm.thing, thing); // all checks are performed in there. + + return BMIT_CONTINUE; + } + if (thing->type == MT_DLZ_HOVER) { if (tm.thing->type == MT_PLAYER) diff --git a/src/p_mobj.c b/src/p_mobj.c index 990758b8b..4b156a7c6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10137,10 +10137,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; - case MT_DLZ_SEASAW_SPAWN: - Obj_DLZSeasawThink(mobj); - break; - case MT_DLZ_SUCKEDRING: Obj_DLZSuckedRingThink(mobj); if (P_MobjWasRemoved(mobj)) @@ -10177,6 +10173,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; + case MT_DLZ_SEASAW_SPAWN: + Obj_DLZSeasawThink(mobj); + break; + + case MT_GPZ_SEASAW_SPAWN: + Obj_GPZSeasawThink(mobj); + break; + case MT_BALLSWITCH_BALL: { Obj_BallSwitchThink(mobj); @@ -11635,9 +11639,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_RIDEROIDNODE: Obj_RideroidNodeSpawn(mobj); break; - case MT_DLZ_SEASAW_SPAWN: - Obj_DLZSeasawSpawn(mobj); - break; case MT_DLZ_HOVER: Obj_DLZHoverSpawn(mobj); break; @@ -11674,6 +11675,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BLENDEYE_PUYO_DUST: mobj->sprite = mobj->movedir = P_RandomRange(PR_DECORATION, SPR_PUYA, SPR_PUYE); break; + case MT_DLZ_SEASAW_SPAWN: + Obj_DLZSeasawSpawn(mobj); + break; + case MT_GPZ_SEASAW_SPAWN: + Obj_GPZSeasawSpawn(mobj); + break; default: break; }