mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-08 22:56:00 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into tutorial-pass
This commit is contained in:
commit
6c7a1c14e5
58 changed files with 2392 additions and 342 deletions
|
|
@ -50,6 +50,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
p_floor.c
|
||||
p_inter.c
|
||||
p_lights.c
|
||||
p_link.cpp
|
||||
p_loop.c
|
||||
p_map.c
|
||||
p_mapthing.cpp
|
||||
|
|
@ -600,7 +601,8 @@ if((CMAKE_COMPILER_IS_GNUCC) AND NOT ("${CMAKE_SYSTEM_NAME}" MATCHES Darwin))
|
|||
message(STATUS "Will make separate debug symbols in *.debug")
|
||||
add_custom_command(TARGET SRB2SDL2 POST_BUILD
|
||||
COMMAND ${OBJCOPY} ${OBJCOPY_ONLY_KEEP_DEBUG} $<TARGET_FILE:SRB2SDL2> $<TARGET_FILE:SRB2SDL2>.debug
|
||||
COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:SRB2SDL2>
|
||||
# mold linker: .gnu_debuglink is present by default, so --add-gnu-debuglink would fail
|
||||
COMMAND ${OBJCOPY} --strip-debug --remove-section=.gnu_debuglink $<TARGET_FILE:SRB2SDL2>
|
||||
COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE:SRB2SDL2>.debug $<TARGET_FILE:SRB2SDL2>
|
||||
)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -214,7 +214,12 @@ optional<SoundChunk> try_load_gme(tcb::span<std::byte> data)
|
|||
|
||||
optional<SoundChunk> srb2::audio::try_load_chunk(tcb::span<std::byte> data)
|
||||
{
|
||||
optional<SoundChunk> ret;
|
||||
optional<SoundChunk> ret = nullopt;
|
||||
|
||||
if (data.size() == 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = try_load_dmx(data);
|
||||
if (ret)
|
||||
|
|
@ -232,5 +237,5 @@ optional<SoundChunk> srb2::audio::try_load_chunk(tcb::span<std::byte> data)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return nullopt;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2190,9 +2190,9 @@ void D_MapChange(UINT16 mapnum, INT32 newgametype, boolean pencoremode, boolean
|
|||
}
|
||||
}
|
||||
|
||||
void D_SetupVote(void)
|
||||
void D_SetupVote(INT16 newgametype)
|
||||
{
|
||||
UINT8 buf[(VOTE_NUM_LEVELS * 2) + 2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes
|
||||
UINT8 buf[(VOTE_NUM_LEVELS * 2) + 4];
|
||||
UINT8 *p = buf;
|
||||
|
||||
INT32 i;
|
||||
|
|
@ -2200,13 +2200,14 @@ void D_SetupVote(void)
|
|||
UINT16 votebuffer[VOTE_NUM_LEVELS + 1];
|
||||
memset(votebuffer, UINT16_MAX, sizeof(votebuffer));
|
||||
|
||||
WRITEINT16(p, newgametype);
|
||||
WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE)));
|
||||
WRITEUINT8(p, G_SometimesGetDifferentEncore());
|
||||
|
||||
for (i = 0; i < VOTE_NUM_LEVELS; i++)
|
||||
{
|
||||
UINT16 m = G_RandMap(
|
||||
G_TOLFlag(gametype),
|
||||
G_TOLFlag(newgametype),
|
||||
prevmap, false,
|
||||
(i < VOTE_NUM_LEVELS-1),
|
||||
votebuffer
|
||||
|
|
@ -5305,6 +5306,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
|
|||
|
||||
static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
INT16 newGametype = 0;
|
||||
boolean baseEncore = false;
|
||||
boolean optionalEncore = false;
|
||||
INT16 tempVoteLevels[VOTE_NUM_LEVELS][2];
|
||||
|
|
@ -5320,6 +5322,7 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
}
|
||||
|
||||
newGametype = READINT16(*cp);
|
||||
baseEncore = (boolean)READUINT8(*cp);
|
||||
optionalEncore = (boolean)READUINT8(*cp);
|
||||
|
||||
|
|
@ -5329,6 +5332,17 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
baseEncore = optionalEncore = false;
|
||||
}
|
||||
|
||||
if (newGametype < 0 || newGametype >= numgametypes)
|
||||
{
|
||||
if (server)
|
||||
{
|
||||
I_Error("Got_SetupVotecmd: Gametype %d out of range (numgametypes = %d)", newGametype, numgametypes);
|
||||
}
|
||||
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad gametype %d received from %s\n"), newGametype, player_names[playernum]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < VOTE_NUM_LEVELS; i++)
|
||||
{
|
||||
tempVoteLevels[i][0] = (UINT16)READUINT16(*cp);
|
||||
|
|
@ -5348,6 +5362,12 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
}
|
||||
|
||||
{
|
||||
INT16 oldGametype = gametype;
|
||||
G_SetGametype(newGametype);
|
||||
D_GameTypeChanged(oldGametype);
|
||||
}
|
||||
|
||||
if (optionalEncore == true)
|
||||
{
|
||||
tempVoteLevels[VOTE_NUM_LEVELS - 1][1] ^= VOTE_MOD_ENCORE;
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ void Command_Retry_f(void);
|
|||
boolean G_GamestateUsesExitLevel(void);
|
||||
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
|
||||
void D_MapChange(UINT16 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pforcespecialstage);
|
||||
void D_SetupVote(void);
|
||||
void D_SetupVote(INT16 newgametype);
|
||||
void D_ModifyClientVote(UINT8 player, SINT8 voted);
|
||||
void D_PickVote(void);
|
||||
void ObjectPlace_OnChange(void);
|
||||
|
|
|
|||
|
|
@ -431,6 +431,11 @@ static inline int lib_getenum(lua_State *L)
|
|||
}
|
||||
else if (fastncmp("S_",word,2)) {
|
||||
p = word+2;
|
||||
if (fastcmp(p, "FIRSTFREESLOT"))
|
||||
{
|
||||
lua_pushinteger(L, S_FIRSTFREESLOT);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < NUMSTATEFREESLOTS; i++) {
|
||||
if (!FREE_STATES[i])
|
||||
break;
|
||||
|
|
@ -448,6 +453,11 @@ static inline int lib_getenum(lua_State *L)
|
|||
}
|
||||
else if (fastncmp("MT_",word,3)) {
|
||||
p = word+3;
|
||||
if (fastcmp(p, "FIRSTFREESLOT"))
|
||||
{
|
||||
lua_pushinteger(L, MT_FIRSTFREESLOT);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < NUMMOBJFREESLOTS; i++) {
|
||||
if (!FREE_MOBJS[i])
|
||||
break;
|
||||
|
|
@ -465,6 +475,11 @@ static inline int lib_getenum(lua_State *L)
|
|||
}
|
||||
else if (fastncmp("SPR_",word,4)) {
|
||||
p = word+4;
|
||||
if (fastcmp(p, "FIRSTFREESLOT"))
|
||||
{
|
||||
lua_pushinteger(L, SPR_FIRSTFREESLOT);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < NUMSPRITES; i++)
|
||||
if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
|
||||
lua_pushinteger(L, i);
|
||||
|
|
|
|||
|
|
@ -4831,6 +4831,39 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
|
||||
// MT_IVOBALL
|
||||
"S_IVOBALL",
|
||||
|
||||
"S_SA2_CRATE_DEBRIS",
|
||||
"S_SA2_CRATE_DEBRIS_E",
|
||||
"S_SA2_CRATE_DEBRIS_F",
|
||||
"S_SA2_CRATE_DEBRIS_G",
|
||||
"S_SA2_CRATE_DEBRIS_H",
|
||||
"S_SA2_CRATE_DEBRIS_METAL",
|
||||
|
||||
"S_ICECAPBLOCK_DEBRIS",
|
||||
"S_ICECAPBLOCK_DEBRIS_C",
|
||||
"S_ICECAPBLOCK_DEBRIS_D",
|
||||
"S_ICECAPBLOCK_DEBRIS_E",
|
||||
"S_ICECAPBLOCK_DEBRIS_F",
|
||||
|
||||
// MT_SPEAR
|
||||
"S_SPEAR_ROD",
|
||||
"S_SPEAR_TIP",
|
||||
"S_SPEAR_HILT_FRONT",
|
||||
"S_SPEAR_HILT_BACK",
|
||||
"S_SPEAR_WALL",
|
||||
|
||||
// MT_BSZLAMP_S
|
||||
"S_BLMS",
|
||||
"S_BLMM",
|
||||
"S_BLML",
|
||||
|
||||
// MT_BSZSLAMP
|
||||
"S_BSWL",
|
||||
"S_BSWC",
|
||||
|
||||
"S_BETA_PARTICLE_WHEEL",
|
||||
"S_BETA_PARTICLE_ICON",
|
||||
"S_BETA_PARTICLE_EXPLOSION",
|
||||
};
|
||||
|
||||
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
|
||||
|
|
@ -6057,6 +6090,24 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_IVOBALL",
|
||||
"MT_PATROLIVOBALL",
|
||||
"MT_AIRIVOBALL",
|
||||
|
||||
"MT_BOX_SIDE",
|
||||
"MT_BOX_DEBRIS",
|
||||
"MT_SA2_CRATE",
|
||||
"MT_ICECAPBLOCK",
|
||||
|
||||
"MT_SPEAR",
|
||||
"MT_SPEARVISUAL",
|
||||
"MT_BSZLAMP_S",
|
||||
"MT_BSZLAMP_M",
|
||||
"MT_BSZLAMP_L",
|
||||
"MT_BSZSLAMP",
|
||||
"MT_BSZSLCHA",
|
||||
|
||||
"MT_BETA_EMITTER",
|
||||
"MT_BETA_PARTICLE_PHYSICAL",
|
||||
"MT_BETA_PARTICLE_VISUAL",
|
||||
"MT_BETA_PARTICLE_EXPLOSION",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ extern "C" {
|
|||
|
||||
// Selected by user.
|
||||
extern INT16 gamemap;
|
||||
extern boolean g_reloadingMap;
|
||||
extern char mapmusname[7];
|
||||
extern UINT16 mapmusflags;
|
||||
extern UINT32 mapmusposition;
|
||||
extern UINT32 mapmusresume;
|
||||
extern UINT8 mapmusrng;
|
||||
|
|
|
|||
|
|
@ -1536,6 +1536,7 @@ void F_StartTitleScreen(void)
|
|||
gamestate_t prevwipegamestate = wipegamestate;
|
||||
titlemapinaction = true;
|
||||
gamemap = titleMapNum+1;
|
||||
g_reloadingMap = false;
|
||||
|
||||
G_DoLoadLevelEx(true, GS_TITLESCREEN);
|
||||
if (!titlemap)
|
||||
|
|
@ -1576,6 +1577,7 @@ void F_StartTitleScreen(void)
|
|||
G_SetGamestate(GS_TITLESCREEN);
|
||||
titlemapinaction = false;
|
||||
gamemap = 1; // g_game.c
|
||||
g_reloadingMap = false;
|
||||
CON_ClearHUD();
|
||||
}
|
||||
|
||||
|
|
|
|||
14
src/g_game.c
14
src/g_game.c
|
|
@ -105,12 +105,12 @@ static void G_DoWorldDone(void);
|
|||
static void G_DoStartVote(void);
|
||||
|
||||
char mapmusname[7]; // Music name
|
||||
UINT16 mapmusflags; // Track and reset bit
|
||||
UINT32 mapmusposition; // Position to jump to
|
||||
UINT32 mapmusresume;
|
||||
UINT8 mapmusrng; // Random selection result
|
||||
|
||||
INT16 gamemap = 1;
|
||||
INT16 gamemap = 0;
|
||||
boolean g_reloadingMap;
|
||||
UINT32 maptol;
|
||||
|
||||
preciptype_t globalweather = PRECIP_NONE;
|
||||
|
|
@ -3062,7 +3062,7 @@ static gametype_t defaultgametypes[] =
|
|||
{
|
||||
"Special",
|
||||
"GT_SPECIAL",
|
||||
GTR_CATCHER|GTR_SPECIALSTART|GTR_ROLLINGSTART|GTR_CIRCUIT,
|
||||
GTR_CATCHER|GTR_SPECIALSTART|GTR_ROLLINGSTART|GTR_CIRCUIT|GTR_NOPOSITION,
|
||||
TOL_SPECIAL,
|
||||
int_time,
|
||||
0,
|
||||
|
|
@ -3152,7 +3152,7 @@ INT32 G_GuessGametypeByTOL(UINT32 tol)
|
|||
//
|
||||
void G_SetGametype(INT16 gtype)
|
||||
{
|
||||
if (gtype < 0 || gtype > numgametypes)
|
||||
if (gtype < 0 || gtype >= numgametypes)
|
||||
{
|
||||
I_Error("G_SetGametype: Bad gametype change %d (was %d/\"%s\")", gtype, gametype, gametypes[gametype]->name);
|
||||
}
|
||||
|
|
@ -4385,7 +4385,7 @@ static void G_DoStartVote(void)
|
|||
{
|
||||
if (gamestate == GS_VOTING)
|
||||
I_Error("G_DoStartVote: NEXTMAP_VOTING causes recursive vote!");
|
||||
D_SetupVote();
|
||||
D_SetupVote(gametype);
|
||||
}
|
||||
gameaction = ga_nothing;
|
||||
}
|
||||
|
|
@ -5930,11 +5930,9 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
|||
}
|
||||
}
|
||||
|
||||
g_reloadingMap = (map == gamemap);
|
||||
gamemap = map;
|
||||
|
||||
// Don't carry over custom music change to another map.
|
||||
mapmusflags |= MUSIC_RELOADRESET;
|
||||
|
||||
automapactive = false;
|
||||
imcontinuing = false;
|
||||
|
||||
|
|
|
|||
455
src/info.c
455
src/info.c
|
|
@ -986,6 +986,21 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"FBTN",
|
||||
"SFTR",
|
||||
|
||||
"SABX",
|
||||
"ICBL",
|
||||
|
||||
"BSSP",
|
||||
"BSPB",
|
||||
"BSPR",
|
||||
"BSSR",
|
||||
"BLMS",
|
||||
"BLMM",
|
||||
"BLML",
|
||||
"BSWL",
|
||||
"BSWC",
|
||||
|
||||
"LCLA",
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
"VIEW",
|
||||
};
|
||||
|
|
@ -5677,6 +5692,39 @@ state_t states[NUMSTATES] =
|
|||
|
||||
// MT_IVOBALL
|
||||
{SPR_BSPH, 2|FF_SEMIBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_IVOBALL
|
||||
|
||||
{SPR_UNKN, FF_FULLBRIGHT, -1, {A_RandomStateRange}, S_SA2_CRATE_DEBRIS_E, S_SA2_CRATE_DEBRIS_H, S_NULL}, // S_SA2_CRATE_DEBRIS
|
||||
{SPR_SABX, 4, 70, {NULL}, 0, 0, S_NULL}, // S_SA2_CRATE_DEBRIS_E
|
||||
{SPR_SABX, 5, 70, {NULL}, 0, 0, S_NULL}, // S_SA2_CRATE_DEBRIS_F
|
||||
{SPR_SABX, 6, 70, {NULL}, 0, 0, S_NULL}, // S_SA2_CRATE_DEBRIS_G
|
||||
{SPR_SABX, 7, 70, {NULL}, 0, 0, S_NULL}, // S_SA2_CRATE_DEBRIS_H
|
||||
{SPR_SABX, 12, 70, {NULL}, 0, 0, S_NULL}, // S_SA2_CRATE_DEBRIS_METAL
|
||||
|
||||
{SPR_UNKN, FF_FULLBRIGHT, -1, {A_RandomStateRange}, S_ICECAPBLOCK_DEBRIS_C, S_ICECAPBLOCK_DEBRIS_F, S_NULL}, // S_ICECAPBLOCK_DEBRIS
|
||||
{SPR_ICBL, 2, 70, {NULL}, 0, 0, S_NULL}, // S_ICECAPBLOCK_DEBRIS_C
|
||||
{SPR_ICBL, 3, 70, {NULL}, 0, 0, S_NULL}, // S_ICECAPBLOCK_DEBRIS_D
|
||||
{SPR_ICBL, 4, 70, {NULL}, 0, 0, S_NULL}, // S_ICECAPBLOCK_DEBRIS_E
|
||||
{SPR_ICBL, 5, 70, {NULL}, 0, 0, S_NULL}, // S_ICECAPBLOCK_DEBRIS_F
|
||||
|
||||
// MT_SPEAR
|
||||
{SPR_BSSP, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPEAR_ROD
|
||||
{SPR_BSSP, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPEAR_TIP
|
||||
{SPR_BSPR, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPEAR_HILT_FRONT
|
||||
{SPR_BSPB, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPEAR_HILT_BACK
|
||||
{SPR_BSSR, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPEAR_WALL
|
||||
|
||||
// MT_BSZLAMP_S
|
||||
{SPR_BLMS, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLMS
|
||||
{SPR_BLMM, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLMM
|
||||
{SPR_BLML, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLML
|
||||
|
||||
// MT_BSZSLAMP
|
||||
{SPR_BSWL, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BSWL
|
||||
{SPR_BSWC, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BSWC
|
||||
|
||||
{SPR_LCLA, 0|FF_FULLBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BETA_PARTICLE_WHEEL
|
||||
{SPR_LCLA, 1|FF_FULLBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BETA_PARTICLE_ICON
|
||||
{SPR_LCLA, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BETA_PARTICLE_EXPLOSION
|
||||
};
|
||||
|
||||
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||
|
|
@ -24855,7 +24903,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
16, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -24882,7 +24930,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
16, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SOLID|MF_NOCLIP|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
MF_SOLID|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -24909,7 +24957,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
16, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -24936,7 +24984,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -24963,7 +25011,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -30257,7 +30305,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags
|
||||
MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_DONTPUNT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -30632,8 +30680,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
0, // radius
|
||||
0, // height
|
||||
40*FRACUNIT, // radius
|
||||
80*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
1, // damage
|
||||
|
|
@ -32200,6 +32248,397 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_SCENERY|MF_SPECIAL|MF_NOGRAVITY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BOX_SIDE
|
||||
-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
|
||||
80*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOCLIPTHING, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BOX_DEBRIS
|
||||
-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
|
||||
0*FRACUNIT, // radius
|
||||
0*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOCLIPTHING, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_SA2_CRATE
|
||||
2529, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1, // 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
|
||||
80*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_SCENERY|MF_DONTPUNT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_ICECAPBLOCK
|
||||
3750, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1, // 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
|
||||
80*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_SCENERY|MF_DONTPUNT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SPEAR
|
||||
3450, // doomednum
|
||||
S_SPEAR_ROD, // 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
|
||||
80*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION|MF_SCENERY|MF_NOHITLAGFORME, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_SPEARVISUAL
|
||||
-1, // doomednum
|
||||
S_UNKNOWN, // 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
|
||||
1*FRACUNIT, // radius
|
||||
1*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIPHEIGHT|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BSZLAMP_S
|
||||
3452, // doomednum
|
||||
S_BLMS, // spawnstate
|
||||
1, // 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, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
0, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BSZLAMP_M
|
||||
3453, // doomednum
|
||||
S_BLMM, // spawnstate
|
||||
1, // 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, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
0, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BSZLAMP_L
|
||||
3454, // doomednum
|
||||
S_BLML, // spawnstate
|
||||
1, // 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, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
0, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BSZSLAMP
|
||||
3469, // doomednum
|
||||
S_BSWL, // spawnstate
|
||||
1, // 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
|
||||
128*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
0, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BSZSLCHA
|
||||
3470, // doomednum
|
||||
S_BSWC, // spawnstate
|
||||
1, // 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
|
||||
128*FRACUNIT, // radius
|
||||
128*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
0, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BETA_EMITTER
|
||||
2699, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1, // 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
|
||||
0, // radius
|
||||
0, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOSECTOR|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BETA_PARTICLE_PHYSICAL
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1, // 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
|
||||
24*FRACUNIT, // radius
|
||||
128*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_NOGRAVITY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BETA_PARTICLE_VISUAL
|
||||
-1, // doomednum
|
||||
S_NULL, // spawnstate
|
||||
1, // 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
|
||||
0, // radius
|
||||
0, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_BETA_PARTICLE_EXPLOSION
|
||||
-1, // doomednum
|
||||
S_BETA_PARTICLE_EXPLOSION, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // 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
|
||||
80*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
1, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_NOHITLAGFORME|MF_SPECIAL|MF_DONTPUNT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
66
src/info.h
66
src/info.h
|
|
@ -1540,6 +1540,21 @@ typedef enum sprite
|
|||
SPR_FBTN,
|
||||
SPR_SFTR,
|
||||
|
||||
SPR_SABX,
|
||||
SPR_ICBL,
|
||||
|
||||
SPR_BSSP,
|
||||
SPR_BSPB,
|
||||
SPR_BSPR,
|
||||
SPR_BSSR,
|
||||
SPR_BLMS,
|
||||
SPR_BLMM,
|
||||
SPR_BLML,
|
||||
SPR_BSWL,
|
||||
SPR_BSWC,
|
||||
|
||||
SPR_LCLA,
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
SPR_VIEW,
|
||||
|
||||
|
|
@ -6102,6 +6117,39 @@ typedef enum state
|
|||
// MT_IVOBALL
|
||||
S_IVOBALL,
|
||||
|
||||
S_SA2_CRATE_DEBRIS,
|
||||
S_SA2_CRATE_DEBRIS_E,
|
||||
S_SA2_CRATE_DEBRIS_F,
|
||||
S_SA2_CRATE_DEBRIS_G,
|
||||
S_SA2_CRATE_DEBRIS_H,
|
||||
S_SA2_CRATE_DEBRIS_METAL,
|
||||
|
||||
S_ICECAPBLOCK_DEBRIS,
|
||||
S_ICECAPBLOCK_DEBRIS_C,
|
||||
S_ICECAPBLOCK_DEBRIS_D,
|
||||
S_ICECAPBLOCK_DEBRIS_E,
|
||||
S_ICECAPBLOCK_DEBRIS_F,
|
||||
|
||||
// MT_SPEAR
|
||||
S_SPEAR_ROD,
|
||||
S_SPEAR_TIP,
|
||||
S_SPEAR_HILT_FRONT,
|
||||
S_SPEAR_HILT_BACK,
|
||||
S_SPEAR_WALL,
|
||||
|
||||
// MT_BSZLAMP_S
|
||||
S_BLMS,
|
||||
S_BLMM,
|
||||
S_BLML,
|
||||
|
||||
// MT_BSZSLAMP
|
||||
S_BSWL,
|
||||
S_BSWC,
|
||||
|
||||
S_BETA_PARTICLE_WHEEL,
|
||||
S_BETA_PARTICLE_ICON,
|
||||
S_BETA_PARTICLE_EXPLOSION,
|
||||
|
||||
S_FIRSTFREESLOT,
|
||||
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
|
||||
NUMSTATES
|
||||
|
|
@ -7348,6 +7396,24 @@ typedef enum mobj_type
|
|||
MT_PATROLIVOBALL,
|
||||
MT_AIRIVOBALL,
|
||||
|
||||
MT_BOX_SIDE,
|
||||
MT_BOX_DEBRIS,
|
||||
MT_SA2_CRATE,
|
||||
MT_ICECAPBLOCK,
|
||||
|
||||
MT_SPEAR,
|
||||
MT_SPEARVISUAL,
|
||||
MT_BSZLAMP_S,
|
||||
MT_BSZLAMP_M,
|
||||
MT_BSZLAMP_L,
|
||||
MT_BSZSLAMP,
|
||||
MT_BSZSLCHA,
|
||||
|
||||
MT_BETA_EMITTER,
|
||||
MT_BETA_PARTICLE_PHYSICAL,
|
||||
MT_BETA_PARTICLE_VISUAL,
|
||||
MT_BETA_PARTICLE_EXPLOSION,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
|
|
@ -431,10 +431,10 @@ public:
|
|||
head = offset;
|
||||
break;
|
||||
case SeekFrom::kEnd:
|
||||
if (-offset >= static_cast<StreamOffset>(span_.size())) {
|
||||
if (static_cast<StreamOffset>(span_.size()) + offset < 0) {
|
||||
throw std::logic_error("end offset is out of bounds");
|
||||
}
|
||||
head = span_.size() - offset;
|
||||
head = span_.size() + offset;
|
||||
break;
|
||||
case SeekFrom::kCurrent:
|
||||
if (head_ + offset < 0) {
|
||||
|
|
@ -526,10 +526,10 @@ public:
|
|||
head = offset;
|
||||
break;
|
||||
case SeekFrom::kEnd:
|
||||
if (-offset >= static_cast<StreamOffset>(vec_.size())) {
|
||||
if (static_cast<StreamOffset>(vec_.size()) + offset < 0) {
|
||||
throw std::logic_error("end offset is out of bounds");
|
||||
}
|
||||
head = vec_.size() - offset;
|
||||
head = vec_.size() + offset;
|
||||
break;
|
||||
case SeekFrom::kCurrent:
|
||||
if (head_ + offset < 0) {
|
||||
|
|
|
|||
|
|
@ -821,7 +821,7 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
}
|
||||
|
||||
g_battleufo.due = starttime;
|
||||
g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID();
|
||||
g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1;
|
||||
}
|
||||
|
||||
UINT8 K_Bumpers(player_t *player)
|
||||
|
|
|
|||
|
|
@ -1233,7 +1233,8 @@ void K_PuntHazard(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
boolean K_PuntCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if (t1->flags & MF_DONTPUNT)
|
||||
// MF_SHOOTABLE will get damaged directly, instead
|
||||
if (t1->flags & (MF_DONTPUNT | MF_SHOOTABLE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ void K_HandleFollower(player_t *player)
|
|||
K_UpdateFollowerState(player->follower, fl->idlestate, FOLLOWERSTATE_IDLE);
|
||||
|
||||
P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear
|
||||
P_SetTarget(&player->follower->punt_ref, player->mo);
|
||||
player->follower->angle = player->follower->old_angle = player->mo->angle;
|
||||
|
||||
// This is safe to only spawn it here, the follower is removed then respawned when switched.
|
||||
|
|
@ -427,10 +428,12 @@ void K_HandleFollower(player_t *player)
|
|||
bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_FRONT);
|
||||
P_SetTarget(&player->follower->hnext, bmobj);
|
||||
P_SetTarget(&bmobj->target, player->follower); // Used to know if we have to despawn at some point.
|
||||
P_SetTarget(&bmobj->punt_ref, player->mo);
|
||||
|
||||
bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_BACK);
|
||||
P_SetTarget(&player->follower->hnext->hnext, bmobj); // this seems absolutely stupid, I know, but this will make updating the momentums/flags of these a bit easier.
|
||||
P_SetTarget(&bmobj->target, player->follower); // Ditto
|
||||
P_SetTarget(&bmobj->punt_ref, player->mo);
|
||||
}
|
||||
}
|
||||
else // follower exists, woo!
|
||||
|
|
|
|||
35
src/k_kart.c
35
src/k_kart.c
|
|
@ -3914,9 +3914,22 @@ void K_RemoveGrowShrink(player_t *player)
|
|||
player->roundconditions.consecutive_grow_lasers = 0;
|
||||
}
|
||||
|
||||
// Should this object actually scale check?
|
||||
// Scale-to-scale comparisons only make sense for objects that expect to have dynamic scale.
|
||||
static boolean K_IsScaledItem(mobj_t *mobj)
|
||||
{
|
||||
return mobj && !P_MobjWasRemoved(mobj) &&
|
||||
(mobj->type == MT_ORBINAUT || mobj->type == MT_JAWZ || mobj->type == MT_GACHABOM
|
||||
|| mobj->type == MT_BANANA || mobj->type == MT_EGGMANITEM || mobj->type == MT_BALLHOG
|
||||
|| mobj->type == MT_SSMINE || mobj->type == MT_LANDMINE || mobj->type == MT_SINK
|
||||
|| mobj->type == MT_GARDENTOP || mobj->type == MT_DROPTARGET || mobj->type == MT_PLAYER);
|
||||
}
|
||||
|
||||
|
||||
boolean K_IsBigger(mobj_t *compare, mobj_t *other)
|
||||
{
|
||||
fixed_t compareScale, otherScale;
|
||||
const fixed_t requiredDifference = (mapobjectscale/4);
|
||||
|
||||
if ((compare == NULL || P_MobjWasRemoved(compare) == true)
|
||||
|| (other == NULL || P_MobjWasRemoved(other) == true))
|
||||
|
|
@ -3924,6 +3937,18 @@ boolean K_IsBigger(mobj_t *compare, mobj_t *other)
|
|||
return false;
|
||||
}
|
||||
|
||||
// If a player is colliding with a non-kartitem object, we don't care about what scale that object is:
|
||||
// mappers are liable to fuck with the scale for their own reasons, and we need to compare against the
|
||||
// player's base scale instead to match expectations.
|
||||
if (K_IsScaledItem(compare) != K_IsScaledItem(other))
|
||||
{
|
||||
if (compare->type == MT_PLAYER)
|
||||
return (compare->scale > requiredDifference + FixedMul(mapobjectscale, P_GetMobjDefaultScale(compare)));
|
||||
else if (other->type == MT_PLAYER)
|
||||
return false; // Haha what the fuck are you doing
|
||||
// fallthrough
|
||||
}
|
||||
|
||||
if ((compareScale = P_GetMobjDefaultScale(compare)) != FRACUNIT)
|
||||
{
|
||||
compareScale = FixedDiv(compare->scale, compareScale);
|
||||
|
|
@ -3942,7 +3967,7 @@ boolean K_IsBigger(mobj_t *compare, mobj_t *other)
|
|||
otherScale = other->scale;
|
||||
}
|
||||
|
||||
return (compareScale > otherScale + (mapobjectscale / 4));
|
||||
return (compareScale > otherScale + requiredDifference);
|
||||
}
|
||||
|
||||
static fixed_t K_TumbleZ(mobj_t *mo, fixed_t input)
|
||||
|
|
@ -8057,6 +8082,9 @@ static void K_UpdateTripwire(player_t *player)
|
|||
P_SetTarget(&front->target, player->mo);
|
||||
P_SetTarget(&back->target, player->mo);
|
||||
|
||||
P_SetTarget(&front->punt_ref, player->mo);
|
||||
P_SetTarget(&back->punt_ref, player->mo);
|
||||
|
||||
front->dispoffset = 1;
|
||||
front->old_angle = back->old_angle = K_MomentumAngle(player->mo);
|
||||
back->dispoffset = -1;
|
||||
|
|
@ -13160,6 +13188,11 @@ boolean K_IsPlayingDisplayPlayer(player_t *player)
|
|||
|
||||
boolean K_PlayerCanPunt(player_t *player)
|
||||
{
|
||||
if (player->trickpanel > TRICKSTATE_READY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4548,12 +4548,14 @@ void M_DrawVideoModes(void)
|
|||
(SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : 0x80,
|
||||
cv_scr_width.value, cv_scr_height.value));
|
||||
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+16,
|
||||
recommendedflags, "Marked modes are recommended.");
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+24,
|
||||
highlightflags, "Other modes may have visual errors.");
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+32,
|
||||
highlightflags, "Larger modes may have performance issues.");
|
||||
recommendedflags, "Modes marked in GREEN are recommended.");
|
||||
/*
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+16,
|
||||
highlightflags, "High resolutions stress your PC more, but will");
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+24,
|
||||
highlightflags, "look sharper. Balance visual quality and FPS!");
|
||||
*/
|
||||
}
|
||||
|
||||
// Draw the cursor for the VidMode menu
|
||||
|
|
|
|||
|
|
@ -184,8 +184,7 @@ void Obj_BattleUFODeath(mobj_t *ufo);
|
|||
void Obj_LinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_SpawnBattleUFOFromSpawner(void);
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void);
|
||||
void Obj_ResetUFOSpawners(void);
|
||||
INT32 Obj_RandomBattleUFOSpawnerID(void);
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam);
|
||||
|
||||
/* Power-Up Aura */
|
||||
|
|
@ -230,7 +229,6 @@ void Obj_FakeShadowThink(mobj_t *shadow);
|
|||
boolean Obj_FakeShadowZ(const mobj_t *shadow, fixed_t *return_z, pslope_t **return_slope);
|
||||
|
||||
/* Checkpoints */
|
||||
void Obj_ResetCheckpoints(void);
|
||||
void Obj_LinkCheckpoint(mobj_t *end);
|
||||
void Obj_UnlinkCheckpoint(mobj_t *end);
|
||||
void Obj_CheckpointThink(mobj_t *end);
|
||||
|
|
@ -321,6 +319,26 @@ void Obj_PatrolIvoBallInit(mobj_t *mo);
|
|||
void Obj_PatrolIvoBallThink(mobj_t *mo);
|
||||
void Obj_PatrolIvoBallTouch(mobj_t *special, mobj_t *toucher);
|
||||
|
||||
/* SA2 Crates / Ice Cap Blocks */
|
||||
void Obj_BoxSideThink(mobj_t *mo);
|
||||
void Obj_TryCrateInit(mobj_t *mo);
|
||||
boolean Obj_TryCrateThink(mobj_t *mo);
|
||||
void Obj_TryCrateTouch(mobj_t *special, mobj_t *toucher);
|
||||
void Obj_TryCrateDamage(mobj_t *target, mobj_t *inflictor);
|
||||
|
||||
/* Lavender Shrine Spears */
|
||||
void Obj_SpearInit(mobj_t *mo);
|
||||
void Obj_SpearThink(mobj_t *mo);
|
||||
|
||||
/* Lost Colony Fuel Canister */
|
||||
void Obj_FuelCanisterEmitterInit(mobj_t *mo);
|
||||
boolean Obj_FuelCanisterVisualThink(mobj_t *mo);
|
||||
boolean Obj_FuelCanisterEmitterThink(mobj_t *mo);
|
||||
boolean Obj_FuelCanisterThink(mobj_t *mo);
|
||||
void Obj_FuelCanisterTouch(mobj_t *special, mobj_t *toucher);
|
||||
void Obj_FuelCanisterExplosionTouch(mobj_t *special, mobj_t *toucher);
|
||||
boolean Obj_FuelCanisterExplosionThink(mobj_t *mo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -940,6 +940,7 @@ boolean K_StartCeremony(void)
|
|||
&& mapheaderinfo[podiumMapNum]->lumpnum != LUMPERROR)
|
||||
{
|
||||
gamemap = podiumMapNum+1;
|
||||
g_reloadingMap = false;
|
||||
|
||||
encoremode = grandprixinfo.encore;
|
||||
|
||||
|
|
@ -1034,8 +1035,6 @@ void K_ResetCeremony(void)
|
|||
{
|
||||
mapmusrng--;
|
||||
}
|
||||
|
||||
mapmusflags |= MUSIC_RELOADRESET;
|
||||
}
|
||||
|
||||
if (!grandprixinfo.cup)
|
||||
|
|
|
|||
|
|
@ -299,9 +299,6 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
} else if (fastcmp(word,"mapmusname")) {
|
||||
lua_pushstring(L, mapmusname);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"mapmusflags")) {
|
||||
lua_pushinteger(L, mapmusflags);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"mapmusposition")) {
|
||||
lua_pushinteger(L, mapmusposition);
|
||||
return 1;
|
||||
|
|
@ -424,8 +421,6 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
|
|||
|
||||
strncpy(mapmusname, str, strlength);
|
||||
}
|
||||
else if (fastcmp(word, "mapmusflags"))
|
||||
mapmusflags = (UINT16)luaL_checkinteger(L, 2);
|
||||
else if (fastcmp(word, "mapmusrng"))
|
||||
mapmusrng = (UINT8)luaL_checkinteger(L, 2);
|
||||
// SRB2Kart
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ struct Vec2
|
|||
{
|
||||
T x, y;
|
||||
|
||||
Vec2() : x{}, y{} {}
|
||||
Vec2(T x_, T y_) : x(x_), y(y_) {}
|
||||
Vec2(T z) : x(z), y(z) {}
|
||||
constexpr Vec2() : x{}, y{} {}
|
||||
constexpr Vec2(T x_, T y_) : x(x_), y(y_) {}
|
||||
constexpr Vec2(T z) : x(z), y(z) {}
|
||||
|
||||
template <typename U>
|
||||
Vec2(const Vec2<U>& b) : Vec2(b.x, b.y) {}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ menuitem_t OPTIONS_Gameplay[] =
|
|||
{IT_SPACE | IT_NOTHING, NULL, NULL,
|
||||
NULL, {NULL}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Minimum Input Delay", "Practice for online play! Higher = more delay.",
|
||||
{IT_STRING | IT_CVAR, "Minimum Input Delay", "Practice for online play! Higher = more delay, 0 = instant response.",
|
||||
NULL, {.cvar = &cv_mindelay}, 0, 0},
|
||||
|
||||
{IT_SPACE | IT_NOTHING, NULL, NULL,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
menuitem_t OPTIONS_VideoModes[] = {
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Select a resolution.",
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Select a resolution. Higher = sharper game, lower = higher FPS.",
|
||||
NULL, {.routine = M_HandleVideoModes}, 0, 0}, // dummy menuitem for the control func
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/// \file menus/transient/pause-game.c
|
||||
/// \brief In-game/pause menus
|
||||
|
||||
#include "../../d_netcmd.h"
|
||||
#include "../../k_menu.h"
|
||||
#include "../../k_grandprix.h" // K_CanChangeRules
|
||||
#include "../../m_cond.h"
|
||||
|
|
@ -332,7 +333,10 @@ void M_HandlePauseMenuGametype(INT32 choice)
|
|||
if (menugametype != gametype)
|
||||
{
|
||||
M_ClearMenus(true);
|
||||
COM_ImmedExecute(va("randommap -gt %s", gametypes[menugametype]->name));
|
||||
if (server || IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
D_SetupVote(menugametype);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
110
src/mobj.hpp
110
src/mobj.hpp
|
|
@ -13,8 +13,12 @@
|
|||
#include <optional>
|
||||
|
||||
#include "math/fixed.hpp"
|
||||
#include "math/line_segment.hpp"
|
||||
#include "math/vec.hpp"
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "k_hitlag.h"
|
||||
#include "k_kart.h"
|
||||
#include "info.h"
|
||||
#include "p_local.h"
|
||||
#include "p_mobj.h"
|
||||
|
|
@ -27,16 +31,20 @@ namespace srb2
|
|||
|
||||
struct Mobj : mobj_t
|
||||
{
|
||||
using fixed = math::Fixed;
|
||||
using line_segment = math::LineSegment<fixed>;
|
||||
using vec2 = math::Vec2<fixed>;
|
||||
|
||||
// TODO: Vec3 would be nice
|
||||
struct PosArg
|
||||
{
|
||||
math::Fixed x, y, z;
|
||||
fixed x, y, z;
|
||||
|
||||
PosArg() : PosArg(0, 0, 0) {}
|
||||
PosArg(fixed_t x_, fixed_t y_, fixed_t z_) : x(x_), y(y_), z(z_) {}
|
||||
PosArg(fixed x_, fixed y_, fixed z_) : x(x_), y(y_), z(z_) {}
|
||||
|
||||
template <typename T>
|
||||
PosArg(math::Vec2<T> p, fixed_t z) : PosArg(p.x, p.y, z) {}
|
||||
PosArg(math::Vec2<T> p, fixed z) : PosArg(p.x, p.y, z) {}
|
||||
|
||||
PosArg(const mobj_t* mobj) : PosArg(mobj->x, mobj->y, mobj->z) {}
|
||||
};
|
||||
|
|
@ -97,19 +105,26 @@ struct Mobj : mobj_t
|
|||
|
||||
PosArg center() const { return {x, y, z + (height / 2)}; }
|
||||
PosArg pos() const { return {x, y, z}; }
|
||||
math::Vec2<math::Fixed> pos2d() const { return {x, y}; }
|
||||
math::Fixed top() const { return z + height; }
|
||||
vec2 pos2d() const { return {x, y}; }
|
||||
fixed top() const { return z + height; }
|
||||
|
||||
bool is_flipped() const { return eflags & MFE_VERTICALFLIP; }
|
||||
math::Fixed flip(fixed_t x) const { return x * P_MobjFlip(this); }
|
||||
fixed flip(fixed x) const { return x * P_MobjFlip(this); }
|
||||
|
||||
// Collision helper
|
||||
bool z_overlaps(const Mobj* b) const { return z < b->top() && b->z < top(); }
|
||||
|
||||
void move_origin(const PosArg& p) { P_MoveOrigin(this, p.x, p.y, p.z); }
|
||||
void set_origin(const PosArg& p) { P_SetOrigin(this, p.x, p.y, p.z); }
|
||||
void instathrust(angle_t angle, fixed_t speed) { P_InstaThrust(this, angle, speed); }
|
||||
void thrust(angle_t angle, fixed_t speed) { P_Thrust(this, angle, speed); }
|
||||
void instathrust(angle_t angle, fixed speed) { P_InstaThrust(this, angle, speed); }
|
||||
void thrust(angle_t angle, fixed speed) { P_Thrust(this, angle, speed); }
|
||||
|
||||
static void bounce(Mobj* t1, Mobj* t2) { K_KartBouncing(t1, t2); }
|
||||
void solid_bounce(Mobj* solid) { K_KartSolidBounce(this, solid); }
|
||||
|
||||
// A = bottom left corner
|
||||
// this->aabb; the standard bounding box. This is inapproporiate for paper collision!
|
||||
line_segment aabb() const { return {{x - radius, y - radius}, {x + radius, y + radius}}; }
|
||||
|
||||
|
||||
//
|
||||
|
|
@ -150,15 +165,15 @@ struct Mobj : mobj_t
|
|||
// Scale
|
||||
//
|
||||
|
||||
math::Fixed scale() const { return mobj_t::scale; }
|
||||
fixed scale() const { return mobj_t::scale; }
|
||||
|
||||
void scale(fixed_t n)
|
||||
void scale(fixed n)
|
||||
{
|
||||
mobj_t::scale = n;
|
||||
P_SetScale(this, n);
|
||||
mobj_t::destscale = n;
|
||||
}
|
||||
|
||||
void scale_to(fixed_t stop, std::optional<fixed_t> speed = {})
|
||||
void scale_to(fixed stop, std::optional<fixed> speed = {})
|
||||
{
|
||||
mobj_t::destscale = stop;
|
||||
|
||||
|
|
@ -168,13 +183,68 @@ struct Mobj : mobj_t
|
|||
}
|
||||
}
|
||||
|
||||
void scale_between(fixed_t start, fixed_t stop, std::optional<fixed_t> speed = {})
|
||||
void scale_between(fixed start, fixed stop, std::optional<fixed> speed = {})
|
||||
{
|
||||
mobj_t::scale = start;
|
||||
P_SetScale(this, start);
|
||||
scale_to(stop, speed);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Sprite offsets
|
||||
//
|
||||
|
||||
#define FIXED_METHOD(member) \
|
||||
fixed member() const { return mobj_t::member; } \
|
||||
void member(fixed n) { mobj_t::member = n; }
|
||||
|
||||
FIXED_METHOD(spritexscale)
|
||||
FIXED_METHOD(spriteyscale)
|
||||
FIXED_METHOD(spritexoffset)
|
||||
FIXED_METHOD(spriteyoffset)
|
||||
FIXED_METHOD(sprxoff)
|
||||
FIXED_METHOD(spryoff)
|
||||
FIXED_METHOD(sprzoff)
|
||||
|
||||
vec2 spritescale() const { return {spritexscale(), spriteyscale()}; }
|
||||
void spritescale(const vec2& v)
|
||||
{
|
||||
spritexscale(v.x);
|
||||
spriteyscale(v.y);
|
||||
}
|
||||
|
||||
vec2 spriteoffset() const { return {spritexoffset(), spriteyoffset()}; }
|
||||
void spriteoffset(const vec2& v)
|
||||
{
|
||||
spritexoffset(v.x);
|
||||
spriteyoffset(v.y);
|
||||
}
|
||||
|
||||
vec2 sproff2d() const { return {sprxoff(), spryoff()}; }
|
||||
void sproff2d(const vec2& v)
|
||||
{
|
||||
sprxoff(v.x);
|
||||
spryoff(v.y);
|
||||
}
|
||||
|
||||
void linkdraw(bool n) { flags2 = n ? flags2 | MF2_LINKDRAW : flags2 & ~MF2_LINKDRAW; }
|
||||
|
||||
// WARNING: sets tracer!
|
||||
void linkdraw(Mobj* parent)
|
||||
{
|
||||
tracer(parent);
|
||||
linkdraw(true);
|
||||
}
|
||||
|
||||
void linkdraw(Mobj* parent, INT32 offset)
|
||||
{
|
||||
linkdraw(parent);
|
||||
dispoffset = offset;
|
||||
}
|
||||
|
||||
// TODO: Vec3
|
||||
|
||||
|
||||
//
|
||||
// Sound
|
||||
//
|
||||
|
|
@ -194,6 +264,18 @@ struct Mobj : mobj_t
|
|||
voice(sfx, volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Hitlag
|
||||
//
|
||||
|
||||
INT32 hitlag() const { return mobj_t::hitlag; }
|
||||
void hitlag(INT32 tics, bool damage = false) { K_AddHitLag(this, tics, damage); }
|
||||
void hitlag(Mobj* inflictor, Mobj* source, INT32 tics, bool damage)
|
||||
{
|
||||
K_SetHitLagForObjects(this, inflictor, source, tics, damage);
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace srb2
|
||||
|
|
|
|||
86
src/mobj_list.hpp
Normal file
86
src/mobj_list.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef mobj_list_hpp
|
||||
#define mobj_list_hpp
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "cxxutil.hpp"
|
||||
#include "mobj.hpp"
|
||||
#include "mobj_list_view.hpp"
|
||||
|
||||
namespace srb2
|
||||
{
|
||||
|
||||
// Requires:
|
||||
// void T::next(T*)
|
||||
// T* T::next() const
|
||||
template <typename T, mobj_t*& Head>
|
||||
struct MobjList
|
||||
{
|
||||
static_assert(std::is_convertible_v<T, mobj_t>);
|
||||
|
||||
MobjList() {}
|
||||
|
||||
T* front() const { return static_cast<T*>(Head); }
|
||||
bool empty() const { return !front(); }
|
||||
|
||||
void push_front(T* ptr)
|
||||
{
|
||||
ptr->next(front());
|
||||
front(ptr);
|
||||
}
|
||||
|
||||
void erase(T* node)
|
||||
{
|
||||
if (front() == node)
|
||||
{
|
||||
front(node->next());
|
||||
node->next(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto view = this->view();
|
||||
auto end = view.end();
|
||||
auto it = view.begin();
|
||||
|
||||
SRB2_ASSERT(it != end);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
T* prev = *it;
|
||||
|
||||
it++;
|
||||
|
||||
if (it == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*it == node)
|
||||
{
|
||||
prev->next(node->next());
|
||||
node->next(nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto begin() const { return view().begin(); }
|
||||
auto end() const { return view().end(); }
|
||||
|
||||
private:
|
||||
void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; }
|
||||
auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); }
|
||||
};
|
||||
|
||||
}; // namespace srb2
|
||||
|
||||
#endif/*mobj_list_hpp*/
|
||||
84
src/mobj_list_view.hpp
Normal file
84
src/mobj_list_view.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef mobj_list_view_hpp
|
||||
#define mobj_list_view_hpp
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "p_mobj.h"
|
||||
|
||||
namespace srb2
|
||||
{
|
||||
|
||||
// for (T* ptr : MobjList(hnext(), [](T* ptr) { return ptr->hnext(); }))
|
||||
template <typename T, typename F>
|
||||
struct MobjListView
|
||||
{
|
||||
static_assert(std::is_convertible_v<T, mobj_t>);
|
||||
|
||||
struct Iterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T*;
|
||||
using pointer = value_type;
|
||||
using reference = value_type;
|
||||
|
||||
Iterator(pointer ptr, F adv) : ptr_(deref(ptr)), adv_(adv) {}
|
||||
Iterator& operator=(const Iterator& b)
|
||||
{
|
||||
// adv_ may be a lambda. However, lambdas are not
|
||||
// copy assignable. Therefore, perform copy
|
||||
// construction instead!
|
||||
this->~Iterator();
|
||||
return *new(this) Iterator {b};
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& b) const { return ptr_ == b.ptr_; };
|
||||
bool operator!=(const Iterator& b) const { return ptr_ != b.ptr_; };
|
||||
|
||||
reference operator*() const { return ptr_; }
|
||||
pointer operator->() { return ptr_; }
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
ptr_ = deref(adv_(ptr_));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator prev = *this;
|
||||
++(*this);
|
||||
return prev;
|
||||
}
|
||||
|
||||
private:
|
||||
pointer ptr_;
|
||||
F adv_;
|
||||
|
||||
static T* deref(T* ptr) { return !P_MobjWasRemoved(ptr) ? ptr : nullptr; }
|
||||
};
|
||||
|
||||
MobjListView(T* ptr, F adv) : ptr_(ptr), adv_(adv) {}
|
||||
|
||||
Iterator begin() const { return {ptr_, adv_}; }
|
||||
Iterator end() const { return {nullptr, adv_}; }
|
||||
|
||||
private:
|
||||
T* ptr_;
|
||||
F adv_;
|
||||
};
|
||||
|
||||
}; // namespace srb2
|
||||
|
||||
#endif/*mobj_list_view_hpp*/
|
||||
|
|
@ -35,6 +35,12 @@ void Music_Init(void)
|
|||
tune.nightcoreable = true;
|
||||
}
|
||||
|
||||
{
|
||||
Tune& tune = g_tunes.insert("level_nosync", g_tunes.find("level"));
|
||||
|
||||
tune.sync = false;
|
||||
}
|
||||
|
||||
{
|
||||
Tune& tune = g_tunes.insert("position");
|
||||
|
||||
|
|
@ -133,9 +139,9 @@ void Music_Init(void)
|
|||
}
|
||||
|
||||
{
|
||||
Tune& tune = g_tunes.insert("menu_nocred");
|
||||
Tune& tune = g_tunes.insert("menu_nocred", g_tunes.find("menu"));
|
||||
|
||||
tune.priority = 100;
|
||||
tune.credit = false;
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -165,14 +171,10 @@ void Music_Init(void)
|
|||
}
|
||||
|
||||
{
|
||||
Tune& tune = g_tunes.insert("stereo_fade");
|
||||
Tune& tune = g_tunes.insert("stereo_fade", g_tunes.find("stereo"));
|
||||
|
||||
tune.priority = 1000;
|
||||
tune.fade_out = 5000;
|
||||
tune.fade_out_inclusive = false;
|
||||
tune.resist = true;
|
||||
tune.keep_open = true;
|
||||
tune.credit = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,3 +352,13 @@ const char* Music_CurrentId(void)
|
|||
{
|
||||
return g_tunes.current_id();
|
||||
}
|
||||
|
||||
void Music_BatchExempt(const char* id)
|
||||
{
|
||||
Tune* tune = g_tunes.find(id);
|
||||
|
||||
if (tune)
|
||||
{
|
||||
tune->resist_once = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,10 @@ void Music_Remap(const char *id, const char *song);
|
|||
// Set whether a tune should loop.
|
||||
void Music_Loop(const char *id, boolean loop);
|
||||
|
||||
// Temporarily exemplify a tune from batch operations, such
|
||||
// as Music_StopAll.
|
||||
void Music_BatchExempt(const char *id);
|
||||
|
||||
|
||||
//
|
||||
// Query properties.
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ public:
|
|||
return it != map_.end() ? const_cast<Tune*>(&it->second) : nullptr;
|
||||
}
|
||||
|
||||
Tune& insert(const char* id)
|
||||
Tune& insert(const char* id, const Tune* original = nullptr)
|
||||
{
|
||||
auto res = map_.emplace(id, Tune{});
|
||||
auto res = map_.emplace(id, original ? *original : Tune{});
|
||||
|
||||
SRB2_ASSERT(res.second);
|
||||
|
||||
|
|
@ -73,6 +73,12 @@ public:
|
|||
{
|
||||
for (auto& [_, tune] : map_)
|
||||
{
|
||||
if (tune.resist_once)
|
||||
{
|
||||
tune.resist_once = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tune.resist)
|
||||
{
|
||||
f(tune);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public:
|
|||
// from TuneManager::stop_all etc. It must be
|
||||
// stopped/paused individually.
|
||||
bool resist = false;
|
||||
bool resist_once = false; // set at runtime
|
||||
|
||||
// This tune shows a credit when first played (not
|
||||
// resumed).
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
orbinaut.c
|
||||
jawz.c
|
||||
duel-bomb.c
|
||||
broly.c
|
||||
broly.cpp
|
||||
ufo.c
|
||||
monitor.c
|
||||
item-spot.c
|
||||
|
|
@ -44,6 +44,9 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
mega-barrier.cpp
|
||||
frost-thrower.cpp
|
||||
ivoball.cpp
|
||||
crate.cpp
|
||||
spear.cpp
|
||||
fuel.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(versus)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "../math/fixed.hpp"
|
||||
#include "../mobj.hpp"
|
||||
#include "../mobj_list.hpp"
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../m_random.h"
|
||||
|
|
@ -9,101 +13,96 @@
|
|||
#include "../k_objects.h"
|
||||
#include "../k_kart.h"
|
||||
|
||||
using srb2::math::Fixed;
|
||||
using srb2::Mobj;
|
||||
using srb2::MobjList;
|
||||
|
||||
extern mobj_t* svg_battleUfoSpawners;
|
||||
|
||||
#define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body
|
||||
#define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn
|
||||
#define BATTLEUFO_BOB_AMP (4) // UFO bob strength
|
||||
#define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed
|
||||
|
||||
#define spawner_id(o) ((o)->thing_args[0])
|
||||
|
||||
#define ufo_spawner(o) ((o)->target)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Spawner : mobj_t
|
||||
struct Spawner : Mobj
|
||||
{
|
||||
INT32 id() const { return spawner_id(this); }
|
||||
void thing_args() = delete;
|
||||
INT32 id() const { return this->mobj_t::thing_args[0]; }
|
||||
|
||||
void hnext() = delete;
|
||||
Spawner* next() const { return Mobj::hnext<Spawner>(); }
|
||||
void next(Spawner* n) { Mobj::hnext(n); }
|
||||
};
|
||||
|
||||
struct UFO : mobj_t
|
||||
struct UFO : Mobj
|
||||
{
|
||||
Spawner* spawner() const { return static_cast<Spawner*>(ufo_spawner(this)); }
|
||||
void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); }
|
||||
void target() = delete;
|
||||
Spawner* spawner() const { return Mobj::target<Spawner>(); }
|
||||
void spawner(Spawner* n) { Mobj::target(n); }
|
||||
|
||||
void spawn_beam()
|
||||
{
|
||||
mobj_t *x;
|
||||
Mobj *x = spawn_from<Mobj>({0, 0, height / 4}, MT_BATTLEUFO_BEAM);
|
||||
|
||||
x = P_SpawnMobjFromMobj(this, 0, 0, FixedDiv(this->height / 4, this->scale), MT_BATTLEUFO_BEAM);
|
||||
x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE;
|
||||
x->colorized = true;
|
||||
x->color = SKINCOLOR_SAPPHIRE;
|
||||
}
|
||||
};
|
||||
|
||||
struct SpawnerCompare
|
||||
{
|
||||
bool operator()(const Spawner* a, const Spawner* b) const
|
||||
void bob()
|
||||
{
|
||||
return a->id() < b->id();
|
||||
// Copied and slightly modified from k_kart.c
|
||||
Fixed sine = (BATTLEUFO_BOB_AMP * Fixed {FSIN(M_TAU_FIXED * BATTLEUFO_BOB_SPEED * leveltime)}) / 4;
|
||||
|
||||
momz = flip(sine * scale());
|
||||
}
|
||||
};
|
||||
|
||||
class SpawnerList
|
||||
{
|
||||
private:
|
||||
std::set<Spawner*, SpawnerCompare> set_;
|
||||
MobjList<Spawner, svg_battleUfoSpawners> list_;
|
||||
|
||||
public:
|
||||
void insert(Spawner* spawner)
|
||||
{
|
||||
auto [it, inserted] = set_.insert(spawner);
|
||||
|
||||
if (inserted)
|
||||
{
|
||||
mobj_t* dummy = nullptr;
|
||||
P_SetTarget(&dummy, spawner);
|
||||
}
|
||||
}
|
||||
|
||||
void erase(Spawner* spawner)
|
||||
{
|
||||
if (set_.erase(spawner))
|
||||
{
|
||||
mobj_t* dummy = spawner;
|
||||
P_SetTarget(&dummy, nullptr);
|
||||
}
|
||||
}
|
||||
void insert(Spawner* spawner) { list_.push_front(spawner); }
|
||||
void erase(Spawner* spawner) { list_.erase(spawner); }
|
||||
|
||||
Spawner* next(INT32 order) const
|
||||
{
|
||||
auto it = std::upper_bound(
|
||||
set_.begin(),
|
||||
set_.end(),
|
||||
order,
|
||||
[](INT32 a, const Spawner* b) { return a < b->id(); }
|
||||
);
|
||||
using T = const Spawner*;
|
||||
|
||||
return it != set_.end() ? *it : *set_.begin();
|
||||
auto it = std::find_if(list_.begin(), list_.end(), [order](T p) { return order < p->id(); });
|
||||
auto min = [&](auto cmp) { return std::min_element(list_.begin(), list_.end(), cmp); };
|
||||
|
||||
return *(it != list_.end()
|
||||
? min([order](T a, T b) { return order < a->id() && a->id() < b->id(); })
|
||||
: min([](T a, T b) { return a->id() < b->id(); }));
|
||||
}
|
||||
|
||||
INT32 random_id() const
|
||||
{
|
||||
if (set_.empty())
|
||||
if (list_.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto it = set_.begin();
|
||||
auto it = list_.begin();
|
||||
std::size_t count = std::distance(it, list_.end());
|
||||
|
||||
std::advance(it, P_RandomKey(PR_BATTLEUFO, set_.size()));
|
||||
if (count > 1u)
|
||||
{
|
||||
std::advance(it, P_RandomKey(PR_BATTLEUFO, count - 1u));
|
||||
}
|
||||
|
||||
return (*std::prev(it == set_.begin() ? set_.end() : it))->id();
|
||||
return it->id();
|
||||
}
|
||||
|
||||
void spawn_ufo() const
|
||||
{
|
||||
if (set_.empty())
|
||||
if (list_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -123,10 +122,7 @@ void Obj_BattleUFOThink(mobj_t *mobj)
|
|||
{
|
||||
UFO* ufo = static_cast<UFO*>(mobj);
|
||||
|
||||
// Copied and slightly modified from k_kart.c
|
||||
fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK));
|
||||
fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo);
|
||||
ufo->momz = targz;
|
||||
ufo->bob();
|
||||
|
||||
if ((leveltime/2) & 1)
|
||||
{
|
||||
|
|
@ -227,16 +223,11 @@ void Obj_SpawnBattleUFOFromSpawner(void)
|
|||
g_spawners.spawn_ufo();
|
||||
}
|
||||
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void)
|
||||
INT32 Obj_RandomBattleUFOSpawnerID(void)
|
||||
{
|
||||
return g_spawners.random_id();
|
||||
}
|
||||
|
||||
void Obj_ResetUFOSpawners(void)
|
||||
{
|
||||
g_spawners = {};
|
||||
}
|
||||
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam)
|
||||
{
|
||||
P_SetObjectMomZ(beam, beam->info->speed, true);
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../info.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../m_easing.h"
|
||||
#include "../p_local.h"
|
||||
#include "../s_sound.h"
|
||||
|
||||
/* An object may not be visible on the same tic:
|
||||
1) that it spawned
|
||||
2) that it cycles to the next state */
|
||||
#define BUFFER_TICS (2)
|
||||
|
||||
#define broly_duration(o) ((o)->extravalue1)
|
||||
#define broly_maxscale(o) ((o)->extravalue2)
|
||||
|
||||
static inline fixed_t
|
||||
get_unit_linear (const mobj_t *x)
|
||||
{
|
||||
const tic_t t = (x->tics - BUFFER_TICS);
|
||||
|
||||
return t * FRACUNIT / broly_duration(x);
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_SpawnBrolyKi
|
||||
( mobj_t * source,
|
||||
tic_t duration)
|
||||
{
|
||||
mobj_t *x;
|
||||
|
||||
if (duration <= 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = P_SpawnMobjFromMobj(
|
||||
source, 0, 0, 0, MT_BROLY);
|
||||
|
||||
P_SetTarget(&x->target, source);
|
||||
|
||||
// Shrink into center of source object.
|
||||
x->z = (source->z + source->height / 2);
|
||||
|
||||
x->colorized = true;
|
||||
x->color = source->color;
|
||||
x->hitlag = 0; // do not copy source hitlag
|
||||
|
||||
broly_maxscale(x) = 64 * mapobjectscale;
|
||||
broly_duration(x) = duration;
|
||||
|
||||
x->tics = (duration + BUFFER_TICS);
|
||||
|
||||
K_ReduceVFXForEveryone(x);
|
||||
|
||||
S_StartSound(x, sfx_cdfm74);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
boolean
|
||||
Obj_BrolyKiThink (mobj_t *x)
|
||||
{
|
||||
if (broly_duration(x) <= 0)
|
||||
{
|
||||
P_RemoveMobj(x);
|
||||
return false;
|
||||
}
|
||||
|
||||
const fixed_t
|
||||
t = get_unit_linear(x),
|
||||
n = Easing_OutSine(t, 0, broly_maxscale(x));
|
||||
|
||||
P_InstaScale(x, n);
|
||||
|
||||
return true;
|
||||
}
|
||||
38
src/objects/broly.cpp
Normal file
38
src/objects/broly.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "broly.hpp"
|
||||
|
||||
#include "../doomstat.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../sounds.h"
|
||||
|
||||
using namespace srb2::objects;
|
||||
|
||||
mobj_t *
|
||||
Obj_SpawnBrolyKi
|
||||
( mobj_t * source,
|
||||
tic_t duration)
|
||||
{
|
||||
Broly* x = Broly::spawn<Broly>(static_cast<Mobj*>(source), duration, {64 * mapobjectscale, 0});
|
||||
|
||||
x->colorized = true;
|
||||
x->color = source->color;
|
||||
|
||||
K_ReduceVFXForEveryone(x);
|
||||
x->voice(sfx_cdfm74);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
boolean
|
||||
Obj_BrolyKiThink (mobj_t *x)
|
||||
{
|
||||
return static_cast<Broly*>(x)->think();
|
||||
}
|
||||
96
src/objects/broly.hpp
Normal file
96
src/objects/broly.hpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef objects_broly_hpp
|
||||
#define objects_broly_hpp
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "../info.h"
|
||||
#include "../m_easing.h"
|
||||
|
||||
namespace srb2::objects
|
||||
{
|
||||
|
||||
struct Broly : Mobj
|
||||
{
|
||||
static constexpr mobjtype_t kMobjType = MT_BROLY;
|
||||
|
||||
/* An object may not be visible on the same tic:
|
||||
1) that it spawned
|
||||
2) that it cycles to the next state */
|
||||
static constexpr int kBufferTics = 2;
|
||||
|
||||
void extravalue1() = delete;
|
||||
tic_t duration() const { return mobj_t::extravalue1; }
|
||||
void duration(tic_t n) { mobj_t::extravalue1 = n; }
|
||||
|
||||
void threshold() = delete;
|
||||
void extravalue2() = delete;
|
||||
Vec2<Fixed> size() const { return {mobj_t::threshold, mobj_t::extravalue2}; }
|
||||
void size(const Vec2<Fixed>& n)
|
||||
{
|
||||
mobj_t::threshold = n.x;
|
||||
mobj_t::extravalue2 = n.y;
|
||||
}
|
||||
|
||||
bool valid() const { return duration(); }
|
||||
|
||||
tic_t remaining() const { return tics - kBufferTics; }
|
||||
|
||||
Fixed linear() const { return (remaining() * FRACUNIT) / duration(); }
|
||||
|
||||
template <typename T>
|
||||
static T* spawn(Mobj* source, tic_t duration, const Vec2<Fixed>& size)
|
||||
{
|
||||
static_assert(std::is_base_of_v<Broly, T>);
|
||||
|
||||
if (duration == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T* x = Mobj::spawn<T>(source->center(), T::kMobjType);
|
||||
|
||||
x->target(source);
|
||||
|
||||
// Shrink into center of source object.
|
||||
x->z -= x->height / 2;
|
||||
|
||||
x->size(size);
|
||||
x->duration(duration);
|
||||
|
||||
x->tics = (duration + kBufferTics);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool think()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
const Fixed center = z + (height / 2);
|
||||
const Vec2<Fixed> v = size();
|
||||
|
||||
scale(Easing_OutSine(linear(), v.y, v.x));
|
||||
z = center - (height / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace srb2::objects
|
||||
|
||||
#endif/*objects_broly_hpp*/
|
||||
|
|
@ -8,10 +8,11 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "../mobj_list.hpp"
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../doomtype.h"
|
||||
#include "../info.h"
|
||||
|
|
@ -32,10 +33,13 @@
|
|||
#include "../sounds.h"
|
||||
#include "../tables.h"
|
||||
|
||||
extern mobj_t* svg_checkpoints;
|
||||
|
||||
#define checkpoint_id(o) ((o)->thing_args[0])
|
||||
#define checkpoint_other(o) ((o)->target)
|
||||
#define checkpoint_orb(o) ((o)->tracer)
|
||||
#define checkpoint_arm(o) ((o)->hnext)
|
||||
#define checkpoint_next(o) ((o)->hprev)
|
||||
#define checkpoint_var(o) ((o)->movedir)
|
||||
#define checkpoint_speed(o) ((o)->movecount)
|
||||
#define checkpoint_speed_multiplier(o) ((o)->movefactor)
|
||||
|
|
@ -120,6 +124,9 @@ struct Checkpoint : mobj_t
|
|||
Arm* arm() const { return static_cast<Arm*>(checkpoint_arm(this)); }
|
||||
void arm(Arm* n) { P_SetTarget(&checkpoint_arm(this), n); }
|
||||
|
||||
Checkpoint* next() const { return static_cast<Checkpoint*>(checkpoint_next(this)); }
|
||||
void next(Checkpoint* n) { P_SetTarget(&checkpoint_next(this), n); }
|
||||
|
||||
fixed_t var() const { return checkpoint_var(this); }
|
||||
void var(fixed_t n) { checkpoint_var(this) = n; }
|
||||
|
||||
|
|
@ -391,34 +398,23 @@ private:
|
|||
|
||||
struct CheckpointManager
|
||||
{
|
||||
auto begin() { return vec_.begin(); }
|
||||
auto end() { return vec_.end(); }
|
||||
auto begin() { return list_.begin(); }
|
||||
auto end() { return list_.end(); }
|
||||
|
||||
auto find(INT32 id) { return std::find_if(begin(), end(), [id](Checkpoint* chk) { return chk->id() == id; }); }
|
||||
|
||||
void push_back(Checkpoint* chk) { vec_.push_back(chk); }
|
||||
void push_front(Checkpoint* chk) { list_.push_front(chk); }
|
||||
|
||||
void erase(const Checkpoint* chk)
|
||||
{
|
||||
if (auto it = std::find(vec_.begin(), vec_.end(), chk); it != end())
|
||||
{
|
||||
vec_.erase(it);
|
||||
}
|
||||
}
|
||||
void erase(Checkpoint* chk) { list_.erase(chk); }
|
||||
|
||||
private:
|
||||
std::vector<Checkpoint*> vec_;
|
||||
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
|
||||
};
|
||||
|
||||
CheckpointManager g_checkpoints;
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_ResetCheckpoints(void)
|
||||
{
|
||||
g_checkpoints = {};
|
||||
}
|
||||
|
||||
void Obj_LinkCheckpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
|
|
@ -456,7 +452,7 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
|||
}
|
||||
else
|
||||
{
|
||||
g_checkpoints.push_back(chk);
|
||||
g_checkpoints.push_front(chk);
|
||||
}
|
||||
|
||||
chk->gingerbread();
|
||||
|
|
@ -464,7 +460,7 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
|||
|
||||
void Obj_UnlinkCheckpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<const Checkpoint*>(end);
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
|
||||
g_checkpoints.erase(chk);
|
||||
|
||||
|
|
|
|||
391
src/objects/crate.cpp
Normal file
391
src/objects/crate.cpp
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Original Lua script by Lat
|
||||
// Hardcoded by jartha
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
#include "../math/fixed.hpp"
|
||||
#include "../math/line_segment.hpp"
|
||||
#include "../math/vec.hpp"
|
||||
#include "../mobj.hpp"
|
||||
#include "../mobj_list_view.hpp"
|
||||
|
||||
#include "../d_player.h"
|
||||
#include "../doomtype.h"
|
||||
#include "../info.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../p_maputl.h"
|
||||
#include "../p_pspr.h"
|
||||
#include "../r_defs.h"
|
||||
|
||||
using srb2::math::Fixed;
|
||||
using srb2::math::LineSegment;
|
||||
using srb2::math::Vec2;
|
||||
using srb2::Mobj;
|
||||
using srb2::MobjListView;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using frame_layout = std::array<int, 6>; // -z, +z, -x, -y, +x, +y
|
||||
|
||||
struct SA2CrateConfig
|
||||
{
|
||||
static constexpr spritenum_t kSprite = SPR_SABX;
|
||||
static constexpr frame_layout kFrames = {3, 2, 0, 0, 0, 0};
|
||||
static constexpr statenum_t kDefaultDebris = S_SA2_CRATE_DEBRIS;
|
||||
};
|
||||
|
||||
struct IceCapBlockConfig
|
||||
{
|
||||
static constexpr spritenum_t kSprite = SPR_ICBL;
|
||||
static constexpr frame_layout kFrames = {6, 6, 0, 0, 0, 0};
|
||||
static constexpr statenum_t kDefaultDebris = S_ICECAPBLOCK_DEBRIS;
|
||||
};
|
||||
|
||||
struct Graphic : Mobj
|
||||
{
|
||||
void hnext() = delete;
|
||||
Graphic* next() const { return Mobj::hnext<Graphic>(); }
|
||||
void next(Graphic* n) { Mobj::hnext(n); }
|
||||
|
||||
Graphic* dress(spritenum_t sprite, UINT32 frame)
|
||||
{
|
||||
this->sprite = sprite;
|
||||
this->frame = frame;
|
||||
this->renderflags |= RF_NOSPLATBILLBOARD;
|
||||
return this;
|
||||
}
|
||||
|
||||
Graphic* xy(fixed_t x, fixed_t y)
|
||||
{
|
||||
this->sproff2d({x, y});
|
||||
return this;
|
||||
}
|
||||
|
||||
Graphic* z(fixed_t z)
|
||||
{
|
||||
this->sprzoff(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
Graphic* turn(angle_t angle)
|
||||
{
|
||||
this->angle = angle;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
struct Side : Graphic
|
||||
{
|
||||
bool valid() const { return Mobj::valid() && Mobj::valid(owner()); }
|
||||
|
||||
void think()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
move_origin(owner());
|
||||
renderflags = owner()->renderflags;
|
||||
}
|
||||
};
|
||||
|
||||
struct Toucher : Mobj
|
||||
{
|
||||
bool boosting() const { return player && (player->sneakertimer || K_PlayerCanPunt(player)); }
|
||||
};
|
||||
|
||||
struct AnyBox : Graphic
|
||||
{
|
||||
template <typename F>
|
||||
bool visit(F&& visitor);
|
||||
|
||||
void update()
|
||||
{
|
||||
visit([](auto box) { box->mobj_t::eflags &= ~MFE_ONGROUND; });
|
||||
}
|
||||
};
|
||||
|
||||
template <class Config>
|
||||
struct Box : AnyBox
|
||||
{
|
||||
static constexpr Fixed kIntendedSize = 128*FRACUNIT;
|
||||
static constexpr Vec2<Fixed> kScrunch = {4*FRACUNIT/5, 6*FRACUNIT/5};
|
||||
|
||||
void extravalue1() = delete;
|
||||
statenum_t debris_state() const { return static_cast<statenum_t>(mobj_t::extravalue1); }
|
||||
void debris_state(statenum_t n) { mobj_t::extravalue1 = n; }
|
||||
|
||||
auto gfx() { return MobjListView(static_cast<Graphic*>(this), [](Graphic* g) { return g->next(); }); }
|
||||
|
||||
void init()
|
||||
{
|
||||
scale(scale() * (kIntendedSize / Fixed {info->height}));
|
||||
|
||||
Graphic* node = this;
|
||||
int i = 0;
|
||||
auto dress = [&](Graphic* g, UINT32 ff) { return g->dress(Config::kSprite, Config::kFrames[i++] | ff); };
|
||||
auto side = [&](UINT32 ff)
|
||||
{
|
||||
Side* side = spawn_from<Side>({}, MT_BOX_SIDE);
|
||||
side->owner(this);
|
||||
node->next(side); // link
|
||||
node = side;
|
||||
return dress(side, ff);
|
||||
};
|
||||
|
||||
dress(this, FF_FLOORSPRITE); // bottom (me)
|
||||
side(FF_FLOORSPRITE)->z(height); // top
|
||||
|
||||
// sides
|
||||
side(FF_PAPERSPRITE)->xy(-radius, 0)->turn(ANGLE_270);
|
||||
side(FF_PAPERSPRITE)->xy(0, -radius);
|
||||
side(FF_PAPERSPRITE)->xy(+radius, 0)->turn(ANGLE_90);
|
||||
side(FF_PAPERSPRITE)->xy(0, +radius)->turn(ANGLE_180);
|
||||
|
||||
debris_state(Config::kDefaultDebris);
|
||||
}
|
||||
|
||||
bool think()
|
||||
{
|
||||
if (fuse)
|
||||
{
|
||||
fuse--;
|
||||
renderflags ^= RF_DONTDRAW;
|
||||
|
||||
if (!fuse)
|
||||
{
|
||||
update_nearby();
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void touch(Toucher* toucher)
|
||||
{
|
||||
if (fuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
P_DamageMobj(this, toucher, nullptr, 1, DMG_NORMAL);
|
||||
|
||||
if (!toucher->boosting())
|
||||
{
|
||||
toucher->solid_bounce(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool damage_valid(const Mobj* inflictor) const { return !fuse && Mobj::valid(inflictor); }
|
||||
|
||||
void damage(Mobj* inflictor)
|
||||
{
|
||||
if (!damage_valid(inflictor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
inflictor->hitlag(3);
|
||||
fuse = 10;
|
||||
|
||||
// scrunch crate sides
|
||||
for (Graphic* g : gfx())
|
||||
{
|
||||
if (g->frame & FF_PAPERSPRITE)
|
||||
{
|
||||
g->frame++;
|
||||
g->spritescale(kScrunch);
|
||||
}
|
||||
else
|
||||
{
|
||||
g->spritescale(kScrunch.x);
|
||||
}
|
||||
|
||||
// reset interp
|
||||
g->mobj_t::old_spritexscale = g->spritexscale();
|
||||
g->mobj_t::old_spriteyscale = g->spriteyscale();
|
||||
|
||||
g->sproff2d(g->sproff2d() * kScrunch.x);
|
||||
g->sprzoff(g->sprzoff() * kScrunch.y);
|
||||
}
|
||||
|
||||
debris(inflictor);
|
||||
update_nearby();
|
||||
}
|
||||
|
||||
private:
|
||||
void debris(Mobj* inflictor)
|
||||
{
|
||||
if (debris_state() >= NUMSTATES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto rng = [&](int x, int y) { return P_RandomRange(PR_DECORATION, x, y) * scale(); };
|
||||
auto rng_xyz = [&](int x) { return std::tuple(rng(-x, x), rng(-x, x), rng(0, x)); };
|
||||
|
||||
auto spawn = [&]
|
||||
{
|
||||
auto [x, y, z] = rng_xyz(info->height / FRACUNIT);
|
||||
Mobj* p = spawn_from<Mobj>({x, y, z}, MT_BOX_DEBRIS);
|
||||
|
||||
p->scale_between(scale() / 2, scale());
|
||||
p->state(debris_state());
|
||||
|
||||
std::tie(x, y, z) = rng_xyz(4);
|
||||
|
||||
p->momx = (inflictor->momx / 8) + x;
|
||||
p->momy = (inflictor->momy / 8) + y;
|
||||
p->momz = (Fixed::hypot(inflictor->momx, inflictor->momy) / 4) + z;
|
||||
};
|
||||
|
||||
spawn();
|
||||
spawn();
|
||||
spawn();
|
||||
spawn();
|
||||
spawn();
|
||||
spawn();
|
||||
}
|
||||
|
||||
void update_nearby() const
|
||||
{
|
||||
LineSegment<Fixed> search = aabb();
|
||||
Vec2<Fixed> org{bmaporgx, bmaporgy};
|
||||
|
||||
search.a -= org + MAXRADIUS;
|
||||
search.b -= org - MAXRADIUS;
|
||||
|
||||
search.a.x = static_cast<UINT32>(search.a.x) >> MAPBLOCKSHIFT;
|
||||
search.b.x = static_cast<UINT32>(search.b.x) >> MAPBLOCKSHIFT;
|
||||
search.a.y = static_cast<UINT32>(search.a.y) >> MAPBLOCKSHIFT;
|
||||
search.b.y = static_cast<UINT32>(search.b.y) >> MAPBLOCKSHIFT;
|
||||
|
||||
BMBOUNDFIX(search.a.x, search.b.x, search.b.x, search.b.y);
|
||||
|
||||
for (INT32 bx = search.a.x; bx <= search.b.x; ++bx)
|
||||
{
|
||||
for (INT32 by = search.a.y; by <= search.b.y; ++by)
|
||||
{
|
||||
P_BlockThingsIterator(
|
||||
bx,
|
||||
by,
|
||||
[](mobj_t* thing)
|
||||
{
|
||||
static_cast<AnyBox*>(thing)->update();
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Crate : Box<SA2CrateConfig>
|
||||
{
|
||||
static constexpr int kMetalFrameStart = 8;
|
||||
|
||||
void thing_args() = delete;
|
||||
bool metal() const { return mobj_t::thing_args[0]; }
|
||||
|
||||
void init()
|
||||
{
|
||||
Box::init();
|
||||
|
||||
if (metal())
|
||||
{
|
||||
for (Graphic* g : gfx())
|
||||
{
|
||||
g->frame += kMetalFrameStart;
|
||||
}
|
||||
|
||||
debris_state(S_SA2_CRATE_DEBRIS_METAL);
|
||||
}
|
||||
}
|
||||
|
||||
void damage(Toucher* inflictor)
|
||||
{
|
||||
if (!Box::damage_valid(inflictor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (metal() && !inflictor->boosting())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Box::damage(inflictor);
|
||||
}
|
||||
};
|
||||
|
||||
struct Ice : Box<IceCapBlockConfig>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
bool AnyBox::visit(F&& visitor)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MT_SA2_CRATE:
|
||||
visitor(static_cast<Crate*>(this));
|
||||
break;
|
||||
|
||||
case MT_ICECAPBLOCK:
|
||||
visitor(static_cast<Ice*>(this));
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_BoxSideThink(mobj_t* mobj)
|
||||
{
|
||||
static_cast<Side*>(mobj)->think();
|
||||
}
|
||||
|
||||
void Obj_TryCrateInit(mobj_t* mobj)
|
||||
{
|
||||
static_cast<AnyBox*>(mobj)->visit([&](auto box) { box->init(); });
|
||||
}
|
||||
|
||||
boolean Obj_TryCrateThink(mobj_t* mobj)
|
||||
{
|
||||
bool c = false;
|
||||
static_cast<AnyBox*>(mobj)->visit([&](auto box) { c = box->think(); });
|
||||
return c;
|
||||
}
|
||||
|
||||
void Obj_TryCrateTouch(mobj_t* special, mobj_t* toucher)
|
||||
{
|
||||
static_cast<AnyBox*>(special)->visit([&](auto box) { box->touch(static_cast<Toucher*>(toucher)); });
|
||||
}
|
||||
|
||||
void Obj_TryCrateDamage(mobj_t* target, mobj_t* inflictor)
|
||||
{
|
||||
static_cast<AnyBox*>(target)->visit([&](auto box) { box->damage(static_cast<Toucher*>(inflictor)); });
|
||||
}
|
||||
|
|
@ -276,6 +276,7 @@ static void spawn_lens_flare(mobj_t *emerald)
|
|||
void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse)
|
||||
{
|
||||
P_SetTarget(&emerald_orbit(emerald), target);
|
||||
P_SetTarget(&emerald->punt_ref, target);
|
||||
|
||||
if (P_MobjWasRemoved(emerald_award(emerald)))
|
||||
{
|
||||
|
|
|
|||
236
src/objects/fuel.cpp
Normal file
236
src/objects/fuel.cpp
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "broly.hpp"
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../sounds.h"
|
||||
#include "../tables.h"
|
||||
|
||||
using namespace srb2::objects;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct FuelCanister : Mobj
|
||||
{
|
||||
struct Emitter : Mobj
|
||||
{
|
||||
void thing_args() = delete;
|
||||
tic_t frequency() const { return mobj_t::thing_args[0]; }
|
||||
tic_t initial_timer() const { return mobj_t::thing_args[1]; }
|
||||
|
||||
void extravalue1() = delete;
|
||||
tic_t timer() const { return mobj_t::extravalue1; }
|
||||
void timer(tic_t n) { mobj_t::extravalue1 = n; }
|
||||
|
||||
void init()
|
||||
{
|
||||
timer(initial_timer());
|
||||
}
|
||||
|
||||
bool think()
|
||||
{
|
||||
if (timer() > 0)
|
||||
{
|
||||
timer(timer() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
timer(frequency());
|
||||
|
||||
FuelCanister::spawn(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vis : Mobj
|
||||
{
|
||||
void extravalue1() = delete;
|
||||
angle_t phys_angle_ofs() const { return mobj_t::extravalue1; }
|
||||
void phys_angle_ofs(angle_t n) { mobj_t::extravalue1 = n; }
|
||||
|
||||
void extravalue2() = delete;
|
||||
angle_t vis_angle_ofs() const { return mobj_t::extravalue2; }
|
||||
void vis_angle_ofs(angle_t n) { mobj_t::extravalue2 = n; }
|
||||
|
||||
bool valid() const { return Mobj::valid() && Mobj::valid(target()); }
|
||||
|
||||
bool think()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
const angle_t angleOutward = target()->angle + phys_angle_ofs();
|
||||
|
||||
move_origin({target()->pos2d() + (vector(angleOutward) * Fixed {radius}), target()->z});
|
||||
angle = angleOutward + vis_angle_ofs();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Explosion : Broly
|
||||
{
|
||||
static constexpr mobjtype_t kMobjType = MT_BETA_PARTICLE_EXPLOSION;
|
||||
|
||||
static Explosion* spawn(Mobj* source)
|
||||
{
|
||||
Explosion* x = Broly::spawn<Explosion>(source, 3*TICRATE, {1, 8 * mapobjectscale});
|
||||
x->voice(sfx_lcfuel);
|
||||
return x;
|
||||
}
|
||||
|
||||
void touch(Mobj* toucher)
|
||||
{
|
||||
if (!P_DamageMobj(toucher, this, this, 1, DMG_NORMAL))
|
||||
{
|
||||
auto& hitlag = toucher->mobj_t::hitlag;
|
||||
|
||||
// Hitlag = remaining duration of explosion
|
||||
if (hitlag >= 0 && hitlag + 0u < remaining())
|
||||
{
|
||||
hitlag = remaining();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool think() { return Broly::think(); }
|
||||
};
|
||||
|
||||
bool valid() const { return Mobj::valid() && momz; }
|
||||
|
||||
static FuelCanister* spawn(Mobj* source)
|
||||
{
|
||||
FuelCanister* caps = source->spawn_from<FuelCanister>({}, MT_BETA_PARTICLE_PHYSICAL);
|
||||
caps->init();
|
||||
return caps;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
momz = 8 * scale();
|
||||
z -= momz;
|
||||
|
||||
pieces<Wheel>();
|
||||
pieces<Icon>();
|
||||
}
|
||||
|
||||
bool think()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
angle += 8 * ANG1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void touch(Mobj* toucher)
|
||||
{
|
||||
Explosion::spawn(toucher);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Wheel
|
||||
{
|
||||
static constexpr int kSides = 6;
|
||||
static constexpr statenum_t kState = S_BETA_PARTICLE_WHEEL;
|
||||
static constexpr int kRadius = 8;
|
||||
static constexpr Fixed kScale = FRACUNIT;
|
||||
static constexpr angle_t kAngleOffset = 0;
|
||||
static constexpr int kZOffset = 0;
|
||||
};
|
||||
|
||||
struct Icon
|
||||
{
|
||||
static constexpr int kSides = 2;
|
||||
static constexpr statenum_t kState = S_BETA_PARTICLE_ICON;
|
||||
static constexpr int kRadius = 8;
|
||||
static constexpr Fixed kScale = 3*FRACUNIT/4;
|
||||
static constexpr angle_t kAngleOffset = ANGLE_90;
|
||||
static constexpr int kZOffset = 64;
|
||||
};
|
||||
|
||||
static Vec2<Fixed> vector(angle_t angle) { return {FCOS(angle), FSIN(angle)}; }
|
||||
|
||||
template <class Config>
|
||||
void pieces()
|
||||
{
|
||||
constexpr angle_t kAngleBetween = ANGLE_MAX / Config::kSides;
|
||||
|
||||
const Fixed zOfs = Config::kZOffset * (Fixed {FRACUNIT} / Config::kScale);
|
||||
const Fixed radius = Config::kRadius * scale();
|
||||
const Fixed scale = Config::kScale * this->scale();
|
||||
|
||||
for (int i = 1; i <= Config::kSides; ++i)
|
||||
{
|
||||
angle_t angleOutward = i * kAngleBetween;
|
||||
|
||||
Vis* vis = spawn_from<Vis>({vector(angle + angleOutward) * radius, 0}, MT_BETA_PARTICLE_VISUAL);
|
||||
|
||||
vis->state(Config::kState);
|
||||
vis->target(this);
|
||||
vis->scale(scale);
|
||||
vis->radius = radius;
|
||||
vis->spriteyoffset(zOfs);
|
||||
|
||||
vis->phys_angle_ofs(angleOutward);
|
||||
vis->vis_angle_ofs(Config::kAngleOffset);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_FuelCanisterEmitterInit(mobj_t *mo)
|
||||
{
|
||||
static_cast<FuelCanister::Emitter*>(mo)->init();
|
||||
}
|
||||
|
||||
boolean Obj_FuelCanisterVisualThink(mobj_t *mo)
|
||||
{
|
||||
return static_cast<FuelCanister::Vis*>(mo)->think();
|
||||
}
|
||||
|
||||
boolean Obj_FuelCanisterEmitterThink(mobj_t *mo)
|
||||
{
|
||||
return static_cast<FuelCanister::Emitter*>(mo)->think();
|
||||
}
|
||||
|
||||
boolean Obj_FuelCanisterThink(mobj_t *mo)
|
||||
{
|
||||
return static_cast<FuelCanister*>(mo)->think();
|
||||
}
|
||||
|
||||
void Obj_FuelCanisterTouch(mobj_t *special, mobj_t *toucher)
|
||||
{
|
||||
static_cast<FuelCanister*>(special)->touch(static_cast<Mobj*>(toucher));
|
||||
}
|
||||
|
||||
void Obj_FuelCanisterExplosionTouch(mobj_t *special, mobj_t *toucher)
|
||||
{
|
||||
static_cast<FuelCanister::Explosion*>(special)->touch(static_cast<Mobj*>(toucher));
|
||||
}
|
||||
|
||||
boolean Obj_FuelCanisterExplosionThink(mobj_t *mo)
|
||||
{
|
||||
return static_cast<FuelCanister::Explosion*>(mo)->think();
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ struct IvoBall : Mobj
|
|||
Fixed wave{(x / mapobjectscale) + (y / mapobjectscale)};
|
||||
offset(wave / kRippleFactor);
|
||||
color = SKINCOLOR_TANGERINE;
|
||||
sprzoff = kFloat * mapobjectscale;
|
||||
sprzoff(kFloat * mapobjectscale);
|
||||
}
|
||||
|
||||
void think()
|
||||
|
|
@ -81,7 +81,7 @@ struct IvoBall : Mobj
|
|||
|
||||
fixed_t ballTimer = leveltime + offset();
|
||||
Fixed bob = kBobHeight * Fixed {FSIN((M_TAU_FIXED * kBobTime) * ballTimer)};
|
||||
spriteyoffset = bob;
|
||||
spriteyoffset(bob);
|
||||
|
||||
colorized = !((ballTimer / kFlashTime) & 1);
|
||||
}
|
||||
|
|
|
|||
19
src/objects/objects.hpp
Normal file
19
src/objects/objects.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef objects_objects_hpp
|
||||
#define objects_objects_hpp
|
||||
|
||||
#include "../math/fixed.hpp"
|
||||
#include "../math/vec.hpp"
|
||||
#include "../mobj.hpp"
|
||||
|
||||
#include "../k_objects.h"
|
||||
|
||||
namespace srb2::objects
|
||||
{
|
||||
|
||||
using srb2::Mobj;
|
||||
using srb2::math::Fixed;
|
||||
using srb2::math::Vec2;
|
||||
|
||||
}; // namespace srb2::objects
|
||||
|
||||
#endif/*objects_objects_hpp*/
|
||||
179
src/objects/spear.cpp
Normal file
179
src/objects/spear.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Original Lua script by Lat
|
||||
// Hardcoded by jartha
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../math/fixed.hpp"
|
||||
#include "../math/vec.hpp"
|
||||
#include "../mobj.hpp"
|
||||
#include "../mobj_list_view.hpp"
|
||||
|
||||
#include "../doomstat.h"
|
||||
#include "../doomtype.h"
|
||||
#include "../info.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../tables.h"
|
||||
|
||||
using srb2::math::Fixed;
|
||||
using srb2::math::Vec2;
|
||||
using srb2::Mobj;
|
||||
using srb2::MobjListView;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
Vec2<Fixed> angle_vector(angle_t x)
|
||||
{
|
||||
return Vec2<Fixed> {FCOS(x), FSIN(x)};
|
||||
}
|
||||
|
||||
struct Spear : Mobj
|
||||
{
|
||||
enum Mode
|
||||
{
|
||||
kWait,
|
||||
kShake,
|
||||
kPush,
|
||||
kPull,
|
||||
kNumModes,
|
||||
};
|
||||
|
||||
static constexpr tic_t kWaitTimes[kNumModes] = {
|
||||
TICRATE,
|
||||
TICRATE/2,
|
||||
TICRATE/2,
|
||||
TICRATE,
|
||||
};
|
||||
|
||||
void extravalue1() = delete;
|
||||
int mode() const { return mobj_t::extravalue1; }
|
||||
void mode(int n)
|
||||
{
|
||||
mobj_t::extravalue1 = n;
|
||||
timer(kWaitTimes[n]);
|
||||
}
|
||||
|
||||
void extravalue2() = delete;
|
||||
tic_t timer() const { return mobj_t::extravalue2; }
|
||||
void timer(tic_t n) { mobj_t::extravalue2 = n; }
|
||||
|
||||
void threshold() = delete;
|
||||
Fixed dist() const { return mobj_t::threshold; }
|
||||
void dist(Fixed n) { mobj_t::threshold = n; }
|
||||
|
||||
void thing_args() = delete;
|
||||
bool delayed_start() const { return mobj_t::thing_args[0]; }
|
||||
|
||||
void init()
|
||||
{
|
||||
mode(kWait);
|
||||
|
||||
if (delayed_start())
|
||||
{
|
||||
timer(timer() + TICRATE*3/2);
|
||||
}
|
||||
|
||||
auto piece = [&](statenum_t state)
|
||||
{
|
||||
Mobj* vis = spawn_from<Mobj>({}, MT_SPEARVISUAL);
|
||||
vis->state(state);
|
||||
return vis;
|
||||
};
|
||||
|
||||
Vec2<Fixed> v = angle_vector(angle) * scale();
|
||||
auto divider = [&](statenum_t state, int offset)
|
||||
{
|
||||
Mobj* vis = piece(state);
|
||||
vis->angle = angle - ANGLE_90;
|
||||
vis->sproff2d(v * offset);
|
||||
return vis;
|
||||
};
|
||||
|
||||
Mobj* head = this;
|
||||
auto link = [&](Mobj* vis)
|
||||
{
|
||||
vis->punt_ref(this);
|
||||
head->hnext(vis);
|
||||
head = vis;
|
||||
return vis;
|
||||
};
|
||||
|
||||
Mobj* wall = divider(S_SPEAR_WALL, 0); // never moves
|
||||
|
||||
set_origin({pos2d() + (angle_vector(angle) * Fixed {radius}), z});
|
||||
|
||||
link(divider(S_SPEAR_HILT_BACK, 26));
|
||||
Mobj* front = link(divider(S_SPEAR_HILT_FRONT, 34));
|
||||
|
||||
Mobj* tip = piece(S_SPEAR_TIP);
|
||||
tip->angle = angle;
|
||||
link(tip);
|
||||
|
||||
// Whether you use a positive or negative offset
|
||||
// depends on how the sprite would originally be
|
||||
// sorted...
|
||||
this->linkdraw(wall, -5); // this sorts the rod behind the wall plate
|
||||
tip->linkdraw(front, -5); // this sorts the tip IN FRONT of the rod
|
||||
}
|
||||
|
||||
void think()
|
||||
{
|
||||
Vec2<Fixed> p = pos2d() - vector();
|
||||
dist(new_dist());
|
||||
Mobj::PosArg mpos{p + vector(), z};
|
||||
|
||||
move_origin(mpos);
|
||||
for (Mobj* vis : MobjListView(hnext(), [](Mobj* vis) { return vis->hnext(); }))
|
||||
{
|
||||
vis->move_origin(mpos);
|
||||
}
|
||||
|
||||
timer(timer() - 1);
|
||||
if (!timer())
|
||||
{
|
||||
mode((mode() + 1) % kNumModes);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Fixed new_dist() const
|
||||
{
|
||||
static constexpr int kMinDist = -96;
|
||||
static constexpr int kMaxDist = 0;
|
||||
|
||||
switch (mode())
|
||||
{
|
||||
default:
|
||||
return kMinDist * scale();
|
||||
case kShake:
|
||||
return (leveltime & 1 ? kMinDist : kMinDist + 4) * scale();
|
||||
case kPush:
|
||||
return std::min(scale() * kMaxDist, dist() + (16 * scale()));
|
||||
case kPull:
|
||||
return std::max(scale() * kMinDist, dist() - (4 * scale()));
|
||||
}
|
||||
}
|
||||
|
||||
Vec2<Fixed> vector() const { return angle_vector(angle) * dist(); }
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_SpearInit(mobj_t* mobj)
|
||||
{
|
||||
static_cast<Spear*>(mobj)->init();
|
||||
}
|
||||
|
||||
void Obj_SpearThink(mobj_t* mobj)
|
||||
{
|
||||
static_cast<Spear*>(mobj)->think();
|
||||
}
|
||||
|
|
@ -563,6 +563,11 @@ void Controller::search()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (player->spectator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not retarget existing target or owner.
|
||||
if (mobj == chasing() || mobj == source())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -988,6 +988,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
}
|
||||
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
{
|
||||
Obj_TryCrateTouch(special, toucher);
|
||||
return;
|
||||
}
|
||||
|
||||
case MT_BETA_PARTICLE_PHYSICAL:
|
||||
{
|
||||
Obj_FuelCanisterTouch(special, toucher);
|
||||
break;
|
||||
}
|
||||
|
||||
case MT_BETA_PARTICLE_EXPLOSION:
|
||||
{
|
||||
Obj_FuelCanisterExplosionTouch(special, toucher);
|
||||
return;
|
||||
}
|
||||
|
||||
default: // SOC or script pickup
|
||||
P_SetTarget(&special->target, toucher);
|
||||
break;
|
||||
|
|
@ -2842,10 +2861,19 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false;
|
||||
}
|
||||
|
||||
if (target->type == MT_BALLSWITCH_BALL)
|
||||
switch (target->type)
|
||||
{
|
||||
Obj_BallSwitchDamaged(target, inflictor, source);
|
||||
return false;
|
||||
case MT_BALLSWITCH_BALL:
|
||||
Obj_BallSwitchDamaged(target, inflictor, source);
|
||||
return false;
|
||||
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
Obj_TryCrateDamage(target, inflictor);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!force)
|
||||
|
|
|
|||
49
src/p_link.cpp
Normal file
49
src/p_link.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "p_link.h"
|
||||
#include "p_mobj.h"
|
||||
|
||||
|
||||
#define LINK_PACK \
|
||||
svg_battleUfoSpawners,\
|
||||
svg_checkpoints
|
||||
|
||||
|
||||
using link = mobj_t*;
|
||||
using each_ref = std::initializer_list<std::reference_wrapper<mobj_t*>>;
|
||||
|
||||
link LINK_PACK;
|
||||
|
||||
void P_InitMobjPointers(void)
|
||||
{
|
||||
for (mobj_t*& head : each_ref {LINK_PACK})
|
||||
{
|
||||
head = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void P_SaveMobjPointers(void(*fn)(mobj_t*))
|
||||
{
|
||||
for (mobj_t* head : {LINK_PACK})
|
||||
{
|
||||
fn(head);
|
||||
}
|
||||
}
|
||||
|
||||
void P_LoadMobjPointers(void(*fn)(mobj_t**))
|
||||
{
|
||||
for (mobj_t*& head : each_ref {LINK_PACK})
|
||||
{
|
||||
fn(&head);
|
||||
}
|
||||
}
|
||||
27
src/p_link.h
Normal file
27
src/p_link.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef p_link_h
|
||||
#define p_link_h
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void P_InitMobjPointers(void);
|
||||
void P_SaveMobjPointers(void(*callback)(mobj_t*));
|
||||
void P_LoadMobjPointers(void(*callback)(mobj_t**));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif/*p_link_h*/
|
||||
42
src/p_map.c
42
src/p_map.c
|
|
@ -1200,8 +1200,6 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
if ((thing->type == MT_SPRINGSHELL || thing->type == MT_YELLOWSHELL) && thing->health > 0
|
||||
&& (tm.thing->player || (tm.thing->flags & MF_PUSHABLE)) && tm.thing->health > 0)
|
||||
{
|
||||
|
|
@ -1474,11 +1472,11 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
// The bump has to happen last
|
||||
if (P_IsObjectOnGround(thing) && tm.thing->momz < 0 && tm.thing->player->trickpanel)
|
||||
{
|
||||
P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_WIPEOUT|DMG_STEAL);
|
||||
P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_TUMBLE);
|
||||
}
|
||||
else if (P_IsObjectOnGround(tm.thing) && thing->momz < 0 && thing->player->trickpanel)
|
||||
{
|
||||
P_DamageMobj(tm.thing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL);
|
||||
P_DamageMobj(tm.thing, thing, thing, 1, DMG_TUMBLE);
|
||||
}
|
||||
|
||||
if (K_KartBouncing(tm.thing, thing) == true)
|
||||
|
|
@ -1618,6 +1616,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
K_KartBouncing(tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if ((thing->flags & MF_SHOOTABLE) && K_PlayerCanPunt(tm.thing->player))
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tm.thing->z > thing->z + thing->height)
|
||||
return BMIT_CONTINUE; // overhead
|
||||
if (tm.thing->z + tm.thing->height < thing->z)
|
||||
return BMIT_CONTINUE; // underneath
|
||||
|
||||
P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->flags & MF_SOLID)
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -1634,6 +1643,31 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
}
|
||||
}
|
||||
|
||||
switch (tm.thing->type)
|
||||
{
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
// Let crates stack on top of solid objects (this
|
||||
// includes other crates).
|
||||
if (thing->flags & MF_SOLID)
|
||||
{
|
||||
fixed_t thingtop = thing->z + thing->height;
|
||||
if (tm.thing->z > thing->z && thingtop > tm.floorz)
|
||||
{
|
||||
tm.floorz = thingtop;
|
||||
tm.floorrover = NULL;
|
||||
tm.floorslope = NULL;
|
||||
tm.floorpic = -1;
|
||||
tm.floorstep = 0;
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// This code is causing conflicts for Ring Racers,
|
||||
// as solid objects cause bumping. If you need to
|
||||
// bring back this code for a moving platform-style
|
||||
|
|
|
|||
108
src/p_mobj.c
108
src/p_mobj.c
|
|
@ -5434,6 +5434,9 @@ void P_RunOverlays(void)
|
|||
mo->scale = mo->destscale = FixedMul(mo->target->scale, mo->movefactor);
|
||||
mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir;
|
||||
|
||||
P_SetTarget(&mo->punt_ref, mo->target->punt_ref);
|
||||
mo->reappear = mo->target->reappear;
|
||||
|
||||
if (!(mo->threshold & OV_DONTSCREENOFFSET))
|
||||
{
|
||||
mo->spritexoffset = mo->target->spritexoffset;
|
||||
|
|
@ -6836,6 +6839,47 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
Obj_PatrolIvoBallThink(mobj);
|
||||
return;
|
||||
}
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
{
|
||||
if (!Obj_TryCrateThink(mobj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_BOX_SIDE:
|
||||
{
|
||||
Obj_BoxSideThink(mobj);
|
||||
return;
|
||||
}
|
||||
case MT_SPEAR:
|
||||
{
|
||||
Obj_SpearThink(mobj);
|
||||
return;
|
||||
}
|
||||
case MT_SPEARVISUAL:
|
||||
{
|
||||
return;
|
||||
}
|
||||
case MT_BETA_PARTICLE_VISUAL:
|
||||
{
|
||||
Obj_FuelCanisterVisualThink(mobj);
|
||||
return;
|
||||
}
|
||||
case MT_BETA_EMITTER:
|
||||
{
|
||||
Obj_FuelCanisterEmitterThink(mobj);
|
||||
return;
|
||||
}
|
||||
case MT_BETA_PARTICLE_EXPLOSION:
|
||||
{
|
||||
if (Obj_FuelCanisterExplosionThink(mobj) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_VWREF:
|
||||
case MT_VWREB:
|
||||
{
|
||||
|
|
@ -10233,6 +10277,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
Obj_SidewaysFreezeThrusterThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BETA_PARTICLE_PHYSICAL:
|
||||
{
|
||||
if (!Obj_FuelCanisterThink(mobj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
|
|
@ -11006,6 +11058,10 @@ fixed_t P_GetMobjDefaultScale(mobj_t *mobj)
|
|||
case MT_HANAGUMIHALL_STEAM:
|
||||
case MT_HANAGUMIHALL_NPC:
|
||||
return 2*FRACUNIT;
|
||||
case MT_SPEAR:
|
||||
return 2*FRACUNIT;
|
||||
case MT_BETA_EMITTER:
|
||||
return 4*FRACUNIT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -14476,6 +14532,22 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
|
|||
Obj_PatrolIvoBallInit(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
{
|
||||
Obj_TryCrateInit(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_SPEAR:
|
||||
{
|
||||
Obj_SpearInit(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BETA_EMITTER:
|
||||
{
|
||||
Obj_FuelCanisterEmitterInit(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -14502,24 +14574,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
|
|||
return true;
|
||||
}
|
||||
|
||||
static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||
void P_CopyMapThingSpecialFieldsToMobj(const mapthing_t *mthing, mobj_t *mobj)
|
||||
{
|
||||
mobj_t *mobj = NULL;
|
||||
size_t arg = SIZE_MAX;
|
||||
|
||||
mobj = P_SpawnMobj(x, y, z, type);
|
||||
mobj->spawnpoint = mthing;
|
||||
|
||||
mobj->angle = FixedAngle(mthing->angle << FRACBITS);
|
||||
mobj->pitch = FixedAngle(mthing->pitch << FRACBITS);
|
||||
mobj->roll = FixedAngle(mthing->roll << FRACBITS);
|
||||
|
||||
P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
|
||||
mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
|
||||
|
||||
mobj->spritexscale = mthing->spritexscale;
|
||||
mobj->spriteyscale = mthing->spriteyscale;
|
||||
|
||||
P_SetThingTID(mobj, mthing->tid);
|
||||
|
||||
mobj->special = mthing->special;
|
||||
|
|
@ -14573,6 +14631,26 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
|
|||
mobj->script_stringargs[arg] = Z_Realloc(mobj->script_stringargs[arg], len + 1, PU_LEVEL, NULL);
|
||||
M_Memcpy(mobj->script_stringargs[arg], mthing->script_stringargs[arg], len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||
{
|
||||
mobj_t *mobj = NULL;
|
||||
|
||||
mobj = P_SpawnMobj(x, y, z, type);
|
||||
mobj->spawnpoint = mthing;
|
||||
|
||||
mobj->angle = FixedAngle(mthing->angle << FRACBITS);
|
||||
mobj->pitch = FixedAngle(mthing->pitch << FRACBITS);
|
||||
mobj->roll = FixedAngle(mthing->roll << FRACBITS);
|
||||
|
||||
P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
|
||||
mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
|
||||
|
||||
mobj->spritexscale = mthing->spritexscale;
|
||||
mobj->spriteyscale = mthing->spriteyscale;
|
||||
|
||||
P_CopyMapThingSpecialFieldsToMobj(mthing, mobj);
|
||||
|
||||
if (!P_SetupSpawnedMapThing(mthing, mobj))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -557,6 +557,7 @@ fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const f
|
|||
fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y);
|
||||
|
||||
mobj_t *P_SpawnMapThing(mapthing_t *mthing);
|
||||
void P_CopyMapThingSpecialFieldsToMobj(const mapthing_t *mthing, mobj_t *mobj);
|
||||
void P_SpawnHoop(mapthing_t *mthing);
|
||||
void P_SpawnItemPattern(mapthing_t *mthing);
|
||||
void P_SpawnItemLine(mapthing_t *mt1, mapthing_t *mt2);
|
||||
|
|
|
|||
137
src/p_saveg.c
137
src/p_saveg.c
|
|
@ -36,6 +36,7 @@
|
|||
#include "lua_script.h"
|
||||
#include "p_slopes.h"
|
||||
#include "m_cond.h" // netUnlocked
|
||||
#include "p_link.h"
|
||||
|
||||
// SRB2Kart
|
||||
#include "k_grandprix.h"
|
||||
|
|
@ -50,6 +51,8 @@
|
|||
savedata_t savedata;
|
||||
savedata_cup_t cupsavedata;
|
||||
|
||||
static savebuffer_t *current_savebuffer;
|
||||
|
||||
// Block UINT32s to attempt to ensure that the correct data is
|
||||
// being sent and received
|
||||
#define ARCHIVEBLOCK_MISC 0x7FEEDEED
|
||||
|
|
@ -3839,6 +3842,11 @@ static void SavePolyfadeThinker(savebuffer_t *save, const thinker_t *th, const U
|
|||
WRITEINT32(save->p, ht->timer);
|
||||
}
|
||||
|
||||
static void WriteMobjPointer(mobj_t *mobj)
|
||||
{
|
||||
WRITEUINT32(current_savebuffer->p, SaveMobjnum(mobj));
|
||||
}
|
||||
|
||||
static void P_NetArchiveThinkers(savebuffer_t *save)
|
||||
{
|
||||
const thinker_t *th;
|
||||
|
|
@ -3846,6 +3854,8 @@ static void P_NetArchiveThinkers(savebuffer_t *save)
|
|||
|
||||
WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS);
|
||||
|
||||
P_SaveMobjPointers(WriteMobjPointer);
|
||||
|
||||
for (i = 0; i < NUM_THINKERLISTS; i++)
|
||||
{
|
||||
UINT32 numsaved = 0;
|
||||
|
|
@ -4538,6 +4548,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
|
|||
mobj->script_stringargs[j][len] = '\0';
|
||||
}
|
||||
}
|
||||
else if (mobj->spawnpoint)
|
||||
{
|
||||
P_CopyMapThingSpecialFieldsToMobj(mobj->spawnpoint, mobj);
|
||||
}
|
||||
if (diff2 & MD2_FLOORSPRITESLOPE)
|
||||
{
|
||||
pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj);
|
||||
|
|
@ -5234,6 +5248,11 @@ static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker)
|
|||
return &ht->thinker;
|
||||
}
|
||||
|
||||
static void ReadMobjPointer(mobj_t **mobj_p)
|
||||
{
|
||||
*mobj_p = LoadMobj(READUINT32(current_savebuffer->p));
|
||||
}
|
||||
|
||||
static void P_NetUnArchiveThinkers(savebuffer_t *save)
|
||||
{
|
||||
thinker_t *currentthinker;
|
||||
|
|
@ -5269,6 +5288,8 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save)
|
|||
// we don't want the removed mobjs to come back
|
||||
P_InitThinkers();
|
||||
|
||||
P_LoadMobjPointers(ReadMobjPointer);
|
||||
|
||||
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
|
|
@ -5572,12 +5593,26 @@ static inline void P_UnArchivePolyObjects(savebuffer_t *save)
|
|||
P_UnArchivePolyObj(save, &PolyObjects[i]);
|
||||
}
|
||||
|
||||
static mobj_t *RelinkMobj(mobj_t **ptr)
|
||||
{
|
||||
UINT32 temp = (UINT32)(size_t)*ptr;
|
||||
*ptr = NULL;
|
||||
return P_SetTarget(ptr, P_FindNewPosition(temp));
|
||||
}
|
||||
|
||||
static void RelinkMobjVoid(mobj_t **ptr)
|
||||
{
|
||||
RelinkMobj(ptr);
|
||||
}
|
||||
|
||||
static void P_RelinkPointers(void)
|
||||
{
|
||||
thinker_t *currentthinker;
|
||||
mobj_t *mobj;
|
||||
UINT32 temp, i;
|
||||
|
||||
P_LoadMobjPointers(RelinkMobjVoid);
|
||||
|
||||
// use info field (value = oldposition) to relink mobjs
|
||||
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
|
||||
currentthinker = currentthinker->next)
|
||||
|
|
@ -5592,37 +5627,27 @@ static void P_RelinkPointers(void)
|
|||
|
||||
if (mobj->tracer)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->tracer;
|
||||
mobj->tracer = NULL;
|
||||
if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->tracer))
|
||||
CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->target)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->target;
|
||||
mobj->target = NULL;
|
||||
if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->target))
|
||||
CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->hnext)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->hnext;
|
||||
mobj->hnext = NULL;
|
||||
if (!P_SetTarget(&mobj->hnext, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->hnext))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->hprev)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->hprev;
|
||||
mobj->hprev = NULL;
|
||||
if (!P_SetTarget(&mobj->hprev, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->hprev))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->itnext)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->itnext;
|
||||
mobj->itnext = NULL;
|
||||
if (!P_SetTarget(&mobj->itnext, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->itnext))
|
||||
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->terrain)
|
||||
|
|
@ -5636,23 +5661,17 @@ static void P_RelinkPointers(void)
|
|||
}
|
||||
if (mobj->terrainOverlay)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->terrainOverlay;
|
||||
mobj->terrainOverlay = NULL;
|
||||
if (!P_SetTarget(&mobj->terrainOverlay, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->terrainOverlay))
|
||||
CONS_Debug(DBG_GAMELOGIC, "terrainOverlay not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->punt_ref)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->punt_ref;
|
||||
mobj->punt_ref = NULL;
|
||||
if (!P_SetTarget(&mobj->punt_ref, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->punt_ref))
|
||||
CONS_Debug(DBG_GAMELOGIC, "punt_ref not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->owner)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->owner;
|
||||
mobj->owner = NULL;
|
||||
if (!P_SetTarget(&mobj->owner, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->owner))
|
||||
CONS_Debug(DBG_GAMELOGIC, "owner not found on %d\n", mobj->type);
|
||||
}
|
||||
}
|
||||
|
|
@ -5664,37 +5683,27 @@ static void P_RelinkPointers(void)
|
|||
|
||||
if (players[i].skybox.viewpoint)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].skybox.viewpoint;
|
||||
players[i].skybox.viewpoint = NULL;
|
||||
if (!P_SetTarget(&players[i].skybox.viewpoint, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].skybox.viewpoint))
|
||||
CONS_Debug(DBG_GAMELOGIC, "skybox.viewpoint not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].skybox.centerpoint)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].skybox.centerpoint;
|
||||
players[i].skybox.centerpoint = NULL;
|
||||
if (!P_SetTarget(&players[i].skybox.centerpoint, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].skybox.centerpoint))
|
||||
CONS_Debug(DBG_GAMELOGIC, "skybox.centerpoint not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].awayview.mobj)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].awayview.mobj;
|
||||
players[i].awayview.mobj = NULL;
|
||||
if (!P_SetTarget(&players[i].awayview.mobj, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].awayview.mobj))
|
||||
CONS_Debug(DBG_GAMELOGIC, "awayview.mobj not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].followmobj)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].followmobj;
|
||||
players[i].followmobj = NULL;
|
||||
if (!P_SetTarget(&players[i].followmobj, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].followmobj))
|
||||
CONS_Debug(DBG_GAMELOGIC, "followmobj not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].follower)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].follower;
|
||||
players[i].follower = NULL;
|
||||
if (!P_SetTarget(&players[i].follower, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].follower))
|
||||
CONS_Debug(DBG_GAMELOGIC, "follower not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].currentwaypoint)
|
||||
|
|
@ -5726,72 +5735,52 @@ static void P_RelinkPointers(void)
|
|||
}
|
||||
if (players[i].hoverhyudoro)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].hoverhyudoro;
|
||||
players[i].hoverhyudoro = NULL;
|
||||
if (!P_SetTarget(&players[i].hoverhyudoro, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].hoverhyudoro))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].stumbleIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].stumbleIndicator;
|
||||
players[i].stumbleIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].stumbleIndicator, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].stumbleIndicator))
|
||||
CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].wavedashIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].wavedashIndicator;
|
||||
players[i].wavedashIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].wavedashIndicator, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].wavedashIndicator))
|
||||
CONS_Debug(DBG_GAMELOGIC, "wavedashIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].trickIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].trickIndicator;
|
||||
players[i].trickIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].trickIndicator, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].trickIndicator))
|
||||
CONS_Debug(DBG_GAMELOGIC, "trickIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].whip)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].whip;
|
||||
players[i].whip = NULL;
|
||||
if (!P_SetTarget(&players[i].whip, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].whip))
|
||||
CONS_Debug(DBG_GAMELOGIC, "whip not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].hand)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].hand;
|
||||
players[i].hand = NULL;
|
||||
if (!P_SetTarget(&players[i].hand, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].hand))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hand 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)))
|
||||
if (!RelinkMobj(&players[i].ringShooter))
|
||||
CONS_Debug(DBG_GAMELOGIC, "ringShooter not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].flickyAttacker)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].flickyAttacker;
|
||||
players[i].flickyAttacker = NULL;
|
||||
if (!P_SetTarget(&players[i].flickyAttacker, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].flickyAttacker))
|
||||
CONS_Debug(DBG_GAMELOGIC, "flickyAttacker not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].powerup.flickyController)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].powerup.flickyController;
|
||||
players[i].powerup.flickyController = NULL;
|
||||
if (!P_SetTarget(&players[i].powerup.flickyController, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].powerup.flickyController))
|
||||
CONS_Debug(DBG_GAMELOGIC, "powerup.flickyController not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].powerup.barrier)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].powerup.barrier;
|
||||
players[i].powerup.barrier = NULL;
|
||||
if (!P_SetTarget(&players[i].powerup.barrier, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].powerup.barrier))
|
||||
CONS_Debug(DBG_GAMELOGIC, "powerup.barrier not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
|
|
@ -6422,17 +6411,13 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
|
|||
gametic = READUINT32(save->p);
|
||||
|
||||
gamemap = READINT16(save->p);
|
||||
g_reloadingMap = false;
|
||||
|
||||
// gamemap changed; we assume that its map header is always valid,
|
||||
// so make it so
|
||||
if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1])
|
||||
I_Error("P_NetUnArchiveMisc: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders);
|
||||
|
||||
// tell the sound code to reset the music since we're skipping what
|
||||
// normally sets this flag
|
||||
if (!reloading)
|
||||
mapmusflags |= MUSIC_RELOADRESET;
|
||||
|
||||
G_SetGamestate(READINT16(save->p));
|
||||
|
||||
gametype = READINT16(save->p);
|
||||
|
|
@ -6687,6 +6672,8 @@ void P_SaveGame(savebuffer_t *save)
|
|||
|
||||
void P_SaveNetGame(savebuffer_t *save, boolean resending)
|
||||
{
|
||||
current_savebuffer = save;
|
||||
|
||||
thinker_t *th;
|
||||
mobj_t *mobj;
|
||||
UINT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
|
||||
|
|
@ -6763,6 +6750,8 @@ badloadgame:
|
|||
|
||||
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
||||
{
|
||||
current_savebuffer = save;
|
||||
|
||||
CV_LoadNetVars(&save->p);
|
||||
|
||||
if (!P_NetUnArchiveMisc(save, reloading))
|
||||
|
|
|
|||
|
|
@ -8069,7 +8069,7 @@ static void P_InitMinimapInfo(void)
|
|||
|
||||
void P_ResetLevelMusic(void)
|
||||
{
|
||||
mapmusrng = 0;
|
||||
UINT8 idx = 0;
|
||||
|
||||
if (mapheaderinfo[gamemap-1]->musname_size > 1)
|
||||
{
|
||||
|
|
@ -8090,20 +8090,46 @@ void P_ResetLevelMusic(void)
|
|||
|
||||
if (tempmapmus_size > 1)
|
||||
{
|
||||
mapmusrng = P_RandomKey(PR_MUSICSELECT, tempmapmus_size);
|
||||
if (g_reloadingMap)
|
||||
{
|
||||
// If restarting the map, simply cycle
|
||||
// through available alt music.
|
||||
idx = (mapmusrng + 1) % tempmapmus_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = P_RandomKey(PR_MUSICSELECT, tempmapmus_size);
|
||||
}
|
||||
//CONS_Printf("Rolled position %u, maps to %u\n", mapmusrng, tempmapmus[mapmusrng]);
|
||||
mapmusrng = tempmapmus[mapmusrng];
|
||||
idx = tempmapmus[idx];
|
||||
}
|
||||
}
|
||||
|
||||
mapmusrng = idx;
|
||||
}
|
||||
|
||||
void P_LoadLevelMusic(void)
|
||||
{
|
||||
tic_t level_music_start = starttime + (TICRATE/2);
|
||||
const char *music = mapheaderinfo[gamemap-1]->musname[mapmusrng];
|
||||
|
||||
Music_StopAll();
|
||||
Music_Remap("level", mapheaderinfo[gamemap-1]->musname[mapmusrng]);
|
||||
Music_Seek("level", max(leveltime, level_music_start) - level_music_start);
|
||||
if (gametyperules & GTR_NOPOSITION)
|
||||
{
|
||||
if (!stricmp(Music_Song("level_nosync"), music))
|
||||
{
|
||||
// Do not reset music if it is the same
|
||||
Music_BatchExempt("level_nosync");
|
||||
}
|
||||
Music_StopAll();
|
||||
Music_Remap("level_nosync", music);
|
||||
}
|
||||
else
|
||||
{
|
||||
Music_StopAll();
|
||||
Music_Remap("level", music);
|
||||
|
||||
tic_t level_music_start = starttime + (TICRATE/2);
|
||||
Music_Seek("level", max(leveltime, level_music_start) - level_music_start);
|
||||
}
|
||||
}
|
||||
|
||||
/** Loads a level from a lump or external wad.
|
||||
|
|
|
|||
10
src/p_tick.c
10
src/p_tick.c
|
|
@ -29,6 +29,7 @@
|
|||
#include "r_main.h"
|
||||
#include "r_fps.h"
|
||||
#include "d_clisrv.h" // UpdateChallenges
|
||||
#include "p_link.h"
|
||||
|
||||
// Object place
|
||||
#include "m_cheat.h"
|
||||
|
|
@ -299,8 +300,7 @@ void P_InitThinkers(void)
|
|||
skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL;
|
||||
}
|
||||
|
||||
Obj_ResetUFOSpawners();
|
||||
Obj_ResetCheckpoints();
|
||||
P_InitMobjPointers();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -975,7 +975,11 @@ void P_Ticker(boolean run)
|
|||
if (leveltime == (starttime + (TICRATE/2)))
|
||||
{
|
||||
// Plays the music after the starting countdown.
|
||||
Music_Play("level");
|
||||
if (!Music_Playing("level_nosync"))
|
||||
{
|
||||
// Do not stop level_nosync
|
||||
Music_Play(Music_Song("level_nosync")[0] ? "level_nosync" : "level");
|
||||
}
|
||||
}
|
||||
else if (starttime != introtime)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1332,6 +1332,11 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
{
|
||||
G_BeginLevelExit();
|
||||
}
|
||||
|
||||
if (specialstageinfo.valid == true && losing == false && P_MobjWasRemoved(player->mo) == false)
|
||||
{
|
||||
K_MakeObjectReappear(player->mo);
|
||||
}
|
||||
}
|
||||
|
||||
K_InitPlayerTally(player);
|
||||
|
|
|
|||
|
|
@ -1656,8 +1656,6 @@ static void R_ProjectBoundingBox(mobj_t *thing, vissprite_t *vis)
|
|||
|
||||
box->sortscale = vis->sortscale; // link sorting to sprite
|
||||
box->dispoffset = vis->dispoffset + 5;
|
||||
|
||||
box->cut = static_cast<spritecut_e>(box->cut | SC_LINKDRAW);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2086,7 +2086,7 @@ void S_ShowMusicCredit(void)
|
|||
char credittext[128] = "";
|
||||
char *work = NULL;
|
||||
size_t len = 128, worklen;
|
||||
INT32 widthused = BASEVIDWIDTH, workwidth;
|
||||
INT32 widthused = (3*BASEVIDWIDTH/4) - 7, workwidth;
|
||||
|
||||
if (!cv_songcredits.value)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1251,6 +1251,8 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
|
||||
{"ivobal", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Ivo Ball
|
||||
|
||||
{"lcfuel", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Fuel Capsule explodes"},
|
||||
|
||||
// Damage sounds
|
||||
{"dmga1", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"},
|
||||
{"dmga2", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"},
|
||||
|
|
|
|||
|
|
@ -1323,6 +1323,9 @@ typedef enum
|
|||
// Ivo Ball
|
||||
sfx_ivobal,
|
||||
|
||||
// Fuel Capsule
|
||||
sfx_lcfuel,
|
||||
|
||||
// Damage sounds
|
||||
sfx_dmga1,
|
||||
sfx_dmga2,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue