Add PlayerRespawn hook

This commit is contained in:
Lactozilla 2023-08-14 19:34:34 -03:00
parent fac87627a4
commit 8728ed1ec0
8 changed files with 244 additions and 84 deletions

View file

@ -637,6 +637,14 @@ extern tic_t gametic;
#define localgametic leveltime #define localgametic leveltime
typedef struct
{
fixed_t x, y, z;
angle_t angle;
boolean spawn_on_ceiling;
boolean spawn_flipped;
} spawnpoint_t;
enum enum
{ {
PLAYER_START_TYPE_COOP, PLAYER_START_TYPE_COOP,

View file

@ -2836,10 +2836,21 @@ void G_SpawnPlayer(INT32 playernum)
void G_MovePlayerToSpawnOrStarpost(INT32 playernum) void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
{ {
if (players[playernum].starposttime) spawnpoint_t *spawnpoint = LUA_HookPlayerRespawn(&players[playernum]);
P_MovePlayerToStarpost(playernum);
else if (spawnpoint == NULL)
P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum)); {
if (players[playernum].starposttime)
P_MovePlayerToStarpost(playernum);
else
spawnpoint = G_FindSpawnPoint(playernum);
}
if (spawnpoint)
{
P_MovePlayerToSpawn(playernum, spawnpoint);
Z_Free(spawnpoint);
}
R_ResetMobjInterpolationState(players[playernum].mo); R_ResetMobjInterpolationState(players[playernum].mo);
@ -3174,13 +3185,13 @@ static mapthing_t *G_GetTeamStartForSpawning(INT32 playernum)
return spawnpoint; return spawnpoint;
} }
mapthing_t *G_FindMapStart(INT32 playernum) spawnpoint_t *G_FindSpawnPoint(INT32 playernum)
{ {
if (!playeringame[playernum]) if (!playeringame[playernum])
return NULL; return NULL;
player_t *player = &players[playernum]; player_t *player = &players[playernum];
mapthing_t *spawnpoint = NULL; mapthing_t *mthing = NULL;
// -- Spectators -- // -- Spectators --
// Order in platform gametypes: Coop->DM->Team // Order in platform gametypes: Coop->DM->Team
@ -3190,9 +3201,9 @@ mapthing_t *G_FindMapStart(INT32 playernum)
// In platform gametypes, spawn in Co-op starts first // In platform gametypes, spawn in Co-op starts first
// Overriden by GTR_DEATHMATCHSTARTS. // Overriden by GTR_DEATHMATCHSTARTS.
if (G_PlatformGametype() && !(gametyperules & GTR_DEATHMATCHSTARTS)) if (G_PlatformGametype() && !(gametyperules & GTR_DEATHMATCHSTARTS))
spawnpoint = G_GetCoopStartForSpawning(playernum); mthing = G_GetCoopStartForSpawning(playernum);
else else
spawnpoint = G_GetMatchStartForSpawning(playernum); mthing = G_GetMatchStartForSpawning(playernum);
} }
// -- CTF -- // -- CTF --
@ -3200,9 +3211,9 @@ mapthing_t *G_FindMapStart(INT32 playernum)
else if (gametyperules & GTR_TEAMFLAGS && G_GametypeHasTeams()) else if (gametyperules & GTR_TEAMFLAGS && G_GametypeHasTeams())
{ {
if (player->ctfteam > TEAM_NONE && player->ctfteam < numteams) if (player->ctfteam > TEAM_NONE && player->ctfteam < numteams)
spawnpoint = G_GetTeamStartForSpawning(playernum); mthing = G_GetTeamStartForSpawning(playernum);
else else
spawnpoint = G_GetMatchStartForSpawning(playernum); mthing = G_GetMatchStartForSpawning(playernum);
} }
// -- DM/Tag/etc -- // -- DM/Tag/etc --
@ -3213,42 +3224,43 @@ mapthing_t *G_FindMapStart(INT32 playernum)
// If the player is not in a team, then this just gets a match start. // If the player is not in a team, then this just gets a match start.
if (G_GametypeHasTeams() && player->ctfteam > TEAM_NONE && player->ctfteam < numteams) if (G_GametypeHasTeams() && player->ctfteam > TEAM_NONE && player->ctfteam < numteams)
{ {
spawnpoint = G_FindTeamStart(playernum); mthing = G_FindTeamStart(playernum);
// If no spawn point was returned, but team starts are available, this means there is no good location // If no spawn point was returned, but team starts are available, this means there is no good location
// for the player to spawn at. In that situation, we display a message telling the player so. // for the player to spawn at. In that situation, we display a message telling the player so.
if (spawnpoint == NULL && G_AreTeamStartsAvailable(player->ctfteam) && P_IsLocalPlayer(player)) if (mthing == NULL && G_AreTeamStartsAvailable(player->ctfteam) && P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any %s starts!\n"), G_GetTeamName(player->ctfteam)); CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any %s starts!\n"), G_GetTeamName(player->ctfteam));
} }
// If that failed, no warning is shown. Instead, this will look for a match start, which may // If that failed, no warning is shown. Instead, this will look for a match start, which may
// then display a warning if no suitable map start was found. // then display a warning if no suitable map start was found.
if (spawnpoint == NULL) if (mthing == NULL)
spawnpoint = G_GetMatchStartForSpawning(playernum); mthing = G_GetMatchStartForSpawning(playernum);
} }
// -- Other game modes -- // -- Other game modes --
// Order: Coop->DM->Team // Order: Coop->DM->Team
else else
spawnpoint = G_GetCoopStartForSpawning(playernum); mthing = G_GetCoopStartForSpawning(playernum);
//No spawns found. ANYWHERE. //No spawns found. ANYWHERE.
if (!spawnpoint) if (!mthing)
{ {
if (nummapthings) if (nummapthings)
{ {
if (P_IsLocalPlayer(player)) if (P_IsLocalPlayer(player))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n")); CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n"));
spawnpoint = &mapthings[0]; mthing = &mapthings[0];
} }
else else
{ {
if (P_IsLocalPlayer(player)) if (P_IsLocalPlayer(player))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n")); CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n"));
return NULL;
} }
} }
return spawnpoint; return P_MakeSpawnPointFromMapthing(mthing);
} }
mapthing_t *G_FindBestPlayerStart(INT32 playernum) mapthing_t *G_FindBestPlayerStart(INT32 playernum)

View file

@ -179,11 +179,13 @@ void G_AddMatchPlayerStart(mapthing_t *mthing);
void G_AddTeamPlayerStart(UINT8 team, mapthing_t *mthing); void G_AddTeamPlayerStart(UINT8 team, mapthing_t *mthing);
void G_CountPlayerStarts(void); void G_CountPlayerStarts(void);
mapthing_t *G_FindMapStart(INT32 playernum);
mapthing_t *G_FindBestPlayerStart(INT32 playernum); mapthing_t *G_FindBestPlayerStart(INT32 playernum);
mapthing_t *G_FindCoopStart(INT32 playernum); mapthing_t *G_FindCoopStart(INT32 playernum);
mapthing_t *G_FindMatchStart(INT32 playernum); mapthing_t *G_FindMatchStart(INT32 playernum);
mapthing_t *G_FindTeamStart(INT32 playernum); mapthing_t *G_FindTeamStart(INT32 playernum);
spawnpoint_t *G_FindSpawnPoint(INT32 playernum);
void G_MovePlayerToSpawnOrStarpost(INT32 playernum); void G_MovePlayerToSpawnOrStarpost(INT32 playernum);
void G_SpawnPlayer(INT32 playernum); void G_SpawnPlayer(INT32 playernum);

View file

@ -72,6 +72,7 @@ automatically.
X (MusicChange),\ X (MusicChange),\
X (PlayerHeight),/* override player height */\ X (PlayerHeight),/* override player height */\
X (PlayerCanEnterSpinGaps),\ X (PlayerCanEnterSpinGaps),\
X (PlayerRespawn),\
X (KeyDown),\ X (KeyDown),\
X (KeyUp),\ X (KeyUp),\
@ -148,4 +149,5 @@ int LUA_HookShouldJingleContinue(player_t *, const char *musname);
int LUA_HookPlayerCmd(player_t *, ticcmd_t *); int LUA_HookPlayerCmd(player_t *, ticcmd_t *);
int LUA_HookMusicChange(const char *oldname, struct MusicChange *); int LUA_HookMusicChange(const char *oldname, struct MusicChange *);
fixed_t LUA_HookPlayerHeight(player_t *player); fixed_t LUA_HookPlayerHeight(player_t *player);
spawnpoint_t *LUA_HookPlayerRespawn(player_t *player);
int LUA_HookPlayerCanEnterSpinGaps(player_t *player); int LUA_HookPlayerCanEnterSpinGaps(player_t *player);

View file

@ -264,7 +264,12 @@ typedef struct Hook_State Hook_State;
typedef void (*Hook_Callback)(Hook_State *); typedef void (*Hook_Callback)(Hook_State *);
struct Hook_State { struct Hook_State {
INT32 status;/* return status to calling function */ union {
int type_int;
fixed_t type_fixed;
boolean type_bool;
void * type_void_pointer;
} status;/* return status to calling function */
void * userdata; void * userdata;
int hook_type; int hook_type;
mobjtype_t mobj_type;/* >0 if mobj hook */ mobjtype_t mobj_type;/* >0 if mobj hook */
@ -313,7 +318,7 @@ static boolean init_hook_type
const char * string, const char * string,
int nonzero int nonzero
){ ){
hook->status = status; hook->status.type_int = status;
if (nonzero) if (nonzero)
{ {
@ -531,13 +536,13 @@ static int call_hooks
static void res_true(Hook_State *hook) static void res_true(Hook_State *hook)
{ {
if (lua_toboolean(gL, -1)) if (lua_toboolean(gL, -1))
hook->status = true; hook->status.type_bool = true;
} }
static void res_false(Hook_State *hook) static void res_false(Hook_State *hook)
{ {
if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1)) if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1))
hook->status = false; hook->status.type_bool = false;
} }
static void res_force(Hook_State *hook) static void res_force(Hook_State *hook)
@ -545,9 +550,9 @@ static void res_force(Hook_State *hook)
if (!lua_isnil(gL, -1)) if (!lua_isnil(gL, -1))
{ {
if (lua_toboolean(gL, -1)) if (lua_toboolean(gL, -1))
hook->status = 1; // Force yes hook->status.type_int = 1; // Force yes
else else
hook->status = 2; // Force no hook->status.type_int = 2; // Force no
} }
} }
@ -563,7 +568,7 @@ int LUA_HookMobj(mobj_t *mobj, int hook_type)
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type) int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type)
@ -575,7 +580,7 @@ int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type)
LUA_PushUserdata(gL, t2, META_MOBJ); LUA_PushUserdata(gL, t2, META_MOBJ);
call_hooks(&hook, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status.type_int;
} }
void LUA_HookVoid(int type) void LUA_HookVoid(int type)
@ -613,7 +618,7 @@ int LUA_HookPlayer(player_t *player, int hook_type)
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type) int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
@ -632,7 +637,7 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
if (hook_type == HOOK(PlayerCmd)) if (hook_type == HOOK(PlayerCmd))
hook_cmd_running = false; hook_cmd_running = false;
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookKey(event_t *event, int hook_type) int LUA_HookKey(event_t *event, int hook_type)
@ -643,7 +648,7 @@ int LUA_HookKey(event_t *event, int hook_type)
LUA_PushUserdata(gL, event, META_KEYEVENT); LUA_PushUserdata(gL, event, META_KEYEVENT);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
void LUA_HookHUD(int hook_type, huddrawlist_h list) void LUA_HookHUD(int hook_type, huddrawlist_h list)
@ -723,7 +728,7 @@ int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line)
LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, line, META_LINE);
call_hooks(&hook, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher) int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher)
@ -735,7 +740,7 @@ int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher)
LUA_PushUserdata(gL, toucher, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
static int damage_hook static int damage_hook
@ -759,7 +764,7 @@ static int damage_hook
lua_pushinteger(gL, damagetype); lua_pushinteger(gL, damagetype);
call_hooks(&hook, 1, results_handler); call_hooks(&hook, 1, results_handler);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
@ -790,7 +795,7 @@ int LUA_HookMobjMoveBlocked(mobj_t *t1, mobj_t *t2, line_t *line)
LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, line, META_LINE);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
typedef struct { typedef struct {
@ -843,7 +848,7 @@ static void res_botai(Hook_State *hook)
B_KeysToTiccmd(botai->tails, botai->cmd, B_KeysToTiccmd(botai->tails, botai->cmd,
k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7]); k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7]);
hook->status = true; hook->status.type_bool = true;
} }
int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
@ -866,7 +871,7 @@ int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
call_hooks(&hook, 8, res_botai); call_hooks(&hook, 8, res_botai);
} }
return hook.status; return hook.status.type_int;
} }
void LUA_HookLinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) void LUA_HookLinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
@ -904,7 +909,7 @@ int LUA_HookPlayerMsg(int source, int target, int flags, char *msg)
lua_pushstring(gL, msg); // msg lua_pushstring(gL, msg); // msg
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype)
@ -918,7 +923,7 @@ int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 d
lua_pushinteger(gL, damagetype); lua_pushinteger(gL, damagetype);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
void LUA_HookNetArchive(lua_CFunction archFunc) void LUA_HookNetArchive(lua_CFunction archFunc)
@ -960,7 +965,7 @@ int LUA_HookMapThingSpawn(mobj_t *mobj, mapthing_t *mthing)
LUA_PushUserdata(gL, mthing, META_MAPTHING); LUA_PushUserdata(gL, mthing, META_MAPTHING);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookFollowMobj(player_t *player, mobj_t *mobj) int LUA_HookFollowMobj(player_t *player, mobj_t *mobj)
@ -972,7 +977,7 @@ int LUA_HookFollowMobj(player_t *player, mobj_t *mobj)
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookPlayerCanDamage(player_t *player, mobj_t *mobj) int LUA_HookPlayerCanDamage(player_t *player, mobj_t *mobj)
@ -984,7 +989,7 @@ int LUA_HookPlayerCanDamage(player_t *player, mobj_t *mobj)
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status.type_int;
} }
void LUA_HookPlayerQuit(player_t *plr, kickreason_t reason) void LUA_HookPlayerQuit(player_t *plr, kickreason_t reason)
@ -1010,7 +1015,7 @@ int LUA_HookTeamSwitch(player_t *player, int newteam, boolean fromspectators, bo
lua_pushboolean(gL, tryingscramble); lua_pushboolean(gL, tryingscramble);
call_hooks(&hook, 1, res_false); call_hooks(&hook, 1, res_false);
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced) int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced)
@ -1026,7 +1031,7 @@ int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolea
call_hooks(&hook, 1, res_force); call_hooks(&hook, 1, res_force);
hud_running = false; hud_running = false;
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend) int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend)
@ -1041,7 +1046,7 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend)
call_hooks(&hook, 1, res_false); call_hooks(&hook, 1, res_false);
hud_running = false; hud_running = false;
} }
return hook.status; return hook.status.type_int;
} }
int LUA_HookShouldJingleContinue(player_t *player, const char *musname) int LUA_HookShouldJingleContinue(player_t *player, const char *musname)
@ -1057,7 +1062,7 @@ int LUA_HookShouldJingleContinue(player_t *player, const char *musname)
call_hooks(&hook, 1, res_true); call_hooks(&hook, 1, res_true);
hud_running = false; hud_running = false;
} }
return hook.status; return hook.status.type_int;
} }
boolean hook_cmd_running = false; boolean hook_cmd_running = false;
@ -1090,7 +1095,7 @@ static void res_musicchange(Hook_State *hook)
if (lua_isstring(gL, -6)) if (lua_isstring(gL, -6))
update_music_name(musicchange); update_music_name(musicchange);
else if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) else if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6))
hook->status = true; hook->status.type_bool = true;
// output 2: mflags override // output 2: mflags override
if (lua_isnumber(gL, -5)) if (lua_isnumber(gL, -5))
@ -1145,7 +1150,7 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param)
lua_settop(gL, 0); lua_settop(gL, 0);
} }
return hook.status; return hook.status.type_int;
} }
static void res_playerheight(Hook_State *hook) static void res_playerheight(Hook_State *hook)
@ -1157,7 +1162,7 @@ static void res_playerheight(Hook_State *hook)
// when an object's height is set to a negative number directly with lua, it's forced to 0 instead. // when an object's height is set to a negative number directly with lua, it's forced to 0 instead.
// here, I think it's better to ignore negatives so that they don't replace any results of previous hooks! // here, I think it's better to ignore negatives so that they don't replace any results of previous hooks!
if (returnedheight >= 0) if (returnedheight >= 0)
hook->status = returnedheight; hook->status.type_fixed = returnedheight;
} }
} }
@ -1169,7 +1174,105 @@ fixed_t LUA_HookPlayerHeight(player_t *player)
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, res_playerheight); call_hooks(&hook, 1, res_playerheight);
} }
return hook.status; return hook.status.type_fixed;
}
static void res_playerrespawn(Hook_State *hook)
{
hook->status.type_void_pointer = NULL;
if (!lua_isnil(gL, -1))
{
if (!lua_istable(gL, -1))
{
CONS_Alert(CONS_WARNING, "table expected in \"PlayerRespawn\" hook, got %s\n", luaL_typename(gL, -1));
return;
}
fixed_t height_offset = 0;
boolean has_z = false;
spawnpoint_t spawnpoint;
memset(&spawnpoint, 0, sizeof(spawnpoint));
lua_pushnil(gL);
while (lua_next(gL, -2))
{
lua_pushvalue(gL, -2);
const char *key = NULL;
if (lua_isstring(gL, -1))
key = lua_tostring(gL, -1);
#define TYPEERROR(f, t) \
CONS_Alert(CONS_WARNING, \
"bad value for \"%s\" in table returned by \"PlayerRespawn\" hook (%s expected, got %s)\n", \
f, lua_typename(gL, t), luaL_typename(gL, -2))
#define GETNUMBER(r,f) \
if (!strcmp(key, f)) \
{ \
if (!lua_isnumber(gL, -2)) \
TYPEERROR(f, LUA_TNUMBER); \
else \
r = lua_tonumber(gL, -2); \
}
#define GETNUMBEROPT(r,f,opt) \
if (!strcmp(key, f)) \
{ \
if (!lua_isnumber(gL, -2)) \
TYPEERROR(f, LUA_TNUMBER); \
else \
r = lua_tonumber(gL, -2); \
opt = true; \
}
#define GETBOOLEAN(r,f) \
if (!strcmp(key, f)) \
{ \
if (!lua_isboolean(gL, -2)) \
TYPEERROR(f, LUA_TBOOLEAN); \
else \
r = lua_toboolean(gL, -2); \
}
if (key)
{
GETNUMBER(spawnpoint.x, "x");
GETNUMBER(spawnpoint.y, "y");
GETNUMBEROPT(spawnpoint.z, "z", has_z);
GETNUMBER(height_offset, "height");
GETNUMBER(spawnpoint.angle, "angle");
GETBOOLEAN(spawnpoint.spawn_on_ceiling, "spawn_on_ceiling");
GETBOOLEAN(spawnpoint.spawn_flipped, "spawn_flipped");
}
#undef GETNUMBER
#undef GETNUMBEROPT
#undef GETBOOLEAN
#undef TYPEERROR
lua_pop(gL, 2);
}
if (!has_z)
P_SetAbsoluteSpawnPointHeight(&spawnpoint, height_offset);
else
spawnpoint.z += height_offset;
spawnpoint_t *result = Z_Calloc(sizeof(spawnpoint_t), PU_STATIC, NULL);
memcpy(result, &spawnpoint, sizeof(spawnpoint_t));
hook->status.type_void_pointer = result;
}
}
spawnpoint_t *LUA_HookPlayerRespawn(player_t *player)
{
Hook_State hook;
if (prepare_hook(&hook, -1, HOOK(PlayerRespawn)))
{
LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, res_playerrespawn);
}
return (spawnpoint_t *)hook.status.type_void_pointer;
} }
int LUA_HookPlayerCanEnterSpinGaps(player_t *player) int LUA_HookPlayerCanEnterSpinGaps(player_t *player)
@ -1180,5 +1283,5 @@ int LUA_HookPlayerCanEnterSpinGaps(player_t *player)
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status.type_int;
} }

View file

@ -15,6 +15,7 @@
#define __P_LOCAL__ #define __P_LOCAL__
#include "command.h" #include "command.h"
#include "doomstat.h"
#include "d_player.h" #include "d_player.h"
#include "d_think.h" #include "d_think.h"
#include "m_fixed.h" #include "m_fixed.h"
@ -126,6 +127,15 @@ void CV_UpdateCam2Dist(void);
extern fixed_t t_cam_dist, t_cam_height, t_cam_rotate; extern fixed_t t_cam_dist, t_cam_height, t_cam_rotate;
extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate;
// Player spawn points
void P_SpawnPlayer(INT32 playernum);
void P_MovePlayerToSpawn(INT32 playernum, spawnpoint_t *mthing);
void P_MovePlayerToStarpost(INT32 playernum);
void P_AfterPlayerSpawn(INT32 playernum);
spawnpoint_t *P_MakeSpawnPointFromMapthing(mapthing_t *mthing);
void P_SetAbsoluteSpawnPointHeight(spawnpoint_t *spawnpoint, fixed_t offset);
INT32 P_GetPlayerControlDirection(player_t *player); INT32 P_GetPlayerControlDirection(player_t *player);
void P_AddPlayerScore(player_t *player, UINT32 amount); void P_AddPlayerScore(player_t *player, UINT32 amount);
void P_StealPlayerScore(player_t *player, UINT32 amount); void P_StealPlayerScore(player_t *player, UINT32 amount);

View file

@ -11726,51 +11726,46 @@ void P_AfterPlayerSpawn(INT32 playernum)
} }
// spawn it at a playerspawn mapthing // spawn it at a playerspawn mapthing
void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) void P_MovePlayerToSpawn(INT32 playernum, spawnpoint_t *spawnpoint)
{ {
fixed_t x = 0, y = 0; fixed_t x, y, z;
angle_t angle = 0; angle_t angle;
fixed_t z;
sector_t *sector;
fixed_t floor, ceiling, ceilingspawn;
player_t *p = &players[playernum]; player_t *p = &players[playernum];
mobj_t *mobj = p->mo; mobj_t *mobj = p->mo;
I_Assert(mobj != NULL); I_Assert(mobj != NULL);
if (mthing) if (spawnpoint)
{ {
x = mthing->x << FRACBITS; x = spawnpoint->x;
y = mthing->y << FRACBITS; y = spawnpoint->y;
angle = FixedAngle(mthing->angle<<FRACBITS); angle = spawnpoint->angle;
}
else
{
// Spawn at the origin as a desperation move if there is no spawnpoint
x = 0;
y = 0;
angle = 0;
} }
//spawn at the origin as a desperation move if there is no mapthing
// set Z height // set Z height
sector = R_PointInSubsector(x, y)->sector; sector_t *sector = R_PointInSubsector(x, y)->sector;
fixed_t floor = P_GetSectorFloorZAt(sector, x, y);
fixed_t ceiling = P_GetSectorCeilingZAt(sector, x, y);
fixed_t ceilingspawn = ceiling - mobjinfo[MT_PLAYER].height;
floor = P_GetSectorFloorZAt (sector, x, y); if (spawnpoint)
ceiling = P_GetSectorCeilingZAt(sector, x, y);
ceilingspawn = ceiling - mobjinfo[MT_PLAYER].height;
if (mthing)
{ {
fixed_t offset = mthing->z << FRACBITS; z = spawnpoint->z;
// Setting the spawnpoint's args[0] will make the player start on the ceiling if (spawnpoint->spawn_flipped) // flip the player!
// Objectflip inverts
if (!!(mthing->args[0]) ^ !!(mthing->options & MTF_OBJECTFLIP))
z = ceilingspawn - offset;
else
z = floor + offset;
if (mthing->options & MTF_OBJECTFLIP) // flip the player!
{ {
mobj->eflags |= MFE_VERTICALFLIP; mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP; mobj->flags2 |= MF2_OBJECTFLIP;
} }
if (mthing->args[0])
if (spawnpoint->spawn_on_ceiling)
P_SetPlayerMobjState(mobj, S_PLAY_FALL); P_SetPlayerMobjState(mobj, S_PLAY_FALL);
else if (metalrecording) else if (metalrecording)
P_SetPlayerMobjState(mobj, S_PLAY_WAIT); P_SetPlayerMobjState(mobj, S_PLAY_WAIT);
@ -11857,6 +11852,40 @@ void P_MovePlayerToStarpost(INT32 playernum)
leveltime = p->starposttime; leveltime = p->starposttime;
} }
spawnpoint_t *P_MakeSpawnPointFromMapthing(mapthing_t *mthing)
{
spawnpoint_t *spawnpoint = Z_Malloc(sizeof(spawnpoint_t), PU_STATIC, NULL);
spawnpoint->x = mthing->x << FRACBITS;
spawnpoint->y = mthing->y << FRACBITS;
spawnpoint->angle = FixedAngle(mthing->angle<<FRACBITS);
// Setting the spawnpoint's args[0] will make the player start on the ceiling
// Objectflip inverts
spawnpoint->spawn_on_ceiling = mthing->args[0];
spawnpoint->spawn_flipped = mthing->options & MTF_OBJECTFLIP;
P_SetAbsoluteSpawnPointHeight(spawnpoint, mthing->z << FRACBITS);
return spawnpoint;
}
void P_SetAbsoluteSpawnPointHeight(spawnpoint_t *spawnpoint, fixed_t offset)
{
sector_t *sector = R_PointInSubsector(spawnpoint->x, spawnpoint->y)->sector;
fixed_t floor = P_GetSectorFloorZAt(sector, spawnpoint->x, spawnpoint->y);
fixed_t ceilingspawn = P_GetSectorCeilingZAt(sector, spawnpoint->x, spawnpoint->y) - mobjinfo[MT_PLAYER].height;
if (!!(spawnpoint->spawn_on_ceiling) ^ !!(spawnpoint->spawn_flipped))
spawnpoint->z = ceilingspawn - offset;
else
spawnpoint->z = floor + offset;
if (spawnpoint->z < floor)
spawnpoint->z = floor;
else if (spawnpoint->z > ceilingspawn)
spawnpoint->z = ceilingspawn;
}
fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale) fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale)
{ {
const subsector_t *ss = R_PointInSubsector(x, y); const subsector_t *ss = R_PointInSubsector(x, y);

View file

@ -486,12 +486,6 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum);
// check mobj against water content, before movement code // check mobj against water content, before movement code
void P_MobjCheckWater(mobj_t *mobj); void P_MobjCheckWater(mobj_t *mobj);
// Player spawn points
void P_SpawnPlayer(INT32 playernum);
void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing);
void P_MovePlayerToStarpost(INT32 playernum);
void P_AfterPlayerSpawn(INT32 playernum);
fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale); fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale);
fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y); fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y);