mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
397 lines
10 KiB
C
397 lines
10 KiB
C
// DR. ROBOTNIK'S RING RACERS
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2025 by "Lat'"
|
|
// Copyright (C) 2025 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 wpzturbine.c
|
|
/// \brief Water Palace Zone turbines and associated bubble object. Yep, this is going to suck.
|
|
|
|
#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"
|
|
|
|
// distance to spawn the fan from the center:
|
|
#define TURBINE_RADIUS 128
|
|
|
|
// default distance at which players activate the turbine:
|
|
#define TURBINE_RANGE (2048*FRACUNIT)
|
|
|
|
// default distance at which players spin away from the turbine
|
|
#define TURBINE_SPIN 1536
|
|
|
|
// spawns the hnext visual list for the turbine.
|
|
// whether we use it or not will depend on its flags.
|
|
void Obj_WPZTurbineSpawn(mobj_t *mo)
|
|
{
|
|
mobj_t *ptr = mo;
|
|
UINT8 i;
|
|
|
|
// spawn the visuals regardless of flags, make em invisible.
|
|
// we'll care about updating em if it's worth doing later.
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
mobj_t *vis = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK);
|
|
P_SetMobjState(vis, S_INVISIBLE);
|
|
vis->tics = 4; // if we don't use it just despawn it later.
|
|
|
|
P_SetTarget(&ptr->hnext, vis);
|
|
ptr = vis;
|
|
}
|
|
}
|
|
|
|
// visually update the turbine's hnext visuals if need be.
|
|
static void Obj_WPZTurbineUpdate(mobj_t *mo)
|
|
{
|
|
angle_t ang = (angle_t)mo->extravalue1;
|
|
mapthing_t *mt = mo->spawnpoint;
|
|
|
|
if (!mt)
|
|
return;
|
|
|
|
// fans
|
|
if (!mt->thing_args[1])
|
|
{
|
|
UINT8 i;
|
|
mobj_t *ptr = mo;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
|
|
fixed_t x = mo->x + FixedMul(mapobjectscale, TURBINE_RADIUS*FINECOSINE(ang>>ANGLETOFINESHIFT));
|
|
fixed_t y = mo->y + FixedMul(mapobjectscale, TURBINE_RADIUS*FINESINE(ang>>ANGLETOFINESHIFT));
|
|
|
|
// get the mobj
|
|
if (ptr && !P_MobjWasRemoved(ptr) && ptr->hnext && !P_MobjWasRemoved(ptr->hnext))
|
|
{
|
|
ptr = ptr->hnext;
|
|
P_MoveOrigin(ptr, x, y, mo->z);
|
|
ptr->tics = 4;
|
|
ptr->sprite = SPR_WPWL;
|
|
ptr->frame = 1|FF_PAPERSPRITE;
|
|
P_SetScale(ptr, mapobjectscale*4);
|
|
ptr->destscale = mapobjectscale*4;
|
|
ptr->angle = ang;
|
|
}
|
|
|
|
ang += (360/8)*ANG1;
|
|
}
|
|
}
|
|
|
|
// Not my code, no clue why this doesn't work, John Fucking Madden
|
|
#if 0
|
|
// bubbles if we're underwater
|
|
if (mo->z < mo->watertop && leveltime%10 == 0)
|
|
{
|
|
|
|
INT32 dradius = TURBINE_SPIN;
|
|
INT32 bubbleradius;
|
|
angle_t bubbleang;
|
|
fixed_t bx, by, bz;
|
|
mobj_t *bubble;
|
|
|
|
if (mt->thing_args[7])
|
|
dradius = mt->thing_args[7];
|
|
|
|
bubbleradius = P_RandomRange(PR_BUBBLE, dradius/4, (dradius*3)/2);
|
|
bubbleang = P_RandomRange(PR_BUBBLE, 0, 359)*ANG1;
|
|
|
|
bx = mo->x + FixedMul(mapobjectscale, bubbleradius*FINECOSINE(bubbleang>>ANGLETOFINESHIFT));
|
|
by = mo->y + FixedMul(mapobjectscale, bubbleradius*FINECOSINE(bubbleang>>ANGLETOFINESHIFT));
|
|
bz = R_PointInSubsector(bx, by)->sector->floorheight;
|
|
|
|
bubble = P_SpawnMobj(bx, by, bz, MT_WATERPALACEBUBBLE);
|
|
bubble->fuse = TICRATE*10;
|
|
bubble->angle = bubbleang;
|
|
bubble->movecount = bubbleradius;
|
|
P_SetTarget(&bubble->tracer, mo);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Obj_WPZTurbineThinker(mobj_t *mo)
|
|
{
|
|
|
|
UINT8 i;
|
|
mapthing_t *mt = mo->spawnpoint;
|
|
boolean opt1 = mt->thing_args[0] != 0;
|
|
fixed_t baseheight = (mt->thing_args[2]) ? (mt->thing_args[2]*FRACUNIT) : (mo->z+mapobjectscale*1024);
|
|
fixed_t sneakerheight = (mt->thing_args[3]) ? (mt->thing_args[3]*FRACUNIT) : (mo->z+mapobjectscale*1768);
|
|
fixed_t range = (mt->thing_args[7]) ? (mt->thing_args[7]*FRACUNIT) : (FixedMul(mapobjectscale, TURBINE_RANGE));
|
|
INT32 rotspeed = (mt->thing_args[5]) ? (mt->thing_args[5]*ANG1/10) : (ANG1*3); // not angle_t for negatives.
|
|
tic_t turbinetime = (mt->thing_args[4]) ? (mt->thing_args[4]) : (TICRATE*3);
|
|
SINT8 mult = (opt1) ? (-1) : (1);
|
|
|
|
mo->extravalue1 += rotspeed*mult;
|
|
|
|
// find players in range and take their phones.
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
player_t *p;
|
|
mobj_t *pmo;
|
|
|
|
if (!playeringame[i] || players[i].spectator || K_isPlayerInSpecialState(&players[i]))
|
|
continue;
|
|
|
|
p = &players[i];
|
|
pmo = p->mo;
|
|
|
|
if (R_PointToDist2(pmo->x, pmo->y, mo->x, mo->y) < range
|
|
&& !p->turbine
|
|
&& p->respawn.state == RESPAWNST_NONE)
|
|
{
|
|
P_SetTarget(&pmo->tracer, mo);
|
|
p->turbine = turbinetime;
|
|
|
|
// to be fully honest i dont rememebr what i was on while writing this
|
|
// but it originally went by mo instead of pmo for angle??? how did it ever *work* ?
|
|
p->turbineangle = ANGLE_180 + R_PointToAngle2(0, 0, mo->momx, mo->momy);
|
|
if (!p->speed)
|
|
p->turbineangle = ANGLE_180 + mo->angle;
|
|
|
|
p->turbineangle += ANG1*45*mult;
|
|
|
|
p->turbineheight = baseheight;
|
|
p->turbinespd = false;
|
|
|
|
if (FixedDiv(p->speed, K_GetKartSpeed(p, false, false)) > FRACUNIT*2 // 200% speed
|
|
&& baseheight != sneakerheight)
|
|
{
|
|
p->turbineheight = sneakerheight;
|
|
p->turbinespd = true;
|
|
}
|
|
|
|
pmo->flags |= MF_NOCLIP;
|
|
}
|
|
}
|
|
Obj_WPZTurbineUpdate(mo);
|
|
}
|
|
|
|
// ported from my lua for convenience of not having to rewrite half the shit code.
|
|
static INT32 angtoint(angle_t a)
|
|
{
|
|
return a/ANG1;
|
|
}
|
|
|
|
// controls player while using a turbine.
|
|
// i do not remember what i smoked before writing the lua version of this code.
|
|
// it's a fucking mess what the fuck does half of this even DO
|
|
void Obj_playerWPZTurbine(player_t *p)
|
|
{
|
|
mobj_t *pmo = p->mo;
|
|
mobj_t *t = pmo->tracer;
|
|
mapthing_t *mt;
|
|
boolean opt1;
|
|
fixed_t dist = FixedMul(mapobjectscale, TURBINE_SPIN)*FRACUNIT;
|
|
INT32 speed = ANG1*3;
|
|
boolean mode = false;
|
|
boolean distreached;
|
|
|
|
fixed_t tx, ty, tz;
|
|
fixed_t momz;
|
|
|
|
|
|
if (!t || P_MobjWasRemoved(t) || p->respawn.state != RESPAWNST_NONE)
|
|
{
|
|
p->turbine = false;
|
|
P_SetTarget(&pmo->tracer, NULL);
|
|
return; // wtf happened
|
|
}
|
|
|
|
if (t->type != MT_WATERPALACETURBINE)
|
|
{
|
|
p->turbine = false;
|
|
return;
|
|
}
|
|
|
|
mt = t->spawnpoint;
|
|
|
|
opt1 = (mt->thing_args[0] != 0);
|
|
|
|
if (mt->thing_args[6])
|
|
dist = mt->thing_args[6]*FRACUNIT;
|
|
|
|
if (mt->thing_args[5])
|
|
speed = mt->thing_args[5]*ANG1/10;
|
|
|
|
if (mt->thing_args[9])
|
|
mode = true;
|
|
|
|
distreached = R_PointToDist2(t->x, t->y, pmo->x, pmo->y) <= dist+32*mapobjectscale;
|
|
|
|
if (mode && !distreached)
|
|
p->turbineangle = (INT32)R_PointToAngle2(t->x, t->y, pmo->x, pmo->y);
|
|
|
|
p->spinouttimer = TICRATE;
|
|
pmo->pitch = 0;
|
|
|
|
// determine target x/y/z
|
|
tx = t->x + (dist/FRACUNIT)*FINECOSINE((angle_t)(p->turbineangle)>>ANGLETOFINESHIFT);
|
|
ty = t->y + (dist/FRACUNIT)*FINESINE((angle_t)(p->turbineangle)>>ANGLETOFINESHIFT);
|
|
tz = p->turbineheight;
|
|
|
|
//CONS_Printf("%d %d\n", tx/FRACUNIT, ty/FRACUNIT);
|
|
|
|
if (mode)
|
|
{
|
|
if (distreached)
|
|
{
|
|
P_MoveOrigin(pmo, tx, ty, pmo->z);
|
|
}
|
|
else
|
|
{
|
|
pmo->momx = FixedMul(FINECOSINE((angle_t)(p->turbineangle)>>ANGLETOFINESHIFT), -(max(p->speed, mapobjectscale*32)));
|
|
pmo->momy = FixedMul(FINESINE((angle_t)(p->turbineangle)>>ANGLETOFINESHIFT), -(max(p->speed, mapobjectscale*32)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmo->momx = (tx - pmo->x)/24 * (p->turbinespd ? 2 : 1);
|
|
pmo->momy = (ty - pmo->y)/24 * (p->turbinespd ? 2 : 1);
|
|
}
|
|
|
|
momz = (tz - pmo->z)/128 * (p->turbinespd+1);
|
|
|
|
if (mt->thing_args[8])
|
|
{
|
|
momz = (mt->thing_args[8]*FRACUNIT) * ((tz < pmo->z) ? -1 : 1);
|
|
|
|
if (momz < 0)
|
|
{
|
|
if (pmo->z + momz < tz)
|
|
{
|
|
momz = pmo->z - tz;
|
|
}
|
|
}
|
|
else if (momz > 0)
|
|
{
|
|
if (pmo->z + momz > tz)
|
|
{
|
|
momz = tz - pmo->z;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
pmo->momz = momz;
|
|
p->turbineangle += (speed * (p->turbinespd ? 2 : 1)) * (opt1 ? -1 : 1);
|
|
P_SetPlayerAngle(p, (angle_t)p->turbineangle + ANGLE_90*(opt1 ? -1 : 1));
|
|
|
|
if (pmo->eflags & MFE_UNDERWATER)
|
|
{
|
|
fixed_t rx = pmo->x + P_RandomRange(PR_DECORATION, -64, 64)*mapobjectscale;
|
|
fixed_t ry = pmo->y + P_RandomRange(PR_DECORATION, -64, 64)*mapobjectscale;
|
|
fixed_t rz = pmo->z + P_RandomRange(PR_DECORATION, -64, 64)*mapobjectscale;
|
|
|
|
mobj_t *bubl = P_SpawnMobj(rx, ry, rz, MT_THOK);
|
|
P_SetScale(bubl, pmo->scale*2);
|
|
bubl->scalespeed = pmo->scale/12;
|
|
bubl->destscale = 1;
|
|
bubl->sprite = SPR_BUBL;
|
|
bubl->frame = 0;
|
|
bubl->tics = TICRATE;
|
|
}
|
|
|
|
|
|
if (pmo->momz < mapobjectscale*6)
|
|
{
|
|
INT32 myang = angtoint(pmo->angle);
|
|
angle_t exitangle = t->angle;
|
|
INT32 targetangle = angtoint(exitangle);
|
|
INT32 launchangle = myang-targetangle;
|
|
|
|
// WHAT WAS I SMOKING
|
|
if ( (opt1 && launchangle > -60 && launchangle < -45)
|
|
|| (!opt1 && launchangle > 45 && launchangle < 60))
|
|
{
|
|
|
|
P_SetPlayerAngle(p, targetangle*ANG1);
|
|
|
|
if (mode)
|
|
P_InstaThrust(pmo, targetangle*ANG1, 128*mapobjectscale);
|
|
else
|
|
{
|
|
fixed_t spd = FixedHypot(pmo->momx, pmo->momy);
|
|
P_InstaThrust(pmo, targetangle*ANG1, spd);
|
|
}
|
|
|
|
P_SetTarget(&pmo->tracer, NULL);
|
|
p->turbineheight = 0;
|
|
p->turbineangle = 0;
|
|
|
|
if (p->turbinespd)
|
|
pmo->momz = mapobjectscale*5 * (pmo->eflags & MFE_UNDERWATER ? 2 : 1);
|
|
|
|
if (pmo->eflags & MFE_UNDERWATER)
|
|
{
|
|
pmo->momz = mapobjectscale*5;
|
|
pmo->momx = (pmo->momx*17)/10;
|
|
pmo->momy = (pmo->momy*17)/10;
|
|
}
|
|
|
|
p->spinouttimer = 0;
|
|
pmo->flags &= ~MF_NOCLIP;
|
|
}
|
|
}
|
|
}
|
|
|
|
// bubbles that circle the turbine
|
|
void Obj_WPZBubbleThink(mobj_t *mo)
|
|
{
|
|
angle_t ang = mo->angle - ANGLE_90;
|
|
mobj_t *t = mo->tracer;
|
|
fixed_t tx, ty;
|
|
mapthing_t *mt;
|
|
|
|
// where
|
|
// where did it go
|
|
if (!t || P_MobjWasRemoved(t))
|
|
{
|
|
P_RemoveMobj(mo);
|
|
return;
|
|
}
|
|
|
|
mt = t->spawnpoint;
|
|
if (!mt)
|
|
return;
|
|
|
|
mo->momz = mapobjectscale*16;
|
|
tx = t->x + FixedMul(mapobjectscale, mo->movecount*FINECOSINE(ang>>ANGLETOFINESHIFT));
|
|
ty = t->y + FixedMul(mapobjectscale, mo->movecount*FINESINE(ang>>ANGLETOFINESHIFT));
|
|
|
|
mo->momx = (tx - mo->x)/24;
|
|
mo->momy = (ty - mo->y)/24;
|
|
|
|
if (leveltime & 1)
|
|
{
|
|
fixed_t rx = mo->x + P_RandomRange(PR_DECORATION, -64, 64)*mapobjectscale;
|
|
fixed_t ry = mo->y + P_RandomRange(PR_DECORATION, -64, 64)*mapobjectscale;
|
|
fixed_t rz = mo->z + P_RandomRange(PR_DECORATION, -64, 64)*mapobjectscale;
|
|
mobj_t *bubl = P_SpawnMobj(rx, ry, rz, MT_THOK);
|
|
P_SetScale(bubl, mapobjectscale*4);
|
|
bubl->destscale = 1;
|
|
bubl->sprite = SPR_BUBL;
|
|
bubl->frame = 0;
|
|
bubl->tics = TICRATE;
|
|
}
|
|
|
|
mo->angle += 3*ANG1 * (mt->thing_args[0] ? -1 : 1);
|
|
|
|
if (mo->z > mo->watertop || mo->z > mo->ceilingz)
|
|
P_RemoveMobj(mo);
|
|
}
|