mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'ringshooter' into 'master'
Ring Shooter (Manual Respawn) See merge request KartKrew/Kart!690
This commit is contained in:
commit
eaf11a1d13
23 changed files with 1171 additions and 154 deletions
|
|
@ -2776,6 +2776,7 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
P_SetTarget(&players[playernum].hoverhyudoro, NULL);
|
||||
P_SetTarget(&players[playernum].stumbleIndicator, NULL);
|
||||
P_SetTarget(&players[playernum].sliptideZipIndicator, NULL);
|
||||
P_SetTarget(&players[playernum].ringShooter, NULL);
|
||||
}
|
||||
|
||||
// Handle parties.
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ static void Got_PickVotecmd(UINT8 **cp, INT32 playernum);
|
|||
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Pause(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Respawn(UINT8 **cp, INT32 playernum);
|
||||
static void Got_RandomSeed(UINT8 **cp, INT32 playernum);
|
||||
static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Teamchange(UINT8 **cp, INT32 playernum);
|
||||
|
|
@ -177,7 +176,6 @@ static void Command_ListWADS_f(void);
|
|||
static void Command_ListDoomednums_f(void);
|
||||
static void Command_RunSOC(void);
|
||||
static void Command_Pause(void);
|
||||
static void Command_Respawn(void);
|
||||
|
||||
static void Command_Version_f(void);
|
||||
#ifdef UPDATE_ALERT
|
||||
|
|
@ -606,7 +604,6 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
|
|||
"RUNSOC", // XD_RUNSOC
|
||||
"REQADDFILE", // XD_REQADDFILE
|
||||
"SETMOTD", // XD_SETMOTD
|
||||
"RESPAWN", // XD_RESPAWN
|
||||
"DEMOTED", // XD_DEMOTED
|
||||
"LUACMD", // XD_LUACMD
|
||||
"LUAVAR", // XD_LUAVAR
|
||||
|
|
@ -664,7 +661,6 @@ void D_RegisterServerCommands(void)
|
|||
RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
|
||||
RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd);
|
||||
RegisterNetXCmd(XD_PAUSE, Got_Pause);
|
||||
RegisterNetXCmd(XD_RESPAWN, Got_Respawn);
|
||||
RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd);
|
||||
RegisterNetXCmd(XD_LUACMD, Got_Luacmd);
|
||||
RegisterNetXCmd(XD_LUAFILE, Got_LuaFile);
|
||||
|
|
@ -711,7 +707,6 @@ void D_RegisterServerCommands(void)
|
|||
|
||||
COM_AddCommand("runsoc", Command_RunSOC);
|
||||
COM_AddCommand("pause", Command_Pause);
|
||||
COM_AddCommand("respawn", Command_Respawn);
|
||||
|
||||
COM_AddCommand("gametype", Command_ShowGametype_f);
|
||||
COM_AddCommand("version", Command_Version_f);
|
||||
|
|
@ -3316,61 +3311,6 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
|
|||
G_ResetAllDeviceRumbles();
|
||||
}
|
||||
|
||||
// Command for stuck characters in netgames, griefing, etc.
|
||||
static void Command_Respawn(void)
|
||||
{
|
||||
UINT8 buf[4];
|
||||
UINT8 *cp = buf;
|
||||
|
||||
|
||||
|
||||
if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING))
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (players[consoleplayer].mo && !P_IsObjectOnGround(players[consoleplayer].mo)) // KART: Nice try, but no, you won't be cheesing spb anymore.
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be on the floor to use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: this probably isnt necessary anymore with v2
|
||||
if (players[consoleplayer].mo && (P_PlayerInPain(&players[consoleplayer]) || spbplace == players[consoleplayer].position)) // KART: Nice try, but no, you won't be cheesing spb anymore (x2)
|
||||
{
|
||||
CONS_Printf(M_GetText("Nice try.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
WRITEINT32(cp, consoleplayer);
|
||||
SendNetXCmd(XD_RESPAWN, &buf, 4);
|
||||
}
|
||||
|
||||
static void Got_Respawn(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
INT32 respawnplayer = READINT32(*cp);
|
||||
|
||||
// You can't respawn someone else. Nice try, there.
|
||||
if (respawnplayer != playernum || P_PlayerInPain(&players[respawnplayer]) || spbplace == players[respawnplayer].position) // srb2kart: "|| (!(gametyperules & GTR_CIRCUIT))"
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal respawn command received from %s\n"), player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (players[respawnplayer].mo)
|
||||
{
|
||||
// incase the above checks were modified to allow sending a respawn on these occasions:
|
||||
if (!P_IsObjectOnGround(players[respawnplayer].mo))
|
||||
return;
|
||||
|
||||
P_DamageMobj(players[respawnplayer].mo, NULL, NULL, 1, DMG_DEATHPIT);
|
||||
demo_extradata[playernum] |= DXD_RESPAWN;
|
||||
}
|
||||
}
|
||||
|
||||
/** Deals with an ::XD_RANDOMSEED message in a netgame.
|
||||
* These messages set the position of the random number LUT and are crucial to
|
||||
* correct synchronization.
|
||||
|
|
|
|||
|
|
@ -158,28 +158,27 @@ typedef enum
|
|||
XD_RUNSOC, // 15
|
||||
XD_REQADDFILE, // 16
|
||||
XD_SETMOTD, // 17
|
||||
XD_RESPAWN, // 18
|
||||
XD_DEMOTED, // 19
|
||||
XD_LUACMD, // 20
|
||||
XD_LUAVAR, // 21
|
||||
XD_LUAFILE, // 22
|
||||
XD_DEMOTED, // 18
|
||||
XD_LUACMD, // 19
|
||||
XD_LUAVAR, // 20
|
||||
XD_LUAFILE, // 21
|
||||
|
||||
// SRB2Kart
|
||||
XD_SETUPVOTE, // 23
|
||||
XD_MODIFYVOTE, // 24
|
||||
XD_PICKVOTE, // 25
|
||||
XD_REMOVEPLAYER,// 26
|
||||
XD_PARTYINVITE, // 27
|
||||
XD_ACCEPTPARTYINVITE, // 28
|
||||
XD_LEAVEPARTY, // 29
|
||||
XD_CANCELPARTYINVITE, // 30
|
||||
XD_CHEAT, // 31
|
||||
XD_ADDBOT, // 32
|
||||
XD_DISCORD, // 33
|
||||
XD_PLAYSOUND, // 34
|
||||
XD_SCHEDULETASK, // 35
|
||||
XD_SCHEDULECLEAR, // 36
|
||||
XD_AUTOMATE, // 37
|
||||
XD_SETUPVOTE, // 22
|
||||
XD_MODIFYVOTE, // 23
|
||||
XD_PICKVOTE, // 24
|
||||
XD_REMOVEPLAYER,// 25
|
||||
XD_PARTYINVITE, // 26
|
||||
XD_ACCEPTPARTYINVITE, // 27
|
||||
XD_LEAVEPARTY, // 28
|
||||
XD_CANCELPARTYINVITE, // 29
|
||||
XD_CHEAT, // 30
|
||||
XD_ADDBOT, // 31
|
||||
XD_DISCORD, // 32
|
||||
XD_PLAYSOUND, // 33
|
||||
XD_SCHEDULETASK, // 34
|
||||
XD_SCHEDULECLEAR, // 35
|
||||
XD_AUTOMATE, // 36
|
||||
|
||||
MAXNETXCMD
|
||||
} netxcmd_t;
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ struct respawnvars_t
|
|||
tic_t dropdash; // Drop Dash charge timer
|
||||
boolean truedeath; // Your soul has left your body
|
||||
boolean manual; // Respawn coords were manually set, please respawn exactly there
|
||||
boolean fromRingShooter; // Respawn was from Ring Shooter, don't allow E-Brake drop
|
||||
boolean init;
|
||||
};
|
||||
|
||||
|
|
@ -505,8 +506,9 @@ struct player_t
|
|||
UINT32 distancetofinish;
|
||||
waypoint_t *currentwaypoint;
|
||||
waypoint_t *nextwaypoint;
|
||||
respawnvars_t respawn; // Respawn info
|
||||
tic_t airtime; // Keep track of how long you've been in the air
|
||||
respawnvars_t respawn; // Respawn info
|
||||
mobj_t *ringShooter; // DEZ respawner object
|
||||
tic_t airtime; // Used to track just air time, but has evolved over time into a general "karted" timer. Rename this variable?
|
||||
UINT8 startboost; // (0 to 125) - Boost you get from start of race or respawn drop dash
|
||||
|
||||
UINT16 flashing;
|
||||
|
|
|
|||
|
|
@ -35,13 +35,15 @@ typedef enum
|
|||
BT_BRAKE = 1<<3, // Brake
|
||||
BT_ATTACK = 1<<4, // Use Item
|
||||
BT_LOOKBACK = 1<<5, // Look Backward
|
||||
BT_RESPAWN = 1<<6, // Respawn
|
||||
BT_VOTE = 1<<7, // Vote
|
||||
|
||||
BT_EBRAKEMASK = (BT_ACCELERATE|BT_BRAKE),
|
||||
BT_SPINDASHMASK = (BT_ACCELERATE|BT_BRAKE|BT_DRIFT),
|
||||
|
||||
// free: 1<<6 to 1<<12
|
||||
// free: 1<<8 to 1<<12
|
||||
|
||||
// Lua garbage
|
||||
// Lua garbage, replace with freeslottable buttons some day
|
||||
BT_LUAA = 1<<13,
|
||||
BT_LUAB = 1<<14,
|
||||
BT_LUAC = 1<<15,
|
||||
|
|
|
|||
|
|
@ -326,6 +326,7 @@ actionpointer_t actionpointers[] =
|
|||
{{A_FlameShieldPaper}, "A_FLAMESHIELDPAPER"},
|
||||
{{A_InvincSparkleRotate}, "A_INVINCSPARKLEROTATE"},
|
||||
{{A_SpawnItemDebrisCloud}, "A_SPAWNITEMDEBRISCLOUD"},
|
||||
{{A_RingShooterFace}, "A_RINGSHOOTERFACE"},
|
||||
|
||||
{{NULL}, "NONE"},
|
||||
|
||||
|
|
@ -3867,6 +3868,15 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
|
||||
"S_SMOOTHLANDING",
|
||||
|
||||
// DEZ Ring Shooter
|
||||
"S_TIREGRABBER",
|
||||
"S_RINGSHOOTER_SIDE",
|
||||
"S_RINGSHOOTER_NIPPLES",
|
||||
"S_RINGSHOOTER_SCREEN",
|
||||
"S_RINGSHOOTER_NUMBERBACK",
|
||||
"S_RINGSHOOTER_NUMBERFRONT",
|
||||
"S_RINGSHOOTER_FACE",
|
||||
|
||||
// DEZ respawn laser
|
||||
"S_DEZLASER",
|
||||
"S_DEZLASER_TRAIL1",
|
||||
|
|
@ -5433,6 +5443,11 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_SMOOTHLANDING",
|
||||
|
||||
"MT_TIREGRABBER",
|
||||
"MT_RINGSHOOTER",
|
||||
"MT_RINGSHOOTER_PART",
|
||||
"MT_RINGSHOOTER_SCREEN",
|
||||
|
||||
"MT_DEZLASER",
|
||||
|
||||
"MT_WAYPOINT",
|
||||
|
|
|
|||
|
|
@ -353,14 +353,6 @@ void G_ReadDemoExtraData(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (extradata & DXD_RESPAWN)
|
||||
{
|
||||
if (players[p].mo)
|
||||
{
|
||||
// Is this how this should work..?
|
||||
P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_DEATHPIT);
|
||||
}
|
||||
}
|
||||
if (extradata & DXD_WEAPONPREF)
|
||||
{
|
||||
WeaponPref_Parse(&demobuf.p, p);
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ extern UINT8 demo_writerng;
|
|||
#define DXD_NAME 0x08 // name changed
|
||||
#define DXD_COLOR 0x10 // color changed
|
||||
#define DXD_FOLLOWER 0x20 // follower was changed
|
||||
#define DXD_RESPAWN 0x40 // "respawn" command in console
|
||||
|
||||
#define DXD_WEAPONPREF 0x80 // netsynced playsim settings were changed
|
||||
|
||||
#define DXD_PST_PLAYING 0x01
|
||||
|
|
|
|||
14
src/g_game.c
14
src/g_game.c
|
|
@ -1324,7 +1324,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
// C
|
||||
if (G_PlayerInputDown(forplayer, gc_spindash, 0))
|
||||
{
|
||||
forward = 0;
|
||||
cmd->buttons |= BT_SPINDASHMASK;
|
||||
}
|
||||
|
||||
|
|
@ -1340,6 +1339,18 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
cmd->buttons |= BT_LOOKBACK;
|
||||
}
|
||||
|
||||
// respawn
|
||||
if (G_PlayerInputDown(forplayer, gc_respawn, 0))
|
||||
{
|
||||
cmd->buttons |= (BT_RESPAWN | BT_EBRAKEMASK);
|
||||
}
|
||||
|
||||
// mp general function button
|
||||
if (G_PlayerInputDown(forplayer, gc_vote, 0))
|
||||
{
|
||||
cmd->buttons |= BT_VOTE;
|
||||
}
|
||||
|
||||
// lua buttons a thru c
|
||||
if (G_PlayerInputDown(forplayer, gc_luaa, 0)) { cmd->buttons |= BT_LUAA; }
|
||||
if (G_PlayerInputDown(forplayer, gc_luab, 0)) { cmd->buttons |= BT_LUAB; }
|
||||
|
|
@ -2633,6 +2644,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
P_SetTarget(&players[player].follower, NULL);
|
||||
P_SetTarget(&players[player].awayview.mobj, NULL);
|
||||
P_SetTarget(&players[player].stumbleIndicator, NULL);
|
||||
P_SetTarget(&players[player].ringShooter, NULL);
|
||||
P_SetTarget(&players[player].followmobj, NULL);
|
||||
|
||||
hoverhyudoro = players[player].hoverhyudoro;
|
||||
|
|
|
|||
|
|
@ -91,13 +91,13 @@ typedef enum
|
|||
|
||||
// alias gameplay controls
|
||||
gc_accel = gc_a,
|
||||
gc_brake = gc_x,
|
||||
gc_drift = gc_r,
|
||||
|
||||
gc_item = gc_l,
|
||||
gc_spindash = gc_c,
|
||||
|
||||
gc_lookback = gc_b,
|
||||
gc_spindash = gc_c,
|
||||
gc_brake = gc_x,
|
||||
gc_respawn = gc_y,
|
||||
gc_vote = gc_z,
|
||||
gc_item = gc_l,
|
||||
gc_drift = gc_r,
|
||||
} gamecontrols_e;
|
||||
|
||||
// mouse values are used once
|
||||
|
|
|
|||
120
src/info.c
120
src/info.c
|
|
@ -606,6 +606,10 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"TWBS", // Tripwire Boost
|
||||
"TWBT", // Tripwire BLASTER
|
||||
"SMLD", // Smooth landing
|
||||
|
||||
"TIRG", // Tire grabbers
|
||||
"RSHT", // DEZ Ring Shooter
|
||||
|
||||
"DEZL", // DEZ Laser respawn
|
||||
|
||||
// Additional Kart Objects
|
||||
|
|
@ -4464,6 +4468,14 @@ state_t states[NUMSTATES] =
|
|||
|
||||
{SPR_SMLD, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_SMOOTHLANDING
|
||||
|
||||
{SPR_TIRG, FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_TIREGRABBER
|
||||
{SPR_RSHT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_SIDE
|
||||
{SPR_RSHT, FF_SEMIBRIGHT|FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NIPPLES
|
||||
{SPR_RSHT, FF_PAPERSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_SCREEN
|
||||
{SPR_RSHT, FF_FULLBRIGHT|FF_PAPERSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NUMBERBACK
|
||||
{SPR_RSHT, FF_FULLBRIGHT|FF_PAPERSPRITE|9, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NUMBERFRONT
|
||||
{SPR_PLAY, FF_FULLBRIGHT|FF_PAPERSPRITE|SPR2_XTRA, -1, {A_RingShooterFace}, 0, 0, S_NULL}, // S_RINGSHOOTER_FACE
|
||||
|
||||
{SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER
|
||||
{SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1
|
||||
{SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL3}, // S_DEZLASER_TRAIL2
|
||||
|
|
@ -24623,6 +24635,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_TIREGRABBER
|
||||
-1, // doomednum
|
||||
S_TIREGRABBER, // 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
|
||||
20*FRACUNIT, // radius
|
||||
36*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_RINGSHOOTER
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_s3ka7, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_s3kad, // deathsound
|
||||
0, // speed
|
||||
24*FRACUNIT, // radius
|
||||
8*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_RINGSHOOTER_PART
|
||||
-1, // doomednum
|
||||
S_RINGSHOOTER_SIDE, // 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
|
||||
6*FRACUNIT, // radius
|
||||
70*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_RINGSHOOTER_SCREEN
|
||||
-1, // doomednum
|
||||
S_RINGSHOOTER_SCREEN, // 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
|
||||
23*FRACUNIT, // radius
|
||||
39*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_DEZLASER
|
||||
-1, // doomednum
|
||||
S_DEZLASER, // spawnstate
|
||||
|
|
|
|||
20
src/info.h
20
src/info.h
|
|
@ -294,6 +294,7 @@ enum actionnum
|
|||
A_FLAMESHIELDPAPER,
|
||||
A_INVINCSPARKLEROTATE,
|
||||
A_SPAWNITEMDEBRISCLOUD,
|
||||
A_RINGSHOOTERFACE,
|
||||
NUMACTIONS
|
||||
};
|
||||
|
||||
|
|
@ -568,6 +569,7 @@ void A_MementosTPParticles();
|
|||
void A_FlameShieldPaper();
|
||||
void A_InvincSparkleRotate();
|
||||
void A_SpawnItemDebrisCloud();
|
||||
void A_RingShooterFace();
|
||||
|
||||
extern boolean actionsoverridden[NUMACTIONS];
|
||||
|
||||
|
|
@ -1157,6 +1159,10 @@ typedef enum sprite
|
|||
SPR_TWBS, // Tripwire Boost
|
||||
SPR_TWBT, // Tripwire BLASTER
|
||||
SPR_SMLD, // Smooth landing
|
||||
|
||||
SPR_TIRG, // Tire grabbers
|
||||
SPR_RSHT, // DEZ Ring Shooter
|
||||
|
||||
SPR_DEZL, // DEZ Laser respawn
|
||||
|
||||
// Additional Kart Objects
|
||||
|
|
@ -4906,6 +4912,15 @@ typedef enum state
|
|||
|
||||
S_SMOOTHLANDING,
|
||||
|
||||
// DEZ Ring Shooter
|
||||
S_TIREGRABBER,
|
||||
S_RINGSHOOTER_SIDE,
|
||||
S_RINGSHOOTER_NIPPLES,
|
||||
S_RINGSHOOTER_SCREEN,
|
||||
S_RINGSHOOTER_NUMBERBACK,
|
||||
S_RINGSHOOTER_NUMBERFRONT,
|
||||
S_RINGSHOOTER_FACE,
|
||||
|
||||
// DEZ Laser respawn
|
||||
S_DEZLASER,
|
||||
S_DEZLASER_TRAIL1,
|
||||
|
|
@ -6508,6 +6523,11 @@ typedef enum mobj_type
|
|||
|
||||
MT_SMOOTHLANDING,
|
||||
|
||||
MT_TIREGRABBER,
|
||||
MT_RINGSHOOTER,
|
||||
MT_RINGSHOOTER_PART,
|
||||
MT_RINGSHOOTER_SCREEN,
|
||||
|
||||
MT_DEZLASER,
|
||||
|
||||
MT_WAYPOINT,
|
||||
|
|
|
|||
34
src/k_kart.c
34
src/k_kart.c
|
|
@ -3407,7 +3407,9 @@ SINT8 K_GetForwardMove(player_t *player)
|
|||
{
|
||||
SINT8 forwardmove = player->cmd.forwardmove;
|
||||
|
||||
if ((player->pflags & PF_STASIS) || (player->carry == CR_SLIDING))
|
||||
if ((player->pflags & PF_STASIS)
|
||||
|| (player->carry == CR_SLIDING)
|
||||
|| Obj_PlayerRingShooterFreeze(player) == true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3418,7 +3420,9 @@ SINT8 K_GetForwardMove(player_t *player)
|
|||
return MAXPLMOVE;
|
||||
}
|
||||
|
||||
if (player->spinouttimer || K_PlayerEBrake(player))
|
||||
if (player->spinouttimer != 0
|
||||
|| K_PressingEBrake(player) == true
|
||||
|| K_PlayerEBrake(player) == true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -7547,6 +7551,11 @@ static void K_UpdateTripwire(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
boolean K_PressingEBrake(player_t *player)
|
||||
{
|
||||
return ((K_GetKartButtons(player) & BT_EBRAKEMASK) == BT_EBRAKEMASK);
|
||||
}
|
||||
|
||||
/** \brief Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c
|
||||
|
||||
\param player player object passed from P_PlayerThink
|
||||
|
|
@ -8074,7 +8083,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
K_SpawnGardenTopSpeedLines(player);
|
||||
}
|
||||
// Only allow drifting while NOT trying to do an spindash input.
|
||||
else if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK)
|
||||
else if (K_PressingEBrake(player) == false)
|
||||
{
|
||||
player->pflags |= PF_DRIFTINPUT;
|
||||
}
|
||||
|
|
@ -8941,10 +8950,16 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (Obj_PlayerRingShooterFreeze(player) == true)
|
||||
{
|
||||
// No turning while using Ring Shooter
|
||||
return 0;
|
||||
}
|
||||
|
||||
currentSpeed = FixedHypot(player->mo->momx, player->mo->momy);
|
||||
|
||||
if ((currentSpeed <= 0) // Not moving
|
||||
&& ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK) // Not e-braking
|
||||
&& (K_PressingEBrake(player) == false) // Not e-braking
|
||||
&& (player->respawn.state == RESPAWNST_NONE) // Not respawning
|
||||
&& (player->curshield != KSHIELD_TOP) // Not riding a Top
|
||||
&& (P_IsObjectOnGround(player->mo) == true)) // On the ground
|
||||
|
|
@ -9730,7 +9745,12 @@ static INT32 K_FlameShieldMax(player_t *player)
|
|||
boolean K_PlayerEBrake(player_t *player)
|
||||
{
|
||||
if (player->respawn.state != RESPAWNST_NONE
|
||||
&& player->respawn.init == true)
|
||||
&& (player->respawn.init == true || player->respawn.fromRingShooter == true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Obj_PlayerRingShooterFreeze(player) == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -9740,7 +9760,7 @@ boolean K_PlayerEBrake(player_t *player)
|
|||
return true;
|
||||
}
|
||||
|
||||
if ((K_GetKartButtons(player) & BT_EBRAKEMASK) == BT_EBRAKEMASK
|
||||
if (K_PressingEBrake(player) == true
|
||||
&& player->drift == 0
|
||||
&& P_PlayerInPain(player) == false
|
||||
&& player->justbumped == 0
|
||||
|
|
@ -11387,6 +11407,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
{
|
||||
player->pflags &= ~PF_AIRFAILSAFE;
|
||||
}
|
||||
|
||||
Obj_RingShooterInput(player);
|
||||
}
|
||||
|
||||
void K_CheckSpectateStatus(void)
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ void K_SpawnBumpEffect(mobj_t *mo);
|
|||
void K_KartMoveAnimation(player_t *player);
|
||||
void K_KartPlayerHUDUpdate(player_t *player);
|
||||
void K_KartResetPlayerColor(player_t *player);
|
||||
boolean K_PressingEBrake(player_t *player);
|
||||
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);
|
||||
void K_KartPlayerAfterThink(player_t *player);
|
||||
fixed_t K_MomentumThreshold(const mobj_t *mo);
|
||||
|
|
|
|||
|
|
@ -106,6 +106,14 @@ void Obj_LoopEndpointCollide(mobj_t *special, mobj_t *toucher);
|
|||
void Obj_BeginDropTargetMorph(mobj_t *target, skincolornum_t color);
|
||||
boolean Obj_DropTargetMorphThink(mobj_t *morph);
|
||||
|
||||
/* Ring Shooter */
|
||||
boolean Obj_RingShooterThinker(mobj_t *mo);
|
||||
boolean Obj_PlayerRingShooterFreeze(player_t *const player);
|
||||
void Obj_RingShooterInput(player_t *player);
|
||||
void Obj_PlayerUsedRingShooter(mobj_t *base, player_t *player);
|
||||
void Obj_RingShooterDelete(mobj_t *mo);
|
||||
void Obj_UpdateRingShooterFace(mobj_t *part);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -175,9 +175,27 @@ void K_DoIngameRespawn(player_t *player)
|
|||
}
|
||||
else if (player->respawn.wp != NULL)
|
||||
{
|
||||
const UINT32 dist = RESPAWN_DIST + (player->airtime * 48);
|
||||
player->respawn.distanceleft = (dist * mapobjectscale) / FRACUNIT;
|
||||
K_RespawnAtWaypoint(player, player->respawn.wp);
|
||||
if (player->respawn.fromRingShooter == true)
|
||||
{
|
||||
waypoint_t *prevWP = player->respawn.wp;
|
||||
while (prevWP->numprevwaypoints > 0)
|
||||
{
|
||||
prevWP = prevWP->prevwaypoints[0];
|
||||
if (K_GetWaypointIsSpawnpoint(prevWP) == true)
|
||||
break;
|
||||
}
|
||||
|
||||
const UINT32 dist = (player->airtime * 48);
|
||||
player->respawn.distanceleft = (dist * mapobjectscale) / FRACUNIT;
|
||||
|
||||
K_RespawnAtWaypoint(player, prevWP);
|
||||
}
|
||||
else
|
||||
{
|
||||
const UINT32 dist = RESPAWN_DIST + (player->airtime * 48);
|
||||
player->respawn.distanceleft = (dist * mapobjectscale) / FRACUNIT;
|
||||
K_RespawnAtWaypoint(player, player->respawn.wp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -465,7 +483,9 @@ static void K_MovePlayerToRespawnPoint(player_t *player)
|
|||
player->mo->momz = step.z;
|
||||
}
|
||||
|
||||
if (player->respawn.init == false && K_PlayerEBrake(player) == true)
|
||||
if (player->respawn.init == false
|
||||
&& player->respawn.fromRingShooter == false
|
||||
&& K_PlayerEBrake(player) == true)
|
||||
{
|
||||
// Manual drop!
|
||||
player->respawn.state = RESPAWNST_DROP;
|
||||
|
|
@ -822,6 +842,7 @@ void K_RespawnChecker(player_t *player)
|
|||
K_MovePlayerToRespawnPoint(player);
|
||||
return;
|
||||
case RESPAWNST_DROP:
|
||||
player->respawn.fromRingShooter = false;
|
||||
player->mo->momx = player->mo->momy = 0;
|
||||
player->flashing = 3;
|
||||
if (player->respawn.timer > 0)
|
||||
|
|
|
|||
|
|
@ -22,11 +22,10 @@ menuitem_t OPTIONS_ProfileControls[] = {
|
|||
{IT_CONTROL, "X", "Brake / Back",
|
||||
"PR_BTX", {.routine = M_ProfileSetControl}, gc_x, 0},
|
||||
|
||||
// @TODO What does this do???
|
||||
{IT_CONTROL, "Y", "N/A ?",
|
||||
{IT_CONTROL, "Y", "Respawn",
|
||||
"PR_BTY", {.routine = M_ProfileSetControl}, gc_y, 0},
|
||||
|
||||
{IT_CONTROL, "Z", "N/A ?",
|
||||
{IT_CONTROL, "Z", "Multiplayer quick-chat / quick-vote",
|
||||
"PR_BTZ", {.routine = M_ProfileSetControl}, gc_z, 0},
|
||||
|
||||
{IT_CONTROL, "L", "Use item",
|
||||
|
|
@ -62,13 +61,13 @@ menuitem_t OPTIONS_ProfileControls[] = {
|
|||
{IT_CONTROL, "RECORD LOSSLESS", "Record a pixel perfect GIF.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_startlossless, 0},
|
||||
|
||||
{IT_CONTROL, "OPEN CHAT", "Opens chatbox in online games.",
|
||||
{IT_CONTROL, "OPEN CHAT", "Opens full keyboard chatting for online games.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_talk, 0},
|
||||
|
||||
{IT_CONTROL, "OPEN TEAM CHAT", "Do we even have team gamemodes?",
|
||||
{IT_CONTROL, "OPEN TEAM CHAT", "Opens team-only full chat for online games.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_teamtalk, 0},
|
||||
|
||||
{IT_CONTROL, "SHOW RANKINGS", "Show mid-game rankings.",
|
||||
{IT_CONTROL, "SHOW RANKINGS", "Display the current rankings mid-game.",
|
||||
NULL, {.routine = M_ProfileSetControl}, gc_rankings, 0},
|
||||
|
||||
{IT_CONTROL, "OPEN CONSOLE", "Opens the developer options console.",
|
||||
|
|
|
|||
|
|
@ -14,4 +14,5 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
item-spot.c
|
||||
loops.c
|
||||
drop-target.c
|
||||
ring-shooter.c
|
||||
)
|
||||
|
|
|
|||
801
src/objects/ring-shooter.c
Normal file
801
src/objects/ring-shooter.c
Normal file
|
|
@ -0,0 +1,801 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) by "Lach"
|
||||
// Copyright (C) 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 ring-shooter.c
|
||||
/// \brief DEZ "Ring Shooter" respawner object
|
||||
|
||||
#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 "../r_skins.h"
|
||||
#include "../k_respawn.h"
|
||||
#include "../lua_hook.h"
|
||||
|
||||
#define RS_FUSE_TIME (4*TICRATE)
|
||||
#define RS_FUSE_BLINK (TICRATE >> 1)
|
||||
|
||||
#define RS_GRABBER_START (16 << FRACBITS)
|
||||
#define RS_GRABBER_SLIDE (RS_GRABBER_START >> 4)
|
||||
#define RS_GRABBER_EXTRA (18 << FRACBITS)
|
||||
|
||||
#define RS_KARTED_INC (3)
|
||||
|
||||
#define rs_base_scalespeed(o) ((o)->scalespeed)
|
||||
#define rs_base_initstate(o) ((o)->threshold)
|
||||
#define rs_base_xscale(o) ((o)->extravalue1)
|
||||
#define rs_base_yscale(o) ((o)->extravalue2)
|
||||
|
||||
#define rs_base_playerid(o) ((o)->lastlook)
|
||||
#define rs_base_playerface(o) ((o)->cusval)
|
||||
#define rs_base_playerlast(o) ((o)->watertop)
|
||||
|
||||
#define rs_base_karted(o) ((o)->movecount)
|
||||
#define rs_base_grabberdist(o) ((o)->movefactor)
|
||||
#define rs_base_canceled(o) ((o)->cvmem)
|
||||
|
||||
#define rs_part_xoffset(o) ((o)->extravalue1)
|
||||
#define rs_part_yoffset(o) ((o)->extravalue2)
|
||||
|
||||
static void RemoveRingShooterPointer(mobj_t *base)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
|
||||
if (rs_base_playerid(base) < 0 || rs_base_playerid(base) >= MAXPLAYERS)
|
||||
{
|
||||
// No pointer set
|
||||
return;
|
||||
}
|
||||
|
||||
// NULL the player's pointer.
|
||||
player = &players[ rs_base_playerid(base) ];
|
||||
P_SetTarget(&player->ringShooter, NULL);
|
||||
|
||||
// Remove our player ID
|
||||
rs_base_playerid(base) = -1;
|
||||
}
|
||||
|
||||
|
||||
static void ChangeRingShooterPointer(mobj_t *base, player_t *player)
|
||||
{
|
||||
// Remove existing pointer first.
|
||||
RemoveRingShooterPointer(base);
|
||||
|
||||
if (player == NULL)
|
||||
{
|
||||
// Just remove it.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set new player pointer.
|
||||
P_SetTarget(&player->ringShooter, base);
|
||||
|
||||
// Set new player ID.
|
||||
rs_base_playerid(base) = (player - players);
|
||||
}
|
||||
|
||||
static void ScalePart(mobj_t *part, mobj_t *base)
|
||||
{
|
||||
part->spritexscale = rs_base_xscale(base);
|
||||
part->spriteyscale = rs_base_yscale(base);
|
||||
|
||||
if (part->type == MT_TIREGRABBER)
|
||||
{
|
||||
part->spritexscale /= 2;
|
||||
part->spriteyscale /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void MovePart(mobj_t *part, mobj_t *base, mobj_t *refNipple)
|
||||
{
|
||||
P_MoveOrigin(
|
||||
part,
|
||||
refNipple->x + FixedMul(rs_part_xoffset(part), rs_base_xscale(base)),
|
||||
refNipple->y + FixedMul(rs_part_yoffset(part), rs_base_xscale(base)),
|
||||
part->z
|
||||
);
|
||||
}
|
||||
|
||||
static void ShowHidePart(mobj_t *part, mobj_t *base)
|
||||
{
|
||||
part->renderflags = (part->renderflags & ~RF_DONTDRAW) | (base->renderflags & RF_DONTDRAW);
|
||||
}
|
||||
|
||||
static fixed_t GetTireDist(mobj_t *base)
|
||||
{
|
||||
return -(RS_GRABBER_EXTRA + rs_base_grabberdist(base));
|
||||
}
|
||||
|
||||
static void MoveTire(mobj_t *part, mobj_t *base)
|
||||
{
|
||||
const fixed_t dis = FixedMul(GetTireDist(base), base->scale);
|
||||
const fixed_t c = FINECOSINE(part->angle >> ANGLETOFINESHIFT);
|
||||
const fixed_t s = FINESINE(part->angle >> ANGLETOFINESHIFT);
|
||||
P_MoveOrigin(
|
||||
part,
|
||||
base->x + FixedMul(dis, c),
|
||||
base->y + FixedMul(dis, s),
|
||||
part->z
|
||||
);
|
||||
}
|
||||
|
||||
// I've tried to reduce redundancy as much as I can,
|
||||
// but check K_SpawnRingShooter if you edit this
|
||||
static void UpdateRingShooterParts(mobj_t *mo)
|
||||
{
|
||||
mobj_t *part, *refNipple;
|
||||
|
||||
part = mo;
|
||||
while (!P_MobjWasRemoved(part->target))
|
||||
{
|
||||
part = part->target;
|
||||
ScalePart(part, mo);
|
||||
MoveTire(part, mo);
|
||||
}
|
||||
|
||||
part = mo;
|
||||
while (!P_MobjWasRemoved(part->hprev))
|
||||
{
|
||||
part = part->hprev;
|
||||
ScalePart(part, mo);
|
||||
}
|
||||
refNipple = part;
|
||||
|
||||
part = mo;
|
||||
while (!P_MobjWasRemoved(part->hnext))
|
||||
{
|
||||
part = part->hnext;
|
||||
MovePart(part, mo, refNipple);
|
||||
ScalePart(part, mo);
|
||||
}
|
||||
|
||||
part = mo->tracer;
|
||||
part->z = mo->z + FixedMul(refNipple->height, rs_base_yscale(mo));
|
||||
MovePart(part, mo, refNipple);
|
||||
ScalePart(part, mo);
|
||||
}
|
||||
|
||||
static void UpdateRingShooterPartsVisibility(mobj_t *mo)
|
||||
{
|
||||
mobj_t *part;
|
||||
|
||||
part = mo;
|
||||
while (!P_MobjWasRemoved(part->target))
|
||||
{
|
||||
part = part->target;
|
||||
ShowHidePart(part, mo);
|
||||
}
|
||||
|
||||
part = mo;
|
||||
while (!P_MobjWasRemoved(part->hprev))
|
||||
{
|
||||
part = part->hprev;
|
||||
ShowHidePart(part, mo);
|
||||
}
|
||||
|
||||
part = mo;
|
||||
while (!P_MobjWasRemoved(part->hnext))
|
||||
{
|
||||
part = part->hnext;
|
||||
ShowHidePart(part, mo);
|
||||
}
|
||||
|
||||
part = mo->tracer;
|
||||
ShowHidePart(part, mo);
|
||||
}
|
||||
|
||||
static void RingShooterCountdown(mobj_t *mo)
|
||||
{
|
||||
mobj_t *part = mo->tracer;
|
||||
|
||||
if (mo->reactiontime < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (--mo->reactiontime > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!P_MobjWasRemoved(part->tracer))
|
||||
{
|
||||
part = part->tracer;
|
||||
part->frame--;
|
||||
}
|
||||
|
||||
switch ((part->frame & FF_FRAMEMASK) - (part->state->frame & FF_FRAMEMASK))
|
||||
{
|
||||
case -1:
|
||||
{
|
||||
mo->reactiontime = -1;
|
||||
|
||||
if (rs_base_playerface(mo) >= 0 && rs_base_playerface(mo) < MAXPLAYERS)
|
||||
{
|
||||
if (playeringame[rs_base_playerface(mo)] == true)
|
||||
{
|
||||
player_t *player = &players[ rs_base_playerid(mo) ];
|
||||
part->skin = &skins[player->skin];
|
||||
}
|
||||
}
|
||||
|
||||
P_SetMobjState(part, S_RINGSHOOTER_FACE);
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
mo->reactiontime = TICRATE;
|
||||
S_StartSound(mo, mo->info->deathsound);
|
||||
|
||||
if (rs_base_playerid(mo) >= 0 && rs_base_playerid(mo) < MAXPLAYERS)
|
||||
{
|
||||
if (playeringame[rs_base_playerid(mo)] == true)
|
||||
{
|
||||
player_t *player = &players[ rs_base_playerid(mo) ];
|
||||
Obj_PlayerUsedRingShooter(mo, player);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
mo->reactiontime = TICRATE;
|
||||
S_StartSound(mo, mo->info->painsound);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void RingShooterFlicker(mobj_t *mo)
|
||||
{
|
||||
UINT32 trans;
|
||||
mobj_t *part = mo->tracer;
|
||||
|
||||
while (!P_MobjWasRemoved(part->tracer))
|
||||
{
|
||||
part = part->tracer;
|
||||
}
|
||||
|
||||
part->renderflags ^= RF_DONTDRAW;
|
||||
if (part->renderflags & RF_DONTDRAW)
|
||||
{
|
||||
trans = FF_TRANS50;
|
||||
}
|
||||
else
|
||||
{
|
||||
trans = 0;
|
||||
}
|
||||
part->target->frame = (part->target->frame & ~FF_TRANSMASK) | trans;
|
||||
}
|
||||
|
||||
static void ActivateRingShooter(mobj_t *mo)
|
||||
{
|
||||
mobj_t *part = mo->tracer;
|
||||
|
||||
while (!P_MobjWasRemoved(part->tracer))
|
||||
{
|
||||
part = part->tracer;
|
||||
part->renderflags &= ~RF_DONTDRAW;
|
||||
part->frame += 4;
|
||||
}
|
||||
|
||||
RingShooterCountdown(mo);
|
||||
}
|
||||
|
||||
static boolean RingShooterInit(mobj_t *mo)
|
||||
{
|
||||
if (rs_base_initstate(mo) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (rs_base_initstate(mo))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
rs_base_yscale(mo) += rs_base_scalespeed(mo);
|
||||
if (rs_base_yscale(mo) >= FRACUNIT)
|
||||
{
|
||||
//rs_base_xscale(mo) -= rs_base_scalespeed(mo);
|
||||
rs_base_initstate(mo)++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
rs_base_scalespeed(mo) -= FRACUNIT/5;
|
||||
rs_base_yscale(mo) += rs_base_scalespeed(mo);
|
||||
rs_base_xscale(mo) -= rs_base_scalespeed(mo);
|
||||
if (rs_base_yscale(mo) < 3*FRACUNIT/4)
|
||||
{
|
||||
rs_base_initstate(mo)++;
|
||||
rs_base_scalespeed(mo) = FRACUNIT >> 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
rs_base_yscale(mo) += rs_base_scalespeed(mo);
|
||||
rs_base_xscale(mo) -= rs_base_scalespeed(mo);
|
||||
if (rs_base_yscale(mo) >= FRACUNIT)
|
||||
{
|
||||
rs_base_initstate(mo)++;
|
||||
rs_base_xscale(mo) = rs_base_yscale(mo) = FRACUNIT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (rs_base_canceled(mo) != 0)
|
||||
{
|
||||
rs_base_initstate(mo) = -1;
|
||||
ActivateRingShooter(mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
rs_base_grabberdist(mo) -= RS_GRABBER_SLIDE;
|
||||
if (rs_base_grabberdist(mo) <= 0)
|
||||
{
|
||||
rs_base_initstate(mo) = -1;
|
||||
rs_base_grabberdist(mo) = 0;
|
||||
ActivateRingShooter(mo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
rs_base_initstate(mo) = 0; // fix invalid states
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateRingShooterParts(mo);
|
||||
return (rs_base_initstate(mo) != -1);
|
||||
}
|
||||
|
||||
boolean Obj_RingShooterThinker(mobj_t *mo)
|
||||
{
|
||||
if (RingShooterInit(mo) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mo->fuse > 0)
|
||||
{
|
||||
mo->fuse--;
|
||||
|
||||
if (mo->fuse == 0)
|
||||
{
|
||||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rs_base_canceled(mo) == 0)
|
||||
{
|
||||
rs_base_karted(mo) += RS_KARTED_INC;
|
||||
|
||||
if (P_MobjWasRemoved(mo->tracer) == false)
|
||||
{
|
||||
RingShooterCountdown(mo);
|
||||
}
|
||||
}
|
||||
|
||||
if (P_MobjWasRemoved(mo->tracer) == false)
|
||||
{
|
||||
RingShooterFlicker(mo);
|
||||
}
|
||||
|
||||
if (mo->fuse < RS_FUSE_BLINK)
|
||||
{
|
||||
if (leveltime & 1)
|
||||
{
|
||||
mo->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
mo->renderflags &= ~RF_DONTDRAW;
|
||||
}
|
||||
|
||||
UpdateRingShooterPartsVisibility(mo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Obj_PlayerUsedRingShooter(mobj_t *base, player_t *player)
|
||||
{
|
||||
const UINT8 playerID = player - players;
|
||||
if (playerID == rs_base_playerlast(base))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The original player should no longer have control over it,
|
||||
// if they are using it via releasing.
|
||||
RemoveRingShooterPointer(base);
|
||||
|
||||
// Respawn using the respawner's karted value.
|
||||
if (rs_base_karted(base) > 0)
|
||||
{
|
||||
player->airtime += rs_base_karted(base);
|
||||
}
|
||||
|
||||
player->respawn.fromRingShooter = true;
|
||||
K_DoIngameRespawn(player);
|
||||
|
||||
// Now other players can run into it!
|
||||
base->flags |= MF_SPECIAL;
|
||||
|
||||
// Reset the fuse so everyone can conga line :B
|
||||
if (base->fuse < RS_FUSE_TIME)
|
||||
{
|
||||
if (base->fuse < RS_FUSE_BLINK)
|
||||
{
|
||||
base->renderflags &= ~RF_DONTDRAW;
|
||||
UpdateRingShooterPartsVisibility(base);
|
||||
}
|
||||
|
||||
base->fuse = RS_FUSE_TIME;
|
||||
}
|
||||
|
||||
// Record the last person to use the ring shooter.
|
||||
rs_base_playerlast(base) = playerID;
|
||||
}
|
||||
|
||||
void Obj_RingShooterDelete(mobj_t *mo)
|
||||
{
|
||||
mobj_t *part;
|
||||
|
||||
RemoveRingShooterPointer(mo);
|
||||
|
||||
part = mo->target;
|
||||
while (P_MobjWasRemoved(part) == false)
|
||||
{
|
||||
mobj_t *delete = part;
|
||||
part = part->target;
|
||||
P_RemoveMobj(delete);
|
||||
}
|
||||
|
||||
part = mo->hprev;
|
||||
while (P_MobjWasRemoved(part) == false)
|
||||
{
|
||||
mobj_t *delete = part;
|
||||
part = part->hprev;
|
||||
P_RemoveMobj(delete);
|
||||
}
|
||||
|
||||
part = mo->hnext;
|
||||
while (P_MobjWasRemoved(part) == false)
|
||||
{
|
||||
mobj_t *delete = part;
|
||||
part = part->hnext;
|
||||
P_RemoveMobj(delete);
|
||||
}
|
||||
|
||||
part = mo->tracer;
|
||||
if (P_MobjWasRemoved(part) == false)
|
||||
{
|
||||
P_RemoveMobj(part);
|
||||
}
|
||||
}
|
||||
|
||||
// I've tried to reduce redundancy as much as I can,
|
||||
// but check P_UpdateRingShooterParts if you edit this
|
||||
static void SpawnRingShooter(player_t *player)
|
||||
{
|
||||
const fixed_t scale = 2*FRACUNIT;
|
||||
mobjinfo_t *info = &mobjinfo[MT_RINGSHOOTER_PART];
|
||||
mobj_t *mo = player->mo;
|
||||
mobj_t *base = P_SpawnMobj(mo->x, mo->y, mo->z, MT_RINGSHOOTER);
|
||||
mobj_t *part, *refNipple;
|
||||
UINT32 frameNum;
|
||||
angle_t angle;
|
||||
vector2_t offset;
|
||||
SINT8 i;
|
||||
|
||||
rs_base_playerid(base) = rs_base_playerlast(base) = -1;
|
||||
rs_base_karted(base) = -(RS_KARTED_INC * TICRATE); // wait for "3"
|
||||
rs_base_grabberdist(base) = RS_GRABBER_START;
|
||||
|
||||
K_FlipFromObject(base, mo);
|
||||
P_SetScale(base, base->destscale = FixedMul(base->destscale, scale));
|
||||
base->angle = mo->angle;
|
||||
base->scalespeed = FRACUNIT/2;
|
||||
base->extravalue1 = FRACUNIT; // horizontal scale
|
||||
base->extravalue2 = 0; // vertical scale
|
||||
base->fuse = RS_FUSE_TIME;
|
||||
|
||||
// the ring shooter object itself is invisible and acts as the thinker
|
||||
// each ring shooter uses four linked lists to keep track of its parts
|
||||
// the hprev chain stores the two NIPPLE BARS
|
||||
// the hnext chain stores the four sides of the box
|
||||
// the tracer chain stores the screen and the screen layers
|
||||
// the target chain stores the tire grabbers
|
||||
|
||||
// spawn the RING NIPPLES
|
||||
part = base;
|
||||
frameNum = 0;
|
||||
FV2_Load(&offset, -96*FRACUNIT, 160*FRACUNIT);
|
||||
FV2_Divide(&offset, scale);
|
||||
for (i = -1; i < 2; i += 2)
|
||||
{
|
||||
P_SetTarget(&part->hprev, P_SpawnMobjFromMobj(base,
|
||||
P_ReturnThrustX(NULL, base->angle - ANGLE_90, i*offset.x) + P_ReturnThrustX(NULL, base->angle, offset.y),
|
||||
P_ReturnThrustY(NULL, base->angle - ANGLE_90, i*offset.x) + P_ReturnThrustY(NULL, base->angle, offset.y),
|
||||
0, MT_RINGSHOOTER_PART));
|
||||
P_SetTarget(&part->hprev->hnext, part);
|
||||
part = part->hprev;
|
||||
P_SetTarget(&part->target, base);
|
||||
|
||||
part->angle = base->angle - i * ANGLE_45;
|
||||
P_SetMobjState(part, S_RINGSHOOTER_NIPPLES);
|
||||
part->frame += frameNum;
|
||||
part->flags |= MF_NOTHINK;
|
||||
part->old_spriteyscale = part->spriteyscale = 0;
|
||||
frameNum++;
|
||||
}
|
||||
refNipple = part; // keep the second ring nipple; its position will be referenced by the box
|
||||
|
||||
// spawn the box
|
||||
part = base;
|
||||
frameNum = 0;
|
||||
angle = base->angle + ANGLE_90;
|
||||
FV2_Load(&offset, offset.x - info->radius, offset.y - info->radius); // set the new origin to the centerpoint of the box
|
||||
FV2_Load(&offset,
|
||||
P_ReturnThrustX(NULL, base->angle - ANGLE_90, offset.x) + P_ReturnThrustX(NULL, base->angle, offset.y),
|
||||
P_ReturnThrustY(NULL, base->angle - ANGLE_90, offset.x) + P_ReturnThrustY(NULL, base->angle, offset.y)); // transform it relative to the base
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
P_SetTarget(&part->hnext, P_SpawnMobjFromMobj(base,
|
||||
offset.x + P_ReturnThrustX(NULL, angle, info->radius),
|
||||
offset.y + P_ReturnThrustY(NULL, angle, info->radius),
|
||||
0, MT_RINGSHOOTER_PART));
|
||||
P_SetTarget(&part->hnext->hprev, part);
|
||||
part = part->hnext;
|
||||
P_SetTarget(&part->target, base);
|
||||
|
||||
if (i == 2)
|
||||
frameNum++;
|
||||
frameNum ^= FF_HORIZONTALFLIP;
|
||||
angle -= ANGLE_90;
|
||||
part->angle = angle;
|
||||
part->frame += frameNum;
|
||||
part->extravalue1 = part->x - refNipple->x;
|
||||
part->extravalue2 = part->y - refNipple->y;
|
||||
part->flags |= MF_NOTHINK;
|
||||
part->old_spriteyscale = part->spriteyscale = 0;
|
||||
}
|
||||
|
||||
// spawn the screen
|
||||
part = P_SpawnMobjFromMobj(base, offset.x, offset.y, 0, MT_RINGSHOOTER_SCREEN);
|
||||
P_SetTarget(&base->tracer, part);
|
||||
P_SetTarget(&part->target, base);
|
||||
part->angle = base->angle - ANGLE_45;
|
||||
part->extravalue1 = part->x - refNipple->x;
|
||||
part->extravalue2 = part->y - refNipple->y;
|
||||
part->flags |= MF_NOTHINK;
|
||||
part->old_spriteyscale = part->spriteyscale = 0;
|
||||
|
||||
// spawn the screen numbers
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
P_SetTarget(&part->tracer, P_SpawnMobjFromMobj(part, 0, 0, 0, MT_OVERLAY));
|
||||
P_SetTarget(&part->tracer->target, part);
|
||||
part = part->tracer;
|
||||
part->angle = part->target->angle;
|
||||
P_SetMobjState(part, S_RINGSHOOTER_NUMBERBACK + i);
|
||||
part->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
|
||||
P_SetTarget(&part->hprev, base);
|
||||
|
||||
// spawn the grabbers
|
||||
part = base;
|
||||
angle = base->angle + ANGLE_45;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
const fixed_t dis = GetTireDist(base);
|
||||
P_SetTarget(
|
||||
&part->target,
|
||||
P_SpawnMobjFromMobj(
|
||||
base,
|
||||
P_ReturnThrustX(NULL, angle, dis),
|
||||
P_ReturnThrustY(NULL, angle, dis),
|
||||
0,
|
||||
MT_TIREGRABBER
|
||||
)
|
||||
);
|
||||
part = part->target;
|
||||
P_SetTarget(&part->tracer, base);
|
||||
|
||||
angle -= ANGLE_90;
|
||||
part->angle = angle;
|
||||
part->extravalue1 = part->extravalue2 = 0;
|
||||
part->old_spriteyscale = part->spriteyscale = 0;
|
||||
}
|
||||
|
||||
ChangeRingShooterPointer(base, player);
|
||||
rs_base_playerface(base) = (player - players);
|
||||
}
|
||||
|
||||
static boolean AllowRingShooter(player_t *player)
|
||||
{
|
||||
const fixed_t minSpeed = 6 * player->mo->scale;
|
||||
|
||||
if (/*(gametyperules & GTR_CIRCUIT) &&*/ leveltime < starttime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->respawn.state != RESPAWNST_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->drift == 0
|
||||
&& player->justbumped == 0
|
||||
&& player->spindashboost == 0
|
||||
&& player->nocontrol == 0
|
||||
&& player->fastfall == 0
|
||||
&& player->speed < minSpeed
|
||||
&& P_PlayerInPain(player) == false
|
||||
&& P_IsObjectOnGround(player->mo) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean Obj_PlayerRingShooterFreeze(player_t *const player)
|
||||
{
|
||||
mobj_t *const base = player->ringShooter;
|
||||
|
||||
if (AllowRingShooter(player) == true
|
||||
&& (player->cmd.buttons & BT_RESPAWN) == BT_RESPAWN
|
||||
&& P_MobjWasRemoved(base) == false)
|
||||
{
|
||||
return (rs_base_canceled(base) == 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Obj_RingShooterInput(player_t *player)
|
||||
{
|
||||
mobj_t *const base = player->ringShooter;
|
||||
|
||||
if (AllowRingShooter(player) == true
|
||||
&& (player->cmd.buttons & BT_RESPAWN) == BT_RESPAWN)
|
||||
{
|
||||
if (P_MobjWasRemoved(base) == true)
|
||||
{
|
||||
SpawnRingShooter(player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rs_base_canceled(base) == 0)
|
||||
{
|
||||
player->mo->momx = player->mo->momy = 0;
|
||||
P_SetPlayerAngle(player, base->angle);
|
||||
fixed_t setz;
|
||||
|
||||
if (base->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
setz = base->z + base->height - player->mo->height;
|
||||
setz = max(setz, player->mo->z);
|
||||
}
|
||||
else
|
||||
{
|
||||
setz = min(player->mo->z, base->z);
|
||||
}
|
||||
|
||||
P_MoveOrigin(
|
||||
player->mo,
|
||||
base->x, base->y,
|
||||
setz
|
||||
);
|
||||
player->fastfall = 0;
|
||||
|
||||
if (base->fuse < RS_FUSE_TIME)
|
||||
{
|
||||
if (base->fuse < RS_FUSE_BLINK)
|
||||
{
|
||||
base->renderflags &= ~RF_DONTDRAW;
|
||||
UpdateRingShooterPartsVisibility(base);
|
||||
}
|
||||
|
||||
base->fuse = RS_FUSE_TIME;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (P_MobjWasRemoved(base) == false)
|
||||
{
|
||||
if (rs_base_initstate(base) != -1)
|
||||
{
|
||||
// We released during the intro animation.
|
||||
// Cancel it entirely, prevent another one being created for a bit.
|
||||
rs_base_canceled(base) = 1;
|
||||
|
||||
if (base->fuse > RS_FUSE_BLINK)
|
||||
{
|
||||
base->fuse = RS_FUSE_BLINK;
|
||||
}
|
||||
}
|
||||
else if (rs_base_canceled(base) == 0)
|
||||
{
|
||||
// We released during the countdown.
|
||||
// We activate with the current karted timer on the ring shooter.
|
||||
Obj_PlayerUsedRingShooter(base, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_UpdateRingShooterFace(mobj_t *part)
|
||||
{
|
||||
mobj_t *const base = part->hprev;
|
||||
player_t *player = NULL;
|
||||
|
||||
if (P_MobjWasRemoved(base) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (rs_base_playerface(base) < 0 || rs_base_playerface(base) >= MAXPLAYERS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (playeringame[ rs_base_playerface(base) ] == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
player = &players[ rs_base_playerface(base) ];
|
||||
|
||||
// it's a good idea to set the actor's skin *before* it uses this action,
|
||||
// but just in case, if it doesn't have the player's skin, set its skin then call the state again to get the correct sprite
|
||||
if (part->skin != &skins[player->skin])
|
||||
{
|
||||
part->skin = &skins[player->skin];
|
||||
P_SetMobjState(part, (statenum_t)(part->state - states));
|
||||
return;
|
||||
}
|
||||
|
||||
// okay, now steal the player's color nyehehehe
|
||||
part->color = player->skincolor;
|
||||
|
||||
// set the frame to the WANTED pic
|
||||
part->frame = (part->frame & ~FF_FRAMEMASK) | FACE_WANTED;
|
||||
|
||||
// set the threshold overlay flags
|
||||
part->threshold = (OV_DONTXYSCALE|OV_DONTSCREENOFFSET);
|
||||
|
||||
// we're going to assume the character's WANTED icon is 32 x 32
|
||||
// let's squish the sprite a bit so that it matches the dimensions of the screen's sprite, which is 26 x 22
|
||||
// (TODO: maybe get the dimensions/offsets from the patches themselves?)
|
||||
part->spritexscale = FixedDiv(26*FRACUNIT, 32*FRACUNIT);
|
||||
part->spriteyscale = FixedDiv(22*FRACUNIT, 32*FRACUNIT);
|
||||
|
||||
// a normal WANTED icon should have (0, 0) offsets
|
||||
// so let's offset it such that it will match the position of the screen's sprite
|
||||
part->spritexoffset = 16*FRACUNIT; // 32 / 2
|
||||
part->spriteyoffset = 28*FRACUNIT + FixedDiv(11*FRACUNIT, part->spriteyscale); // 32 - 4 (generic monster bottom) + 11 (vertical offset of screen sprite from the bottom)
|
||||
}
|
||||
|
|
@ -330,6 +330,7 @@ void A_MementosTPParticles(mobj_t *actor);
|
|||
void A_FlameShieldPaper(mobj_t *actor);
|
||||
void A_InvincSparkleRotate(mobj_t *actor);
|
||||
void A_SpawnItemDebrisCloud(mobj_t *actor);
|
||||
void A_RingShooterFace(mobj_t *actor);
|
||||
|
||||
//for p_enemy.c
|
||||
|
||||
|
|
@ -13810,3 +13811,15 @@ A_SpawnItemDebrisCloud (mobj_t *actor)
|
|||
puff->momz += FixedMul(target->momz, fade);
|
||||
}
|
||||
}
|
||||
|
||||
// sets the actor's
|
||||
// vars do nothing
|
||||
void A_RingShooterFace(mobj_t *actor)
|
||||
{
|
||||
if (LUA_CallAction(A_RINGSHOOTERFACE, actor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Obj_UpdateRingShooterFace(actor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -580,6 +580,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
Obj_LoopEndpointCollide(special, toucher);
|
||||
return;
|
||||
|
||||
case MT_RINGSHOOTER:
|
||||
Obj_PlayerUsedRingShooter(special, player);
|
||||
return;
|
||||
|
||||
default: // SOC or script pickup
|
||||
P_SetTarget(&special->target, toucher);
|
||||
break;
|
||||
|
|
|
|||
87
src/p_mobj.c
87
src/p_mobj.c
|
|
@ -1878,7 +1878,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
FIXED_TO_FLOAT(AngleFixed(oldangle-newangle))
|
||||
);
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
else if (predictedz - mo->z > abs(slopemom.z / 2))
|
||||
{
|
||||
|
|
@ -6641,6 +6641,12 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->momz = newz - mobj->z;
|
||||
}
|
||||
break;
|
||||
case MT_RINGSHOOTER:
|
||||
if (Obj_RingShooterThinker(mobj) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MT_SPINDASHWIND:
|
||||
case MT_DRIFTELECTRICSPARK:
|
||||
mobj->renderflags ^= RF_DONTDRAW;
|
||||
|
|
@ -10399,7 +10405,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
|
||||
if (type == MT_NULL)
|
||||
{
|
||||
#if 0
|
||||
#if 0
|
||||
#ifdef PARANOIA
|
||||
I_Error("Tried to spawn MT_NULL\n");
|
||||
#endif
|
||||
|
|
@ -11140,26 +11146,10 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
iquetail = (iquetail+1)&(ITEMQUESIZE-1);
|
||||
}
|
||||
|
||||
if (mobj->type == MT_KARMAHITBOX) // Remove linked list objects for certain types
|
||||
{
|
||||
mobj_t *cur = mobj->hnext;
|
||||
|
||||
while (cur && !P_MobjWasRemoved(cur))
|
||||
{
|
||||
mobj_t *prev = cur; // Kind of a dumb var, but we need to set cur before we remove the mobj
|
||||
cur = cur->hnext;
|
||||
P_RemoveMobj(prev);
|
||||
}
|
||||
}
|
||||
|
||||
if (mobj->type == MT_OVERLAY)
|
||||
P_RemoveOverlay(mobj);
|
||||
|
||||
if (mobj->type == MT_SPB)
|
||||
spbplace = -1;
|
||||
|
||||
if (P_IsTrackerType(mobj->type))
|
||||
{
|
||||
P_RemoveTracker(mobj);
|
||||
}
|
||||
|
||||
if (mobj->player && mobj->player->followmobj)
|
||||
{
|
||||
|
|
@ -11167,19 +11157,56 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
P_SetTarget(&mobj->player->followmobj, NULL);
|
||||
}
|
||||
|
||||
if (mobj->type == MT_SHRINK_POHBEE)
|
||||
// Remove linked list objects for certain types
|
||||
switch (mobj->type)
|
||||
{
|
||||
Obj_PohbeeRemoved(mobj);
|
||||
}
|
||||
case MT_KARMAHITBOX:
|
||||
{
|
||||
mobj_t *cur = mobj->hnext;
|
||||
|
||||
if (mobj->type == MT_SHRINK_GUN)
|
||||
{
|
||||
Obj_ShrinkGunRemoved(mobj);
|
||||
}
|
||||
while (cur && !P_MobjWasRemoved(cur))
|
||||
{
|
||||
mobj_t *prev = cur; // Kind of a dumb var, but we need to set cur before we remove the mobj
|
||||
cur = cur->hnext;
|
||||
P_RemoveMobj(prev);
|
||||
}
|
||||
|
||||
if (mobj->type == MT_SPECIAL_UFO_PIECE)
|
||||
{
|
||||
Obj_UFOPieceRemoved(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_OVERLAY:
|
||||
{
|
||||
P_RemoveOverlay(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_SPB:
|
||||
{
|
||||
spbplace = -1;
|
||||
break;
|
||||
}
|
||||
case MT_SHRINK_POHBEE:
|
||||
{
|
||||
Obj_PohbeeRemoved(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_SHRINK_GUN:
|
||||
{
|
||||
Obj_ShrinkGunRemoved(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_SPECIAL_UFO_PIECE:
|
||||
{
|
||||
Obj_UFOPieceRemoved(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_RINGSHOOTER:
|
||||
{
|
||||
Obj_RingShooterDelete(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mobj->health = 0; // Just because
|
||||
|
|
|
|||
|
|
@ -63,14 +63,15 @@ savedata_t savedata;
|
|||
// than an UINT16
|
||||
typedef enum
|
||||
{
|
||||
AWAYVIEW = 0x01,
|
||||
FOLLOWITEM = 0x02,
|
||||
FOLLOWER = 0x04,
|
||||
SKYBOXVIEW = 0x08,
|
||||
SKYBOXCENTER = 0x10,
|
||||
HOVERHYUDORO = 0x20,
|
||||
STUMBLE = 0x40,
|
||||
SLIPTIDEZIP = 0x80
|
||||
AWAYVIEW = 0x0001,
|
||||
FOLLOWITEM = 0x0002,
|
||||
FOLLOWER = 0x0004,
|
||||
SKYBOXVIEW = 0x0008,
|
||||
SKYBOXCENTER = 0x0010,
|
||||
HOVERHYUDORO = 0x0020,
|
||||
STUMBLE = 0x0040,
|
||||
SLIPTIDEZIP = 0x0080,
|
||||
RINGSHOOTER = 0x0100
|
||||
} player_saveflags;
|
||||
|
||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||
|
|
@ -217,6 +218,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (players[i].sliptideZipIndicator)
|
||||
flags |= SLIPTIDEZIP;
|
||||
|
||||
if (players[i].ringShooter)
|
||||
flags |= RINGSHOOTER;
|
||||
|
||||
WRITEUINT16(save->p, flags);
|
||||
|
||||
if (flags & SKYBOXVIEW)
|
||||
|
|
@ -240,6 +244,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (flags & SLIPTIDEZIP)
|
||||
WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum);
|
||||
|
||||
if (flags & RINGSHOOTER)
|
||||
WRITEUINT32(save->p, players[i].ringShooter->mobjnum);
|
||||
|
||||
WRITEUINT32(save->p, (UINT32)players[i].followitem);
|
||||
|
||||
WRITEUINT32(save->p, players[i].charflags);
|
||||
|
|
@ -613,6 +620,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
if (flags & SLIPTIDEZIP)
|
||||
players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & RINGSHOOTER)
|
||||
players[i].ringShooter = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
players[i].followitem = (mobjtype_t)READUINT32(save->p);
|
||||
|
||||
//SetPlayerSkinByNum(i, players[i].skin);
|
||||
|
|
@ -4823,6 +4833,13 @@ static void P_RelinkPointers(void)
|
|||
if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].ringShooter)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].ringShooter;
|
||||
players[i].ringShooter = NULL;
|
||||
if (!P_SetTarget(&players[i].ringShooter, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "ringShooter not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue