Merge branch 'rideroid-hardcode' into 'master'

Lat Hardcode

See merge request KartKrew/Kart!1515
This commit is contained in:
Oni 2023-10-08 21:22:18 +00:00
commit c72a2cf94a
29 changed files with 3101 additions and 10 deletions

View file

@ -723,6 +723,50 @@ struct player_t
SINT8 glanceDir; // Direction the player is trying to look backwards in
//////////////
// rideroid //
//////////////
boolean rideroid; // on rideroid y/n
boolean rdnodepull; // being pulled by rideroid node. mo target is set to the node while this is true.
INT32 rideroidangle; // angle the rideroid is going at. This doesn't change once we're on it. INT32 because the code was originally written in lua and fuckshit happens with angle_t.
fixed_t rideroidspeed; // speed the rideroid is to be moving at.
INT32 rideroidrollangle; // rollangle while turning
fixed_t rdaddmomx; // some speed variables to smoothe things out without fighting with the regular momentum system.
fixed_t rdaddmomy;
fixed_t rdaddmomz;
////////////
// bungee //
////////////
UINT8 bungee; // constants are defined with the object file for the bungee.
////////////////////
// dead line zone //
////////////////////
// hovers
tic_t lasthover; // used for the hover mobjs
// rockets
tic_t dlzrocket; // counts up as we stay on a rocket.
angle_t dlzrocketangle; // current travel angle with the rocket.
INT32 dlzrocketanglev; // current vertical travel angle with the rocket. signed instead of angle_t.
fixed_t dlzrocketspd; // current rocket travel speed.
// seasaws (variables are shared with other seasaw-like objects)
boolean seasaw; // true if using a seasaw
tic_t seasawcooldown; // cooldown to avoid triggering the same seasaw over and over
fixed_t seasawdist; // distance from the center of the seasaw when latched.
INT32 seasawangle; // angle from the center of the seasaw when latched.
INT32 seasawangleadd; // used to spin the seasaw
INT32 seasawmoreangle; // used for reverse sesaws in DLZ.
boolean seasawdir; // flips or not seasaw rotation
// water palace turbines (or cnz barrels, or whatever the hell people use it for nowadays)
tic_t turbine; // ticker (while true, we set the tracer to the turbine)
INT32 turbineangle; // angle around the turbine. ...Made in INT32 to make it easier to translate from lua
fixed_t turbineheight; // height around the turbine
boolean turbinespd; // if true, we used a sneaker and get the altpath.
//
SINT8 lives;

View file

@ -4684,6 +4684,20 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_CHECKPOINT_SPARK10",
"S_CHECKPOINT_SPARK11",
"S_RIDEROID",
"S_RIDEROID_ICON",
"S_EGGBALL",
"S_DLZHOVER",
"S_DLZROCKET_L",
"S_DLZROCKET_R",
"S_WPZFOUNTAIN",
"S_WPZFOUNTAINANIM",
"S_KURAGEN",
"S_KURAGENBOMB",
"S_BALLSWITCH_BALL",
"S_BALLSWITCH_BALL_ACTIVE",
"S_BALLSWITCH_PAD",
@ -5845,6 +5859,27 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_CHECKPOINT_END",
"MT_SCRIPT_THING",
"MT_RIDEROID",
"MT_RIDEROIDNODE",
"MT_LSZ_BUNGEE",
"MT_LSZ_EGGBALLSPAWNER",
"MT_LSZ_EGGBALL",
"MT_DLZ_HOVER",
"MT_DLZ_ROCKET",
"MT_DLZ_SEASAW_SPAWN",
"MT_DLZ_SEASAW_HITBOX",
"MT_DLZ_SEASAW_VISUAL",
"MT_DLZ_RINGVACCUM",
"MT_DLZ_SUCKEDRING",
"MT_WATERPALACETURBINE",
"MT_WATERPALACEBUBBLE",
"MT_WATERPALACEFOUNTAIN",
"MT_KURAGEN",
"MT_KURAGENBOMB",
"MT_BALLSWITCH_BALL",
"MT_BALLSWITCH_PAD",
};

View file

@ -896,6 +896,26 @@ char sprnames[NUMSPRITES + 1][5] =
"CPT2", // Checkpoint Stick
"CPT3", // Checkpoint Base
// rideroid (see info.h for detail)
"RDRD",
"RDRA",
"RDRC",
"RDRL",
// leaf storm egg ball.
"LSZB",
// Dead Line Zone
"DLZH",
"DLZR",
"DLZS",
"DLZA",
// Water Palace Zone
"WPWL", // turbine
"WPZF", // fountain
"WPZK", // klagen
"SA2S", // SA2-style Ball Switch
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
@ -5435,6 +5455,25 @@ state_t states[NUMSTATES] =
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK11}, // S_CHECKPOINT_SPARK10
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK1}, // S_CHECKPOINT_SPARK11
// Las Vegas
{SPR_RDRD, 0, -1, {NULL}, 0, 0, S_RIDEROID}, // S_RIDEROID
{SPR_RDRC, FF_ANIMATE|FF_FULLBRIGHT|FF_TRANS30, -1, {NULL}, 3, 2, S_RIDEROID_ICON}, // S_RIDEROID_ICON
// Leaf Storm
{SPR_LSZB, 0, -1, {NULL}, 0, 0, S_EGGBALL}, // S_EGGBALL
// Dead Line
{SPR_DLZH, 0, -1, {NULL}, 0, 0, S_DLZHOVER}, // S_DLZHOVER
{SPR_DLZR, 0, -1, {NULL}, 0, 0, S_DLZROCKET_L}, // S_DLZROCKET_L
{SPR_DLZR, 1, -1, {NULL}, 0, 0, S_DLZROCKET_R}, // S_DLZROCKET_R
// Water Palace
{SPR_WPZF, 0, -1, {NULL}, 0, 0, S_WPZFOUNTAIN}, // S_WPZFOUNTAIN
{SPR_WPZF, 1|FF_ANIMATE, -1, {NULL}, 3, 2, S_WPZFOUNTAINANIM}, // S_WPZFOUNTAINANIM
{SPR_WPZK, FF_ANIMATE, -1, {NULL}, 3, 12, S_KURAGEN}, // S_KURAGEN
{SPR_WPZK, 4, -1, {NULL}, 0, 0, S_KURAGENBOMB}, // S_KURAGENBOMB
{SPR_SA2S, FF_SEMIBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_BALL
{SPR_SA2S, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM|4, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_BALL_ACTIVE
{SPR_SA2S, FF_FLOORSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_PAD
@ -30458,6 +30497,465 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_RIDEROID
-1, // doomednum
S_RIDEROID, // 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
30*FRACUNIT, // radius
40*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_RIDEROIDNODE
3711, // doomednum
S_RIDEROID_ICON, // 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
80*FRACUNIT, // radius
80*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP, // flags
S_NULL // raisestate
},
{ // MT_LSZ_BUNGEE
3440, // 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
127*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_LSZ_EGGBALLSPAWNER
3443, // 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
8*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_LSZ_EGGBALL
-1, // doomednum
S_EGGBALL, // 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
64*FRACUNIT, // height
0, // display offset
DMG_TUMBLE, // mass
0, // damage
sfx_None, // activesound
MF_PAIN, // flags
S_NULL // raisestate
},
{ // MT_DLZ_HOVER,
3430, // doomednum
S_DLZHOVER, // 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
100*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SOLID, // flags
S_NULL // raisestate
},
{ // MT_DLZ_ROCKET,
3431, // 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
100*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // 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_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
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
96*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_SOLID, // flags
S_NULL // raisestate
},
{ // MT_DLZ_SUCKEDRING,
-1, // doomednum
S_RING, // 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
MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_WATERPALACETURBINE
3400, // 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
MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
S_NULL // raisestate
},
{ // MT_WATERPALACEBUBBLE
-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
32*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP, // flags
S_NULL // raisestate
},
{ // MT_WATERPALACEFOUNTAIN
3401, // doomednum
S_WPZFOUNTAIN, // 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
16*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_SOLID, // flags
S_NULL // raisestate
},
{ // MT_KURAGEN
3402, // doomednum
S_KURAGEN, // 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
64*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_KURAGENBOMB
-1, // doomednum
S_KURAGENBOMB, // 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
64*FRACUNIT, // height
0, // display offset
0, // mass
DMG_EXPLODE, // damage
sfx_None, // activesound
MF_PAIN, // flags
S_NULL // raisestate
},
{ // MT_BALLSWITCH_BALL
5000, // doomednum
S_BALLSWITCH_BALL, // spawnstate
@ -30513,6 +31011,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
},
};
skincolor_t skincolors[MAXSKINCOLORS] = {
{"Default", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_NONE

View file

@ -1243,7 +1243,7 @@ typedef enum sprite
SPR_ARK3,
SPR_ARK4,
SPR_ARK5,
SPR_BUMP, // Player/shell bump
SPR_FLEN, // Shell hit graphics stuff
@ -1452,6 +1452,22 @@ typedef enum sprite
SPR_CPT2, // Checkpoint Stick
SPR_CPT3, // Checkpoint Base
SPR_RDRD, // rideroid
SPR_RDRA, // rideroid node sprites
SPR_RDRC,
SPR_RDRL,
SPR_LSZB, // eggman ball.
SPR_DLZH, // DLZ Hover
SPR_DLZR, // DLZ Rocket
SPR_DLZS, // DLZ Seasaw
SPR_DLZA, // Helper arrows for rocket
SPR_WPWL, // turbine
SPR_WPZF, // fountain
SPR_WPZK, // klagen
SPR_SA2S, // SA2-style Ball Switch
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
@ -5864,6 +5880,24 @@ typedef enum state
S_CHECKPOINT_SPARK10,
S_CHECKPOINT_SPARK11,
// rideroid
S_RIDEROID,
S_RIDEROID_ICON,
// leaf storm
S_EGGBALL,
// dead line zone
S_DLZHOVER,
S_DLZROCKET_L,
S_DLZROCKET_R,
// water palace zone
S_WPZFOUNTAIN,
S_WPZFOUNTAINANIM,
S_KURAGEN,
S_KURAGENBOMB,
S_BALLSWITCH_BALL,
S_BALLSWITCH_BALL_ACTIVE,
S_BALLSWITCH_PAD,
@ -7044,6 +7078,27 @@ typedef enum mobj_type
MT_CHECKPOINT_END,
MT_SCRIPT_THING,
MT_RIDEROID,
MT_RIDEROIDNODE,
MT_LSZ_BUNGEE,
MT_LSZ_EGGBALLSPAWNER,
MT_LSZ_EGGBALL,
MT_DLZ_HOVER,
MT_DLZ_ROCKET,
MT_DLZ_SEASAW_SPAWN,
MT_DLZ_SEASAW_HITBOX,
MT_DLZ_SEASAW_VISUAL,
MT_DLZ_RINGVACCUM,
MT_DLZ_SUCKEDRING,
MT_WATERPALACETURBINE,
MT_WATERPALACEBUBBLE,
MT_WATERPALACEFOUNTAIN,
MT_KURAGEN,
MT_KURAGENBOMB,
MT_BALLSWITCH_BALL,
MT_BALLSWITCH_PAD,

View file

@ -57,6 +57,19 @@
// comeback is Battle Mode's karma comeback, also bool
// mapreset is set when enough players fill an empty server
// lat: used for when the player is in some weird state where it wouldn't be wise for it to be overwritten by another object that does similarly wacky shit.
boolean K_isPlayerInSpecialState(player_t *p)
{
return (
p->rideroid
|| p->rdnodepull
|| p->bungee
|| p->dlzrocket
|| p->seasaw
|| p->turbine
);
}
boolean K_IsDuelItem(mobjtype_t type)
{
switch (type)
@ -8305,7 +8318,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->incontrol = 0;
player->incontrol++;
}
player->incontrol = min(player->incontrol, 5*TICRATE);
player->incontrol = max(player->incontrol, -5*TICRATE);
@ -11898,7 +11911,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
K_KartDrift(player, onground);
K_KartSpindash(player);
if (onground == false)
if (onground == false
&& !player->bungee // if this list of condition ever gets bigger, maybe this should become a function.
)
{
K_AirFailsafe(player);
}
@ -11908,6 +11923,23 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
}
Obj_RingShooterInput(player);
if (player->bungee)
Obj_playerBungeeThink(player);
if (player->dlzrocket)
Obj_playerDLZRocket(player);
if (player->seasawcooldown && !player->seasaw)
player->seasawcooldown--;
if (player->turbine)
{
if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer))
Obj_playerWPZTurbine(player);
else
player->turbine--; // acts as a cooldown
}
}
void K_CheckSpectateStatus(boolean considermapreset)

View file

@ -229,6 +229,9 @@ UINT32 K_PointLimitForGametype(void);
boolean K_Cooperative(void);
// lat: used for when the player is in some weird state where it wouldn't be wise for it to be overwritten by another object that does similarly wacky shit.
boolean K_isPlayerInSpecialState(player_t *p);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -233,12 +233,60 @@ boolean Obj_GetCheckpointRespawnPosition(const mobj_t *checkpoint, vector3_t *re
angle_t Obj_GetCheckpointRespawnAngle(const mobj_t *checkpoint);
void Obj_ActivateCheckpointInstantly(mobj_t* mobj);
/* Rideroid / Rideroid Node */
void Obj_RideroidThink(mobj_t *mo);
void Obj_RideroidNodeSpawn(mobj_t *mo);
void Obj_RideroidNodeThink(mobj_t *mo);
void Obj_getPlayerOffRideroid(mobj_t *mo); // used in p_map.c to get off of em when passing transfer lines.
/* LSZ Bungee */
void Obj_BungeeSpecial(mobj_t *mo, player_t *p); // used when the player touches the bungee, to be used in p_inter.c
void Obj_playerBungeeThink(player_t *p); // player interaction with the bungee. The bungee is to be stored in p->mo->tracer.
/* LSZ Balls */
void Obj_EggBallSpawnerThink(mobj_t *mo);
void Obj_EggBallThink(mobj_t *mo);
/* DLZ Rockets */
void Obj_DLZRocketThink(mobj_t *mo);
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);
/* DLZ Ring Vaccum */
void Obj_DLZRingVaccumSpawn(mobj_t *mo);
void Obj_DLZRingVaccumCollide(mobj_t *mo, mobj_t *mo2);
void Obj_DLZSuckedRingThink(mobj_t *mo);
/* WPZ Turbine */
void Obj_WPZTurbineSpawn(mobj_t *mo);
void Obj_WPZTurbineThinker(mobj_t *mo);
void Obj_playerWPZTurbine(player_t *p);
void Obj_WPZBubbleThink(mobj_t *mo);
/* WPZ Fountains */
void Obj_WPZFountainThink(mobj_t *mo);
/* WPZ Kuragens */
void Obj_WPZKuragenThink(mobj_t *mo);
void Obj_WPZKuragenBombThink(mobj_t *mo);
/* Ball Switch */
void Obj_BallSwitchInit(mobj_t *mobj);
void Obj_BallSwitchThink(mobj_t *mobj);
void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher);
void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -465,6 +465,69 @@ static int player_get(lua_State *L)
else if (fastcmp(field,"follower"))
LUA_PushUserdata(L, plr->follower, META_MOBJ);
//
// rideroids
else if (fastcmp(field,"rideroid"))
lua_pushboolean(L, plr->rideroid);
else if (fastcmp(field,"rdnodepull"))
lua_pushboolean(L, plr->rdnodepull);
else if (fastcmp(field,"rideroidangle"))
lua_pushinteger(L, plr->rideroidangle);
else if (fastcmp(field,"rideroidspeed"))
lua_pushinteger(L, plr->rideroidspeed);
else if (fastcmp(field,"rideroidrollangle"))
lua_pushinteger(L, plr->rideroidrollangle);
else if (fastcmp(field,"rdaddmomx"))
lua_pushinteger(L, plr->rdaddmomx);
else if (fastcmp(field,"rdaddmomy"))
lua_pushinteger(L, plr->rdaddmomy);
else if (fastcmp(field,"rdaddmomz"))
lua_pushinteger(L, plr->rdaddmomz);
// bungee
else if (fastcmp(field,"bungee"))
lua_pushinteger(L, plr->bungee);
// dlz hover
else if (fastcmp(field,"lasthover"))
lua_pushinteger(L, plr->lasthover);
// dlz rocket
else if (fastcmp(field,"dlzrocket"))
lua_pushinteger(L, plr->dlzrocket);
else if (fastcmp(field,"dlzrocketangle"))
lua_pushinteger(L, plr->dlzrocketangle);
else if (fastcmp(field,"dlzrocketanglev"))
lua_pushinteger(L, plr->dlzrocketanglev);
else if (fastcmp(field,"dlzrocketspd"))
lua_pushinteger(L, plr->dlzrocketspd);
// seasaws
else if (fastcmp(field,"seasaw"))
lua_pushboolean(L, plr->seasaw);
else if (fastcmp(field,"seasawcooldown"))
lua_pushinteger(L, plr->seasawcooldown);
else if (fastcmp(field,"seasawdist"))
lua_pushinteger(L, plr->seasawdist);
else if (fastcmp(field,"seasawangle"))
lua_pushinteger(L, plr->seasawangle);
else if (fastcmp(field,"seasawangleadd"))
lua_pushinteger(L, plr->seasawangleadd);
else if (fastcmp(field,"seasawmoreangle"))
lua_pushinteger(L, plr->seasawmoreangle);
else if (fastcmp(field,"seasawdir"))
lua_pushboolean(L, plr->seasawdir);
// turbine
else if (fastcmp(field,"turbine"))
lua_pushinteger(L, plr->turbine);
else if (fastcmp(field,"turbineangle"))
lua_pushinteger(L, plr->turbineangle);
else if (fastcmp(field,"turbineheight"))
lua_pushinteger(L, plr->turbineheight);
else if (fastcmp(field,"turbinespd"))
lua_pushinteger(L, plr->turbinespd);
else if (fastcmp(field,"charflags"))
lua_pushinteger(L, plr->charflags);
else if (fastcmp(field,"followitem"))
@ -860,6 +923,70 @@ static int player_set(lua_State *L)
plr->followerready = luaL_checkboolean(L, 3);
else if (fastcmp(field,"follower")) // it's probably best we don't allow the follower mobj to change.
return NOSET;
// time to add to the endless elseif list!!!!
// rideroids
else if (fastcmp(field,"rideroid"))
plr->rideroid = luaL_checkboolean(L, 3);
else if (fastcmp(field,"rdnodepull"))
plr->rdnodepull = luaL_checkboolean(L, 3);
else if (fastcmp(field,"rideroidangle"))
plr->rideroidangle = luaL_checkinteger(L, 3);
else if (fastcmp(field,"rideroidspeed"))
plr->rideroidspeed = luaL_checkinteger(L, 3);
else if (fastcmp(field,"rideroidrollangle"))
plr->rideroidrollangle = luaL_checkinteger(L, 3);
else if (fastcmp(field,"rdaddmomx"))
plr->rdaddmomx = luaL_checkfixed(L, 3);
else if (fastcmp(field,"rdaddmomy"))
plr->rdaddmomy = luaL_checkfixed(L, 3);
else if (fastcmp(field,"rdaddmomz"))
plr->rdaddmomz = luaL_checkfixed(L, 3);
// bungee
else if (fastcmp(field,"bungee"))
plr->bungee = luaL_checkinteger(L, 3);
// dlz hover
else if (fastcmp(field,"lasthover"))
plr->lasthover = luaL_checkinteger(L, 3);
// dlz rocket
else if (fastcmp(field,"dlzrocket"))
plr->dlzrocket = luaL_checkinteger(L, 3);
else if (fastcmp(field,"dlzrocketangle"))
plr->dlzrocketangle = luaL_checkinteger(L, 3);
else if (fastcmp(field,"dlzrocketanglev"))
plr->dlzrocketanglev = luaL_checkinteger(L, 3);
else if (fastcmp(field,"dlzrocketspd"))
plr->dlzrocketspd = luaL_checkfixed(L, 3);
// seasaws
else if (fastcmp(field,"seasaw"))
plr->seasaw = luaL_checkboolean(L, 3);
else if (fastcmp(field,"seasawcooldown"))
plr->seasawcooldown = luaL_checkinteger(L, 3);
else if (fastcmp(field,"seasawdist"))
plr->seasawdist = luaL_checkfixed(L, 3);
else if (fastcmp(field,"seasawangle"))
plr->seasawangle = luaL_checkinteger(L, 3);
else if (fastcmp(field,"seasawangleadd"))
plr->seasawangleadd = luaL_checkinteger(L, 3);
else if (fastcmp(field,"seasawmoreangle"))
plr->seasawmoreangle = luaL_checkinteger(L, 3);
else if (fastcmp(field,"seasawdir"))
plr->seasawdir = luaL_checkboolean(L, 3);
// turbines
else if (fastcmp(field,"turbine"))
plr->turbine = luaL_checkinteger(L, 3);
else if (fastcmp(field,"turbineangle"))
plr->turbineangle = luaL_checkinteger(L, 3);
else if (fastcmp(field,"turbineheight"))
plr->turbineheight = luaL_checkfixed(L, 3);
else if (fastcmp(field,"turbinespd"))
plr->turbinespd = luaL_checkinteger(L, 3);
//
else if (fastcmp(field,"charflags"))
plr->charflags = (UINT32)luaL_checkinteger(L, 3);

View file

@ -73,6 +73,7 @@ typedef enum
PR_SPARKLE, // Endsign and/or Emerald
PR_MOVINGTARGET, // Randomised moving targets
PR_TRACKHAZARD, // Randomised track hazards
PR_BATTLEUFO, // Battle UFO spawning

View file

@ -29,6 +29,14 @@ target_sources(SRB2SDL2 PRIVATE
sneaker-panel.c
emerald.c
checkpoint.cpp
rideroid.c
bungee.c
eggball.c
dlzrocket.c
dlzseasaw.c
dlzothers.c
wpzturbine.c
wpzothers.c
shadow.cpp
ball-switch.cpp
)

119
src/objects/bungee.c Normal file
View file

@ -0,0 +1,119 @@
// 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 bungee.c
/// \brief Leaf Storm bungee interaction/behaviour code to be used in other files.
#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"
#define BUNGEE_NONE 0
#define BUNGEE_LATCH 1
#define BUNGEE_LAUNCH 2
// Touching the bungee, used in p_inter.c
void Obj_BungeeSpecial(mobj_t *mo, player_t *p)
{
mobj_t *latch;
if (P_IsObjectOnGround(p->mo) || p->springstars || K_isPlayerInSpecialState(p))
return;
P_InstaThrust(p->mo, 0, 0);
p->bungee = BUNGEE_LATCH;
p->mo->flags |= MF_NOCLIPTHING; // prevent players from bumping if they latch onto the same bungee.
p->pflags |= PF_NOFASTFALL; // didn't know this flag existed but it's very convenient!!
latch = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_THOK);
P_SetMobjState(latch, S_INVISIBLE);
latch->angle = mo->angle;
S_StartSound(mo, sfx_s3k5a);
P_SetTarget(&p->mo->tracer, latch);
}
// this is the thinker to call on the player when they get bungee'd.
void Obj_playerBungeeThink(player_t *p)
{
mobj_t *bungee = p->mo->tracer;
UINT8 i;
// someone removed it
if (!bungee || P_MobjWasRemoved(bungee))
return;
bungee->tics = 4; // we set this to a low value so that it despawns if the player vanishes for some reason.
if (p->bungee == BUNGEE_LATCH)
{
// rr has super high gravity which gets in the way.
p->mo->flags |= MF_NOGRAVITY;
p->mo->momz = (p->mo->momz*9)/10;
if (abs(p->mo->momz) < 6*mapobjectscale)
{
p->bungee = BUNGEE_LAUNCH;
p->mo->momz = P_MobjFlip(p->mo)*mapobjectscale;
S_StartSound(p->mo, sfx_s3k81);
}
}
else if (p->bungee == BUNGEE_LAUNCH)
{
p->mo->momz = (p->mo->momz*12)/10;
// if we go above/below (depending on our flip flags) the bungee, release us!
if ((p->mo->eflags & MFE_VERTICALFLIP && p->mo->z < bungee->z)
|| (!(p->mo->eflags & MFE_VERTICALFLIP) && p->mo->z > bungee->z ))
{
p->mo->flags &= ~MF_NOGRAVITY;
p->mo->flags &= ~MF_NOCLIPTHING;
p->pflags &= ~PF_NOFASTFALL;
p->bungee = BUNGEE_NONE;
P_InstaThrust(p->mo, bungee->angle, p->mo->momz/8);
p->mo->momz = (p->mo->momz*3)/4;
p->springstars = TICRATE; // these are used as a buffer not to latch to vines again.
p->springcolor = SKINCOLOR_EMERALD;
P_RemoveMobj(bungee);
P_SetTarget(&p->mo->tracer, NULL);
return;
}
}
// basic visuals (but hey they work fine enough!)
for (i=0; i<8; i++)
{
fixed_t xpos = -(bungee->x - p->mo->x) /8 *i;
fixed_t ypos = -(bungee->y - p->mo->y) /8 *i;
fixed_t zpos = -(bungee->z - p->mo->z) /8 *i;
mobj_t *seg = P_SpawnMobj(bungee->x + xpos, bungee->y + ypos, bungee->z + zpos, MT_THOK);
P_SetScale(seg, mapobjectscale/3);
seg->color = SKINCOLOR_EMERALD;
seg->frame = 0;
seg->fuse = 2;
}
}

133
src/objects/dlzothers.c Normal file
View file

@ -0,0 +1,133 @@
// 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 dlzothers.c
/// \brief Dead Line Zone other objects (Hover + Ring Vaccum), they're small enough that we can just lump em together instead of having 2 more small files...
#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"
// Hover:
void Obj_DLZHoverSpawn(mobj_t *mo)
{
P_SetScale(mo, mapobjectscale*4);
mo->destscale = mapobjectscale*4;
}
// collision between MT_PLAYER and hover
void Obj_DLZHoverCollide(mobj_t *mo, mobj_t *mo2)
{
player_t *p = mo->player;
if (!p || p->lasthover == leveltime)
return;
if (abs(mo->z - mo2->z) < 512*mapobjectscale)
{
// momz adjust
if (mo2->eflags & MFE_VERTICALFLIP)
{
if (mo->momz > -16*mapobjectscale)
{
mo->momz -= 8*mapobjectscale;
}
}
else
{
if (mo->momz < 16*mapobjectscale)
{
mo->momz += 8*mapobjectscale;
}
}
// speed adjust
if (p->speed > K_GetKartSpeed(p, false, false))
P_Thrust(mo, R_PointToAngle2(0, 0, -mo->momx, -mo->momy), mapobjectscale/16);
if (!S_SoundPlaying(mo, sfx_s3kc6s))
S_StartSound(mo, sfx_s3kc6s);
p->lasthover = leveltime;
}
}
// Ring Vaccum:
void Obj_DLZRingVaccumSpawn(mobj_t *mo)
{
P_SetScale(mo, mapobjectscale*4);
mo->destscale = mapobjectscale*4;
}
// collision between MT_FLINGRING and ring vaccum
void Obj_DLZRingVaccumCollide(mobj_t *mo, mobj_t *mo2)
{
mobj_t *fake;
if (mo->z + mo->height < mo2->z)
return;
if (mo->z > mo2->z + mo2->height)
return;
if (!P_IsObjectOnGround(mo) || mo->momz)
return;
fake = P_SpawnMobj(mo->x, mo->y, mo->z, MT_DLZ_SUCKEDRING);
P_SetScale(fake, mo->scale);
fake->scalespeed = mapobjectscale/64;
fake->destscale = 1;
P_SetTarget(&fake->target, mo2);
fake->angle = R_PointToAngle2(mo2->x, mo2->y, fake->x, fake->y);
fake->movefactor = R_PointToDist2(mo2->x, mo2->y, fake->x, fake->y);
P_RemoveMobj(mo);
}
void Obj_DLZSuckedRingThink(mobj_t *mo)
{
mobj_t *t = mo->target;
fixed_t x, y;
// commit die if the target disappears for some fucking reason
if (!t || P_MobjWasRemoved(t))
{
P_RemoveMobj(mo);
return;
}
x = t->x + FixedMul(mo->movefactor, FINECOSINE(mo->angle>>ANGLETOFINESHIFT));
y = t->y + FixedMul(mo->movefactor, FINESINE(mo->angle>>ANGLETOFINESHIFT));
P_MoveOrigin(mo, x, y, mo->z);
if (mo->cusval < 24)
mo->cusval++;
mo->angle += mo->cusval*ANG1;
if (mo->cusval > 8 && mo->movefactor)
mo->movefactor -= 1;
if (mo->scale < mapobjectscale/12)
P_RemoveMobj(mo);
}

201
src/objects/dlzrocket.c Normal file
View file

@ -0,0 +1,201 @@
// 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 dlzrocket.c
/// \brief Dead Line Zone free flight rockets! They cool af doe.
#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"
#include "../k_color.h"
#define DLZROCKETDIST 96
#define DLZROCKETSPEED 80
#define DLZROCKETTURNSPEED ((ANG1*3)/2)
#define DLZROCKETVERTSPEED (ANG1)
#define DLZROCKETMAXVERT (ANG1*60)
void Obj_DLZRocketThink(mobj_t *mo)
{
UINT8 i;
angle_t an = mo->angle + ANGLE_90;
if (mo->extravalue1)
return;
for (i = 0; i < 2; i++)
{
fixed_t x = mo->x + FixedMul(mapobjectscale, DLZROCKETDIST*FINECOSINE(an>>ANGLETOFINESHIFT));
fixed_t y = mo->y + FixedMul(mapobjectscale, DLZROCKETDIST*FINESINE(an>>ANGLETOFINESHIFT));
mobj_t *r = P_SpawnMobj(x, y, mo->z, MT_THOK);
P_SetMobjState(r, i ? S_DLZROCKET_L : S_DLZROCKET_R);
P_SetScale(r, (mapobjectscale*3)/2);
r->destscale = (mapobjectscale*3)/2;
r->angle = mo->spawnpoint->angle*ANG1;
r->tics = -1;
an += ANGLE_180;
}
mo->extravalue1 = 1;
}
void Obj_DLZRocketDismount(player_t *p)
{
// we aren't mounted on one.
if (!p->dlzrocket)
return;
p->dlzrocket = 0;
K_SpawnMineExplosion(p->mo, p->mo->color, 3);
S_StartSound(p->mo, sfx_s3k4e);
}
// touching the rocket, initialize player vars etc...
void Obj_DLZRocketSpecial(mobj_t *mo, player_t *p)
{
if (K_isPlayerInSpecialState(p)) // already on one, don't bother resetting, duh.
return;
p->mo->z = mo->z + 16*P_MobjFlip(p->mo)*mapobjectscale;
P_SetPlayerAngle(p->mo->player, mo->angle);
p->dlzrocket = true;
p->dlzrocketangle = mo->angle;
p->dlzrocketanglev = 0;
p->dlzrocketspd = DLZROCKETSPEED;
p->spinouttimer = 0;
p->wipeoutslow = 0;
S_StartSound(mo, sfx_s262);
}
void Obj_playerDLZRocket(player_t *p)
{
fixed_t maxspd = DLZROCKETSPEED;
angle_t visangle;
UINT8 i, j;
p->dlzrocket++;
// helper arrows at the start of the ride to tell players they can move freely
if (p->dlzrocket < TICRATE*2
&& leveltime%10 < 5)
{
mobj_t *arr = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_THOK);
arr->sprite = SPR_DLZA;
arr->frame = FF_FULLBRIGHT;
P_SetScale(arr, 2*mapobjectscale);
arr->tics = 2;
}
// calc max speed
if (p->ringboost)
maxspd += 10;
if (p->startboost)
maxspd += 30;
// set player speed
if (p->dlzrocketspd < maxspd)
p->dlzrocketspd++;
else if (p->dlzrocketspd > maxspd)
p->dlzrocket--;
// so long as PF_STASIS is applied, let the angle be overwritten freely.
// this is used by seasaws but can be used for misc modding purposes too.
if (p->pflags & PF_STASIS)
p->dlzrocketangle = p->mo->angle;
else
{
SINT8 turndir = 0;
P_SetPlayerAngle(p->mo->player, p->dlzrocketangle);
if (p->cmd.turning > 0)
turndir = 1;
else if (p->cmd.turning < 0)
turndir = -1;
p->dlzrocketangle += turndir*DLZROCKETTURNSPEED;
if (p->cmd.throwdir > 0)
p->dlzrocketanglev = min(DLZROCKETMAXVERT, p->dlzrocketanglev + DLZROCKETVERTSPEED);
else if (p->cmd.throwdir < 0)
p->dlzrocketanglev = max(-DLZROCKETMAXVERT, p->dlzrocketanglev - DLZROCKETVERTSPEED);
}
// angle correction on ceilings (THIS CODE LOOKS AWFUL AND IT CAN PROBABLY BE DONE BETTER......)
if ( (!(p->mo->eflags & MFE_VERTICALFLIP) && (p->mo->z+p->mo->height >= p->mo->ceilingz))
|| (p->mo->eflags & MFE_VERTICALFLIP && p->mo->z <= p->mo->floorz))
if ( (!(p->mo->eflags & MFE_VERTICALFLIP) && p->dlzrocketanglev > 0)
|| (p->mo->eflags & MFE_VERTICALFLIP && p->dlzrocketanglev < 0))
p->dlzrocketanglev = 0;
if (!(p->pflags & PF_STASIS))
{
angle_t van = p->dlzrocketanglev /4;
P_InstaThrust(p->mo, p->dlzrocketangle, FixedMul(mapobjectscale, p->dlzrocketspd*FINECOSINE(van>>ANGLETOFINESHIFT)));
p->mo->momz = FixedMul(mapobjectscale, p->dlzrocketspd*FINESINE((angle_t)p->dlzrocketanglev>>ANGLETOFINESHIFT));
}
if (leveltime%4 == 0)
S_StartSound(p->mo, sfx_s1c8);
// finally, visuals.
visangle = p->mo->angle + ANGLE_90;
for (i = 0; i < 2; i++)
{
fixed_t x = p->mo->x + FixedMul(mapobjectscale, 56*FINECOSINE(visangle>>ANGLETOFINESHIFT));
fixed_t y = p->mo->y + FixedMul(mapobjectscale, 56*FINESINE(visangle>>ANGLETOFINESHIFT));
mobj_t *r = P_SpawnMobj(x, y, p->mo->z + 16*mapobjectscale, MT_THOK);
r->fuse = 2;
P_SetMobjState(r, i ? S_DLZROCKET_L : S_DLZROCKET_R);
P_SetScale(r, (mapobjectscale*3)/2);
r->angle = p->mo->angle;
for (j = 0; j < 2; j++)
{
fixed_t xoffs = P_RandomRange(PR_EXPLOSION, -6, 6)*mapobjectscale;
fixed_t yoffs = P_RandomRange(PR_EXPLOSION, -6, 6)*mapobjectscale;
fixed_t soffs = P_RandomRange(PR_EXPLOSION, 0, 3);
mobj_t *expl = P_SpawnMobj(r->x + xoffs, r->y + yoffs, r->z + xoffs, MT_THOK);
P_SetMobjState(expl, S_QUICKBOOM1+soffs);
expl->color = p->mo->color;
P_SetScale(expl, mapobjectscale);
expl->destscale = 2*mapobjectscale;
if (p->startboost)
expl->color = K_RainbowColor(leveltime);
}
visangle += ANGLE_180;
}
if ((p->dlzrocket > 10 && (P_IsObjectOnGround(p->mo) || p->mo->eflags & MFE_JUSTBOUNCEDWALL))
|| p->spinouttimer || p->wipeoutslow || p->tumbleHeight)
Obj_DLZRocketDismount(p);
}

365
src/objects/dlzseasaw.c Normal file
View file

@ -0,0 +1,365 @@
// 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 dlzseasaw.c
/// \brief Dead Line Zone seasaw. Amplifies momentum in a stylish way... and hellish as far as code is concerned, heh!
#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_DLZSeasawUpdate(mobj_t *mo, boolean ghostme)
{
mobj_t *ptr = mo;
mobj_t *ptrp = mo;
UINT8 i, 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->eflags |= MF2_OBJECTFLIP;
}
}
for (i = 0; i < 2; i++)
{
INT32 dist = 32; // visuals dist
INT32 hdist = 16; // hitbox dist
// visuals
for (j = 0; j < 2; j++)
{
// get our mobj.
if (ptr && !P_MobjWasRemoved(ptr) && ptr->hnext && !P_MobjWasRemoved(ptr->hnext))
{
fixed_t x = mo->x + FixedMul(mo->scale, dist*FINECOSINE(visan>>ANGLETOFINESHIFT));
fixed_t y = mo->y + FixedMul(mo->scale, dist*FINESINE(visan>>ANGLETOFINESHIFT));
ptr = ptr->hnext;
P_MoveOrigin(ptr, x, y, mo->z + 8*mapobjectscale*P_MobjFlip(mo));
ptr->angle = visan;
ptr->tics = 3;
P_SetScale(ptr, 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;
}
dist += 55;
}
}
// hitboxes:
for (j = 0; j < 8; j++)
{
// 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;
}
}
visan += ANGLE_180;
}
}
// sets up seasaw spawn objects to update each frame later
void Obj_DLZSeasawSpawn(mobj_t *mo)
{
mobj_t *pole;
mobj_t *ptr = mo;
mobj_t *ptrp = mo;
UINT8 i, 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_DLZS;
pole->frame = 0;
P_SetTarget(&pole->target, mo);
P_SetTarget(&mo->tracer, pole);
if (mo->eflags & MFE_VERTICALFLIP)
pole->eflags |= MFE_VERTICALFLIP;
// spawn visuals / hitboxes.
for (i = 0; i < 2; i++) // for each side...
{
for (j = 0; j < 2; j++) // spawn the 2 visual papersprites on each side.
{
// 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);
vis->sprite = SPR_DLZS;
vis->frame = (j+1)|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;
}
for (j = 0; j < 8; j++) // spawn the 8 hitboxes on each side.
{
// right now we don't care if the objects are positionned properly.
mobj_t *h = P_SpawnMobj(mo->x, mo->y, mo->z + 8*mapobjectscale*P_MobjFlip(mo), MT_DLZ_SEASAW_HITBOX);
h->extravalue1 = i; // keep track of which side we're on.
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;
}
}
// update after spawning the objects so that they appear in the right spot when the map loads.
Obj_DLZSeasawUpdate(mo, false);
}
static void Obj_DLZSeasawReset(mobj_t *mo)
{
mo->extravalue1 = (INT32)mo->angle;
P_SetTarget(&mo->target, NULL);
Obj_DLZSeasawUpdate(mo, false);
}
// main seasaw thinker.
void Obj_DLZSeasawThink(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_DLZSeasawReset(mo);
return;
}
if (!mo->extravalue2)
rot = -1;
// first half of the animation...
if (!p->seasawdir)
{
INT32 angleadd = ANG1*max(4, (mo->movefactor/3)/mapobjectscale) * rot;
if (p->seasawangleadd > 175)
angleadd /= max(1, (p->seasawangleadd - 160)/8);
mo->extravalue1 += angleadd;
p->seasawangle += angleadd;
p->seasawangleadd += max(4, (mo->movefactor/3)/mapobjectscale);
P_SetPlayerAngle(p, (angle_t)(p->seasawangle + ANGLE_90*rot));
//t->angle = p->seasawangle + ANGLE_90*rot;
p->seasawdist++;
p->seasawdist = min(p->seasawdist, (160*mapobjectscale)/FRACUNIT);
if (abs((angleadd)/ANG1 ) < 2) // if we get to 1, invert the rotation!
{
p->seasawdir = true;
p->seasawangleadd = 0; // reset, we're gonna do a full 360!
p->seasawmoreangle = p->seasawangleadd - 170;
S_StartSound(t, sfx_s3k88);
S_StartSound(t, sfx_s3ka2);
}
}
else
{
INT32 angleadd = (mo->cvmem*2 +1)*(-rot);
mo->cvmem++;
p->seasawangleadd += abs(angleadd)/2; // for some reason i need to do this and i'm actually not sure why.
mo->extravalue1 += angleadd*ANG1;
p->seasawangle += angleadd*ANG1;
P_SetPlayerAngle(p, (angle_t)(p->seasawangle - ANGLE_90*rot));
ghost = true;
if (p->seasawangleadd >= 340 + p->seasawmoreangle)
{
// reset everything and send the player zooming
Obj_DLZSeasawReset(mo);
P_SetPlayerAngle(p, mo->angle);
P_MoveOrigin(t, t->x, t->y, t->z); // miscall that to set the position properly.
P_InstaThrust(t, mo->angle, mo->movefactor*3); // send the player flying at triple the speed they came at us with.
S_StartSound(t, sfx_cdfm62);
p->seasawangleadd = 0;
p->seasawangle = 0;
p->seasawmoreangle = 0;
p->seasaw = false;
Obj_DLZSeasawUpdate(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_DLZSeasawReset(mo);
// finally, update the visuals.
Obj_DLZSeasawUpdate(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_DLZSeasawCollide(mobj_t *mo, mobj_t *mo2)
{
player_t *p = mo->player;
INT32 momangle;
boolean invert = false;
// 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)));
// this depends on the side we hit the thing from.
if (abs(((momangle - angtoint(mo2->target->angle) +180) % 360) - 180) > 60)
{
mo2->target->angle += ANGLE_180;
mo2->target->extravalue1 += ANGLE_180;
invert = true;
}
mo2->target->movefactor = p->speed; // keep the speed the player was going at.
mo2->target->extravalue2 = mo2->extravalue1; // which side of the pole are we on?
// if inverted, then invert the value too.
if (invert)
mo2->target->extravalue2 = (!mo2->target->extravalue2) ? 1 : 0;
P_SetTarget(&mo2->target->target, mo);
mo2->target->cvmem = 0;
// set player vars now:
p->seasawdist = R_PointToDist2(mo->x, mo->y, mo2->target->x, mo2->target->y) /FRACUNIT; // distance from us to the center
p->seasawangle = (INT32)R_PointToAngle2(mo2->target->x, mo2->target->y, mo->x, mo->y); // angle from the center to us
p->seasawangleadd = 0;
p->seasawdir = false;
p->seasaw = true;
p->pflags |= PF_STASIS;
p->seasawcooldown = TICRATE/2;
S_StartSound(mo, sfx_s3k88);
}

136
src/objects/eggball.c Normal file
View file

@ -0,0 +1,136 @@
// 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 eggball.c
/// \brief Leaf Storm giant Eggman Balls. And their spawner. Yes, that sounds horribly wrong. No, I'm not changing it.
#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"
#define BALLMINSPAWNTIME 3
#define BALLMAXSPAWNTIME 5
// spawns balls every BALLMINSPAWNTIME to BALLMAXSPAWNTIME seconds.
void Obj_EggBallSpawnerThink(mobj_t *mo)
{
if (!mo->extravalue1)
{
mobj_t *ball = P_SpawnMobj(mo->x, mo->y, mo->z, MT_LSZ_EGGBALL);
if (P_MobjWasRemoved(ball) == false)
{
ball->angle = mo->angle;
P_SetScale(ball, (ball->destscale = 6*mapobjectscale));
}
mo->extravalue1 = P_RandomRange(PR_TRACKHAZARD, TICRATE*BALLMINSPAWNTIME, TICRATE*BALLMAXSPAWNTIME);
}
mo->extravalue1--;
}
// ball thinker, it's mostly for particles and some bouncing n stuff to make em fancy.
// vars:
// threshold -> prevmomz
// movedir -> prevz
void Obj_EggBallThink(mobj_t *mo)
{
const boolean onground = P_IsObjectOnGround(mo);
if (mo->eflags & MFE_JUSTHITFLOOR)
{
if (mo->extravalue1 && P_CheckDeathPitCollide(mo))
{
P_RemoveMobj(mo);
return;
}
if (mo->threshold && mo->threshold < -10*mapobjectscale)
{
UINT8 i;
mo->momz = (fixed_t)(-mo->threshold)/8;
for (i=0; i<16; i++)
{
angle_t an = ANG1;
mobj_t *dust = P_SpawnMobj(mo->x, mo->y, mo->z, MT_DRIFTDUST);
P_SetScale(dust, mapobjectscale*3);
P_InstaThrust(dust, (360/16)*an*i, mapobjectscale*24); // the angle thing is to avoid a warning due to overflows.
dust->momz = P_RandomRange(PR_DECORATION, 0, 7)*mapobjectscale;
}
S_StartSound(mo, sfx_s3k59);
P_StartQuakeFromMobj(FRACUNIT*20, 6, 512 * mapobjectscale, mo);
}
}
if (!mo->extravalue1)
{
if (onground)
{
mo->extravalue1 = 1;
mo->cusval = 24*mapobjectscale;
mo->movedir = mo->z;
}
}
else
{
if (onground && (mo->extravalue2 & 1))
{
fixed_t dx = mo->x + P_RandomRange(PR_DECORATION, -96, 96)*mapobjectscale - mo->momx*2;
fixed_t dy = mo->y + P_RandomRange(PR_DECORATION, -96, 96)*mapobjectscale - mo->momy*2;
fixed_t dz = mo->z;
mobj_t *dust = P_SpawnMobj(dx, dy, dz, MT_DRIFTDUST);
P_SetScale(dust, mapobjectscale*3);
dust->momz = P_RandomRange(PR_DECORATION, 0, 7)*mapobjectscale;
dust->destscale = mapobjectscale*8;
}
P_InstaThrust(mo, mo->angle, mo->cusval);
mo->extravalue2 += 1;
mo->frame = mo->extravalue2 % (24 * 2) / 2; // 24 is for frame Y.
// build up speed
if (onground)
{
if (mo->eflags & MFE_VERTICALFLIP)
{
if (mo->z > (fixed_t)mo->movedir)
{
mo->cusval += max(mapobjectscale/32, abs(mo->z - (fixed_t)mo->movedir)/16);
}
}
else
{
if (mo->z < (fixed_t)mo->movedir)
{
mo->cusval += max(mapobjectscale/32, abs(mo->z - (fixed_t)mo->movedir)/16);
}
}
}
mo->movedir = mo->z;
}
mo->threshold = mo->momz;
}

577
src/objects/rideroid.c Normal file
View file

@ -0,0 +1,577 @@
// 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 rideroid.c
/// \brief Rideroid / Rideroid Node object code. This also has the player behaviour code to be used in k_kart.
#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"
#include "../k_color.h"
#define NODERADIUS 260
#define NODEPULLOK 48
#define NODEROTSPEED ANG1
#define RIDEROIDSPEED 80
#define RIDEROIDMAXADD 8
// static functions that only really get used here...
static void plr_undoRespawn(player_t *p)
{
p->respawn.state = 0;
p->respawn.timer = 0;
}
static void plr_resetRideroidVars(player_t *p)
{
p->rdnodepull = false;
p->rideroid = false;
p->rideroidangle = 0;
p->rideroidspeed = 0;
p->rideroidrollangle = 0;
p->rdaddmomx = 0;
p->rdaddmomy = 0;
p->rdaddmomz = 0;
P_SetTarget(&p->mo->tracer, NULL);
}
// kills the rideroid and removes it from the map.
static void Obj_killRideroid(mobj_t *mo)
{
UINT8 i;
for (i = 0; i < 32; i++)
{
mobj_t *t = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK);
t->color = SKINCOLOR_TEAL;
t->frame = FF_FULLBRIGHT;
t->destscale = 1;
t->momx = P_RandomRange(PR_EXPLOSION, -32, 32)*mapobjectscale;
t->momy = P_RandomRange(PR_EXPLOSION, -32, 32)*mapobjectscale;
t->momz = P_RandomRange(PR_EXPLOSION, -32, 32)*mapobjectscale;
}
P_RemoveMobj(mo);
}
// makes the player get off of the rideroid.
void Obj_getPlayerOffRideroid(mobj_t *mo)
{
mobj_t *pmo = mo->target;
if (pmo && !P_MobjWasRemoved(pmo))
{
player_t *p = pmo->player;
pmo->flags &= ~MF_NOGRAVITY;
if (p)
plr_resetRideroidVars(p);
mo->fuse = TICRATE/2;
mo->momx = mo->momx*2;
mo->momy = mo->momy*2;
mo->momz = 0;
mo->target = NULL;
S_StartSound(mo, sfx_ridr4);
}
}
// this assumes mo->target and mo->target->player is valid.
// if it's not, uuuh well too bad.
static void Obj_explodeRideroid(mobj_t *mo)
{
mobj_t *pmo = mo->target;
Obj_getPlayerOffRideroid(mo);
K_SpawnMineExplosion(pmo, pmo->color, 3);
S_StartSound(pmo, sfx_s3k4e);
Obj_killRideroid(mo);
// @TODO: quake.
}
// used to create a smooth trail.
static fixed_t Obj_rideroidLerp(INT32 start, INT32 finish, INT32 percent)
{
return start + FixedMul(finish-start, FRACUNIT-percent);
}
static void Obj_rideroidTrail(mobj_t *mo)
{
mobj_t *pmo = mo->target;
player_t *p = NULL;
UINT8 i, j;
angle_t h_an = mo->angle + ANG1*90;
if (pmo && !P_MobjWasRemoved(pmo))
{
p = pmo->player; // used to make some graphics local to save on framerate
mo->color = pmo->color;
mo->colorized = pmo->colorized;
}
// from here, we will use the following:
// extravalue1: prev x
// extravalue2: prev y
// cusval: prev z
// cvmem: prev roll angle
for (j = 0; j < 9; j++)
{
for (i = 0; i < 2; i++)
{
INT32 percent = FRACUNIT * (10-j)/10;
angle_t roll = (angle_t)Obj_rideroidLerp((angle_t)mo->cvmem, mo->rollangle, percent);
fixed_t x = (fixed_t)Obj_rideroidLerp((fixed_t)mo->extravalue1, mo->x, percent);
fixed_t y = (fixed_t)Obj_rideroidLerp((fixed_t)mo->extravalue2, mo->y, percent);
fixed_t z = (fixed_t)Obj_rideroidLerp((fixed_t)mo->cusval, mo->z, percent);
angle_t v_an = i ? (roll+ANG1*90) : (roll-ANG1*90);
fixed_t pos = FixedMul(mo->scale, FINESINE(v_an>>ANGLETOFINESHIFT)*60);
fixed_t tx = x+FixedMul(FINECOSINE(h_an>>ANGLETOFINESHIFT), pos);
fixed_t ty = y+FixedMul(FINESINE(h_an>>ANGLETOFINESHIFT), pos);
fixed_t tz = z+FixedMul(FINECOSINE(v_an>>ANGLETOFINESHIFT)*60, mo->scale);
mobj_t *t = P_SpawnMobj(tx, ty, tz, MT_THOK);
t->color = SKINCOLOR_TEAL;
t->frame = FF_FULLBRIGHT|FF_TRANS50;
// 120 is no magic number, the base scale speed is mapobjectscale/12
P_SetScale(t, max(1, mapobjectscale*5/6 - ((10-j)*mapobjectscale/120)));
t->destscale = 1;
if (p)
{
if (j)
t->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(p));
if (p->startboost)
t->color = K_RainbowColor(leveltime);
}
}
}
mo->extravalue1 = (INT32)mo->x;
mo->extravalue2 = (INT32)mo->y;
mo->cusval = (INT32)mo->z;
mo->cvmem = (INT32)mo->rollangle;
}
static void Obj_updateRideroidPos(mobj_t *mo)
{
mobj_t *pmo = mo->target;
fixed_t x = pmo->x + 2*FINECOSINE(pmo->angle>>ANGLETOFINESHIFT);
fixed_t y = pmo->y + 2*FINESINE(pmo->angle>>ANGLETOFINESHIFT);
P_MoveOrigin(mo, x, y, pmo->z - 10*mapobjectscale);
mo->momx = pmo->momx;
mo->momy = pmo->momy;
mo->momz = pmo->momz;
Obj_rideroidTrail(mo);
}
// handles the rideroid and the player attached to it.
void Obj_RideroidThink(mobj_t *mo)
{
player_t *p;
mobj_t *pmo = mo->target;
fixed_t basemomx;
fixed_t basemomy;
fixed_t xthreshold;
fixed_t ythreshold;
// speed values...
fixed_t maxspd = RIDEROIDSPEED*mapobjectscale;
if (!pmo || P_MobjWasRemoved(pmo))
{
if (!mo->fuse)
{
mo->fuse = TICRATE/2;
}
else if (mo->fuse == 1)
{
Obj_killRideroid(mo);
}
else
{
Obj_rideroidTrail(mo);
mo->rollangle += ANG1*24;
}
return;
}
// if we're here, our player should still exist which is kinda crazy!
p = pmo->player;
// pulling towards the node, AKA towards where the rideroid is, which just so happens to be us right now.
if (p->rdnodepull)
{
pmo->momx = (mo->x - pmo->x)/6;
pmo->momy = (mo->y - pmo->y)/6;
pmo->momz = (mo->z - pmo->z)/6;
//CONS_Printf("%d\n", R_PointToDist2(mo->x, mo->y, pmo->x, pmo->y)/FRACUNIT);
if (R_PointToDist2(mo->x, mo->y, pmo->x, pmo->y) < NODEPULLOK*mapobjectscale)
{
p->rideroid = true;
p->rdnodepull = false;
S_StartSound(pmo, sfx_ridr2);
}
return;
}
// if we're here, we made it to the rideroid and we can use it, or something like that!
P_SetTarget(&p->mo->tracer, mo); // keep a reference of the rideroid in the player for convenience.
// calculate the maximum speed we can move at.
// the values are a little arbitrary but they work for how little use these have.
if (p->ringboost)
maxspd = (maxspd*12)/10; // Ring Boost: 120% max speed.
if (p->draftpower)
{
UINT8 draftperc = (p->draftpower*100 / FRACUNIT); // 0-100%
maxspd += (draftperc/5) / 100;
}
if (p->startboost)
maxspd = (maxspd*15)/10; // 150% speed
// increase speed as we go unless we're turning harshly.
if (p->rideroidspeed*mapobjectscale < maxspd)
{
if (abs(p->cmd.turning < 400))
p->rideroidspeed += (p->ringboost ? 2 : 1); // acceleration is also higher with a ring boost.
}
else
p->rideroidspeed -= 1;
// sounds
mo->movecount++; // we use this as a timer for sounds and whatnot.
if (mo->movecount == 1 || !(mo->movecount%TICRATE))
S_StartSound(mo, sfx_ridr3);
// aaaaand the actual gameplay and shit... wooooo
pmo->angle = mo->angle;
pmo->flags |= MF_NOGRAVITY;
// do not let the player touch the ground
// @TODO: check all 4 corners of the player and use P_GetZAt to account for slopes if pmo->standslope isn't NULL.
// right now it's not important as LV doesn't mix rdr and slopes but if somehow i manage to pull through w this shit it'll need to be done
if (pmo->eflags & MFE_VERTICALFLIP)
{
fixed_t minz = pmo->ceilingz - 2*mapobjectscale;
if (pmo->z > minz)
pmo->z = minz;
}
else
{
fixed_t minz = pmo->floorz + 2*mapobjectscale;
if (pmo->z < minz)
pmo->z = minz;
}
// if we hit a wall or get hit, get off of the rideroid.
if (pmo->eflags & MFE_JUSTBOUNCEDWALL || P_PlayerInPain(p))
{
Obj_explodeRideroid(mo);
return;
}
// now actual movement:
// first, do the movement for this frame
P_InstaThrust(pmo, (angle_t)p->rideroidangle, p->rideroidspeed*mapobjectscale);
basemomx = p->mo->momx;
basemomy = p->mo->momy;
pmo->momx += p->rdaddmomx;
pmo->momy += p->rdaddmomy;
pmo->momz += p->rdaddmomz;
pmo->angle = (angle_t)p->rideroidangle;
p->drawangle = (angle_t)p->rideroidangle;
P_SetPlayerAngle(pmo->player, (angle_t)p->rideroidangle);
pmo->rollangle = p->rideroidrollangle;
mo->rollangle = p->rideroidrollangle;
pmo->pitch = 0;
// update the rideroid object (me) to be below the target player
Obj_updateRideroidPos(mo);
// turning left/right
if (p->cmd.turning)
{
fixed_t savemomx = pmo->momx;
fixed_t savemomy = pmo->momy;
SINT8 dir = 0;
INT32 a;
if (p->cmd.turning < -400)
{
a = (INT32)(mo->angle) - ANG1*90;
P_Thrust(pmo, mo->angle - ANGLE_90, 2*mapobjectscale);
p->rideroidrollangle -= ANG1*3;
if (p->rideroidrollangle < -ANG1*25)
p->rideroidrollangle = -ANG1*25;
dir = 1;
}
else if (p->cmd.turning > 400)
{
a = (INT32)(mo->angle) + ANG1*90;
P_Thrust(pmo, mo->angle + ANGLE_90, 2*mapobjectscale);
p->rideroidrollangle += ANG1*3;
if (p->rideroidrollangle > ANG1*25)
p->rideroidrollangle = ANG1*25;
dir = -1;
}
if (dir != 0 && leveltime & 1 && p->rideroidspeed > RIDEROIDSPEED/2)
{
p->rideroidspeed -= 1;
}
if (dir != 0)
{
// save the added momentum
p->rdaddmomx = pmo->momx - basemomx;
p->rdaddmomy = pmo->momy - basemomy;
//CONS_Printf("AX1: %d, AY1: %d\n", p->rdaddmomx/mapobjectscale, p->rdaddmomy/mapobjectscale);
pmo->momx = basemomx;
pmo->momy = basemomy;
/*CONS_Printf("CURR: %d, %d\n", pmo->momx/mapobjectscale, pmo->momy/mapobjectscale);
CONS_Printf("BASE: %d, %d\n", basemomx/mapobjectscale, basemomy/mapobjectscale);
CONS_Printf("ADD: %d, %d\n", p->rdaddmomx/mapobjectscale, p->rdaddmomy/mapobjectscale);*/
// find out how much addmomx and addmomy we can actually get.
// we do this by misusing P_Thrust to calc our values then immediately cancelling it.
basemomx = pmo->momx;
basemomy = pmo->momy;
a = (INT32)(mo->angle) - dir*ANG1*90;
P_Thrust(pmo, (angle_t)a, RIDEROIDMAXADD*3*mapobjectscale);
xthreshold = pmo->momx - basemomx;
ythreshold = pmo->momy - basemomy;
//CONS_Printf("XT: %d (%d), YT: %d (%d)\n", xthreshold/mapobjectscale, abs(xthreshold/mapobjectscale), ythreshold/mapobjectscale, abs(ythreshold/mapobjectscale));
// clamp the momentums using the calculated thresholds.
// the fixedmul check checks if both numbers are of the same sign.
if (abs(p->rdaddmomx) > abs(xthreshold))
p->rdaddmomx = xthreshold;
if (abs(p->rdaddmomy) > abs(ythreshold))
p->rdaddmomy = ythreshold;
//CONS_Printf("AX2: %d, AY2: %d\n", p->rdaddmomx/mapobjectscale, p->rdaddmomy/mapobjectscale);
// now cancel it.
pmo->momx = savemomx;
pmo->momy = savemomy;
//CONS_Printf("NEWCURR: %d, %d\n", pmo->momx/mapobjectscale, pmo->momy/mapobjectscale);
}
}
else // not turning
{
// for some reason doing *= 9/10 causes it to get set to 0 instantly? so it's done like this.
p->rdaddmomx = (p->rdaddmomx*9)/10;
p->rdaddmomy = (p->rdaddmomy*9)/10;
p->rideroidrollangle /= 2;
}
// and now, going up/down
if (p->cmd.throwdir > 0)
{
// if we were going the opposite direction, this helps us change our height very easily.
if (p->rdaddmomz < 0)
p->rdaddmomz /= 2;
p->rdaddmomz = min(RIDEROIDMAXADD*mapobjectscale/7, p->rdaddmomz + mapobjectscale/16);
if (p->rideroidspeed > RIDEROIDSPEED/2
&& abs(p->cmd.turning) > 400
&& leveltime & 1)
p->rideroidspeed -= 1;
}
else if (p->cmd.throwdir < 0)
{
// if we were going the opposite direction, this helps us change our height very easily.
if (p->rdaddmomz > 0)
p->rdaddmomz /= 2;
p->rdaddmomz = max(-RIDEROIDMAXADD*mapobjectscale/7, p->rdaddmomz - mapobjectscale/16);
if (p->rideroidspeed > RIDEROIDSPEED/2
&& abs(p->cmd.turning) > 400
&& leveltime & 1)
p->rideroidspeed -= 1;
}
else
p->rdaddmomz = (p->rdaddmomz*6)/10;
}
// transposed lua code.
// the lua used to continuously P_SpawnMobj the letters which was fine for the intended use case in the original LV iteration.
// however the LV remake spams a lot of these rideroid nodes close to each other which created a huge overhead whether or not they were being displayed.
// so now it's more optimized and only spawns things once.
void Obj_RideroidNodeSpawn(mobj_t *mo)
{
fixed_t radius = NODERADIUS*mapobjectscale; // radius for the text to rotate at.
mobj_t *ptr = mo;
UINT8 i;
UINT8 j;
// make it bigger.
P_SetScale(mo, mo->scale*3);
// spawn the letter things.
for (i = 0; i < 2; i++)
{
angle_t ang = mo->angle + (i)*180;
fixed_t zpos = mo->z + 64*mapobjectscale + mapobjectscale*96*i;
ang *= ANG1; // this has to be done here or the warning prevents the compile, we don't care about overflowing here.
for (j = 0; j < 7; j++)
{
fixed_t xpos = mo->x + FixedMul(radius, FINECOSINE(ang>>ANGLETOFINESHIFT));
fixed_t ypos = mo->y + FixedMul(radius, FINESINE(ang>>ANGLETOFINESHIFT));
mobj_t *let = P_SpawnMobj(xpos, ypos, zpos, MT_THOK);
let->sprite = SPR_RDRL;
let->frame = j|FF_FULLBRIGHT|FF_PAPERSPRITE;
let->fuse = -1;
let->tics = -1;
let->angle = ang + ANG1*90;
let->scale = 2*mapobjectscale;
// set letter in previous thing's hnext, this will let us loop em easily in the looping thinker.
P_SetTarget(&ptr->hnext, let);
// set the ptr to the last letter spawned.
ptr = let;
ang += ANG1*8;
}
}
}
void Obj_RideroidNodeThink(mobj_t *mo)
{
fixed_t radius = NODERADIUS*mapobjectscale; // radius for the text to rotate at.
mobj_t *ptr = mo->hnext;
mobj_t *pmo;
UINT8 i;
mo->angle -= NODEROTSPEED; // continuously rotate.
while (ptr && !P_MobjWasRemoved(ptr))
{
// get the new position, move us here, and move on to the next object in line.
angle_t newang = ptr->angle - NODEROTSPEED;
fixed_t newxpos = mo->x + FixedMul(radius, FINECOSINE((newang - ANG1*90)>>ANGLETOFINESHIFT));
fixed_t newypos = mo->y + FixedMul(radius, FINESINE((newang - ANG1*90)>>ANGLETOFINESHIFT));
P_MoveOrigin(ptr, newxpos, newypos, ptr->z);
ptr->angle = newang;
ptr = ptr->hnext;
}
// check for players coming near us.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].rideroid ||
players[i].rdnodepull || K_isPlayerInSpecialState(&players[i]) || P_PlayerInPain(&players[i]))
continue;
pmo = players[i].mo;
//CONS_Printf("rd: %d\n", players[i].rideroid);
if (R_PointToDist2(mo->x, mo->y, pmo->x, pmo->y) < NODERADIUS*mapobjectscale
&& pmo->z + pmo->height >= mo->z
&& pmo->z <= mo->z + 512*mapobjectscale)
{
mobj_t *rd;
plr_undoRespawn(&players[i]);
plr_resetRideroidVars(&players[i]);
players[i].rdnodepull = true;
players[i].rideroidangle = mo->spawnpoint->angle*ANG1; // reminder that mo->angle changes, so we use the spawnpoint angle.
players[i].rideroidspeed = RIDEROIDSPEED;
P_SetTarget(&pmo->tracer, mo);
// spawn the rideroid.
rd = P_SpawnMobj(mo->x, mo->y, mo->z, MT_RIDEROID);
rd->angle = players[i].rideroidangle;
P_SetTarget(&rd->target, pmo);
S_StartSound(rd, sfx_ridr1);
//CONS_Printf("rd pull\n");
}
}
}

104
src/objects/wpzothers.c Normal file
View file

@ -0,0 +1,104 @@
// 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 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"
// foutains
void Obj_WPZFountainThink(mobj_t *mo)
{
if (mo->state == &states[S_WPZFOUNTAIN]
&& !(mo->eflags & MFE_UNDERWATER))
P_SetMobjState(mo, S_WPZFOUNTAINANIM);
else if (mo->state == &states[S_WPZFOUNTAINANIM]
&& mo->eflags & MFE_UNDERWATER)
P_SetMobjState(mo, S_WPZFOUNTAIN);
}
// kuragens
void Obj_WPZKuragenThink(mobj_t *mo)
{
//(void)mo;
boolean active = false;
// .....and i need to do this... because?
if (!mo->cusval)
{
P_SetScale(mo, mapobjectscale*2);
mo->destscale = mapobjectscale*2;
mo->cusval = 1;
}
if (!(mo->spawnpoint->options & 1 || mo->spawnpoint->thing_args[0])) // extra flag skips player checks, making it a decoration.
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *p;
mobj_t *pmo;
if (!playeringame[i] || players[i].spectator)
continue;
p = &players[i];
pmo = p->mo;
if (R_PointToDist2(pmo->x, pmo->y, mo->x, mo->y) < mapobjectscale*6144)
{
active = true;
break;
}
}
}
if (active && mo->extravalue1)
{
mo->extravalue1--;
if (!mo->extravalue1)
{
mobj_t *b = P_SpawnMobj(mo->x, mo->y, mo->z, MT_KURAGENBOMB);
b->flags2 = mo->flags2 & MF2_OBJECTFLIP;
P_SetScale(b, mapobjectscale*2);
b->destscale = mapobjectscale*2;
mo->extravalue1 = TICRATE*5;
}
}
else
mo->extravalue1 = TICRATE*5/2;
}
// kuragen bomb
void Obj_WPZKuragenBombThink(mobj_t *mo)
{
if (P_IsObjectOnGround(mo))
{
P_SetScale(mo, mapobjectscale/2);
P_RadiusAttack(mo, mo, FRACUNIT*192, DMG_EXPLODE, false);
A_MineExplode(mo);
P_RemoveMobj(mo);
}
}

388
src/objects/wpzturbine.c Normal file
View file

@ -0,0 +1,388 @@
// 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 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;
}
}
// 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);
}
}
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.timer)
{
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->turbine = false;
P_SetTarget(&pmo->tracer, NULL);
return; // wtf happened
}
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);
}

View file

@ -785,6 +785,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
}
case MT_LSZ_BUNGEE:
Obj_BungeeSpecial(special, player);
return;
// CTF Flags
case MT_REDFLAG:
case MT_BLUEFLAG:
@ -837,6 +841,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
Obj_DashRingTouch(special, player);
return;
case MT_DLZ_ROCKET:
Obj_DLZRocketSpecial(special, player);
return;
case MT_BALLSWITCH_BALL:
{
Obj_BallSwitchTouched(special, toucher);

View file

@ -742,6 +742,30 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
// SRB2kart 011617 - Colission[sic] code for kart items //
if (thing->type == MT_DLZ_SEASAW_HITBOX)
{
if (tm.thing->type == MT_PLAYER)
Obj_DLZSeasawCollide(tm.thing, thing); // all checks are performed in there.
return BMIT_CONTINUE;
}
if (thing->type == MT_DLZ_HOVER)
{
if (tm.thing->type == MT_PLAYER)
Obj_DLZHoverCollide(tm.thing, thing);
return BMIT_CONTINUE;
}
if (thing->type == MT_DLZ_RINGVACCUM)
{
if (tm.thing->type == MT_FLINGRING)
Obj_DLZRingVaccumCollide(tm.thing, thing);
return BMIT_CONTINUE;
}
if (tm.thing->type == MT_INSTAWHIP)
{
if (tm.thing->z > thing->z + thing->height)

View file

@ -9703,11 +9703,86 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
case MT_RAINBOWDASHRING:
Obj_RainbowDashRingThink(mobj);
break;
case MT_RIDEROID:
Obj_RideroidThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return false;
}
break;
case MT_RIDEROIDNODE:
Obj_RideroidNodeThink(mobj);
break;
case MT_LSZ_EGGBALLSPAWNER:
Obj_EggBallSpawnerThink(mobj);
break;
case MT_LSZ_EGGBALL:
Obj_EggBallThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return false;
}
break;
case MT_DLZ_ROCKET:
Obj_DLZRocketThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return false;
}
break;
case MT_DLZ_SEASAW_SPAWN:
Obj_DLZSeasawThink(mobj);
break;
case MT_DLZ_SUCKEDRING:
Obj_DLZSuckedRingThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return false;
}
break;
case MT_WATERPALACETURBINE:
Obj_WPZTurbineThinker(mobj);
break;
case MT_WATERPALACEBUBBLE:
Obj_WPZBubbleThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return false;
}
break;
case MT_WATERPALACEFOUNTAIN:
Obj_WPZFountainThink(mobj);
break;
case MT_KURAGEN:
Obj_WPZKuragenThink(mobj);
break;
case MT_KURAGENBOMB:
Obj_WPZKuragenBombThink(mobj);
if (P_MobjWasRemoved(mobj))
{
return false;
}
break;
case MT_BALLSWITCH_BALL:
{
Obj_BallSwitchThink(mobj);
break;
}
default:
// check mobj against possible water content, before movement code
P_MobjCheckWater(mobj);
@ -10611,6 +10686,9 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_SNEAKERPANEL:
thing->shadowscale = 0;
break;
case MT_KURAGEN:
thing->shadowscale = FRACUNIT/4;
break;
default:
if (thing->flags & (MF_ENEMY|MF_BOSS))
thing->shadowscale = FRACUNIT;
@ -11167,6 +11245,21 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
case MT_RAINBOWDASHRING:
Obj_RainbowDashRingSpawn(mobj);
break;
case MT_RIDEROIDNODE:
Obj_RideroidNodeSpawn(mobj);
break;
case MT_DLZ_SEASAW_SPAWN:
Obj_DLZSeasawSpawn(mobj);
break;
case MT_DLZ_HOVER:
Obj_DLZHoverSpawn(mobj);
break;
case MT_DLZ_RINGVACCUM:
Obj_DLZRingVaccumSpawn(mobj);
break;
case MT_WATERPALACETURBINE:
Obj_WPZTurbineSpawn(mobj);
break;
case MT_SNEAKERPANEL:
Obj_SneakerPanelSpawn(mobj);
break;

View file

@ -555,6 +555,37 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT8(save->p, players[i].ringboxaward);
WRITEFIXED(save->p, players[i].outrun);
WRITEUINT8(save->p, players[i].rideroid);
WRITEUINT8(save->p, players[i].rdnodepull);
WRITEINT32(save->p, players[i].rideroidangle);
WRITEFIXED(save->p, players[i].rideroidspeed);
WRITEINT32(save->p, players[i].rideroidrollangle);
WRITEFIXED(save->p, players[i].rdaddmomx);
WRITEFIXED(save->p, players[i].rdaddmomy);
WRITEFIXED(save->p, players[i].rdaddmomz);
WRITEUINT8(save->p, players[i].bungee);
WRITEUINT32(save->p, players[i].lasthover);
WRITEUINT32(save->p, players[i].dlzrocket);
WRITEANGLE(save->p, players[i].dlzrocketangle);
WRITEINT32(save->p, players[i].dlzrocketanglev);
WRITEFIXED(save->p, players[i].dlzrocketspd);
WRITEUINT8(save->p, players[i].seasaw);
WRITEUINT32(save->p, players[i].seasawcooldown);
WRITEFIXED(save->p, players[i].seasawdist);
WRITEINT32(save->p, players[i].seasawangle);
WRITEINT32(save->p, players[i].seasawangleadd);
WRITEINT32(save->p, players[i].seasawmoreangle);
WRITEUINT8(save->p, players[i].seasawdir);
WRITEUINT32(save->p, players[i].turbine);
WRITEINT32(save->p, players[i].turbineangle);
WRITEFIXED(save->p, players[i].turbineheight);
WRITEUINT8(save->p, players[i].turbinespd);
// respawnvars_t
WRITEUINT8(save->p, players[i].respawn.state);
WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp));
@ -1034,6 +1065,37 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].ringboxaward = READUINT8(save->p);
players[i].outrun = READFIXED(save->p);
players[i].rideroid = (boolean)READUINT8(save->p);
players[i].rdnodepull = (boolean)READUINT8(save->p);
players[i].rideroidangle = READINT32(save->p);
players[i].rideroidspeed = READFIXED(save->p);
players[i].rideroidrollangle = READINT32(save->p);
players[i].rdaddmomx = READFIXED(save->p);
players[i].rdaddmomy = READFIXED(save->p);
players[i].rdaddmomz = READFIXED(save->p);
players[i].bungee = READUINT8(save->p);
players[i].lasthover = (tic_t)READUINT32(save->p);
players[i].dlzrocket = (tic_t)READUINT32(save->p);
players[i].dlzrocketangle = READANGLE(save->p);
players[i].dlzrocketanglev = READINT32(save->p);
players[i].dlzrocketspd = READFIXED(save->p);
players[i].seasaw = (boolean)READUINT8(save->p);
players[i].seasawcooldown = READUINT32(save->p);
players[i].seasawdist = READFIXED(save->p);
players[i].seasawangle = READINT32(save->p);
players[i].seasawangleadd = READINT32(save->p);
players[i].seasawmoreangle = READINT32(save->p);
players[i].seasawdir = (boolean)READUINT8(save->p);
players[i].turbine = (tic_t)READUINT32(save->p);
players[i].turbineangle = READINT32(save->p);
players[i].turbineheight = READFIXED(save->p);
players[i].turbinespd = (boolean)READUINT8(save->p);
// respawnvars_t
players[i].respawn.state = READUINT8(save->p);
players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save->p);

View file

@ -7266,7 +7266,7 @@ static void P_ConvertBinaryThingTypes(void)
case 3786: // MT_BATTLEUFO_SPAWNER
mapthings[i].thing_args[0] = mapthings[i].angle;
break;
case 3400: // MT_WATERPALACETURBINE (TODO: not yet hardcoded)
case 3400: // MT_WATERPALACETURBINE
{
mtag_t tag = (mtag_t)mapthings[i].angle;
INT32 j = Tag_FindLineSpecial(2009, tag);
@ -7315,8 +7315,8 @@ static void P_ConvertBinaryThingTypes(void)
break;
}
case 3441: // MT_DASHRING (TODO: not yet hardcoded)
case 3442: // MT_RAINBOWDASHRING (TODO: not yet hardcoded)
case 3441: // MT_DASHRING
case 3442: // MT_RAINBOWDASHRING
mapthings[i].thing_args[0] = mapthings[i].options & 13;
mapthings[i].thing_args[1] = mapthings[i].extrainfo;
break;

View file

@ -46,6 +46,7 @@
#include "console.h" // CON_LogMessage
#include "k_respawn.h"
#include "k_terrain.h"
#include "k_objects.h"
#include "acs/interface.h"
#include "m_easing.h"
@ -1379,6 +1380,7 @@ boolean P_CanActivateSpecial(INT16 special)
{
case 2001: // Finish line
case 2003: // Respawn line
case 2005: // Dismount Flying Object (always true here so that conditions are only kept on execution)
{
return true;
}
@ -4450,6 +4452,18 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
}
break;
case 2005: // Dismount Flying object
// the rideroid is a bit complex so it's the one controlling the player rather than the player controlling it.
// so it is the object needing to be checked for rather than the player
if (mo->player && mo->player->rideroid && mo->tracer
&& !P_MobjWasRemoved(mo->tracer) && mo->tracer->type == MT_RIDEROID)
Obj_getPlayerOffRideroid(mo->tracer);
// dlz rockets are simpler and are tied to the player hence why we check for the player here instead.
if (mo->player && mo->player->dlzrocket)
Obj_DLZRocketDismount(mo->player);
break;
default:
break;
}
@ -9263,9 +9277,9 @@ void T_Pusher(pusher_t *p)
if (thing->angle - angle > ANGLE_180)
thing->player->drawangle = angle - (angle - thing->angle) / 8;
else
thing->player->drawangle = angle + (thing->angle - angle) / 8;
thing->player->drawangle = angle + (thing->angle - angle) / 8;
//P_SetPlayerAngle(thing->player, thing->angle);
}
if (p->exclusive)
@ -9408,7 +9422,7 @@ void P_DoQuakeOffset(UINT8 view, mappoint_t *viewPos, mappoint_t *offset)
viewPos->z - quake->epicenter->z
) - distBuffer;
fixed_t distEase = FixedDiv(max(epidist, 0), quake->radius);
distEase = min(distEase, FRACUNIT);
ir = Easing_InCubic(distEase, ir, 0);

View file

@ -3188,7 +3188,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
lookback = ( player->cmd.buttons & BT_LOOKBACK );
camspeed = cv_cam_speed[num].value;
camstill = cv_cam_still[num].value;
camstill = cv_cam_still[num].value || player->seasaw; // RR: seasaws lock the camera so that it isn't disorienting.
camrotate = cv_cam_rotate[num].value;
camdist = FixedMul(cv_cam_dist[num].value, cameraScale);
camheight = FixedMul(cv_cam_height[num].value, cameraScale);

View file

@ -419,6 +419,7 @@ boolean R_IsDebugLine(seg_t *line)
{
case 2001: // Ring Racers: Finish Line
case 2003: // Ring Racers: Respawn Line
case 2005: // Ring Racers: Dismount flying object Line
return true;
}
}

View file

@ -75,6 +75,9 @@ UINT8 R_DebugLineColor(const line_t *ld)
case 2003: // Ring Racers: Respawn Line
return alt ? 0x23 : 0x00; // red, white
case 2005: // Ring Racers: Dismount flying object Line
return alt ? 0x86 : 0x36; // blue, orange
}
return 0x00;

View file

@ -1210,6 +1210,11 @@ sfxinfo_t S_sfx[NUMSFX] =
{"rank", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Rank slam
{"ridr1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boarding Rideroid"}, // Rideroid Activation
{"ridr2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Rideroid Diveroll
{"ridr3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Rideroid Loop
{"ridr4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Leaving Rideroid
// Damage sounds
{"dmga1", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"},
{"dmga2", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"},

View file

@ -1278,6 +1278,12 @@ typedef enum
sfx_rainbr,
sfx_rank,
// rideroid
sfx_ridr1,
sfx_ridr2,
sfx_ridr3,
sfx_ridr4,
// Damage sounds
sfx_dmga1,