mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-27 07:51:36 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into big-large-map-markers
# Conflicts: # src/d_netcmd.c
This commit is contained in:
commit
1a284ec7c6
76 changed files with 5603 additions and 3055 deletions
|
|
@ -65,6 +65,7 @@ r_skins.c
|
|||
r_sky.c
|
||||
r_splats.c
|
||||
r_things.c
|
||||
r_bbox.c
|
||||
r_textures.c
|
||||
r_patch.c
|
||||
r_patchrotation.c
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "k_menu.h"
|
||||
#include "filesrch.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_random.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include "win32/win_main.h"
|
||||
|
|
@ -243,6 +244,81 @@ static void CONS_Bind_f(void)
|
|||
bindtable[key] = Z_StrDup(COM_Argv(2));
|
||||
}
|
||||
|
||||
static void CONS_Choose_f(void)
|
||||
{
|
||||
size_t na = COM_Argc();
|
||||
|
||||
if (na < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("choose <option1> [<option2>] [<option3>] [...]: Picks a command at random\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
COM_BufAddText(COM_Argv(M_RandomKey(na - 1) + 1));
|
||||
COM_BufAddText("\n");
|
||||
}
|
||||
|
||||
static void CONS_ChooseWeighted_f(void)
|
||||
{
|
||||
size_t na = COM_Argc();
|
||||
size_t i, cmd;
|
||||
const char *commands[40];
|
||||
INT32 weights[40];
|
||||
INT32 totalWeight = 0;
|
||||
INT32 roll;
|
||||
|
||||
if (na < 3)
|
||||
{
|
||||
CONS_Printf(M_GetText("chooseweighted <option1> <weight1> [<option2> <weight2>] [<option3> <weight3>] [...]: Picks a command with weighted randomization\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(weights, 0, sizeof(weights));
|
||||
|
||||
i = 1;
|
||||
cmd = 0;
|
||||
while (i < na)
|
||||
{
|
||||
commands[cmd] = COM_Argv(i);
|
||||
|
||||
i++;
|
||||
if (i >= na)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
weights[cmd] = atoi(COM_Argv(i));
|
||||
totalWeight += weights[cmd];
|
||||
|
||||
i++;
|
||||
cmd++;
|
||||
}
|
||||
|
||||
if (cmd == 0 || totalWeight <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
roll = M_RandomRange(1, totalWeight);
|
||||
|
||||
for (i = 0; i < cmd; i++)
|
||||
{
|
||||
if (roll <= weights[i])
|
||||
{
|
||||
if (commands[i] == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
COM_BufAddText(commands[i]);
|
||||
COM_BufAddText("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
roll -= weights[i];
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// CONSOLE SETUP
|
||||
//======================================================================
|
||||
|
|
@ -445,6 +521,8 @@ void CON_Init(void)
|
|||
CV_RegisterVar(&cons_backpic);
|
||||
CV_RegisterVar(&cons_backcolor);
|
||||
COM_AddCommand("bind", CONS_Bind_f);
|
||||
COM_AddCommand("choose", CONS_Choose_f);
|
||||
COM_AddCommand("chooseweighted", CONS_ChooseWeighted_f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
588
src/d_clisrv.c
588
src/d_clisrv.c
|
|
@ -122,7 +122,7 @@ SINT8 nodetoplayer4[MAXNETNODES]; // say the numplayer for this node if any (spl
|
|||
UINT8 playerpernode[MAXNETNODES]; // used specialy for splitscreen
|
||||
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
|
||||
|
||||
tic_t servermaxping = 800; // server's max ping. Defaults to 800
|
||||
tic_t servermaxping = 20; // server's max delay, in frames. Defaults to 20
|
||||
static tic_t nettics[MAXNETNODES]; // what tic the client have received
|
||||
static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet
|
||||
static UINT8 nodewaiting[MAXNETNODES];
|
||||
|
|
@ -189,6 +189,8 @@ consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_c
|
|||
|
||||
consvar_t cv_httpsource = CVAR_INIT ("http_source", "", CV_SAVE, NULL, NULL);
|
||||
|
||||
consvar_t cv_kicktime = CVAR_INIT ("kicktime", "10", CV_SAVE, CV_Unsigned, NULL);
|
||||
|
||||
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
|
||||
{
|
||||
const size_t d = n / sizeof(ticcmd_t);
|
||||
|
|
@ -890,6 +892,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
|
|||
UINT8 *p;
|
||||
size_t mirror_length;
|
||||
const char *httpurl = cv_httpsource.string;
|
||||
UINT8 prefgametype = (cv_kartgametypepreference.value == -1)
|
||||
? gametype
|
||||
: cv_kartgametypepreference.value;
|
||||
|
||||
netbuffer->packettype = PT_SERVERINFO;
|
||||
netbuffer->u.serverinfo._255 = 255;
|
||||
|
|
@ -914,7 +919,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
|
|||
else
|
||||
netbuffer->u.serverinfo.refusereason = 0;
|
||||
|
||||
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
|
||||
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype],
|
||||
sizeof netbuffer->u.serverinfo.gametypename);
|
||||
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
|
||||
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
|
||||
|
|
@ -1348,7 +1353,7 @@ static void SendAskInfo(INT32 node)
|
|||
if (node != 0 && node != BROADCASTADDR &&
|
||||
cv_rendezvousserver.string[0])
|
||||
{
|
||||
I_NetRequestHolePunch();
|
||||
I_NetRequestHolePunch(node);
|
||||
}
|
||||
|
||||
asktime = I_GetTime();
|
||||
|
|
@ -2028,7 +2033,10 @@ static void CL_ConnectToServer(void)
|
|||
wipegamestate = GS_WAITINGPLAYERS;
|
||||
|
||||
ClearAdminPlayers();
|
||||
Schedule_Clear();
|
||||
Automate_Clear();
|
||||
K_ClearClientPowerLevels();
|
||||
|
||||
pnumnodes = 1;
|
||||
oldtic = 0;
|
||||
#ifndef NONET
|
||||
|
|
@ -2092,57 +2100,83 @@ static void CL_ConnectToServer(void)
|
|||
}
|
||||
|
||||
#ifndef NONET
|
||||
typedef struct banreason_s
|
||||
{
|
||||
char *reason;
|
||||
struct banreason_s *prev; //-1
|
||||
struct banreason_s *next; //+1
|
||||
} banreason_t;
|
||||
|
||||
static banreason_t *reasontail = NULL; //last entry, use prev
|
||||
static banreason_t *reasonhead = NULL; //1st entry, use next
|
||||
|
||||
static void Command_ShowBan(void) //Print out ban list
|
||||
{
|
||||
size_t i;
|
||||
const char *address, *mask;
|
||||
banreason_t *reasonlist = reasonhead;
|
||||
const char *address, *mask, *reason, *username;
|
||||
time_t unbanTime = NO_BAN_TIME;
|
||||
const time_t curTime = time(NULL);
|
||||
|
||||
if (I_GetBanAddress)
|
||||
CONS_Printf(M_GetText("Ban List:\n"));
|
||||
else
|
||||
return;
|
||||
|
||||
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
|
||||
for (i = 0; (address = I_GetBanAddress(i)) != NULL; i++)
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
if (I_GetUnbanTime)
|
||||
unbanTime = I_GetUnbanTime(i);
|
||||
|
||||
if (unbanTime != NO_BAN_TIME && curTime >= unbanTime)
|
||||
continue;
|
||||
|
||||
CONS_Printf("%s: ", sizeu1(i+1));
|
||||
|
||||
if (I_GetBanUsername && (username = I_GetBanUsername(i)) != NULL)
|
||||
CONS_Printf("%s - ", username);
|
||||
|
||||
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
|
||||
CONS_Printf("%s: %s ", sizeu1(i+1), address);
|
||||
CONS_Printf("%s", address);
|
||||
else
|
||||
CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask);
|
||||
CONS_Printf("%s/%s", address, mask);
|
||||
|
||||
if (reasonlist && reasonlist->reason)
|
||||
CONS_Printf("(%s)\n", reasonlist->reason);
|
||||
else
|
||||
CONS_Printf("\n");
|
||||
if (I_GetBanReason && (reason = I_GetBanReason(i)) != NULL)
|
||||
CONS_Printf(" - %s", reason);
|
||||
|
||||
if (reasonlist) reasonlist = reasonlist->next;
|
||||
if (unbanTime != NO_BAN_TIME)
|
||||
{
|
||||
// these are fudged a little to match what a joiner sees
|
||||
int minutes = ((unbanTime - curTime) + 30) / 60;
|
||||
int hours = (minutes + 1) / 60;
|
||||
int days = (hours + 1) / 24;
|
||||
if (days)
|
||||
CONS_Printf(" (%d day%s)", days, days > 1 ? "s" : "");
|
||||
else if (hours)
|
||||
CONS_Printf(" (%d hour%s)", hours, hours > 1 ? "s" : "");
|
||||
else if (minutes)
|
||||
CONS_Printf(" (%d minute%s)", minutes, minutes > 1 ? "s" : "");
|
||||
else
|
||||
CONS_Printf(" (<1 minute)");
|
||||
}
|
||||
|
||||
CONS_Printf("\n");
|
||||
}
|
||||
|
||||
if (i == 0 && !address)
|
||||
CONS_Printf(M_GetText("(empty)\n"));
|
||||
}
|
||||
|
||||
static boolean bansLoaded = false;
|
||||
// If you're a community contributor looking to improve how bans are written, please
|
||||
// offer your changes back to our Git repository. Kart Krew reserve the right to
|
||||
// utilise format numbers in use by community builds for different layouts.
|
||||
#define BANFORMAT 1
|
||||
|
||||
void D_SaveBan(void)
|
||||
{
|
||||
FILE *f;
|
||||
size_t i;
|
||||
banreason_t *reasonlist = reasonhead;
|
||||
const char *address, *mask;
|
||||
const char *username, *reason;
|
||||
const time_t curTime = time(NULL);
|
||||
time_t unbanTime = NO_BAN_TIME;
|
||||
const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt");
|
||||
|
||||
if (!reasonhead)
|
||||
if (bansLoaded != true)
|
||||
{
|
||||
remove(path);
|
||||
// You didn't even get to ATTEMPT to load bans.txt.
|
||||
// Don't immediately save nothing over it.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2154,78 +2188,79 @@ void D_SaveBan(void)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
|
||||
// Add header.
|
||||
fprintf(f, "BANFORMAT %d\n", BANFORMAT);
|
||||
|
||||
for (i = 0; (address = I_GetBanAddress(i)) != NULL; i++)
|
||||
{
|
||||
if (I_GetUnbanTime)
|
||||
{
|
||||
unbanTime = I_GetUnbanTime(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
}
|
||||
|
||||
if (unbanTime != NO_BAN_TIME && curTime >= unbanTime)
|
||||
{
|
||||
// This one has served their sentence.
|
||||
// We don't need to save them in the file anymore.
|
||||
continue;
|
||||
}
|
||||
|
||||
mask = NULL;
|
||||
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
|
||||
fprintf(f, "%s 0", address);
|
||||
fprintf(f, "%s/0", address);
|
||||
else
|
||||
fprintf(f, "%s %s", address, mask);
|
||||
fprintf(f, "%s/%s", address, mask);
|
||||
|
||||
if (reasonlist && reasonlist->reason)
|
||||
fprintf(f, " %s\n", reasonlist->reason);
|
||||
// TODO: it'd be nice to convert this to an actual date-time,
|
||||
// so it'd be easier to edit outside of the game.
|
||||
fprintf(f, " %ld", (long)unbanTime);
|
||||
|
||||
username = NULL;
|
||||
if (I_GetBanUsername && (username = I_GetBanUsername(i)) != NULL)
|
||||
fprintf(f, " \"%s\"", username);
|
||||
else
|
||||
fprintf(f, " %s\n", "NA");
|
||||
fprintf(f, " \"%s\"", "Direct IP ban");
|
||||
|
||||
if (reasonlist) reasonlist = reasonlist->next;
|
||||
reason = NULL;
|
||||
if (I_GetBanReason && (reason = I_GetBanReason(i)) != NULL)
|
||||
fprintf(f, " \"%s\"\n", reason);
|
||||
else
|
||||
fprintf(f, " \"%s\"\n", "No reason given");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void Ban_Add(const char *reason)
|
||||
{
|
||||
banreason_t *reasonlist = malloc(sizeof(*reasonlist));
|
||||
|
||||
if (!reasonlist)
|
||||
return;
|
||||
if (!reason)
|
||||
reason = "NA";
|
||||
|
||||
reasonlist->next = NULL;
|
||||
reasonlist->reason = Z_StrDup(reason);
|
||||
if ((reasonlist->prev = reasontail) == NULL)
|
||||
reasonhead = reasonlist;
|
||||
else
|
||||
reasontail->next = reasonlist;
|
||||
reasontail = reasonlist;
|
||||
}
|
||||
|
||||
static void Ban_Clear(void)
|
||||
{
|
||||
banreason_t *temp;
|
||||
|
||||
I_ClearBans();
|
||||
|
||||
reasontail = NULL;
|
||||
|
||||
while (reasonhead)
|
||||
{
|
||||
temp = reasonhead->next;
|
||||
Z_Free(reasonhead->reason);
|
||||
free(reasonhead);
|
||||
reasonhead = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static void Command_ClearBans(void)
|
||||
{
|
||||
if (!I_ClearBans)
|
||||
return;
|
||||
|
||||
Ban_Clear();
|
||||
I_ClearBans();
|
||||
D_SaveBan();
|
||||
}
|
||||
|
||||
static void Ban_Load_File(boolean warning)
|
||||
void D_LoadBan(boolean warning)
|
||||
{
|
||||
FILE *f;
|
||||
size_t i;
|
||||
const char *address, *mask;
|
||||
size_t i, j;
|
||||
char *address, *mask;
|
||||
char *username, *reason;
|
||||
time_t unbanTime = NO_BAN_TIME;
|
||||
char buffer[MAX_WADPATH];
|
||||
UINT8 banmode = 0;
|
||||
boolean malformed = false;
|
||||
|
||||
if (!I_ClearBans)
|
||||
return;
|
||||
|
||||
// We at least attempted loading bans.txt
|
||||
bansLoaded = true;
|
||||
|
||||
f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r");
|
||||
|
||||
if (!f)
|
||||
|
|
@ -2235,24 +2270,115 @@ static void Ban_Load_File(boolean warning)
|
|||
return;
|
||||
}
|
||||
|
||||
Ban_Clear();
|
||||
I_ClearBans();
|
||||
|
||||
for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++)
|
||||
for (i = 0; fgets(buffer, (int)sizeof(buffer), f); i++)
|
||||
{
|
||||
address = strtok(buffer, " \t\r\n");
|
||||
address = strtok(buffer, " /\t\r\n");
|
||||
mask = strtok(NULL, " \t\r\n");
|
||||
|
||||
I_SetBanAddress(address, mask);
|
||||
if (i == 0 && !strncmp(address, "BANFORMAT", 9))
|
||||
{
|
||||
if (mask)
|
||||
{
|
||||
banmode = atoi(mask);
|
||||
}
|
||||
switch (banmode)
|
||||
{
|
||||
case BANFORMAT: // currently supported format
|
||||
//case 0: -- permitted only when BANFORMAT string not present
|
||||
break;
|
||||
default:
|
||||
{
|
||||
fclose(f);
|
||||
CONS_Alert(CONS_WARNING, "Could not load unknown ban.txt for ban list (BANFORMAT %s, expected %d)\n", mask, BANFORMAT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Ban_Add(strtok(NULL, "\r\n"));
|
||||
if (I_SetBanAddress(address, mask) == false) // invalid IP input?
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "\"%s/%s\" is not a valid IP address, discarding...\n", address, mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
// One-way legacy format conversion -- the game will crash otherwise
|
||||
if (banmode == 0)
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
username = NULL; // not guaranteed to be accurate, but only sane substitute
|
||||
reason = strtok(NULL, "\r\n");
|
||||
if (reason && reason[0] == 'N' && reason[1] == 'A' && reason[2] == '\0')
|
||||
{
|
||||
reason = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = strtok(NULL, " \"\t\r\n");
|
||||
if (reason)
|
||||
{
|
||||
unbanTime = atoi(reason);
|
||||
reason = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
username = strtok(NULL, "\"\t\r\n"); // go until next "
|
||||
if (!username)
|
||||
{
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
strtok(NULL, "\"\t\r\n"); // remove first "
|
||||
reason = strtok(NULL, "\"\r\n"); // go until next "
|
||||
if (!reason)
|
||||
{
|
||||
malformed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce MAX_REASONLENGTH.
|
||||
if (reason)
|
||||
{
|
||||
j = 0;
|
||||
while (reason[j] != '\0')
|
||||
{
|
||||
if ((j++) < MAX_REASONLENGTH)
|
||||
continue;
|
||||
reason[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (I_SetUnbanTime)
|
||||
I_SetUnbanTime(unbanTime);
|
||||
|
||||
if (I_SetBanUsername)
|
||||
I_SetBanUsername(username);
|
||||
|
||||
if (I_SetBanReason)
|
||||
I_SetBanReason(reason);
|
||||
}
|
||||
|
||||
if (malformed)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "One or more lines of ban.txt are malformed. The game can correct for this, but some data may be lost.\n");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#undef BANFORMAT
|
||||
|
||||
static void Command_ReloadBan(void) //recheck ban.txt
|
||||
{
|
||||
Ban_Load_File(true);
|
||||
D_LoadBan(true);
|
||||
}
|
||||
|
||||
static void Command_connect(void)
|
||||
|
|
@ -2397,6 +2523,8 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
splitscreen_original_party_size[playernum] = 0;
|
||||
|
||||
memset(&players[playernum], 0, sizeof (player_t));
|
||||
|
||||
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -2426,14 +2554,14 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
|
|||
|
||||
K_CalculateBattleWanted();
|
||||
|
||||
LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting
|
||||
LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting
|
||||
|
||||
// don't look through someone's view who isn't there
|
||||
if (playernum == displayplayers[0] && !demo.playback)
|
||||
{
|
||||
// Call ViewpointSwitch hooks here.
|
||||
// The viewpoint was forcibly changed.
|
||||
LUAh_ViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true);
|
||||
LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true);
|
||||
displayplayers[0] = consoleplayer;
|
||||
}
|
||||
|
||||
|
|
@ -2454,11 +2582,6 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
|
|||
|
||||
player_name_changes[playernum] = 0;
|
||||
|
||||
if (IsPlayerAdmin(playernum))
|
||||
{
|
||||
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
|
||||
}
|
||||
|
||||
LUA_InvalidatePlayer(&players[playernum]);
|
||||
|
||||
K_CheckBumpers();
|
||||
|
|
@ -2602,7 +2725,7 @@ static void Command_Ban(void)
|
|||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
|
||||
CONS_Printf(M_GetText("ban <playername/playernum> <reason>: ban and kick a player\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2617,83 +2740,95 @@ static void Command_Ban(void)
|
|||
UINT8 buf[3 + MAX_REASONLENGTH];
|
||||
UINT8 *p = buf;
|
||||
const SINT8 pn = nametonum(COM_Argv(1));
|
||||
const INT32 node = playernode[(INT32)pn];
|
||||
|
||||
if (pn == -1 || pn == 0)
|
||||
return;
|
||||
|
||||
WRITEUINT8(p, pn);
|
||||
|
||||
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
|
||||
if (COM_Argc() == 2)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
|
||||
WRITEUINT8(p, KICK_MSG_GO_AWAY);
|
||||
WRITEUINT8(p, KICK_MSG_BANNED);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server) // only the server is allowed to do this right now
|
||||
size_t i, j = COM_Argc();
|
||||
char message[MAX_REASONLENGTH];
|
||||
|
||||
//Steal from the motd code so you don't have to put the reason in quotes.
|
||||
strlcpy(message, COM_Argv(2), sizeof message);
|
||||
for (i = 3; i < j; i++)
|
||||
{
|
||||
Ban_Add(COM_Argv(2));
|
||||
D_SaveBan(); // save the ban list
|
||||
strlcat(message, " ", sizeof message);
|
||||
strlcat(message, COM_Argv(i), sizeof message);
|
||||
}
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
{
|
||||
WRITEUINT8(p, KICK_MSG_BANNED);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t i, j = COM_Argc();
|
||||
char message[MAX_REASONLENGTH];
|
||||
|
||||
//Steal from the motd code so you don't have to put the reason in quotes.
|
||||
strlcpy(message, COM_Argv(2), sizeof message);
|
||||
for (i = 3; i < j; i++)
|
||||
{
|
||||
strlcat(message, " ", sizeof message);
|
||||
strlcat(message, COM_Argv(i), sizeof message);
|
||||
}
|
||||
|
||||
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
|
||||
WRITESTRINGN(p, message, MAX_REASONLENGTH);
|
||||
SendNetXCmd(XD_KICK, &buf, p - buf);
|
||||
}
|
||||
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
|
||||
WRITESTRINGN(p, message, MAX_REASONLENGTH);
|
||||
SendNetXCmd(XD_KICK, &buf, p - buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
|
||||
}
|
||||
|
||||
static void Command_BanIP(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
size_t ac = COM_Argc();
|
||||
|
||||
if (ac < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("banip <ip> <reason>: ban an ip address\n"));
|
||||
CONS_Printf(M_GetText("banip <ip> [<reason>]: ban an ip address\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (server) // Only the server can use this, otherwise does nothing.
|
||||
{
|
||||
const char *address = (COM_Argv(1));
|
||||
const char *reason;
|
||||
char *addressInput = Z_StrDup(COM_Argv(1));
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
reason = NULL;
|
||||
else
|
||||
const char *address = NULL;
|
||||
const char *mask = NULL;
|
||||
|
||||
const char *reason = NULL;
|
||||
|
||||
address = strtok(addressInput, "/");
|
||||
mask = strtok(NULL, "");
|
||||
|
||||
if (ac > 2)
|
||||
{
|
||||
reason = COM_Argv(2);
|
||||
}
|
||||
|
||||
|
||||
if (I_SetBanAddress && I_SetBanAddress(address, NULL))
|
||||
if (I_SetBanAddress && I_SetBanAddress(address, mask))
|
||||
{
|
||||
if (reason)
|
||||
CONS_Printf("Banned IP address %s for: %s\n", address, reason);
|
||||
{
|
||||
CONS_Printf(
|
||||
"Banned IP address %s%s for: %s\n",
|
||||
address,
|
||||
(mask && (strlen(mask) > 0)) ? va("/%s", mask) : "",
|
||||
reason
|
||||
);
|
||||
}
|
||||
else
|
||||
CONS_Printf("Banned IP address %s\n", address);
|
||||
{
|
||||
CONS_Printf(
|
||||
"Banned IP address %s%s\n",
|
||||
address,
|
||||
(mask && (strlen(mask) > 0)) ? va("/%s", mask) : ""
|
||||
);
|
||||
}
|
||||
|
||||
if (I_SetUnbanTime)
|
||||
I_SetUnbanTime(NO_BAN_TIME);
|
||||
|
||||
if (I_SetBanUsername)
|
||||
I_SetBanUsername(NULL);
|
||||
|
||||
if (I_SetBanReason)
|
||||
I_SetBanReason(reason);
|
||||
|
||||
Ban_Add(reason);
|
||||
D_SaveBan();
|
||||
}
|
||||
else
|
||||
|
|
@ -2771,6 +2906,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
char buf[3 + MAX_REASONLENGTH];
|
||||
char *reason = buf;
|
||||
kickreason_t kickreason = KR_KICK;
|
||||
UINT32 banMinutes = 0;
|
||||
|
||||
pnum = READUINT8(*p);
|
||||
msg = READUINT8(*p);
|
||||
|
|
@ -2829,18 +2965,49 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
msg = KICK_MSG_CON_FAIL;
|
||||
}
|
||||
|
||||
if (msg == KICK_MSG_CUSTOM_BAN || msg == KICK_MSG_CUSTOM_KICK)
|
||||
{
|
||||
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
|
||||
}
|
||||
|
||||
//CONS_Printf("\x82%s ", player_names[pnum]);
|
||||
|
||||
// If a verified admin banned someone, the server needs to know about it.
|
||||
// If the playernum isn't zero (the server) then the server needs to record the ban.
|
||||
if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN))
|
||||
// Save bans here. Used to be split between here and the actual command, depending on
|
||||
// whenever the server did it or a remote admin did it, but it's simply more convenient
|
||||
// to keep it all in one place.
|
||||
if (server)
|
||||
{
|
||||
if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
|
||||
#ifndef NONET
|
||||
else
|
||||
Ban_Add(reason);
|
||||
#endif
|
||||
if (msg == KICK_MSG_GO_AWAY || msg == KICK_MSG_CUSTOM_KICK)
|
||||
{
|
||||
// Kick as a temporary ban.
|
||||
banMinutes = cv_kicktime.value;
|
||||
}
|
||||
|
||||
if (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN || banMinutes)
|
||||
{
|
||||
if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Ban failed. Invalid node?\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (I_SetBanUsername)
|
||||
I_SetBanUsername(player_names[pnum]);
|
||||
|
||||
if (I_SetBanReason)
|
||||
I_SetBanReason(reason);
|
||||
|
||||
if (I_SetUnbanTime)
|
||||
{
|
||||
if (banMinutes)
|
||||
I_SetUnbanTime(time(NULL) + (banMinutes * 60));
|
||||
else
|
||||
I_SetUnbanTime(NO_BAN_TIME);
|
||||
}
|
||||
|
||||
D_SaveBan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msg == KICK_MSG_PLAYER_QUIT)
|
||||
|
|
@ -2855,7 +3022,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
kickreason = KR_KICK;
|
||||
break;
|
||||
case KICK_MSG_PING_HIGH:
|
||||
HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false);
|
||||
HU_AddChatText(va("\x82*%s left the game (Broke delay limit)", player_names[pnum]), false);
|
||||
kickreason = KR_PINGLIMIT;
|
||||
break;
|
||||
case KICK_MSG_CON_FAIL:
|
||||
|
|
@ -2909,12 +3076,10 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
kickreason = KR_BAN;
|
||||
break;
|
||||
case KICK_MSG_CUSTOM_KICK:
|
||||
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
|
||||
HU_AddChatText(va("\x82*%s has been kicked (%s)", player_names[pnum], reason), false);
|
||||
kickreason = KR_KICK;
|
||||
break;
|
||||
case KICK_MSG_CUSTOM_BAN:
|
||||
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
|
||||
HU_AddChatText(va("\x82*%s has been banned (%s)", player_names[pnum], reason), false);
|
||||
kickreason = KR_BAN;
|
||||
break;
|
||||
|
|
@ -2937,23 +3102,25 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
|
||||
if (playernode[pnum] == playernode[consoleplayer])
|
||||
{
|
||||
LUAh_GameQuit(false);
|
||||
#ifdef DUMPCONSISTENCY
|
||||
if (msg == KICK_MSG_CON_FAIL) SV_SavedGame();
|
||||
#endif
|
||||
LUA_HookBool(false, HOOK(GameQuit)); //Lua hooks handled differently now
|
||||
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_StartTitle();
|
||||
|
||||
if (msg == KICK_MSG_CON_FAIL)
|
||||
M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_PING_HIGH)
|
||||
M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
M_StartMessage(M_GetText("Server closed connection\n(Broke delay limit)\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_BANNED)
|
||||
M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_CUSTOM_KICK)
|
||||
M_StartMessage(va(M_GetText("You have been kicked\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
M_StartMessage(va(M_GetText("You have been kicked\n(%s)\n\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_CUSTOM_BAN)
|
||||
M_StartMessage(va(M_GetText("You have been banned\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
M_StartMessage(va(M_GetText("You have been banned\n(%s)\n\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
else
|
||||
M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
}
|
||||
|
|
@ -3109,17 +3276,17 @@ consvar_t cv_discordinvites = CVAR_INIT ("discordinvites", "Everyone", CV_SAVE|C
|
|||
|
||||
static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}};
|
||||
|
||||
consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL);
|
||||
consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "2", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL);
|
||||
consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
// max file size to send to a player (in kilobytes)
|
||||
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL);
|
||||
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "51200", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL);
|
||||
consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
// Speed of file downloading (in packets per tic)
|
||||
static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL);
|
||||
static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "32", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL);
|
||||
|
||||
static void Got_AddPlayer(UINT8 **p, INT32 playernum);
|
||||
static void Got_RemovePlayer(UINT8 **p, INT32 playernum);
|
||||
|
|
@ -3181,7 +3348,7 @@ void D_ClientServerInit(void)
|
|||
#ifdef DUMPCONSISTENCY
|
||||
CV_RegisterVar(&cv_dumpconsistency);
|
||||
#endif
|
||||
Ban_Load_File(false);
|
||||
D_LoadBan(false);
|
||||
#endif
|
||||
|
||||
gametic = 0;
|
||||
|
|
@ -3211,6 +3378,9 @@ static void ResetNode(INT32 node)
|
|||
sendingsavegame[node] = false;
|
||||
resendingsavegame[node] = false;
|
||||
savegameresendcooldown[node] = 0;
|
||||
|
||||
bannednode[node].banid = SIZE_MAX;
|
||||
bannednode[node].timeleft = NO_BAN_TIME;
|
||||
}
|
||||
|
||||
void SV_ResetServer(void)
|
||||
|
|
@ -3233,14 +3403,18 @@ void SV_ResetServer(void)
|
|||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
LUA_InvalidatePlayer(&players[i]);
|
||||
playeringame[i] = false;
|
||||
playernode[i] = UINT8_MAX;
|
||||
sprintf(player_names[i], "Player %c", 'A' + i);
|
||||
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
|
||||
K_ClearClientPowerLevels();
|
||||
splitscreen_invitations[i] = -1;
|
||||
}
|
||||
|
||||
memset(playeringame, false, sizeof playeringame);
|
||||
memset(playernode, UINT8_MAX, sizeof playernode);
|
||||
|
||||
ClearAdminPlayers();
|
||||
Schedule_Clear();
|
||||
Automate_Clear();
|
||||
K_ClearClientPowerLevels();
|
||||
|
||||
memset(splitscreen_invitations, -1, sizeof splitscreen_invitations);
|
||||
memset(splitscreen_partied, 0, sizeof splitscreen_partied);
|
||||
memset(player_name_changes, 0, sizeof player_name_changes);
|
||||
|
||||
|
|
@ -3325,6 +3499,8 @@ void D_QuitNetGame(void)
|
|||
|
||||
D_CloseConnection();
|
||||
ClearAdminPlayers();
|
||||
Schedule_Clear();
|
||||
Automate_Clear();
|
||||
K_ClearClientPowerLevels();
|
||||
|
||||
DEBFILE("===========================================================================\n"
|
||||
|
|
@ -3455,7 +3631,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
|
|||
if (server && multiplayer && motd[0] != '\0')
|
||||
COM_BufAddText(va("sayto %d %s\n", newplayernum, motd));
|
||||
|
||||
LUAh_PlayerJoin(newplayernum);
|
||||
LUA_HookInt(newplayernum, HOOK(PlayerJoin));
|
||||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
DRPC_UpdatePresence();
|
||||
|
|
@ -3537,7 +3713,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
|
|||
HU_AddChatText(va("\x82*Bot %d has been added to the game", newplayernum+1), false);
|
||||
}
|
||||
|
||||
LUAh_PlayerJoin(newplayernum);
|
||||
LUA_HookInt(newplayernum, HOOK(PlayerJoin));
|
||||
}
|
||||
|
||||
static boolean SV_AddWaitingPlayers(SINT8 node, const char *name, const char *name2, const char *name3, const char *name4)
|
||||
|
|
@ -3788,32 +3964,87 @@ static void HandleConnect(SINT8 node)
|
|||
// It's too much effort to legimately fix right now. Just prevent it from reaching that state.
|
||||
UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
|
||||
|
||||
if (bannednode && bannednode[node])
|
||||
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server."));
|
||||
if (bannednode && bannednode[node].banid != SIZE_MAX)
|
||||
{
|
||||
const char *reason = NULL;
|
||||
|
||||
// Get the reason...
|
||||
if (!I_GetBanReason || (reason = I_GetBanReason(bannednode[node].banid)) == NULL)
|
||||
reason = "No reason given";
|
||||
|
||||
if (bannednode[node].timeleft != NO_BAN_TIME)
|
||||
{
|
||||
// these are fudged a little to allow it to sink in for impatient rejoiners
|
||||
int minutes = (bannednode[node].timeleft + 30) / 60;
|
||||
int hours = (minutes + 1) / 60;
|
||||
int days = (hours + 1) / 24;
|
||||
|
||||
if (days)
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: %d day%s)", reason, days, days > 1 ? "s" : ""));
|
||||
}
|
||||
else if (hours)
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: %d hour%s)", reason, hours, hours > 1 ? "s" : ""));
|
||||
}
|
||||
else if (minutes)
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: %d minute%s)", reason, minutes, minutes > 1 ? "s" : ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: <1 minute)", reason));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_SendRefuse(node, va("B|%s", reason));
|
||||
}
|
||||
}
|
||||
else if (netbuffer->u.clientcfg._255 != 255 ||
|
||||
netbuffer->u.clientcfg.packetversion != PACKETVERSION)
|
||||
{
|
||||
SV_SendRefuse(node, "Incompatible packet formats.");
|
||||
}
|
||||
else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION,
|
||||
sizeof netbuffer->u.clientcfg.application))
|
||||
{
|
||||
SV_SendRefuse(node, "Different Ring Racers modifications\nare not compatible.");
|
||||
}
|
||||
else if (netbuffer->u.clientcfg.version != VERSION
|
||||
|| netbuffer->u.clientcfg.subversion != SUBVERSION)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Different Ring Racers versions cannot\nplay a netgame!\n(server version %d.%d)"), VERSION, SUBVERSION));
|
||||
}
|
||||
else if (!cv_allownewplayer.value && node)
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment."));
|
||||
}
|
||||
else if (D_NumPlayers() >= maxplayers)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), maxplayers));
|
||||
}
|
||||
else if (netgame && netbuffer->u.clientcfg.localplayers > MAXSPLITSCREENPLAYERS) // Hacked client?
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("Too many players from\nthis node."));
|
||||
}
|
||||
else if (netgame && D_NumPlayers() + netbuffer->u.clientcfg.localplayers > maxplayers)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Number of local players\nwould exceed maximum: %d"), maxplayers));
|
||||
}
|
||||
else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join?
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("No players from\nthis node."));
|
||||
}
|
||||
else if (luafiletransfers)
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("The server is broadcasting a file\nrequested by a Lua script.\nPlease wait a bit and then\ntry rejoining."));
|
||||
}
|
||||
else if (netgame && joindelay > 2 * (tic_t)cv_joindelay.value * TICRATE)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."),
|
||||
(joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NONET
|
||||
|
|
@ -3883,7 +4114,7 @@ static void HandleConnect(SINT8 node)
|
|||
static void HandleShutdown(SINT8 node)
|
||||
{
|
||||
(void)node;
|
||||
LUAh_GameQuit(false);
|
||||
LUA_HookBool(false, HOOK(GameQuit));
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_StartTitle();
|
||||
|
|
@ -3898,7 +4129,7 @@ static void HandleShutdown(SINT8 node)
|
|||
static void HandleTimeout(SINT8 node)
|
||||
{
|
||||
(void)node;
|
||||
LUAh_GameQuit(false);
|
||||
LUA_HookBool(false, HOOK(GameQuit));
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_StartTitle();
|
||||
|
|
@ -4087,13 +4318,22 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
|||
break;
|
||||
}
|
||||
|
||||
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
|
||||
reason), NULL, MM_NOTHING);
|
||||
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_StartTitle();
|
||||
|
||||
if (reason[1] == '|')
|
||||
{
|
||||
M_StartMessage(va("You have been %sfrom the server\n\nReason:\n%s",
|
||||
(reason[0] == 'B') ? "banned\n" : "temporarily\nkicked ",
|
||||
reason+2), NULL, MM_NOTHING);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
|
||||
reason), NULL, MM_NOTHING);
|
||||
}
|
||||
|
||||
free(reason);
|
||||
|
||||
// Will be reset by caller. Signals refusal.
|
||||
|
|
@ -4704,7 +4944,10 @@ static void GetPackets(void)
|
|||
|
||||
if (netbuffer->packettype == PT_CLIENTJOIN && server)
|
||||
{
|
||||
HandleConnect(node);
|
||||
if (!levelloading) // Otherwise just ignore
|
||||
{
|
||||
HandleConnect(node);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node == servernode && client && cl_mode != CL_SEARCHING)
|
||||
|
|
@ -5291,7 +5534,18 @@ boolean TryRunTics(tic_t realtics)
|
|||
ps_tictime = I_GetPreciseTime();
|
||||
|
||||
G_Ticker((gametic % NEWTICRATERATIO) == 0);
|
||||
if (Playing() && netgame && (gametic % TICRATE == 0))
|
||||
{
|
||||
Schedule_Run();
|
||||
|
||||
if (cv_livestudioaudience.value)
|
||||
{
|
||||
LiveStudioAudience();
|
||||
}
|
||||
}
|
||||
|
||||
ExtraDataTicker();
|
||||
|
||||
gametic++;
|
||||
consistancy[gametic%BACKUPTICS] = Consistancy();
|
||||
|
||||
|
|
@ -5421,7 +5675,7 @@ static void UpdatePingTable(void)
|
|||
if (! server_lagless && playernode[i] > 0 && !players[i].spectator)
|
||||
{
|
||||
lag = GetLag(playernode[i]);
|
||||
realpingtable[i] += (INT32)(lag * (1000.00f/TICRATE));
|
||||
realpingtable[i] += lag;
|
||||
|
||||
if (! fastest || lag < fastest)
|
||||
fastest = lag;
|
||||
|
|
@ -5429,7 +5683,7 @@ static void UpdatePingTable(void)
|
|||
else
|
||||
{
|
||||
// TicsToMilliseconds can't handle pings over 1000ms lol
|
||||
realpingtable[i] += (INT32)(GetLag(playernode[i]) * (1000.00f/TICRATE));
|
||||
realpingtable[i] += GetLag(playernode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5447,7 +5701,7 @@ static void UpdatePingTable(void)
|
|||
else
|
||||
lag = GetLag(0);
|
||||
|
||||
lag = ( realpingtable[0] + G_TicsToMilliseconds(lag) );
|
||||
lag = ( realpingtable[0] + lag );
|
||||
|
||||
switch (playerpernode[0])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -394,6 +394,7 @@ extern INT32 mapchangepending;
|
|||
extern doomdata_t *netbuffer;
|
||||
extern consvar_t cv_stunserver;
|
||||
extern consvar_t cv_httpsource;
|
||||
extern consvar_t cv_kicktime;
|
||||
|
||||
extern consvar_t cv_showjoinaddress;
|
||||
extern consvar_t cv_playbackspeed;
|
||||
|
|
|
|||
51
src/d_net.c
51
src/d_net.c
|
|
@ -75,7 +75,7 @@ boolean (*I_NetCanGet)(void) = NULL;
|
|||
void (*I_NetCloseSocket)(void) = NULL;
|
||||
void (*I_NetFreeNodenum)(INT32 nodenum) = NULL;
|
||||
SINT8 (*I_NetMakeNodewPort)(const char *address, const char* port) = NULL;
|
||||
void (*I_NetRequestHolePunch)(void) = NULL;
|
||||
void (*I_NetRequestHolePunch)(INT32 node) = NULL;
|
||||
void (*I_NetRegisterHolePunch)(void) = NULL;
|
||||
boolean (*I_NetOpenSocket)(void) = NULL;
|
||||
boolean (*I_Ban) (INT32 node) = NULL;
|
||||
|
|
@ -83,8 +83,14 @@ void (*I_ClearBans)(void) = NULL;
|
|||
const char *(*I_GetNodeAddress) (INT32 node) = NULL;
|
||||
const char *(*I_GetBanAddress) (size_t ban) = NULL;
|
||||
const char *(*I_GetBanMask) (size_t ban) = NULL;
|
||||
const char *(*I_GetBanUsername) (size_t ban) = NULL;
|
||||
const char *(*I_GetBanReason) (size_t ban) = NULL;
|
||||
time_t (*I_GetUnbanTime) (size_t ban) = NULL;
|
||||
boolean (*I_SetBanAddress) (const char *address, const char *mask) = NULL;
|
||||
boolean *bannednode = NULL;
|
||||
boolean (*I_SetBanUsername) (const char *username) = NULL;
|
||||
boolean (*I_SetBanReason) (const char *reason) = NULL;
|
||||
boolean (*I_SetUnbanTime) (time_t timestamp) = NULL;
|
||||
bannednode_t *bannednode = NULL;
|
||||
|
||||
|
||||
// network stats
|
||||
|
|
@ -1389,6 +1395,7 @@ struct pingcell
|
|||
{
|
||||
INT32 num;
|
||||
INT32 ms;
|
||||
INT32 f;
|
||||
};
|
||||
|
||||
static int pingcellcmp(const void *va, const void *vb)
|
||||
|
|
@ -1412,6 +1419,7 @@ void Command_Ping_f(void)
|
|||
INT32 pingc;
|
||||
|
||||
int name_width = 0;
|
||||
int f_width = 0;
|
||||
int ms_width = 0;
|
||||
|
||||
int n;
|
||||
|
|
@ -1419,21 +1427,35 @@ void Command_Ping_f(void)
|
|||
|
||||
pingc = 0;
|
||||
for (i = 1; i < MAXPLAYERS; ++i)
|
||||
if (playeringame[i])
|
||||
{
|
||||
n = strlen(player_names[i]);
|
||||
if (n > name_width)
|
||||
name_width = n;
|
||||
if (playeringame[i])
|
||||
{
|
||||
INT32 ms;
|
||||
|
||||
n = playerpingtable[i];
|
||||
if (n > ms_width)
|
||||
ms_width = n;
|
||||
n = strlen(player_names[i]);
|
||||
if (n > name_width)
|
||||
name_width = n;
|
||||
|
||||
pingv[pingc].num = i;
|
||||
pingv[pingc].ms = playerpingtable[i];
|
||||
pingc++;
|
||||
n = playerpingtable[i];
|
||||
if (n > f_width)
|
||||
f_width = n;
|
||||
|
||||
ms = (INT32)(playerpingtable[i] * (1000.00f / TICRATE));
|
||||
n = ms;
|
||||
if (n > ms_width)
|
||||
ms_width = n;
|
||||
|
||||
pingv[pingc].num = i;
|
||||
pingv[pingc].f = playerpingtable[i];
|
||||
pingv[pingc].ms = ms;
|
||||
pingc++;
|
||||
}
|
||||
}
|
||||
|
||||
if (f_width < 10) f_width = 1;
|
||||
else if (f_width < 100) f_width = 2;
|
||||
else f_width = 3;
|
||||
|
||||
if (ms_width < 10) ms_width = 1;
|
||||
else if (ms_width < 100) ms_width = 2;
|
||||
else ms_width = 3;
|
||||
|
|
@ -1442,15 +1464,16 @@ void Command_Ping_f(void)
|
|||
|
||||
for (i = 0; i < pingc; ++i)
|
||||
{
|
||||
CONS_Printf("%02d : %-*s %*d ms\n",
|
||||
CONS_Printf("%02d : %-*s %*d frames (%*d ms)\n",
|
||||
pingv[i].num,
|
||||
name_width, player_names[pingv[i].num],
|
||||
f_width, pingv[i].f,
|
||||
ms_width, pingv[i].ms);
|
||||
}
|
||||
|
||||
if (!server && playeringame[consoleplayer])
|
||||
{
|
||||
CONS_Printf("\nYour ping is %d ms\n", playerpingtable[consoleplayer]);
|
||||
CONS_Printf("\nYour ping is %d frames (%d ms)\n", playerpingtable[consoleplayer], (INT32)(playerpingtable[i] * (1000.00f / TICRATE)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ boolean HGetPacket(void);
|
|||
void D_SetDoomcom(void);
|
||||
#ifndef NONET
|
||||
void D_SaveBan(void);
|
||||
void D_LoadBan(boolean warning);
|
||||
#endif
|
||||
boolean D_CheckNetGame(void);
|
||||
void D_CloseConnection(void);
|
||||
|
|
|
|||
743
src/d_netcmd.c
743
src/d_netcmd.c
|
|
@ -99,6 +99,9 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum);
|
|||
static void Got_Teamchange(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Clearscores(UINT8 **cp, INT32 playernum);
|
||||
static void Got_DiscordInfo(UINT8 **cp, INT32 playernum);
|
||||
static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Automatecmd(UINT8 **cp, INT32 playernum);
|
||||
|
||||
static void PointLimit_OnChange(void);
|
||||
static void TimeLimit_OnChange(void);
|
||||
|
|
@ -147,6 +150,9 @@ static void KartEncore_OnChange(void);
|
|||
static void KartComeback_OnChange(void);
|
||||
static void KartEliminateLast_OnChange(void);
|
||||
|
||||
static void Schedule_OnChange(void);
|
||||
static void LiveStudioAudience_OnChange(void);
|
||||
|
||||
#ifdef NETGAME_DEVMODE
|
||||
static void Fishcake_OnChange(void);
|
||||
#endif
|
||||
|
|
@ -157,6 +163,8 @@ static void Command_Stopdemo_f(void);
|
|||
static void Command_StartMovie_f(void);
|
||||
static void Command_StopMovie_f(void);
|
||||
static void Command_Map_f(void);
|
||||
static void Command_RandomMap(void);
|
||||
static void Command_RestartLevel(void);
|
||||
static void Command_ResetCamera_f(void);
|
||||
|
||||
static void Command_View_f (void);
|
||||
|
|
@ -220,6 +228,12 @@ static void Command_Archivetest_f(void);
|
|||
|
||||
static void Command_KartGiveItem_f(void);
|
||||
|
||||
static void Command_Schedule_Add(void);
|
||||
static void Command_Schedule_Clear(void);
|
||||
static void Command_Schedule_List(void);
|
||||
|
||||
static void Command_Automate_Set(void);
|
||||
|
||||
// =========================================================================
|
||||
// CLIENT VARIABLES
|
||||
// =========================================================================
|
||||
|
|
@ -406,6 +420,8 @@ static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, "
|
|||
consvar_t cv_kartencore = CVAR_INIT ("kartencore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange);
|
||||
static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}};
|
||||
consvar_t cv_kartvoterulechanges = CVAR_INIT ("kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL);
|
||||
static CV_PossibleValue_t kartgametypepreference_cons_t[] = {{-1, "None"}, {GT_RACE, "Race"}, {GT_BATTLE, "Battle"}, {0, NULL}};
|
||||
consvar_t cv_kartgametypepreference = CVAR_INIT ("kartgametypepreference", "None", CV_NETVAR, kartgametypepreference_cons_t, NULL);
|
||||
static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Percentage"}, {2, "Kilometers"}, {3, "Miles"}, {4, "Fracunits"}, {0, NULL}};
|
||||
consvar_t cv_kartspeedometer = CVAR_INIT ("kartdisplayspeed", "Percentage", CV_SAVE, kartspeedometer_cons_t, NULL); // use tics in display
|
||||
static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}};
|
||||
|
|
@ -503,20 +519,23 @@ consvar_t cv_allowexitlevel = CVAR_INIT ("allowexitlevel", "No", CV_NETVAR, CV_Y
|
|||
|
||||
consvar_t cv_netstat = CVAR_INIT ("netstat", "Off", 0, CV_OnOff, NULL); // show bandwidth statistics
|
||||
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange);
|
||||
consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "210", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange);
|
||||
//static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange);
|
||||
consvar_t cv_maxping = CVAR_INIT ("maxping", "800", CV_SAVE, CV_Unsigned, NULL);
|
||||
consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "210", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange);
|
||||
consvar_t cv_maxping = CVAR_INIT ("maxdelay", "20", CV_SAVE, CV_Unsigned, NULL);
|
||||
|
||||
consvar_t cv_lagless = CVAR_INIT ("lagless", "Off", CV_SAVE|CV_NETVAR|CV_CALL, CV_OnOff, Lagless_OnChange);
|
||||
|
||||
static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_pingtimeout = CVAR_INIT ("pingtimeout", "10", CV_SAVE|CV_NETVAR, pingtimeout_cons_t, NULL);
|
||||
consvar_t cv_pingtimeout = CVAR_INIT ("maxdelaytimeout", "10", CV_SAVE|CV_NETVAR, pingtimeout_cons_t, NULL);
|
||||
|
||||
// show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping)
|
||||
static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
|
||||
consvar_t cv_showping = CVAR_INIT ("showping", "Always", CV_SAVE, showping_cons_t, NULL);
|
||||
|
||||
static CV_PossibleValue_t pingmeasurement_cons_t[] = {{0, "Frames"}, {1, "Milliseconds"}, {0, NULL}};
|
||||
consvar_t cv_pingmeasurement = CVAR_INIT ("pingmeasurement", "Frames", CV_SAVE, pingmeasurement_cons_t, NULL);
|
||||
|
||||
consvar_t cv_showviewpointtext = CVAR_INIT ("showviewpointtext", "On", CV_SAVE, CV_OnOff, NULL);
|
||||
|
||||
// Intermission time Tails 04-19-2002
|
||||
|
|
@ -545,6 +564,16 @@ consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NUL
|
|||
|
||||
consvar_t cv_director = CVAR_INIT ("director", "Off", 0, CV_OnOff, NULL);
|
||||
|
||||
consvar_t cv_schedule = CVAR_INIT ("schedule", "On", CV_NETVAR|CV_CALL, CV_OnOff, Schedule_OnChange);
|
||||
|
||||
consvar_t cv_automate = CVAR_INIT ("automate", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
#ifdef DEVELOP
|
||||
consvar_t cv_livestudioaudience = CVAR_INIT ("livestudioaudience", "On", CV_NETVAR|CV_CALL, CV_OnOff, LiveStudioAudience_OnChange);
|
||||
#else
|
||||
consvar_t cv_livestudioaudience = CVAR_INIT ("livestudioaudience", "Off", CV_NETVAR|CV_CALL, CV_OnOff, LiveStudioAudience_OnChange);
|
||||
#endif
|
||||
|
||||
char timedemo_name[256];
|
||||
boolean timedemo_csv;
|
||||
char timedemo_csv_id[256];
|
||||
|
|
@ -560,44 +589,66 @@ UINT8 splitscreen = 0;
|
|||
boolean circuitmap = false;
|
||||
INT32 adminplayers[MAXPLAYERS];
|
||||
|
||||
// Scheduled commands.
|
||||
scheduleTask_t **schedule = NULL;
|
||||
size_t schedule_size = 0;
|
||||
size_t schedule_len = 0;
|
||||
|
||||
// Automation commands
|
||||
char *automate_commands[AEV__MAX];
|
||||
|
||||
const char *automate_names[AEV__MAX] =
|
||||
{
|
||||
"RoundStart", // AEV_ROUNDSTART
|
||||
"IntermissionStart", // AEV_INTERMISSIONSTART
|
||||
"VoteStart" // AEV_VOTESTART
|
||||
};
|
||||
|
||||
UINT32 livestudioaudience_timer = 90;
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename net text commands
|
||||
const char *netxcmdnames[MAXNETXCMD - 1] =
|
||||
{
|
||||
"NAMEANDCOLOR",
|
||||
"WEAPONPREF",
|
||||
"KICK",
|
||||
"NETVAR",
|
||||
"SAY",
|
||||
"MAP",
|
||||
"EXITLEVEL",
|
||||
"ADDFILE",
|
||||
"PAUSE",
|
||||
"ADDPLAYER",
|
||||
"TEAMCHANGE",
|
||||
"CLEARSCORES",
|
||||
"VERIFIED",
|
||||
"RANDOMSEED",
|
||||
"RUNSOC",
|
||||
"REQADDFILE",
|
||||
"SETMOTD",
|
||||
"RESPAWN",
|
||||
"DEMOTED",
|
||||
"LUACMD",
|
||||
"LUAVAR",
|
||||
"LUAFILE",
|
||||
"NAMEANDCOLOR", // XD_NAMEANDCOLOR
|
||||
"WEAPONPREF", // XD_WEAPONPREF
|
||||
"KICK", // XD_KICK
|
||||
"NETVAR", // XD_NETVAR
|
||||
"SAY", // XD_SAY
|
||||
"MAP", // XD_MAP
|
||||
"EXITLEVEL", // XD_EXITLEVEL
|
||||
"ADDFILE", // XD_ADDFILE
|
||||
"PAUSE", // XD_PAUSE
|
||||
"ADDPLAYER", // XD_ADDPLAYER
|
||||
"TEAMCHANGE", // XD_TEAMCHANGE
|
||||
"CLEARSCORES", // XD_CLEARSCORES
|
||||
"VERIFIED", // XD_VERIFIED
|
||||
"RANDOMSEED", // XD_RANDOMSEED
|
||||
"RUNSOC", // XD_RUNSOC
|
||||
"REQADDFILE", // XD_REQADDFILE
|
||||
"SETMOTD", // XD_SETMOTD
|
||||
"RESPAWN", // XD_RESPAWN
|
||||
"DEMOTED", // XD_DEMOTED
|
||||
"LUACMD", // XD_LUACMD
|
||||
"LUAVAR", // XD_LUAVAR
|
||||
"LUAFILE", // XD_LUAFILE
|
||||
|
||||
// SRB2Kart
|
||||
"SETUPVOTE",
|
||||
"MODIFYVOTE",
|
||||
"PICKVOTE",
|
||||
"REMOVEPLAYER",
|
||||
"POWERLEVEL",
|
||||
"PARTYINVITE",
|
||||
"ACCEPTPARTYINVITE",
|
||||
"LEAVEPARTY",
|
||||
"CANCELPARTYINVITE",
|
||||
"GIVEITEM",
|
||||
"ADDBOT"
|
||||
"SETUPVOTE", // XD_SETUPVOTE
|
||||
"MODIFYVOTE", // XD_MODIFYVOTE
|
||||
"PICKVOTE", // XD_PICKVOTE
|
||||
"REMOVEPLAYER", // XD_REMOVEPLAYER
|
||||
"POWERLEVEL", // XD_POWERLEVEL
|
||||
"PARTYINVITE", // XD_PARTYINVITE
|
||||
"ACCEPTPARTYINVITE", // XD_ACCEPTPARTYINVITE
|
||||
"LEAVEPARTY", // XD_LEAVEPARTY
|
||||
"CANCELPARTYINVITE", // XD_CANCELPARTYINVITE
|
||||
"GIVEITEM", // XD_GIVEITEM
|
||||
"ADDBOT", // XD_ADDBOT
|
||||
"DISCORD", // XD_DISCORD
|
||||
"PLAYSOUND", // XD_PLAYSOUND
|
||||
"SCHEDULETASK", // XD_SCHEDULETASK
|
||||
"SCHEDULECLEAR", // XD_SCHEDULECLEAR
|
||||
"AUTOMATE" // XD_AUTOMATE
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
|
|
@ -646,6 +697,10 @@ void D_RegisterServerCommands(void)
|
|||
|
||||
RegisterNetXCmd(XD_GIVEITEM, Got_GiveItemcmd);
|
||||
|
||||
RegisterNetXCmd(XD_SCHEDULETASK, Got_ScheduleTaskcmd);
|
||||
RegisterNetXCmd(XD_SCHEDULECLEAR, Got_ScheduleClearcmd);
|
||||
RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd);
|
||||
|
||||
// Remote Administration
|
||||
COM_AddCommand("password", Command_Changepassword_f);
|
||||
COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin
|
||||
|
|
@ -663,6 +718,8 @@ void D_RegisterServerCommands(void)
|
|||
RegisterNetXCmd(XD_CLEARSCORES, Got_Clearscores);
|
||||
COM_AddCommand("clearscores", Command_Clearscores_f);
|
||||
COM_AddCommand("map", Command_Map_f);
|
||||
COM_AddCommand("randommap", Command_RandomMap);
|
||||
COM_AddCommand("restartlevel", Command_RestartLevel);
|
||||
|
||||
COM_AddCommand("exitgame", Command_ExitGame_f);
|
||||
COM_AddCommand("retry", Command_Retry_f);
|
||||
|
|
@ -701,6 +758,12 @@ void D_RegisterServerCommands(void)
|
|||
|
||||
COM_AddCommand("kartgiveitem", Command_KartGiveItem_f);
|
||||
|
||||
COM_AddCommand("schedule_add", Command_Schedule_Add);
|
||||
COM_AddCommand("schedule_clear", Command_Schedule_Clear);
|
||||
COM_AddCommand("schedule_list", Command_Schedule_List);
|
||||
|
||||
COM_AddCommand("automate_set", Command_Automate_Set);
|
||||
|
||||
// for master server connection
|
||||
AddMServCommands();
|
||||
|
||||
|
|
@ -760,17 +823,22 @@ void D_RegisterServerCommands(void)
|
|||
COM_AddCommand("ping", Command_Ping_f);
|
||||
CV_RegisterVar(&cv_nettimeout);
|
||||
CV_RegisterVar(&cv_jointimeout);
|
||||
|
||||
CV_RegisterVar(&cv_kicktime);
|
||||
CV_RegisterVar(&cv_skipmapcheck);
|
||||
CV_RegisterVar(&cv_sleep);
|
||||
CV_RegisterVar(&cv_maxping);
|
||||
CV_RegisterVar(&cv_lagless);
|
||||
CV_RegisterVar(&cv_pingtimeout);
|
||||
CV_RegisterVar(&cv_showping);
|
||||
CV_RegisterVar(&cv_pingmeasurement);
|
||||
CV_RegisterVar(&cv_showviewpointtext);
|
||||
|
||||
CV_RegisterVar(&cv_director);
|
||||
|
||||
CV_RegisterVar(&cv_schedule);
|
||||
CV_RegisterVar(&cv_automate);
|
||||
CV_RegisterVar(&cv_livestudioaudience);
|
||||
|
||||
CV_RegisterVar(&cv_dummyconsvar);
|
||||
|
||||
#ifdef USE_STUN
|
||||
|
|
@ -961,6 +1029,11 @@ void D_RegisterClientCommands(void)
|
|||
CV_RegisterVar(&cv_consolechat);
|
||||
CV_RegisterVar(&cv_chatnotifications);
|
||||
CV_RegisterVar(&cv_chatbacktint);
|
||||
|
||||
CV_RegisterVar(&cv_shoutname);
|
||||
CV_RegisterVar(&cv_shoutcolor);
|
||||
CV_RegisterVar(&cv_autoshout);
|
||||
|
||||
CV_RegisterVar(&cv_songcredits);
|
||||
CV_RegisterVar(&cv_tutorialprompt);
|
||||
CV_RegisterVar(&cv_showfocuslost);
|
||||
|
|
@ -1008,6 +1081,7 @@ void D_RegisterClientCommands(void)
|
|||
// screen.c
|
||||
CV_RegisterVar(&cv_fullscreen);
|
||||
CV_RegisterVar(&cv_renderview);
|
||||
CV_RegisterVar(&cv_renderhitbox);
|
||||
CV_RegisterVar(&cv_vhseffect);
|
||||
CV_RegisterVar(&cv_shittyscreen);
|
||||
CV_RegisterVar(&cv_renderer);
|
||||
|
|
@ -1076,6 +1150,15 @@ void D_RegisterClientCommands(void)
|
|||
* \sa CleanupPlayerName, SetPlayerName, Got_NameAndColor
|
||||
* \author Graue <graue@oceanbase.org>
|
||||
*/
|
||||
|
||||
static boolean AllowedPlayerNameChar(char ch)
|
||||
{
|
||||
if (!isprint(ch) || ch == ';' || ch == '"' || (UINT8)(ch) >= 0x80)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
|
||||
{
|
||||
INT32 ix;
|
||||
|
|
@ -1097,7 +1180,7 @@ boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
|
|||
// Also, anything over 0x80 is disallowed too, since compilers love to
|
||||
// differ on whether they're printable characters or not.
|
||||
for (ix = 0; name[ix] != '\0'; ix++)
|
||||
if (!isprint(name[ix]) || name[ix] == ';' || (UINT8)(name[ix]) >= 0x80)
|
||||
if (!AllowedPlayerNameChar(name[ix]))
|
||||
return false;
|
||||
|
||||
// Check if a player is currently using the name, case-insensitively.
|
||||
|
|
@ -1188,8 +1271,7 @@ void CleanupPlayerName(INT32 playernum, const char *newname)
|
|||
|
||||
do
|
||||
{
|
||||
/* from EnsurePlayerNameIsGood */
|
||||
if (!isprint(*p) || *p == ';' || (UINT8)*p >= 0x80)
|
||||
if (!AllowedPlayerNameChar(*p))
|
||||
break;
|
||||
}
|
||||
while (*++p) ;
|
||||
|
|
@ -2475,27 +2557,28 @@ void D_SetupVote(void)
|
|||
UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes
|
||||
UINT8 *p = buf;
|
||||
INT32 i;
|
||||
UINT8 secondgt = G_SometimesGetDifferentGametype();
|
||||
UINT8 gt = (cv_kartgametypepreference.value == -1) ? gametype : cv_kartgametypepreference.value;
|
||||
UINT8 secondgt = G_SometimesGetDifferentGametype(gt);
|
||||
INT16 votebuffer[4] = {-1,-1,-1,0};
|
||||
|
||||
if ((cv_kartencore.value == 1) && (gametyperules & GTR_CIRCUIT))
|
||||
WRITEUINT8(p, (gametype|0x80));
|
||||
if ((cv_kartencore.value == 1) && (gametypedefaultrules[gt] & GTR_CIRCUIT))
|
||||
WRITEUINT8(p, (gt|VOTEMODIFIER_ENCORE));
|
||||
else
|
||||
WRITEUINT8(p, gametype);
|
||||
WRITEUINT8(p, gt);
|
||||
WRITEUINT8(p, secondgt);
|
||||
secondgt &= ~0x80;
|
||||
secondgt &= ~VOTEMODIFIER_ENCORE;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
UINT16 m;
|
||||
if (i == 2) // sometimes a different gametype
|
||||
m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer);
|
||||
else if (i >= 3) // unknown-random and force-unknown MAP HELL
|
||||
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, (i-2), (i < 4), votebuffer);
|
||||
else if (i >= 3) // unknown-random and formerly force-unknown MAP HELL
|
||||
m = G_RandMap(G_TOLFlag(gt), prevmap, 0, (i-2), (i < 4), votebuffer);
|
||||
else
|
||||
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer);
|
||||
m = G_RandMap(G_TOLFlag(gt), prevmap, 0, 0, true, votebuffer);
|
||||
if (i < 3)
|
||||
votebuffer[i] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error
|
||||
votebuffer[i] = m;
|
||||
WRITEUINT16(p, m);
|
||||
}
|
||||
|
||||
|
|
@ -2951,10 +3034,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
|||
demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING;
|
||||
demo.savebutton = 0;
|
||||
|
||||
// Sal: Is this needed?
|
||||
// From experimenting with Lua scripts in vanilla I found a lot of annoying & potentially desync-y things with MapChange.
|
||||
LUAh_MapChange(mapnumber);
|
||||
|
||||
G_InitNew(pencoremode, mapnumber, resetplayer, skipprecutscene, FLS);
|
||||
if (demo.playback && !demo.timing)
|
||||
precache = true;
|
||||
|
|
@ -2972,6 +3051,67 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void Command_RandomMap(void)
|
||||
{
|
||||
INT32 oldmapnum;
|
||||
INT32 newmapnum;
|
||||
INT32 newgametype;
|
||||
boolean newencoremode;
|
||||
boolean newresetplayers;
|
||||
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle singleplayer conditions.
|
||||
// The existing ones are way too annoyingly complicated and "anti-cheat" for my tastes.
|
||||
|
||||
if (Playing())
|
||||
{
|
||||
newgametype = gametype;
|
||||
newencoremode = encoremode;
|
||||
newresetplayers = false;
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
oldmapnum = gamemap-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldmapnum = prevmap;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newgametype = cv_dummygametype.value; // Changed from cv_newgametype to match newmenus
|
||||
newencoremode = false;
|
||||
newresetplayers = true;
|
||||
oldmapnum = -1;
|
||||
}
|
||||
|
||||
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, 0, 0, false, NULL) + 1;
|
||||
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
|
||||
}
|
||||
|
||||
static void Command_RestartLevel(void)
|
||||
{
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Playing())
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be in a game to use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
D_MapChange(gamemap, gametype, encoremode, false, 0, false, false);
|
||||
}
|
||||
|
||||
static void Command_Pause(void)
|
||||
{
|
||||
UINT8 buf[2];
|
||||
|
|
@ -3438,7 +3578,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
}
|
||||
|
||||
// Don't switch team, just go away, please, go awaayyyy, aaauuauugghhhghgh
|
||||
if (!LUAh_TeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled))
|
||||
if (!LUA_HookTeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled))
|
||||
return;
|
||||
|
||||
//Make sure that the right team number is sent. Keep in mind that normal clients cannot change to certain teams in certain gametypes.
|
||||
|
|
@ -3534,7 +3674,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
{
|
||||
if (localplayertable[i] == playernum)
|
||||
{
|
||||
LUAh_ViewpointSwitch(players+playernum, players+playernum, true);
|
||||
LUA_HookViewpointSwitch(players+playernum, players+playernum, true);
|
||||
displayplayers[i] = playernum;
|
||||
break;
|
||||
}
|
||||
|
|
@ -3688,9 +3828,7 @@ void SetAdminPlayer(INT32 playernum)
|
|||
|
||||
void ClearAdminPlayers(void)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
adminplayers[i] = -1;
|
||||
memset(adminplayers, -1, sizeof(adminplayers));
|
||||
}
|
||||
|
||||
void RemoveAdminPlayer(INT32 playernum)
|
||||
|
|
@ -3807,6 +3945,218 @@ static void Got_Removal(UINT8 **cp, INT32 playernum)
|
|||
CONS_Printf(M_GetText("You are no longer a server administrator.\n"));
|
||||
}
|
||||
|
||||
void Schedule_Run(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (schedule_len == 0)
|
||||
{
|
||||
// No scheduled tasks to run.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cv_schedule.value)
|
||||
{
|
||||
// We don't WANT to run tasks.
|
||||
return;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
{
|
||||
// Don't engage in automation while in a restricted context.
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
|
||||
if (task == NULL)
|
||||
{
|
||||
// Shouldn't happen.
|
||||
break;
|
||||
}
|
||||
|
||||
if (task->timer > 0)
|
||||
{
|
||||
task->timer--;
|
||||
}
|
||||
|
||||
if (task->timer == 0)
|
||||
{
|
||||
// Reset timer
|
||||
task->timer = task->basetime;
|
||||
|
||||
// Run command for server
|
||||
if (server)
|
||||
{
|
||||
CONS_Printf(
|
||||
"%d seconds elapsed, running \"" "\x82" "%s" "\x80" "\".\n",
|
||||
task->basetime,
|
||||
task->command
|
||||
);
|
||||
|
||||
COM_BufAddText(task->command);
|
||||
COM_BufAddText("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Schedule_Insert(scheduleTask_t *addTask)
|
||||
{
|
||||
if (schedule_len >= schedule_size)
|
||||
{
|
||||
if (schedule_size == 0)
|
||||
{
|
||||
schedule_size = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
schedule_size *= 2;
|
||||
}
|
||||
|
||||
schedule = Z_ReallocAlign(
|
||||
(void*) schedule,
|
||||
sizeof(scheduleTask_t*) * schedule_size,
|
||||
PU_STATIC,
|
||||
NULL,
|
||||
sizeof(scheduleTask_t*) * 8
|
||||
);
|
||||
}
|
||||
|
||||
schedule[schedule_len] = addTask;
|
||||
schedule_len++;
|
||||
}
|
||||
|
||||
void Schedule_Add(INT16 basetime, INT16 timeleft, const char *command)
|
||||
{
|
||||
scheduleTask_t *task = (scheduleTask_t*) Z_CallocAlign(
|
||||
sizeof(scheduleTask_t),
|
||||
PU_STATIC,
|
||||
NULL,
|
||||
sizeof(scheduleTask_t) * 8
|
||||
);
|
||||
|
||||
task->basetime = basetime;
|
||||
task->timer = timeleft;
|
||||
task->command = Z_StrDup(command);
|
||||
|
||||
Schedule_Insert(task);
|
||||
}
|
||||
|
||||
void Schedule_Clear(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
|
||||
if (task->command)
|
||||
Z_Free(task->command);
|
||||
}
|
||||
|
||||
schedule_len = 0;
|
||||
schedule_size = 0;
|
||||
schedule = NULL;
|
||||
}
|
||||
|
||||
void Automate_Set(automateEvents_t type, const char *command)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
// Since there's no list command or anything for this,
|
||||
// we don't need this code to run for anyone but the server.
|
||||
return;
|
||||
}
|
||||
|
||||
if (automate_commands[type] != NULL)
|
||||
{
|
||||
// Free the old command.
|
||||
Z_Free(automate_commands[type]);
|
||||
}
|
||||
|
||||
if (command == NULL || strlen(command) == 0)
|
||||
{
|
||||
// Remove the command.
|
||||
automate_commands[type] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New command.
|
||||
automate_commands[type] = Z_StrDup(command);
|
||||
}
|
||||
}
|
||||
|
||||
void Automate_Run(automateEvents_t type)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
// Only the server should be doing this.
|
||||
return;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
{
|
||||
// Don't engage in automation while in a restricted context.
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PARANOIA
|
||||
if (type >= AEV__MAX)
|
||||
{
|
||||
// Shouldn't happen.
|
||||
I_Error("Attempted to run invalid automation type.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!cv_automate.value)
|
||||
{
|
||||
// We don't want to run automation.
|
||||
return;
|
||||
}
|
||||
|
||||
if (automate_commands[type] == NULL)
|
||||
{
|
||||
// No command to run.
|
||||
return;
|
||||
}
|
||||
|
||||
CONS_Printf(
|
||||
"Running %s automate command \"" "\x82" "%s" "\x80" "\"...\n",
|
||||
automate_names[type],
|
||||
automate_commands[type]
|
||||
);
|
||||
|
||||
COM_BufAddText(automate_commands[type]);
|
||||
COM_BufAddText("\n");
|
||||
}
|
||||
|
||||
void Automate_Clear(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < AEV__MAX; i++)
|
||||
{
|
||||
Automate_Set(i, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void LiveStudioAudience(void)
|
||||
{
|
||||
if (livestudioaudience_timer == 0)
|
||||
{
|
||||
S_StartSound(NULL, sfx_mbv91);
|
||||
livestudioaudience_timer = 90;
|
||||
}
|
||||
else
|
||||
{
|
||||
livestudioaudience_timer--;
|
||||
}
|
||||
}
|
||||
|
||||
static void Command_MotD_f(void)
|
||||
{
|
||||
size_t i, j;
|
||||
|
|
@ -4454,7 +4804,7 @@ static void Command_Playintro_f(void)
|
|||
*/
|
||||
FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void)
|
||||
{
|
||||
LUAh_GameQuit(true);
|
||||
LUA_HookBool(true, HOOK(GameQuit));
|
||||
I_Quit();
|
||||
}
|
||||
|
||||
|
|
@ -4918,6 +5268,13 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
gt = (UINT8)READUINT8(*cp);
|
||||
secondgt = (UINT8)READUINT8(*cp);
|
||||
|
||||
// Strip illegal Encore flag.
|
||||
if ((gt & VOTEMODIFIER_ENCORE)
|
||||
&& !(gametypedefaultrules[(gt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT))
|
||||
{
|
||||
gt &= ~VOTEMODIFIER_ENCORE;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tempvotelevels[i][0] = (UINT16)READUINT16(*cp);
|
||||
|
|
@ -4931,6 +5288,19 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
}
|
||||
|
||||
// If third entry has an illelegal Encore flag... (illelegal!?)
|
||||
if ((secondgt & VOTEMODIFIER_ENCORE)
|
||||
&& !(gametypedefaultrules[(secondgt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT))
|
||||
{
|
||||
secondgt &= ~VOTEMODIFIER_ENCORE;
|
||||
// Apply it to the second entry instead, gametype permitting!
|
||||
if (gametypedefaultrules[gt] & GTR_CIRCUIT)
|
||||
{
|
||||
tempvotelevels[1][1] |= VOTEMODIFIER_ENCORE;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, set third entry's gametype/Encore status.
|
||||
tempvotelevels[2][1] = secondgt;
|
||||
|
||||
memcpy(votelevels, tempvotelevels, sizeof(votelevels));
|
||||
|
|
@ -4989,6 +5359,101 @@ static void Got_GiveItemcmd(UINT8 **cp, INT32 playernum)
|
|||
players[playernum].itemamount = amt;
|
||||
}
|
||||
|
||||
static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
char command[MAXTEXTCMD];
|
||||
INT16 seconds;
|
||||
|
||||
seconds = READINT16(*cp);
|
||||
READSTRING(*cp, command);
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText ("Illegal schedule task received from %s\n"),
|
||||
player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule_Add(seconds, seconds, (const char *)command);
|
||||
|
||||
if (server || consoleplayer == playernum)
|
||||
{
|
||||
CONS_Printf(
|
||||
"OK! Running \"" "\x82" "%s" "\x80" "\" every " "\x82" "%d" "\x80" " seconds.\n",
|
||||
command,
|
||||
seconds
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
(void)cp;
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText ("Illegal schedule clear received from %s\n"),
|
||||
player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule_Clear();
|
||||
|
||||
if (server || consoleplayer == playernum)
|
||||
{
|
||||
CONS_Printf("All scheduled tasks have been cleared.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void Got_Automatecmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
UINT8 eventID;
|
||||
char command[MAXTEXTCMD];
|
||||
|
||||
eventID = READUINT8(*cp);
|
||||
READSTRING(*cp, command);
|
||||
|
||||
if (
|
||||
(playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
|| (eventID >= AEV__MAX)
|
||||
)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText ("Illegal automate received from %s\n"),
|
||||
player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Automate_Set(eventID, command);
|
||||
|
||||
if (server || consoleplayer == playernum)
|
||||
{
|
||||
if (command[0] == '\0')
|
||||
{
|
||||
CONS_Printf(
|
||||
"Removed the %s automate command.\n",
|
||||
automate_names[eventID]
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf(
|
||||
"Set the %s automate command to \"" "\x82" "%s" "\x80" "\".\n",
|
||||
automate_names[eventID],
|
||||
command
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints the number of displayplayers[0].
|
||||
*
|
||||
* \todo Possibly remove this; it was useful for debugging at one point.
|
||||
|
|
@ -5027,7 +5492,7 @@ void Command_ExitGame_f(void)
|
|||
{
|
||||
INT32 i;
|
||||
|
||||
LUAh_GameQuit(false);
|
||||
LUA_HookBool(false, HOOK(GameQuit));
|
||||
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
|
|
@ -5253,6 +5718,135 @@ static void Command_KartGiveItem_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void Command_Schedule_Add(void)
|
||||
{
|
||||
UINT8 buf[MAXTEXTCMD];
|
||||
UINT8 *buf_p = buf;
|
||||
|
||||
size_t ac;
|
||||
INT16 seconds;
|
||||
const char *command;
|
||||
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ac = COM_Argc();
|
||||
if (ac < 3)
|
||||
{
|
||||
CONS_Printf("schedule <seconds> <...>: runs the specified commands on a recurring timer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
seconds = atoi(COM_Argv(1));
|
||||
|
||||
if (seconds <= 0)
|
||||
{
|
||||
CONS_Printf("Timer must be at least 1 second.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
command = COM_Argv(2);
|
||||
|
||||
WRITEINT16(buf_p, seconds);
|
||||
WRITESTRING(buf_p, command);
|
||||
|
||||
SendNetXCmd(XD_SCHEDULETASK, buf, buf_p - buf);
|
||||
}
|
||||
|
||||
static void Command_Schedule_Clear(void)
|
||||
{
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SendNetXCmd(XD_SCHEDULECLEAR, NULL, 0);
|
||||
}
|
||||
|
||||
static void Command_Schedule_List(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
// I set it up in a way that this information could be available
|
||||
// to everyone, but HOSTMOD has it server/admin-only too, so eh?
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (schedule_len == 0)
|
||||
{
|
||||
CONS_Printf("No tasks are scheduled.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
|
||||
CONS_Printf(
|
||||
"In " "\x82" "%d" "\x80" " second%s: " "\x82" "%s" "\x80" "\n",
|
||||
task->timer,
|
||||
(task->timer > 1) ? "s" : "",
|
||||
task->command
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void Command_Automate_Set(void)
|
||||
{
|
||||
UINT8 buf[MAXTEXTCMD];
|
||||
UINT8 *buf_p = buf;
|
||||
|
||||
size_t ac;
|
||||
|
||||
const char *event;
|
||||
size_t eventID;
|
||||
|
||||
const char *command;
|
||||
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ac = COM_Argc();
|
||||
if (ac < 3)
|
||||
{
|
||||
CONS_Printf("automate_set <event> <command>: sets the command to run each time a event triggers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
event = COM_Argv(1);
|
||||
|
||||
for (eventID = 0; eventID < AEV__MAX; eventID++)
|
||||
{
|
||||
if (strcasecmp(event, automate_names[eventID]) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventID == AEV__MAX)
|
||||
{
|
||||
CONS_Printf("Unknown event type \"%s\".\n", event);
|
||||
return;
|
||||
}
|
||||
|
||||
command = COM_Argv(2);
|
||||
|
||||
WRITEUINT8(buf_p, eventID);
|
||||
WRITESTRING(buf_p, command);
|
||||
|
||||
SendNetXCmd(XD_AUTOMATE, buf, buf_p - buf);
|
||||
}
|
||||
|
||||
/** Makes a change to ::cv_forceskin take effect immediately.
|
||||
*
|
||||
* \sa Command_SetForcedSkin_f, cv_forceskin, forcedskin
|
||||
|
|
@ -5871,6 +6465,33 @@ static void KartEliminateLast_OnChange(void)
|
|||
P_CheckRacers();
|
||||
}
|
||||
|
||||
static void Schedule_OnChange(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (cv_schedule.value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (schedule_len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset timers when turning off.
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
task->timer = task->basetime;
|
||||
}
|
||||
}
|
||||
|
||||
static void LiveStudioAudience_OnChange(void)
|
||||
{
|
||||
livestudioaudience_timer = 90;
|
||||
}
|
||||
|
||||
void Got_DiscordInfo(UINT8 **p, INT32 playernum)
|
||||
{
|
||||
if (playernum != serverplayer /*&& !IsPlayerAdmin(playernum)*/)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ extern consvar_t cv_kartfrantic;
|
|||
extern consvar_t cv_kartcomeback;
|
||||
extern consvar_t cv_kartencore;
|
||||
extern consvar_t cv_kartvoterulechanges;
|
||||
extern consvar_t cv_kartgametypepreference;
|
||||
extern consvar_t cv_kartspeedometer;
|
||||
extern consvar_t cv_kartvoices;
|
||||
extern consvar_t cv_kartbot;
|
||||
|
|
@ -117,6 +118,7 @@ extern consvar_t cv_maxping;
|
|||
extern consvar_t cv_lagless;
|
||||
extern consvar_t cv_pingtimeout;
|
||||
extern consvar_t cv_showping;
|
||||
extern consvar_t cv_pingmeasurement;
|
||||
extern consvar_t cv_showviewpointtext;
|
||||
|
||||
extern consvar_t cv_skipmapcheck;
|
||||
|
|
@ -127,6 +129,10 @@ extern consvar_t cv_perfstats;
|
|||
|
||||
extern consvar_t cv_director;
|
||||
|
||||
extern consvar_t cv_schedule;
|
||||
|
||||
extern consvar_t cv_livestudioaudience;
|
||||
|
||||
extern char timedemo_name[256];
|
||||
extern boolean timedemo_csv;
|
||||
extern char timedemo_csv_id[256];
|
||||
|
|
@ -170,6 +176,10 @@ typedef enum
|
|||
XD_GIVEITEM, // 32
|
||||
XD_ADDBOT, // 33
|
||||
XD_DISCORD, // 34
|
||||
XD_PLAYSOUND, // 35
|
||||
XD_SCHEDULETASK, // 36
|
||||
XD_SCHEDULECLEAR, // 37
|
||||
XD_AUTOMATE, // 38
|
||||
|
||||
MAXNETXCMD
|
||||
} netxcmd_t;
|
||||
|
|
@ -238,6 +248,37 @@ void RemoveAdminPlayer(INT32 playernum);
|
|||
void ItemFinder_OnChange(void);
|
||||
void D_SetPassword(const char *pw);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 basetime;
|
||||
UINT16 timer;
|
||||
char *command;
|
||||
} scheduleTask_t;
|
||||
|
||||
extern scheduleTask_t **schedule;
|
||||
extern size_t schedule_size;
|
||||
extern size_t schedule_len;
|
||||
|
||||
void Schedule_Run(void);
|
||||
void Schedule_Insert(scheduleTask_t *addTask);
|
||||
void Schedule_Add(INT16 basetime, INT16 timeleft, const char *command);
|
||||
void Schedule_Clear(void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AEV_ROUNDSTART,
|
||||
AEV_INTERMISSIONSTART,
|
||||
AEV_VOTESTART,
|
||||
AEV__MAX
|
||||
} automateEvents_t;
|
||||
|
||||
void Automate_Run(automateEvents_t type);
|
||||
void Automate_Set(automateEvents_t type, const char *command);
|
||||
void Automate_Clear(void);
|
||||
|
||||
extern UINT32 livestudioaudience_timer;
|
||||
void LiveStudioAudience(void);
|
||||
|
||||
// used for the player setup menu
|
||||
UINT8 CanChangeSkin(INT32 playernum);
|
||||
|
||||
|
|
|
|||
|
|
@ -1007,7 +1007,6 @@ static void SV_EndFileSend(INT32 node)
|
|||
filestosend--;
|
||||
}
|
||||
|
||||
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
|
||||
#define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE))
|
||||
|
||||
/** Handles file transmission
|
||||
|
|
@ -1040,14 +1039,7 @@ void FileSendTicker(void)
|
|||
if (!filestosend) // No file to send
|
||||
return;
|
||||
|
||||
if (cv_downloadspeed.value) // New behavior
|
||||
packetsent = cv_downloadspeed.value;
|
||||
else // Old behavior
|
||||
{
|
||||
packetsent = PACKETPERTIC;
|
||||
if (!packetsent)
|
||||
packetsent = 1;
|
||||
}
|
||||
packetsent = cv_downloadspeed.value;
|
||||
|
||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||
|
||||
|
|
|
|||
|
|
@ -584,6 +584,8 @@ typedef struct player_s
|
|||
|
||||
UINT8 stairjank;
|
||||
|
||||
UINT8 shrinkLaserDelay;
|
||||
|
||||
#ifdef HWRENDER
|
||||
fixed_t fovadd; // adjust FOV for hw rendering
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3755,6 +3755,15 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
// Caked-Up Booty-Sheet Ghost
|
||||
"S_HYUDORO",
|
||||
|
||||
// Grow
|
||||
"S_GROW_PARTICLE",
|
||||
|
||||
// Shrink
|
||||
"S_SHRINK_GUN",
|
||||
"S_SHRINK_CHAIN",
|
||||
"S_SHRINK_LASER",
|
||||
"S_SHRINK_PARTICLE",
|
||||
|
||||
// The legend
|
||||
"S_SINK",
|
||||
"S_SINK_SHIELD",
|
||||
|
|
@ -4506,6 +4515,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
// because sadly no one remembers this place while searching for full state names.
|
||||
const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity testing later.
|
||||
"MT_NULL",
|
||||
"MT_RAY",
|
||||
"MT_UNKNOWN",
|
||||
|
||||
"MT_THOK", // Thok! mobj
|
||||
|
|
@ -5336,6 +5346,14 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_HYUDORO",
|
||||
"MT_HYUDORO_CENTER",
|
||||
|
||||
"MT_GROW_PARTICLE",
|
||||
|
||||
"MT_SHRINK_POHBEE",
|
||||
"MT_SHRINK_GUN",
|
||||
"MT_SHRINK_CHAIN",
|
||||
"MT_SHRINK_LASER",
|
||||
"MT_SHRINK_PARTICLE",
|
||||
|
||||
"MT_SINK", // Kitchen Sink Stuff
|
||||
"MT_SINK_SHIELD",
|
||||
"MT_SINKTRAIL",
|
||||
|
|
|
|||
|
|
@ -817,7 +817,6 @@ extern consvar_t cv_forceskin; // force clients to use the server's skin
|
|||
extern consvar_t cv_downloading; // allow clients to downloading WADs.
|
||||
extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu
|
||||
extern consvar_t cv_jointimeout;
|
||||
extern consvar_t cv_maxping;
|
||||
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
|
||||
extern INT32 serverplayer;
|
||||
extern INT32 adminplayers[MAXPLAYERS];
|
||||
|
|
|
|||
|
|
@ -368,6 +368,8 @@ typedef UINT32 tic_t;
|
|||
#define UINT2RGBA(a) (UINT32)((a&0xff)<<24)|((a&0xff00)<<8)|((a&0xff0000)>>8)|(((UINT32)a&0xff000000)>>24)
|
||||
#endif
|
||||
|
||||
#define TOSTR(x) #x
|
||||
|
||||
/* preprocessor dumb and needs second macro to expand input */
|
||||
#define WSTRING2(s) L ## s
|
||||
#define WSTRING(s) WSTRING2 (s)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "fastcmp.h"
|
||||
|
||||
#include "lua_hud.h"
|
||||
#include "lua_hook.h"
|
||||
|
||||
// SRB2Kart
|
||||
#include "k_menu.h"
|
||||
|
|
@ -2103,7 +2104,7 @@ luahook:
|
|||
if (renderisnewtic)
|
||||
{
|
||||
LUA_HUD_ClearDrawList(luahuddrawlist_title);
|
||||
LUAh_TitleHUD(luahuddrawlist_title);
|
||||
LUA_HookHUD(luahuddrawlist_title, HUD_HOOK(title));
|
||||
}
|
||||
LUA_HUD_DrawList(luahuddrawlist_title);
|
||||
}
|
||||
|
|
|
|||
134
src/g_game.c
134
src/g_game.c
|
|
@ -380,6 +380,36 @@ consvar_t cv_chatbacktint = CVAR_INIT ("chatbacktint", "On", CV_SAVE, CV_OnOff,
|
|||
static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}};
|
||||
consvar_t cv_consolechat = CVAR_INIT ("chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL);
|
||||
|
||||
// Shout settings
|
||||
// The relevant ones are CV_NETVAR because too lazy to send them any other way
|
||||
consvar_t cv_shoutname = CVAR_INIT ("shout_name", "SERVER", CV_NETVAR, NULL, NULL);
|
||||
|
||||
static CV_PossibleValue_t shoutcolor_cons_t[] =
|
||||
{
|
||||
{-1, "Player color"},
|
||||
{0, "White"},
|
||||
{1, "Yellow"},
|
||||
{2, "Purple"},
|
||||
{3, "Green"},
|
||||
{4, "Blue"},
|
||||
{5, "Red"},
|
||||
{6, "Gray"},
|
||||
{7, "Orange"},
|
||||
{8, "Sky-blue"},
|
||||
{9, "Gold"},
|
||||
{10, "Lavender"},
|
||||
{11, "Aqua-green"},
|
||||
{12, "Magenta"},
|
||||
{13, "Pink"},
|
||||
{14, "Brown"},
|
||||
{15, "Tan"},
|
||||
{0, NULL}
|
||||
};
|
||||
consvar_t cv_shoutcolor = CVAR_INIT ("shout_color", "Red", CV_NETVAR, shoutcolor_cons_t, NULL);
|
||||
|
||||
// If on and you're an admin, your messages will automatically become shouts.
|
||||
consvar_t cv_autoshout = CVAR_INIT ("autoshout", "Off", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
// Pause game upon window losing focus
|
||||
consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL);
|
||||
|
||||
|
|
@ -1172,7 +1202,7 @@ aftercmdinput:
|
|||
*/
|
||||
if (addedtogame && gamestate == GS_LEVEL)
|
||||
{
|
||||
LUAh_PlayerCmd(player, cmd);
|
||||
LUA_HookTiccmd(player, cmd, HOOK(PlayerCmd));
|
||||
|
||||
// Send leveltime when this tic was generated to the server for control lag calculations.
|
||||
// Only do this when in a level. Also do this after the hook, so that it can't overwrite this.
|
||||
|
|
@ -1202,7 +1232,7 @@ aftercmdinput:
|
|||
{
|
||||
// Call ViewpointSwitch hooks here.
|
||||
// The viewpoint was forcibly changed.
|
||||
LUAh_ViewpointSwitch(player, &players[consoleplayer], true);
|
||||
LUA_HookViewpointSwitch(player, &players[consoleplayer], true);
|
||||
displayplayers[0] = consoleplayer;
|
||||
}
|
||||
}
|
||||
|
|
@ -1253,6 +1283,7 @@ static void weaponPrefChange4(void)
|
|||
//
|
||||
void G_DoLoadLevel(boolean resetplayer)
|
||||
{
|
||||
boolean doAutomate = false;
|
||||
INT32 i;
|
||||
|
||||
// Make sure objectplace is OFF when you first start the level!
|
||||
|
|
@ -1286,6 +1317,10 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
else
|
||||
titlemapinaction = TITLEMAP_OFF;
|
||||
|
||||
// Doing this matches HOSTMOD behavior.
|
||||
// Is that desired? IDK
|
||||
doAutomate = (gamestate != GS_LEVEL);
|
||||
|
||||
G_SetGamestate(GS_LEVEL);
|
||||
if (wipegamestate == GS_MENU)
|
||||
M_ClearMenus(true);
|
||||
|
|
@ -1324,6 +1359,11 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
CON_ClearHUD();
|
||||
|
||||
server_lagless = cv_lagless.value;
|
||||
|
||||
if (doAutomate == true)
|
||||
{
|
||||
Automate_Run(AEV_ROUNDSTART);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -2475,7 +2515,7 @@ void G_SpawnPlayer(INT32 playernum)
|
|||
|
||||
P_SpawnPlayer(playernum);
|
||||
G_MovePlayerToSpawnOrStarpost(playernum);
|
||||
LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
|
||||
LUA_HookPlayer(&players[playernum], HOOK(PlayerSpawn)); // Lua hook for player spawning :)
|
||||
}
|
||||
|
||||
void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
|
||||
|
|
@ -3202,51 +3242,53 @@ boolean G_GametypeHasSpectators(void)
|
|||
//
|
||||
// Oh, yeah, and we sometimes flip encore mode on here too.
|
||||
//
|
||||
INT16 G_SometimesGetDifferentGametype(void)
|
||||
INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype)
|
||||
{
|
||||
boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1) && (gametyperules & GTR_CIRCUIT));
|
||||
// Most of the gametype references in this condition are intentionally not prefgametype.
|
||||
// This is so a server CAN continue playing a gametype if they like the taste of it.
|
||||
// The encore check needs prefgametype so can't use G_RaceGametype...
|
||||
boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1)
|
||||
&& ((gametyperules|gametypedefaultrules[prefgametype]) & GTR_CIRCUIT));
|
||||
UINT8 encoremodifier = 0;
|
||||
|
||||
if (!cv_kartvoterulechanges.value // never
|
||||
&& encorescramble != 1) // destroying the code for this one instance
|
||||
return gametype;
|
||||
|
||||
if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3))
|
||||
if (encorepossible)
|
||||
{
|
||||
randmapbuffer[NUMMAPS]--;
|
||||
if (encorepossible)
|
||||
if (encorescramble != -1)
|
||||
{
|
||||
if (encorescramble != -1)
|
||||
encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission
|
||||
else
|
||||
{
|
||||
switch (cv_kartvoterulechanges.value)
|
||||
{
|
||||
case 3: // always
|
||||
randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set
|
||||
break;
|
||||
case 2: // frequent
|
||||
encorepossible = M_RandomChance(FRACUNIT>>1);
|
||||
break;
|
||||
case 1: // sometimes
|
||||
default:
|
||||
encorepossible = M_RandomChance(FRACUNIT>>2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encorepossible != (cv_kartencore.value == 1))
|
||||
return (gametype|0x80);
|
||||
encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission
|
||||
}
|
||||
return gametype;
|
||||
else
|
||||
{
|
||||
switch (cv_kartvoterulechanges.value)
|
||||
{
|
||||
case 3: // always
|
||||
encorepossible = true;
|
||||
break;
|
||||
case 2: // frequent
|
||||
encorepossible = M_RandomChance(FRACUNIT>>1);
|
||||
break;
|
||||
case 1: // sometimes
|
||||
encorepossible = M_RandomChance(FRACUNIT>>2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encorepossible != (cv_kartencore.value == 1))
|
||||
encoremodifier = VOTEMODIFIER_ENCORE;
|
||||
}
|
||||
|
||||
if (!cv_kartvoterulechanges.value) // never (again)
|
||||
return gametype;
|
||||
if (!cv_kartvoterulechanges.value) // never
|
||||
return (gametype|encoremodifier);
|
||||
|
||||
if (randmapbuffer[NUMMAPS] > 0 && (cv_kartvoterulechanges.value != 3))
|
||||
{
|
||||
randmapbuffer[NUMMAPS]--;
|
||||
return (gametype|encoremodifier);
|
||||
}
|
||||
|
||||
switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv?
|
||||
{
|
||||
case 3: // always
|
||||
randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible)
|
||||
break;
|
||||
case 1: // sometimes
|
||||
randmapbuffer[NUMMAPS] = 5; // per "cup"
|
||||
break;
|
||||
|
|
@ -3257,9 +3299,17 @@ INT16 G_SometimesGetDifferentGametype(void)
|
|||
break;
|
||||
}
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
return GT_RACE;
|
||||
return GT_BATTLE;
|
||||
// Only this response is prefgametype-based.
|
||||
// todo custom gametypes
|
||||
if (prefgametype == GT_BATTLE)
|
||||
{
|
||||
// Intentionally does not use encoremodifier!
|
||||
if (cv_kartencore.value == 1)
|
||||
return (GT_RACE|VOTEMODIFIER_ENCORE);
|
||||
return (GT_RACE);
|
||||
}
|
||||
// This might appear wrong HERE, but the game will display the Encore possibility on the second voting choice instead.
|
||||
return (GT_BATTLE|encoremodifier);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -4627,7 +4677,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
|||
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer);
|
||||
else
|
||||
{
|
||||
LUAh_MapChange(gamemap);
|
||||
LUA_HookInt(gamemap, HOOK(MapChange));
|
||||
G_DoLoadLevel(resetplayer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ extern boolean promptactive;
|
|||
extern consvar_t cv_tutorialprompt;
|
||||
|
||||
extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection;
|
||||
extern consvar_t cv_shoutname, cv_shoutcolor, cv_autoshout;
|
||||
extern consvar_t cv_songcredits;
|
||||
|
||||
extern consvar_t cv_pauseifunfocused;
|
||||
|
|
@ -181,7 +182,8 @@ boolean G_IsSpecialStage(INT32 mapnum);
|
|||
boolean G_GametypeUsesLives(void);
|
||||
boolean G_GametypeHasTeams(void);
|
||||
boolean G_GametypeHasSpectators(void);
|
||||
INT16 G_SometimesGetDifferentGametype(void);
|
||||
#define VOTEMODIFIER_ENCORE 0x80
|
||||
INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype);
|
||||
UINT8 G_GetGametypeColor(INT16 gt);
|
||||
void G_ExitLevel(void);
|
||||
void G_NextLevel(void);
|
||||
|
|
|
|||
|
|
@ -499,6 +499,9 @@ INT32 G_KeyStringtoNum(const char *keystr)
|
|||
{
|
||||
UINT32 j;
|
||||
|
||||
if (!keystr[0])
|
||||
return 0;
|
||||
|
||||
if (!keystr[1] && keystr[0] > ' ' && keystr[0] <= 'z')
|
||||
return keystr[0];
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ typedef struct
|
|||
// Predefined shader types
|
||||
enum
|
||||
{
|
||||
SHADER_NONE = -1,
|
||||
SHADER_DEFAULT = 0,
|
||||
|
||||
SHADER_FLOOR,
|
||||
|
|
@ -235,7 +236,8 @@ enum EPolyFlags
|
|||
PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y
|
||||
PF_ForceWrapX = 0x00020000, // Forces repeat texture on X
|
||||
PF_ForceWrapY = 0x00040000, // Forces repeat texture on Y
|
||||
PF_Ripple = 0x00100000 // Water ripple effect. The current backend doesn't use it for anything.
|
||||
PF_Ripple = 0x00100000, // Water ripple effect. The current backend doesn't use it for anything.
|
||||
PF_WireFrame = 0x00200000, // Draws vertices as lines instead of triangles
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ typedef struct gl_vissprite_s
|
|||
|
||||
boolean flip, vflip;
|
||||
boolean precip; // Tails 08-25-2002
|
||||
boolean bbox;
|
||||
boolean rotated;
|
||||
UINT8 translucency; //alpha level 0-255
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ static void HWR_ProjectSprite(mobj_t *thing);
|
|||
#ifdef HWPRECIP
|
||||
static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
|
||||
#endif
|
||||
static void HWR_ProjectBoundingBox(mobj_t *thing);
|
||||
static void HWR_RollTransform(FTransform *tr, angle_t roll);
|
||||
|
||||
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
|
||||
|
|
@ -4109,6 +4110,54 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
|
|||
HWR_LinkDrawHackAdd(wallVerts, spr);
|
||||
}
|
||||
|
||||
static void HWR_DrawBoundingBox(gl_vissprite_t *vis)
|
||||
{
|
||||
FOutVector v[24];
|
||||
FSurfaceInfo Surf = {0};
|
||||
|
||||
//
|
||||
// create a cube (side view)
|
||||
//
|
||||
// 5--4 3
|
||||
// |
|
||||
// |
|
||||
// 0--1 2
|
||||
//
|
||||
// repeat this 4 times (overhead)
|
||||
//
|
||||
//
|
||||
// 17 20 21 11
|
||||
// 16 15 14 10
|
||||
// 27 22 *--* 07 12
|
||||
// | |
|
||||
// 26 23 *--* 06 13
|
||||
// 24 00 01 02
|
||||
// 25 05 04 03
|
||||
//
|
||||
|
||||
v[000].x = v[005].x = v[015].x = v[016].x = v[017].x = v[020].x =
|
||||
v[022].x = v[023].x = v[024].x = v[025].x = v[026].x = v[027].x = vis->x1; // west
|
||||
|
||||
v[001].x = v[002].x = v[003].x = v[004].x = v[006].x = v[007].x =
|
||||
v[010].x = v[011].x = v[012].x = v[013].x = v[014].x = v[021].x = vis->x2; // east
|
||||
|
||||
v[000].z = v[001].z = v[002].z = v[003].z = v[004].z = v[005].z =
|
||||
v[006].z = v[013].z = v[023].z = v[024].z = v[025].z = v[026].z = vis->z1; // south
|
||||
|
||||
v[007].z = v[010].z = v[011].z = v[012].z = v[014].z = v[015].z =
|
||||
v[016].z = v[017].z = v[020].z = v[021].z = v[022].z = v[027].z = vis->z2; // north
|
||||
|
||||
v[000].y = v[001].y = v[002].y = v[006].y = v[007].y = v[010].y =
|
||||
v[014].y = v[015].y = v[016].y = v[022].y = v[023].y = v[024].y = vis->gz; // bottom
|
||||
|
||||
v[003].y = v[004].y = v[005].y = v[011].y = v[012].y = v[013].y =
|
||||
v[017].y = v[020].y = v[021].y = v[025].y = v[026].y = v[027].y = vis->gzt; // top
|
||||
|
||||
Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj));
|
||||
|
||||
HWR_ProcessPolygon(&Surf, v, 24, PF_Modulated|PF_NoTexture|PF_WireFrame, SHADER_NONE, false);
|
||||
}
|
||||
|
||||
// -----------------+
|
||||
// HWR_DrawSprite : Draw flat sprites
|
||||
// : (monsters, bonuses, weapons, lights, ...)
|
||||
|
|
@ -4562,9 +4611,16 @@ static int CompareVisSprites(const void *p1, const void *p2)
|
|||
int frame1;
|
||||
int frame2;
|
||||
|
||||
int linkdraw1;
|
||||
int linkdraw2;
|
||||
|
||||
// bbox doesn't need to be sorted
|
||||
if (spr1->bbox || spr2->bbox)
|
||||
return 0;
|
||||
|
||||
// check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer
|
||||
int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer;
|
||||
int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer;
|
||||
linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer;
|
||||
linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer;
|
||||
|
||||
// ^ is the XOR operation
|
||||
// if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use
|
||||
|
|
@ -4954,6 +5010,9 @@ static void HWR_DrawSprites(void)
|
|||
for (i = 0; i < gl_visspritecount; i++)
|
||||
{
|
||||
gl_vissprite_t *spr = gl_vsprorder[i];
|
||||
if (spr->bbox)
|
||||
HWR_DrawBoundingBox(spr);
|
||||
else
|
||||
#ifdef HWPRECIP
|
||||
if (spr->precip)
|
||||
HWR_DrawPrecipitationSprite(spr);
|
||||
|
|
@ -5052,8 +5111,15 @@ static void HWR_AddSprites(sector_t *sec)
|
|||
limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale;
|
||||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||||
{
|
||||
if (R_ThingVisibleWithinDist(thing, limit_dist))
|
||||
HWR_ProjectSprite(thing);
|
||||
if (R_ThingWithinDist(thing, limit_dist))
|
||||
{
|
||||
if (R_ThingVisible(thing))
|
||||
{
|
||||
HWR_ProjectSprite(thing);
|
||||
}
|
||||
|
||||
HWR_ProjectBoundingBox(thing);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HWPRECIP
|
||||
|
|
@ -5552,6 +5618,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
|
|||
vis->vflip = vflip;
|
||||
|
||||
vis->precip = false;
|
||||
vis->bbox = false;
|
||||
}
|
||||
|
||||
#ifdef HWPRECIP
|
||||
|
|
@ -5675,6 +5742,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
vis->gz = vis->gzt - (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale);
|
||||
|
||||
vis->precip = true;
|
||||
vis->bbox = false;
|
||||
|
||||
// okay... this is a hack, but weather isn't networked, so it should be ok
|
||||
if (!(thing->precipflags & PCF_THUNK))
|
||||
|
|
@ -5685,6 +5753,60 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void HWR_ProjectBoundingBox(mobj_t *thing)
|
||||
{
|
||||
gl_vissprite_t *vis;
|
||||
float tr_x, tr_y;
|
||||
float tz;
|
||||
float rad;
|
||||
|
||||
// uncapped/interpolation
|
||||
interpmobjstate_t interp = {0};
|
||||
|
||||
if (!thing)
|
||||
return;
|
||||
|
||||
if (!R_ThingBoundingBoxVisible(thing))
|
||||
return;
|
||||
|
||||
if (R_UsingFrameInterpolation() && !paused)
|
||||
{
|
||||
R_InterpolateMobjState(thing, rendertimefrac, &interp);
|
||||
}
|
||||
else
|
||||
{
|
||||
R_InterpolateMobjState(thing, FRACUNIT, &interp);
|
||||
}
|
||||
|
||||
// transform the origin point
|
||||
tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx;
|
||||
tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy;
|
||||
|
||||
// rotation around vertical axis
|
||||
tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
|
||||
|
||||
// thing is behind view plane?
|
||||
if (tz < ZCLIP_PLANE)
|
||||
return;
|
||||
|
||||
tr_x += gl_viewx;
|
||||
tr_y += gl_viewy;
|
||||
|
||||
rad = FIXED_TO_FLOAT(thing->radius);
|
||||
|
||||
vis = HWR_NewVisSprite();
|
||||
vis->x1 = tr_x - rad;
|
||||
vis->x2 = tr_x + rad;
|
||||
vis->z1 = tr_y - rad;
|
||||
vis->z2 = tr_y + rad;
|
||||
vis->gz = FIXED_TO_FLOAT(interp.z);
|
||||
vis->gzt = vis->gz + FIXED_TO_FLOAT(thing->height);
|
||||
vis->mobj = thing;
|
||||
|
||||
vis->precip = false;
|
||||
vis->bbox = true;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Sky dome rendering, ported from PrBoom+
|
||||
// ==========================================================================
|
||||
|
|
|
|||
|
|
@ -713,11 +713,11 @@ static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMi
|
|||
UINT16 w = gpatch->width, h = gpatch->height;
|
||||
UINT32 size = w*h;
|
||||
RGBA_t *image, *blendimage, *cur, blendcolor;
|
||||
UINT8 translation[16]; // First the color index
|
||||
UINT8 cutoff[16]; // Brightness cutoff before using the next color
|
||||
UINT8 translation[17]; // First the color index
|
||||
UINT8 cutoff[17]; // Brightness cutoff before using the next color
|
||||
UINT8 translen = 0;
|
||||
UINT8 i;
|
||||
UINT8 colorbrightnesses[16];
|
||||
UINT8 colorbrightnesses[17];
|
||||
UINT8 color_match_lookup[256]; // optimization attempt
|
||||
|
||||
blendcolor = V_GetColor(0); // initialize
|
||||
|
|
@ -788,6 +788,11 @@ static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMi
|
|||
translen++;
|
||||
}
|
||||
|
||||
if (translen > 0)
|
||||
translation[translen] = translation[translen-1]; // extended to accomodate secondi if firsti equal to translen-1
|
||||
if (translen > 1)
|
||||
cutoff[translen] = cutoff[translen-1] = 0; // as above
|
||||
|
||||
if (skinnum == TC_RAINBOW && translen > 0)
|
||||
{
|
||||
UINT16 b;
|
||||
|
|
@ -803,7 +808,7 @@ static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMi
|
|||
{
|
||||
UINT16 brightdif = 256;
|
||||
|
||||
color_match_lookup[i] = 0;
|
||||
color_match_lookup[b] = 0;
|
||||
for (i = 0; i < translen; i++)
|
||||
{
|
||||
if (b > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is)
|
||||
|
|
@ -820,6 +825,9 @@ static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMi
|
|||
}
|
||||
}
|
||||
|
||||
if (translen > 0)
|
||||
colorbrightnesses[translen] = colorbrightnesses[translen-1];
|
||||
|
||||
while (size--)
|
||||
{
|
||||
if (skinnum == TC_HITLAG)
|
||||
|
|
|
|||
|
|
@ -1061,6 +1061,12 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole
|
|||
EXPORT void HWRAPI(SetShader) (int type)
|
||||
{
|
||||
#ifdef GL_SHADERS
|
||||
if (type == SHADER_NONE)
|
||||
{
|
||||
UnSetShader();
|
||||
return;
|
||||
}
|
||||
|
||||
if (gl_allowshaders != HWD_SHADEROPTION_OFF)
|
||||
{
|
||||
gl_shader_t *shader = gl_shaderstate.current;
|
||||
|
|
@ -2319,7 +2325,7 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI
|
|||
|
||||
pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x);
|
||||
pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s);
|
||||
pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts);
|
||||
pglDrawArrays(PolyFlags & PF_WireFrame ? GL_LINES : GL_TRIANGLE_FAN, 0, iNumPts);
|
||||
|
||||
if (PolyFlags & PF_RemoveYWrap)
|
||||
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ consvar_t cv_masterserver_token = CVAR_INIT
|
|||
NULL
|
||||
);
|
||||
|
||||
#define HMS_QUERY_VERSION "?v=2.2"
|
||||
|
||||
#ifdef MASTERSERVER
|
||||
|
||||
static int hms_started;
|
||||
|
|
@ -174,7 +176,7 @@ HMS_connect (const char *format, ...)
|
|||
|
||||
va_start (ap, format);
|
||||
url = malloc(seek + vsnprintf(0, 0, format, ap) +
|
||||
sizeof "?v=2" - 1 +
|
||||
sizeof HMS_QUERY_VERSION - 1 +
|
||||
token_length + 1);
|
||||
va_end (ap);
|
||||
|
||||
|
|
@ -188,8 +190,8 @@ HMS_connect (const char *format, ...)
|
|||
seek += vsprintf(&url[seek], format, ap);
|
||||
va_end (ap);
|
||||
|
||||
strcpy(&url[seek], "?v=2");
|
||||
seek += sizeof "?v=2" - 1;
|
||||
strcpy(&url[seek], HMS_QUERY_VERSION);
|
||||
seek += sizeof HMS_QUERY_VERSION - 1;
|
||||
|
||||
if (quack_token)
|
||||
sprintf(&url[seek], "&token=%s", quack_token);
|
||||
|
|
|
|||
145
src/hu_stuff.c
145
src/hu_stuff.c
|
|
@ -64,8 +64,11 @@
|
|||
#define HU_INPUTX 0
|
||||
#define HU_INPUTY 0
|
||||
|
||||
#define HU_SERVER_SAY 1 // Server message (dedicated).
|
||||
#define HU_CSAY 2 // Server CECHOes to everyone.
|
||||
typedef enum
|
||||
{
|
||||
HU_SHOUT = 1, // Shout message
|
||||
HU_CSAY = 1<<1, // Middle-of-screen server message
|
||||
} sayflags_t;
|
||||
|
||||
//-------------------------------------------
|
||||
// heads up font
|
||||
|
|
@ -75,6 +78,7 @@
|
|||
// Note: I'd like to adress that at this point we might *REALLY* want to work towards a common drawString function that can take any font we want because this is really turning into a MESS. :V -Lat'
|
||||
patch_t *pinggfx[5]; // small ping graphic
|
||||
patch_t *mping[5]; // smaller ping graphic
|
||||
patch_t *pingmeasure[2]; // ping measurement graphic
|
||||
|
||||
patch_t *framecounter;
|
||||
patch_t *frameslash; // framerate stuff. Used in screen.c
|
||||
|
|
@ -169,6 +173,7 @@ static void Command_Say_f(void);
|
|||
static void Command_Sayto_f(void);
|
||||
static void Command_Sayteam_f(void);
|
||||
static void Command_CSay_f(void);
|
||||
static void Command_Shout(void);
|
||||
static void Got_Saycmd(UINT8 **p, INT32 playernum);
|
||||
#endif
|
||||
|
||||
|
|
@ -192,6 +197,9 @@ void HU_LoadGraphics(void)
|
|||
HU_UpdatePatch(&mping[i], "MPING%d", i+1);
|
||||
}
|
||||
|
||||
HU_UpdatePatch(&pingmeasure[0], "PINGD");
|
||||
HU_UpdatePatch(&pingmeasure[1], "PINGMS");
|
||||
|
||||
// fps stuff
|
||||
HU_UpdatePatch(&framecounter, "FRAMER");
|
||||
HU_UpdatePatch(&frameslash, "FRAMESL");
|
||||
|
|
@ -209,6 +217,7 @@ void HU_Init(void)
|
|||
COM_AddCommand("sayto", Command_Sayto_f);
|
||||
COM_AddCommand("sayteam", Command_Sayteam_f);
|
||||
COM_AddCommand("csay", Command_CSay_f);
|
||||
COM_AddCommand("shout", Command_Shout);
|
||||
RegisterNetXCmd(XD_SAY, Got_Saycmd);
|
||||
#endif
|
||||
|
||||
|
|
@ -473,7 +482,7 @@ void HU_AddChatText(const char *text, boolean playsound)
|
|||
* to -32 to say to everyone on that player's team. Note: This means you
|
||||
* have to add 1 to the player number, since they are 0 to 31 internally.
|
||||
*
|
||||
* The flag HU_SERVER_SAY will be set if it is the dedicated server speaking.
|
||||
* The flag HU_SHOUT will be set if it is the dedicated server speaking.
|
||||
*
|
||||
* This function obtains the message using COM_Argc() and COM_Argv().
|
||||
*
|
||||
|
|
@ -500,14 +509,17 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
|
|||
return;
|
||||
}
|
||||
|
||||
// Only servers/admins can CSAY.
|
||||
if(!server && !(IsPlayerAdmin(consoleplayer)))
|
||||
flags &= ~HU_CSAY;
|
||||
// Only servers/admins can shout or CSAY.
|
||||
if (!server && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
flags &= ~(HU_SHOUT|HU_CSAY);
|
||||
}
|
||||
|
||||
// We handle HU_SERVER_SAY, not the caller.
|
||||
flags &= ~HU_SERVER_SAY;
|
||||
if(dedicated && !(flags & HU_CSAY))
|
||||
flags |= HU_SERVER_SAY;
|
||||
// Enforce shout for the dedicated server.
|
||||
if (dedicated && !(flags & HU_CSAY))
|
||||
{
|
||||
flags |= HU_SHOUT;
|
||||
}
|
||||
|
||||
buf[0] = target;
|
||||
buf[1] = flags;
|
||||
|
|
@ -581,6 +593,8 @@ static void Command_Say_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// Autoshout is handled by HU_queueChatChar.
|
||||
// If you're using the say command, you can use the shout command, lol.
|
||||
DoSayCommand(0, 1, 0);
|
||||
}
|
||||
|
||||
|
|
@ -644,7 +658,7 @@ static void Command_CSay_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if(!server && !IsPlayerAdmin(consoleplayer))
|
||||
if (!server && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use csay.\n"));
|
||||
return;
|
||||
|
|
@ -652,6 +666,24 @@ static void Command_CSay_f(void)
|
|||
|
||||
DoSayCommand(0, 1, HU_CSAY);
|
||||
}
|
||||
|
||||
static void Command_Shout(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("shout <message>: send a message with special alert sound, name, and color\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use shout.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
DoSayCommand(0, 1, HU_SHOUT);
|
||||
}
|
||||
|
||||
static tic_t stop_spamming[MAXPLAYERS];
|
||||
|
||||
/** Receives a message, processing an ::XD_SAY command.
|
||||
|
|
@ -675,7 +707,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
msg = (char *)*p;
|
||||
SKIPSTRING(*p);
|
||||
|
||||
if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
|
||||
if ((cv_mute.value || flags & (HU_CSAY|HU_SHOUT)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, cv_mute.value ?
|
||||
M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
|
||||
|
|
@ -704,7 +736,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
// before we do anything, let's verify the guy isn't spamming, get this easier on us.
|
||||
|
||||
//if (stop_spamming[playernum] != 0 && cv_chatspamprotection.value && !(flags & HU_CSAY))
|
||||
if (stop_spamming[playernum] != 0 && consoleplayer != playernum && cv_chatspamprotection.value && !(flags & HU_CSAY))
|
||||
if (stop_spamming[playernum] != 0 && consoleplayer != playernum && cv_chatspamprotection.value && !(flags & (HU_CSAY|HU_SHOUT)))
|
||||
{
|
||||
CONS_Debug(DBG_NETPLAY,"Received SAY cmd too quickly from Player %d (%s), assuming as spam and blocking message.\n", playernum+1, player_names[playernum]);
|
||||
stop_spamming[playernum] = 4;
|
||||
|
|
@ -715,7 +747,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
|
||||
// run the lua hook even if we were supposed to eat the msg, netgame consistency goes first.
|
||||
|
||||
if (LUAh_PlayerMsg(playernum, target, flags, msg, spam_eatmsg))
|
||||
if (LUA_HookPlayerMsg(playernum, target, flags, msg, spam_eatmsg))
|
||||
return;
|
||||
|
||||
if (spam_eatmsg)
|
||||
|
|
@ -737,8 +769,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
action = true;
|
||||
}
|
||||
|
||||
if (flags & HU_SERVER_SAY)
|
||||
dispname = "SERVER";
|
||||
if (flags & HU_SHOUT)
|
||||
dispname = cv_shoutname.zstring;
|
||||
else
|
||||
dispname = player_names[playernum];
|
||||
|
||||
|
|
@ -764,7 +796,30 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
char *tempchar = NULL;
|
||||
char color_prefix[2];
|
||||
|
||||
if (players[playernum].spectator)
|
||||
if (flags & HU_SHOUT)
|
||||
{
|
||||
if (cv_shoutcolor.value == -1)
|
||||
{
|
||||
UINT16 chatcolor = skincolors[players[playernum].skincolor].chatcolor;
|
||||
|
||||
if (chatcolor > V_TANMAP)
|
||||
{
|
||||
sprintf(color_prefix, "%c", '\x80');
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(color_prefix, "%c", '\x80' + (chatcolor >> V_CHARCOLORSHIFT));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(color_prefix, "%c", '\x80' + cv_shoutcolor.value);
|
||||
}
|
||||
|
||||
// Colorize full text
|
||||
cstart = textcolor = color_prefix;
|
||||
}
|
||||
else if (players[playernum].spectator)
|
||||
{
|
||||
// grey text
|
||||
cstart = textcolor = "\x86";
|
||||
|
|
@ -851,7 +906,10 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
fmt2 = "%s<%s%s>\x80%s %s%s";
|
||||
}*/
|
||||
|
||||
HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg), cv_chatnotifications.value); // add to chat
|
||||
HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg), (cv_chatnotifications.value) && !(flags & HU_SHOUT)); // add to chat
|
||||
|
||||
if ((cv_chatnotifications.value) && (flags & HU_SHOUT))
|
||||
S_StartSound(NULL, sfx_sysmsg);
|
||||
|
||||
if (tempchar)
|
||||
Z_Free(tempchar);
|
||||
|
|
@ -1175,7 +1233,7 @@ static void HU_queueChatChar(INT32 c)
|
|||
else
|
||||
buf[0] = target;
|
||||
|
||||
buf[1] = 0; // flags
|
||||
buf[1] = ((server || IsPlayerAdmin(consoleplayer)) && cv_autoshout.value) ? HU_SHOUT : 0; // flags
|
||||
SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1);
|
||||
}
|
||||
return;
|
||||
|
|
@ -2154,7 +2212,7 @@ void HU_Drawer(void)
|
|||
if (renderisnewtic)
|
||||
{
|
||||
LUA_HUD_ClearDrawList(luahuddrawlist_scores);
|
||||
LUAh_ScoresHUD(luahuddrawlist_scores);
|
||||
LUA_HookHUD(luahuddrawlist_scores, HUD_HOOK(scores));
|
||||
}
|
||||
LUA_HUD_DrawList(luahuddrawlist_scores);
|
||||
}
|
||||
|
|
@ -2277,15 +2335,15 @@ void HU_Erase(void)
|
|||
//======================================================================
|
||||
|
||||
static int
|
||||
Ping_gfx_num (int ping)
|
||||
Ping_gfx_num (int lag)
|
||||
{
|
||||
if (ping < 76)
|
||||
if (lag < 2)
|
||||
return 0;
|
||||
else if (ping < 137)
|
||||
else if (lag < 4)
|
||||
return 1;
|
||||
else if (ping < 256)
|
||||
else if (lag < 7)
|
||||
return 2;
|
||||
else if (ping < 500)
|
||||
else if (lag < 10)
|
||||
return 3;
|
||||
else
|
||||
return 4;
|
||||
|
|
@ -2294,22 +2352,37 @@ Ping_gfx_num (int ping)
|
|||
//
|
||||
// HU_drawPing
|
||||
//
|
||||
void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags)
|
||||
void HU_drawPing(INT32 x, INT32 y, UINT32 lag, INT32 flags)
|
||||
{
|
||||
INT32 gfxnum; // gfx to draw
|
||||
UINT8 const *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
|
||||
UINT8 *colormap = NULL;
|
||||
INT32 measureid = cv_pingmeasurement.value ? 1 : 0;
|
||||
INT32 gfxnum; // gfx to draw
|
||||
|
||||
gfxnum = Ping_gfx_num(ping);
|
||||
gfxnum = Ping_gfx_num(lag);
|
||||
|
||||
V_DrawScaledPatch(x, y, flags, pinggfx[gfxnum]);
|
||||
if (servermaxping && ping > servermaxping && hu_tick < 4) // flash ping red if too high
|
||||
V_DrawPingNum(x, y+9, flags, ping, colormap);
|
||||
else
|
||||
V_DrawPingNum(x, y+9, flags, ping, NULL);
|
||||
if (measureid == 1)
|
||||
V_DrawScaledPatch(x+11 - pingmeasure[measureid]->width, y+9, flags, pingmeasure[measureid]);
|
||||
V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]);
|
||||
|
||||
if (servermaxping && lag > servermaxping && hu_tick < 4)
|
||||
{
|
||||
// flash ping red if too high
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
|
||||
}
|
||||
|
||||
if (cv_pingmeasurement.value)
|
||||
{
|
||||
lag = (INT32)(lag * (1000.00f / TICRATE));
|
||||
}
|
||||
|
||||
x = V_DrawPingNum(x + (measureid == 1 ? 11 - pingmeasure[measureid]->width : 10), y+9, flags, lag, colormap);
|
||||
|
||||
if (measureid == 0)
|
||||
V_DrawScaledPatch(x+1 - pingmeasure[measureid]->width, y+9, flags, pingmeasure[measureid]);
|
||||
}
|
||||
|
||||
void
|
||||
HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, INT32 flags)
|
||||
HU_drawMiniPing (INT32 x, INT32 y, UINT32 lag, INT32 flags)
|
||||
{
|
||||
patch_t *patch;
|
||||
INT32 w = BASEVIDWIDTH;
|
||||
|
|
@ -2319,7 +2392,7 @@ HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, INT32 flags)
|
|||
w /= 2;
|
||||
}
|
||||
|
||||
patch = mping[Ping_gfx_num(ping)];
|
||||
patch = mping[Ping_gfx_num(lag)];
|
||||
|
||||
if (( flags & V_SNAPTORIGHT ))
|
||||
x += ( w - SHORT (patch->width) );
|
||||
|
|
|
|||
18
src/i_net.h
18
src/i_net.h
|
|
@ -31,6 +31,8 @@
|
|||
/// For use on the internet
|
||||
#define INETPACKETLENGTH 1024
|
||||
|
||||
#define NO_BAN_TIME (time_t)(-1)
|
||||
|
||||
extern INT16 hardware_MAXPACKETLENGTH;
|
||||
extern INT32 net_bandwidth; // in byte/s
|
||||
|
||||
|
|
@ -150,7 +152,7 @@ extern void (*I_NetCloseSocket)(void);
|
|||
|
||||
/** \brief send a hole punching request
|
||||
*/
|
||||
extern void (*I_NetRequestHolePunch)(void);
|
||||
extern void (*I_NetRequestHolePunch)(INT32 node);
|
||||
|
||||
/** \brief register this machine on the hole punching server
|
||||
*/
|
||||
|
|
@ -162,8 +164,20 @@ extern void (*I_ClearBans)(void);
|
|||
extern const char *(*I_GetNodeAddress) (INT32 node);
|
||||
extern const char *(*I_GetBanAddress) (size_t ban);
|
||||
extern const char *(*I_GetBanMask) (size_t ban);
|
||||
extern const char *(*I_GetBanUsername) (size_t ban);
|
||||
extern const char *(*I_GetBanReason) (size_t ban);
|
||||
extern time_t (*I_GetUnbanTime) (size_t ban);
|
||||
extern boolean (*I_SetBanAddress) (const char *address,const char *mask);
|
||||
extern boolean *bannednode;
|
||||
extern boolean (*I_SetBanUsername) (const char *username);
|
||||
extern boolean (*I_SetBanReason) (const char *reason);
|
||||
extern boolean (*I_SetUnbanTime) (time_t timestamp);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t banid;
|
||||
time_t timeleft;
|
||||
} bannednode_t;
|
||||
extern bannednode_t *bannednode;
|
||||
|
||||
/// \brief Called by D_SRB2Main to be defined by extern network driver
|
||||
boolean I_InitNetwork(void);
|
||||
|
|
|
|||
263
src/i_tcp.c
263
src/i_tcp.c
|
|
@ -138,8 +138,6 @@
|
|||
|
||||
#endif // !NONET
|
||||
|
||||
#define MAXBANS 100
|
||||
|
||||
#include "i_system.h"
|
||||
#include "i_time.h"
|
||||
#include "i_net.h"
|
||||
|
|
@ -148,6 +146,7 @@
|
|||
#include "i_tcp.h"
|
||||
#include "m_argv.h"
|
||||
#include "stun.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
#include "doomstat.h"
|
||||
|
||||
|
|
@ -189,6 +188,16 @@
|
|||
#if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (USE_WINSOCK1)
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mysockaddr_t address;
|
||||
UINT8 mask;
|
||||
char *username;
|
||||
char *reason;
|
||||
time_t timestamp;
|
||||
} banned_t;
|
||||
|
||||
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
|
||||
static size_t mysocketses = 0;
|
||||
static int myfamily[MAXNETNODES+1] = {0};
|
||||
|
|
@ -197,13 +206,14 @@
|
|||
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
|
||||
static size_t broadcastaddresses = 0;
|
||||
static boolean nodeconnected[MAXNETNODES+1];
|
||||
static mysockaddr_t banned[MAXBANS];
|
||||
static UINT8 bannedmask[MAXBANS];
|
||||
static banned_t *banned;
|
||||
static const INT32 hole_punch_magic = MSBF_LONG (0x52eb11);
|
||||
#endif
|
||||
|
||||
static size_t numbans = 0;
|
||||
static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
|
||||
static size_t banned_size = 0;
|
||||
|
||||
static bannednode_t SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
|
||||
static boolean init_tcp_driver = false;
|
||||
|
||||
static const char *serverport_name = DEFAULTPORT;
|
||||
|
|
@ -431,7 +441,7 @@ static const char *SOCK_GetBanAddress(size_t ban)
|
|||
#ifdef NONET
|
||||
return NULL;
|
||||
#else
|
||||
return SOCK_AddrToStr(&banned[ban]);
|
||||
return SOCK_AddrToStr(&banned[ban].address);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -443,12 +453,48 @@ static const char *SOCK_GetBanMask(size_t ban)
|
|||
static char s[16]; //255.255.255.255 netmask? no, just CDIR for only
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
if (sprintf(s,"%d",bannedmask[ban]) > 0)
|
||||
if (sprintf(s,"%d",banned[ban].mask) > 0)
|
||||
return s;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *SOCK_GetBanUsername(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return NULL;
|
||||
#else
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
return banned[ban].username;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *SOCK_GetBanReason(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return NULL;
|
||||
#else
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
return banned[ban].reason;
|
||||
#endif
|
||||
}
|
||||
|
||||
static time_t SOCK_GetUnbanTime(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return NO_BAN_TIME;
|
||||
#else
|
||||
if (ban >= numbans)
|
||||
return NO_BAN_TIME;
|
||||
return banned[ban].timestamp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
||||
{
|
||||
|
|
@ -622,6 +668,8 @@ static boolean SOCK_Get(void)
|
|||
j = getfreenode();
|
||||
if (j > 0)
|
||||
{
|
||||
const time_t curTime = time(NULL);
|
||||
|
||||
M_Memcpy(&clientaddress[j], &fromaddress, fromlen);
|
||||
nodesocket[j] = mysockets[n];
|
||||
DEBFILE(va("New node detected: node:%d address:%s\n", j,
|
||||
|
|
@ -632,15 +680,39 @@ static boolean SOCK_Get(void)
|
|||
// check if it's a banned dude so we can send a refusal later
|
||||
for (i = 0; i < numbans; i++)
|
||||
{
|
||||
if (SOCK_cmpaddr(&fromaddress, &banned[i], bannedmask[i]))
|
||||
if (SOCK_cmpaddr(&fromaddress, &banned[i].address, banned[i].mask))
|
||||
{
|
||||
SOCK_bannednode[j] = true;
|
||||
DEBFILE("This dude has been banned\n");
|
||||
break;
|
||||
if (banned[i].timestamp != NO_BAN_TIME)
|
||||
{
|
||||
if (curTime >= banned[i].timestamp)
|
||||
{
|
||||
SOCK_bannednode[j].timeleft = NO_BAN_TIME;
|
||||
SOCK_bannednode[j].banid = SIZE_MAX;
|
||||
DEBFILE("This dude was banned, but enough time has passed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
SOCK_bannednode[j].timeleft = banned[i].timestamp - curTime;
|
||||
SOCK_bannednode[j].banid = i;
|
||||
DEBFILE("This dude has been temporarily banned\n");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
SOCK_bannednode[j].timeleft = NO_BAN_TIME;
|
||||
SOCK_bannednode[j].banid = i;
|
||||
DEBFILE("This dude has been banned\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == numbans)
|
||||
SOCK_bannednode[j] = false;
|
||||
{
|
||||
SOCK_bannednode[j].timeleft = NO_BAN_TIME;
|
||||
SOCK_bannednode[j].banid = SIZE_MAX;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
@ -1382,9 +1454,9 @@ static void rendezvous(int size)
|
|||
free(addrs);
|
||||
}
|
||||
|
||||
static void SOCK_RequestHolePunch(void)
|
||||
static void SOCK_RequestHolePunch(INT32 node)
|
||||
{
|
||||
mysockaddr_t * addr = &clientaddress[doomcom->remotenode];
|
||||
mysockaddr_t * addr = &clientaddress[node];
|
||||
|
||||
holepunchpacket->addr = addr->ip4.sin_addr.s_addr;
|
||||
holepunchpacket->port = addr->ip4.sin_port;
|
||||
|
|
@ -1435,30 +1507,116 @@ static boolean SOCK_OpenSocket(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void AddBannedIndex(void)
|
||||
{
|
||||
if (numbans >= banned_size)
|
||||
{
|
||||
if (banned_size == 0)
|
||||
{
|
||||
banned_size = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
banned_size *= 2;
|
||||
}
|
||||
|
||||
banned = Z_ReallocAlign(
|
||||
(void*) banned,
|
||||
sizeof(banned_t) * banned_size,
|
||||
PU_STATIC,
|
||||
NULL,
|
||||
sizeof(banned_t) * 8
|
||||
);
|
||||
}
|
||||
|
||||
numbans++;
|
||||
}
|
||||
|
||||
static boolean SOCK_Ban(INT32 node)
|
||||
{
|
||||
INT32 ban;
|
||||
|
||||
if (node > MAXNETNODES)
|
||||
return false;
|
||||
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return false;
|
||||
#else
|
||||
if (numbans == MAXBANS)
|
||||
return false;
|
||||
|
||||
M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (mysockaddr_t));
|
||||
if (banned[numbans].any.sa_family == AF_INET)
|
||||
ban = numbans;
|
||||
AddBannedIndex();
|
||||
|
||||
M_Memcpy(&banned[ban].address, &clientaddress[node], sizeof (mysockaddr_t));
|
||||
|
||||
if (banned[ban].address.any.sa_family == AF_INET)
|
||||
{
|
||||
banned[numbans].ip4.sin_port = 0;
|
||||
bannedmask[numbans] = 32;
|
||||
banned[ban].address.ip4.sin_port = 0;
|
||||
banned[ban].mask = 32;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (banned[numbans].any.sa_family == AF_INET6)
|
||||
else if (banned[ban].address.any.sa_family == AF_INET6)
|
||||
{
|
||||
banned[numbans].ip6.sin6_port = 0;
|
||||
bannedmask[numbans] = 128;
|
||||
banned[ban].address.ip6.sin6_port = 0;
|
||||
banned[ban].mask = 128;
|
||||
}
|
||||
#endif
|
||||
numbans++;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetBanUsername(const char *username)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)username;
|
||||
return false;
|
||||
#else
|
||||
if (username == NULL || strlen(username) == 0)
|
||||
{
|
||||
username = "Direct IP ban";
|
||||
}
|
||||
|
||||
if (banned[numbans - 1].username)
|
||||
{
|
||||
Z_Free(banned[numbans - 1].username);
|
||||
banned[numbans - 1].username = NULL;
|
||||
}
|
||||
|
||||
banned[numbans - 1].username = Z_StrDup(username);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetBanReason(const char *reason)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)reason;
|
||||
return false;
|
||||
#else
|
||||
if (reason == NULL || strlen(reason) == 0)
|
||||
{
|
||||
reason = "No reason given";
|
||||
}
|
||||
|
||||
if (banned[numbans - 1].reason)
|
||||
{
|
||||
Z_Free(banned[numbans - 1].reason);
|
||||
banned[numbans - 1].reason = NULL;
|
||||
}
|
||||
|
||||
banned[numbans - 1].reason = Z_StrDup(reason);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetUnbanTime(time_t timestamp)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)reason;
|
||||
return false;
|
||||
#else
|
||||
banned[numbans - 1].timestamp = timestamp;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1473,7 +1631,7 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
struct my_addrinfo *ai, *runp, hints;
|
||||
int gaie;
|
||||
|
||||
if (numbans == MAXBANS || !address)
|
||||
if (!address)
|
||||
return false;
|
||||
|
||||
memset(&hints, 0x00, sizeof(hints));
|
||||
|
|
@ -1488,26 +1646,42 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
|
||||
runp = ai;
|
||||
|
||||
while(runp != NULL && numbans != MAXBANS)
|
||||
while (runp != NULL)
|
||||
{
|
||||
memcpy(&banned[numbans], runp->ai_addr, runp->ai_addrlen);
|
||||
INT32 ban;
|
||||
UINT8 numericalmask;
|
||||
|
||||
ban = numbans;
|
||||
AddBannedIndex();
|
||||
|
||||
memcpy(&banned[ban].address, runp->ai_addr, runp->ai_addrlen);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (runp->ai_family == AF_INET6)
|
||||
banned[ban].mask = 128;
|
||||
else
|
||||
#endif
|
||||
banned[ban].mask = 32;
|
||||
|
||||
if (mask)
|
||||
bannedmask[numbans] = (UINT8)atoi(mask);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (runp->ai_family == AF_INET6)
|
||||
bannedmask[numbans] = 128;
|
||||
#endif
|
||||
{
|
||||
numericalmask = (UINT8)atoi(mask);
|
||||
}
|
||||
else
|
||||
bannedmask[numbans] = 32;
|
||||
{
|
||||
numericalmask = 0;
|
||||
}
|
||||
|
||||
if (numericalmask > 0 && numericalmask < banned[ban].mask)
|
||||
{
|
||||
banned[ban].mask = numericalmask;
|
||||
}
|
||||
|
||||
// Set defaults, in case anything funny happens.
|
||||
SOCK_SetBanUsername(NULL);
|
||||
SOCK_SetBanReason(NULL);
|
||||
SOCK_SetUnbanTime(NO_BAN_TIME);
|
||||
|
||||
if (bannedmask[numbans] > 32 && runp->ai_family == AF_INET)
|
||||
bannedmask[numbans] = 32;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (bannedmask[numbans] > 128 && runp->ai_family == AF_INET6)
|
||||
bannedmask[numbans] = 128;
|
||||
#endif
|
||||
numbans++;
|
||||
runp = runp->ai_next;
|
||||
}
|
||||
|
||||
|
|
@ -1520,6 +1694,9 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
static void SOCK_ClearBans(void)
|
||||
{
|
||||
numbans = 0;
|
||||
banned_size = 0;
|
||||
Z_Free(banned);
|
||||
banned = NULL;
|
||||
}
|
||||
|
||||
boolean I_InitTcpNetwork(void)
|
||||
|
|
@ -1614,7 +1791,13 @@ boolean I_InitTcpNetwork(void)
|
|||
I_GetNodeAddress = SOCK_GetNodeAddress;
|
||||
I_GetBanAddress = SOCK_GetBanAddress;
|
||||
I_GetBanMask = SOCK_GetBanMask;
|
||||
I_GetBanUsername = SOCK_GetBanUsername;
|
||||
I_GetBanReason = SOCK_GetBanReason;
|
||||
I_GetUnbanTime = SOCK_GetUnbanTime;
|
||||
I_SetBanAddress = SOCK_SetBanAddress;
|
||||
I_SetBanUsername = SOCK_SetBanUsername;
|
||||
I_SetBanReason = SOCK_SetBanReason;
|
||||
I_SetUnbanTime = SOCK_SetUnbanTime;
|
||||
bannednode = SOCK_bannednode;
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
201
src/info.c
201
src/info.c
|
|
@ -573,6 +573,9 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"FLML", // Flame Shield speed lines
|
||||
"FLMF", // Flame Shield flash
|
||||
"HYUU", // Hyudoro
|
||||
"GRWP", // Grow
|
||||
"POHB", // Shrink Poh-Bee
|
||||
"SHRG", // Shrink gun / laser
|
||||
"SINK", // Kitchen Sink
|
||||
"SITR", // Kitchen Sink Trail
|
||||
"KBLN", // Battle Mode Bumper
|
||||
|
|
@ -4314,6 +4317,13 @@ state_t states[NUMSTATES] =
|
|||
|
||||
{SPR_HYUU, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_HYUDORO
|
||||
|
||||
{SPR_GRWP, FF_FULLBRIGHT|FF_ANIMATE, 13, {NULL}, 7, 1, S_NULL}, // S_GROW_PARTICLE
|
||||
|
||||
{SPR_SHRG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRINK_GUN
|
||||
{SPR_POHB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRINK_CHAIN
|
||||
{SPR_SHRG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRINK_LASER
|
||||
{SPR_SHRG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_SHRINK_PARTICLE
|
||||
|
||||
{SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK
|
||||
{SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD
|
||||
{SPR_SITR, 0, 1, {NULL}, 0, 0, S_SINKTRAIL2}, // S_SINKTRAIL1
|
||||
|
|
@ -5120,6 +5130,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_RAY
|
||||
-1, // doomednum
|
||||
S_NULL, // spawnstate
|
||||
0, // 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, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_UNKNOWN
|
||||
-1, // doomednum
|
||||
S_UNKNOWN, // spawnstate
|
||||
|
|
@ -24009,6 +24046,168 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_GROW_PARTICLE
|
||||
-1, // doomednum
|
||||
S_GROW_PARTICLE, // 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
|
||||
4*FRACUNIT, // radius
|
||||
8*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SCENERY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SHRINK_POHBEE
|
||||
-1, // doomednum
|
||||
S_HYUDORO, // 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
|
||||
32*FRACUNIT, // radius
|
||||
24*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SHRINK_GUN
|
||||
-1, // doomednum
|
||||
S_SHRINK_GUN, // 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
|
||||
52*FRACUNIT, // radius
|
||||
120*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SHRINK_CHAIN
|
||||
-1, // doomednum
|
||||
S_SHRINK_CHAIN, // 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
|
||||
26*FRACUNIT, // radius
|
||||
26*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SCENERY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SHRINK_LASER
|
||||
-1, // doomednum
|
||||
S_SHRINK_LASER, // 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
|
||||
16*FRACUNIT, // radius
|
||||
33*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SCENERY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SHRINK_PARTICLE
|
||||
-1, // doomednum
|
||||
S_SHRINK_PARTICLE, // 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
|
||||
26*FRACUNIT, // radius
|
||||
26*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SINK
|
||||
-1, // doomednum
|
||||
S_SINK, // spawnstate
|
||||
|
|
@ -24017,7 +24216,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
sfx_tossed, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
256*FRACUNIT, // painstate
|
||||
S_NULL, // painstate
|
||||
100, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
|
|
|
|||
21
src/info.h
21
src/info.h
|
|
@ -1119,6 +1119,9 @@ typedef enum sprite
|
|||
SPR_FLML, // Flame Shield speed lines
|
||||
SPR_FLMF, // Flame Shield flash
|
||||
SPR_HYUU, // Hyudoro
|
||||
SPR_GRWP, // Grow
|
||||
SPR_POHB, // Shrink Poh-Bee
|
||||
SPR_SHRG, // Shrink gun / laser
|
||||
SPR_SINK, // Kitchen Sink
|
||||
SPR_SITR, // Kitchen Sink Trail
|
||||
SPR_KBLN, // Battle Mode Bumper
|
||||
|
|
@ -4745,6 +4748,15 @@ typedef enum state
|
|||
// Caked-Up Booty-Sheet Ghost
|
||||
S_HYUDORO,
|
||||
|
||||
// Grow
|
||||
S_GROW_PARTICLE,
|
||||
|
||||
// Shrink
|
||||
S_SHRINK_GUN,
|
||||
S_SHRINK_CHAIN,
|
||||
S_SHRINK_LASER,
|
||||
S_SHRINK_PARTICLE,
|
||||
|
||||
// The legend
|
||||
S_SINK,
|
||||
S_SINK_SHIELD,
|
||||
|
|
@ -5532,6 +5544,7 @@ extern playersprite_t free_spr2;
|
|||
typedef enum mobj_type
|
||||
{
|
||||
MT_NULL,
|
||||
MT_RAY, // General purpose mobj
|
||||
MT_UNKNOWN,
|
||||
|
||||
MT_THOK, // Thok! mobj
|
||||
|
|
@ -6362,6 +6375,14 @@ typedef enum mobj_type
|
|||
MT_HYUDORO,
|
||||
MT_HYUDORO_CENTER,
|
||||
|
||||
MT_GROW_PARTICLE,
|
||||
|
||||
MT_SHRINK_POHBEE,
|
||||
MT_SHRINK_GUN,
|
||||
MT_SHRINK_CHAIN,
|
||||
MT_SHRINK_LASER,
|
||||
MT_SHRINK_PARTICLE,
|
||||
|
||||
MT_SINK, // Kitchen Sink Stuff
|
||||
MT_SINK_SHIELD,
|
||||
MT_SINKTRAIL,
|
||||
|
|
|
|||
47
src/k_bot.c
47
src/k_bot.c
|
|
@ -298,7 +298,7 @@ boolean K_BotCanTakeCut(player_t *player)
|
|||
/*--------------------------------------------------
|
||||
static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
||||
|
||||
Gets the bot's speed value, adjusted for predictions.
|
||||
What the bot "thinks" their speed is, for predictions.
|
||||
Mainly to make bots brake earlier when on friction sectors.
|
||||
|
||||
Input Arguments:-
|
||||
|
|
@ -312,6 +312,12 @@ static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
|||
{
|
||||
fixed_t result = speed;
|
||||
|
||||
if (P_IsObjectOnGround(player->mo) == false)
|
||||
{
|
||||
// You have no air control, so don't predict too far ahead.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (player->mo->movefactor != FRACUNIT)
|
||||
{
|
||||
fixed_t moveFactor = player->mo->movefactor;
|
||||
|
|
@ -650,7 +656,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
const fixed_t speed = K_BotSpeedScaled(player, P_AproxDistance(player->mo->momx, player->mo->momy));
|
||||
|
||||
const INT32 startDist = (DEFAULT_WAYPOINT_RADIUS * 2 * mapobjectscale) / FRACUNIT;
|
||||
const INT32 distance = ((speed / FRACUNIT) * futuresight) + startDist;
|
||||
const INT32 maxDist = startDist * 4; // This function gets very laggy when it goes far distances, and going too far isn't very helpful anyway.
|
||||
const INT32 distance = min(((speed / FRACUNIT) * (INT32)futuresight) + startDist, maxDist);
|
||||
|
||||
// Halves radius when encountering a wall on your way to your destination.
|
||||
fixed_t radreduce = FRACUNIT;
|
||||
|
|
@ -660,7 +667,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
angle_t angletonext = ANGLE_MAX;
|
||||
INT32 disttonext = INT32_MAX;
|
||||
|
||||
waypoint_t *finishLine = K_GetFinishLineWaypoint();
|
||||
waypoint_t *wp = player->nextwaypoint;
|
||||
mobj_t *prevwpmobj = player->mo;
|
||||
|
||||
|
|
@ -676,8 +682,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
|
||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT;
|
||||
|
||||
pathfindsuccess = K_PathfindToWaypoint(
|
||||
player->nextwaypoint, finishLine,
|
||||
pathfindsuccess = K_PathfindThruCircuit(
|
||||
player->nextwaypoint, (unsigned)distanceleft,
|
||||
&pathtofinish,
|
||||
useshortcuts, huntbackwards
|
||||
);
|
||||
|
|
@ -720,35 +726,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
// We're done!!
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == pathtofinish.numnodes-1 && disttonext > 0)
|
||||
{
|
||||
// We were pathfinding to the finish, but we want to go past it.
|
||||
// Set up a new pathfind.
|
||||
|
||||
waypoint_t *next = NULL;
|
||||
|
||||
if (finishLine->numnextwaypoints == 0)
|
||||
{
|
||||
distanceleft = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// default to first one
|
||||
next = wp->nextwaypoints[0];
|
||||
|
||||
pathfindsuccess = K_PathfindToWaypoint(
|
||||
next, finishLine,
|
||||
&pathtofinish,
|
||||
useshortcuts, huntbackwards
|
||||
);
|
||||
|
||||
if (pathfindsuccess == false)
|
||||
{
|
||||
distanceleft = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Z_Free(pathtofinish.array);
|
||||
|
|
@ -1247,7 +1224,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
|
||||
// Complete override of all ticcmd functionality
|
||||
if (LUAh_BotTiccmd(player, cmd) == true)
|
||||
if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,6 +425,16 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
case MT_BUBBLESHIELDTRAP:
|
||||
K_AddDodgeObject(thing, side, 20);
|
||||
break;
|
||||
case MT_SHRINK_GUN:
|
||||
if (thing->target == globalsmuggle.botmo)
|
||||
{
|
||||
K_AddAttackObject(thing, side, 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
K_AddDodgeObject(thing, side, 20);
|
||||
}
|
||||
break;
|
||||
case MT_RANDOMITEM:
|
||||
if (anglediff >= 45)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ static brightmapStorage_t *K_GetBrightmapStorageByTextureName(const char *checkN
|
|||
{
|
||||
brightmapStorage_t *bms = &brightmapStorage[i];
|
||||
|
||||
if (checkHash == bms->textureHash)
|
||||
if (checkHash == bms->textureHash && !strncmp(checkName, bms->textureName, 8))
|
||||
{
|
||||
// Name matches.
|
||||
return bms;
|
||||
|
|
@ -119,8 +119,8 @@ static boolean K_BRIGHTLumpParser(UINT8 *data, size_t size)
|
|||
if (bms == NULL)
|
||||
{
|
||||
bms = K_NewBrightmap();
|
||||
strncpy(bms->textureName, tkn, 9);
|
||||
bms->textureHash = quickncasehash(bms->textureName, 8);
|
||||
strncpy(bms->textureName, tkn, 8);
|
||||
bms->textureHash = quickncasehash(tkn, 8);
|
||||
}
|
||||
|
||||
Z_Free(tkn);
|
||||
|
|
@ -129,8 +129,8 @@ static boolean K_BRIGHTLumpParser(UINT8 *data, size_t size)
|
|||
|
||||
if (tkn && pos < size)
|
||||
{
|
||||
strncpy(bms->brightmapName, tkn, 9);
|
||||
bms->brightmapHash = quickncasehash(bms->brightmapName, 8);
|
||||
strncpy(bms->brightmapName, tkn, 8);
|
||||
bms->brightmapHash = quickncasehash(tkn, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ typedef struct brightmapStorage_s
|
|||
// Stores data for brightmap definitions,
|
||||
// before putting them into texturebrightmaps.
|
||||
|
||||
char textureName[9]; // The texture's name.
|
||||
UINT32 textureHash; // The texture name's hash.
|
||||
char textureName[8]; // The texture's name.
|
||||
UINT32 textureHash; // The texture name's hash.
|
||||
|
||||
char brightmapName[9]; // The brightmap's name.
|
||||
UINT32 brightmapHash; // The brightmap name's hash.
|
||||
char brightmapName[8]; // The brightmap's name.
|
||||
UINT32 brightmapHash; // The brightmap name's hash.
|
||||
} brightmapStorage_t;
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
|
|||
130
src/k_kart.c
130
src/k_kart.c
|
|
@ -248,6 +248,7 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_kartcomeback);
|
||||
CV_RegisterVar(&cv_kartencore);
|
||||
CV_RegisterVar(&cv_kartvoterulechanges);
|
||||
CV_RegisterVar(&cv_kartgametypepreference);
|
||||
CV_RegisterVar(&cv_kartspeedometer);
|
||||
CV_RegisterVar(&cv_kartvoices);
|
||||
CV_RegisterVar(&cv_kartbot);
|
||||
|
|
@ -354,7 +355,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
|
|||
//P-Odds 0 1 2 3 4 5 6 7
|
||||
/*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker
|
||||
/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker
|
||||
/*Invincibility*/ { 0, 0, 0, 0, 3, 4, 6, 9 }, // Invincibility
|
||||
/*Invincibility*/ { 0, 0, 0, 0, 3, 4, 5, 7 }, // Invincibility
|
||||
/*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana
|
||||
/*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
|
||||
/*Orbinaut*/ { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut
|
||||
|
|
@ -364,7 +365,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
|
|||
/*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
|
||||
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
|
||||
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
|
||||
/*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink
|
||||
/*Shrink*/ { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink
|
||||
/*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
|
||||
/*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield
|
||||
/*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield
|
||||
|
|
@ -374,7 +375,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
|
|||
/*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
|
||||
/*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
|
||||
/*Sneaker x2*/ { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2
|
||||
/*Sneaker x3*/ { 0, 0, 0, 1, 6,10, 5, 0 }, // Sneaker x3
|
||||
/*Sneaker x3*/ { 0, 0, 0, 1, 6, 9, 5, 0 }, // Sneaker x3
|
||||
/*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
|
||||
/*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10
|
||||
/*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3
|
||||
|
|
@ -2283,6 +2284,77 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo)
|
|||
fast->destscale = 6*((mo->player->invincibilitytimer/TICRATE)*FRACUNIT)/8;
|
||||
}
|
||||
|
||||
static void K_SpawnGrowShrinkParticles(mobj_t *mo, INT32 timer)
|
||||
{
|
||||
const boolean shrink = (timer < 0);
|
||||
const INT32 maxTime = (10*TICRATE);
|
||||
const INT32 noTime = (2*TICRATE);
|
||||
INT32 spawnFreq = 1;
|
||||
|
||||
mobj_t *particle = NULL;
|
||||
fixed_t particleScale = FRACUNIT;
|
||||
fixed_t particleSpeed = 0;
|
||||
|
||||
spawnFreq = abs(timer);
|
||||
|
||||
if (spawnFreq < noTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
spawnFreq -= noTime;
|
||||
|
||||
if (spawnFreq > maxTime)
|
||||
{
|
||||
spawnFreq = maxTime;
|
||||
}
|
||||
|
||||
spawnFreq = (maxTime - spawnFreq) / TICRATE / 4;
|
||||
if (spawnFreq == 0)
|
||||
{
|
||||
spawnFreq++;
|
||||
}
|
||||
|
||||
if (leveltime % spawnFreq != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
particle = P_SpawnMobjFromMobj(
|
||||
mo,
|
||||
P_RandomRange(-32, 32) * FRACUNIT,
|
||||
P_RandomRange(-32, 32) * FRACUNIT,
|
||||
(P_RandomRange(0, 24) + (shrink ? 48 : 0)) * FRACUNIT,
|
||||
MT_GROW_PARTICLE
|
||||
);
|
||||
|
||||
P_SetTarget(&particle->target, mo);
|
||||
|
||||
particle->momx = mo->momx;
|
||||
particle->momy = mo->momy;
|
||||
particle->momz = P_GetMobjZMovement(mo);
|
||||
|
||||
K_MatchGenericExtraFlags(particle, mo);
|
||||
|
||||
particleScale = FixedMul((shrink ? SHRINK_PHYSICS_SCALE : GROW_PHYSICS_SCALE), mapobjectscale);
|
||||
particleSpeed = mo->scale * 4 * P_MobjFlip(mo); // NOT particleScale
|
||||
|
||||
particle->destscale = particleScale;
|
||||
P_SetScale(particle, particle->destscale);
|
||||
|
||||
if (shrink == true)
|
||||
{
|
||||
particle->color = SKINCOLOR_KETCHUP;
|
||||
particle->momz -= particleSpeed;
|
||||
particle->renderflags |= RF_VERTICALFLIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
particle->color = SKINCOLOR_SAPPHIRE;
|
||||
particle->momz += particleSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
void K_SpawnBumpEffect(mobj_t *mo)
|
||||
{
|
||||
mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP);
|
||||
|
|
@ -3642,7 +3714,7 @@ void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 typ
|
|||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
}
|
||||
|
||||
static void K_RemoveGrowShrink(player_t *player)
|
||||
void K_RemoveGrowShrink(player_t *player)
|
||||
{
|
||||
if (player->mo && !P_MobjWasRemoved(player->mo))
|
||||
{
|
||||
|
|
@ -5581,46 +5653,12 @@ void K_DoSneaker(player_t *player, INT32 type)
|
|||
|
||||
static void K_DoShrink(player_t *user)
|
||||
{
|
||||
INT32 i;
|
||||
mobj_t *mobj, *next;
|
||||
|
||||
S_StartSound(user->mo, sfx_kc46); // Sound the BANG!
|
||||
user->pflags |= PF_ATTACKDOWN;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || !players[i].mo)
|
||||
continue;
|
||||
if (&players[i] == user)
|
||||
continue;
|
||||
if (players[i].position < user->position)
|
||||
{
|
||||
//P_FlashPal(&players[i], PAL_NUKE, 10);
|
||||
|
||||
// Grow should get taken away.
|
||||
if (players[i].growshrinktimer > 0)
|
||||
K_RemoveGrowShrink(&players[i]);
|
||||
else
|
||||
{
|
||||
// Start shrinking!
|
||||
K_DropItems(&players[i]);
|
||||
players[i].growshrinktimer = -(15*TICRATE);
|
||||
|
||||
if (players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
{
|
||||
players[i].mo->scalespeed = mapobjectscale/TICRATE;
|
||||
players[i].mo->destscale = FixedMul(mapobjectscale, SHRINK_SCALE);
|
||||
|
||||
if (K_PlayerShrinkCheat(&players[i]) == true)
|
||||
{
|
||||
players[i].mo->destscale = FixedMul(players[i].mo->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
S_StartSound(players[i].mo, sfx_kc59);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Obj_CreateShrinkPohbees(user);
|
||||
|
||||
// kill everything in the kitem list while we're at it:
|
||||
for (mobj = kitemcap; mobj; mobj = next)
|
||||
|
|
@ -6700,7 +6738,7 @@ static void K_MoveHeldObjects(player_t *player)
|
|||
targz += (player->mo->height/2 - 32*player->mo->scale)*6;
|
||||
}
|
||||
|
||||
if (cur->tracer)
|
||||
if (cur->tracer && !P_MobjWasRemoved(cur->tracer))
|
||||
{
|
||||
fixed_t diffx, diffy, diffz;
|
||||
|
||||
|
|
@ -7358,6 +7396,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->growshrinktimer != 0)
|
||||
{
|
||||
K_SpawnGrowShrinkParticles(player->mo, player->growshrinktimer);
|
||||
}
|
||||
|
||||
if (gametype == GT_RACE && player->rings <= 0) // spawn ring debt indicator
|
||||
{
|
||||
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
|
||||
|
|
@ -7522,6 +7565,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
comebackshowninfo = true; // client has already seen the message
|
||||
}
|
||||
|
||||
if (player->shrinkLaserDelay)
|
||||
player->shrinkLaserDelay--;
|
||||
|
||||
if (player->ringdelay)
|
||||
player->ringdelay--;
|
||||
|
||||
|
|
@ -9483,7 +9529,7 @@ void K_AdjustPlayerFriction(player_t *player)
|
|||
}
|
||||
|
||||
// Wipeout slowdown
|
||||
if (player->spinouttimer && player->wipeoutslow)
|
||||
if (player->speed > 0 && player->spinouttimer && player->wipeoutslow)
|
||||
{
|
||||
if (player->offroad)
|
||||
player->mo->friction -= 4912;
|
||||
|
|
@ -10018,7 +10064,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
|
||||
// TODO: gametyperules
|
||||
player->growshrinktimer = (gametype == GT_BATTLE ? 8 : 12) * TICRATE;
|
||||
player->growshrinktimer = max(player->growshrinktimer, (gametype == GT_BATTLE ? 8 : 12) * TICRATE);
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload);
|
|||
void K_DoInstashield(player_t *player);
|
||||
void K_DoPowerClash(player_t *t1, player_t *t2);
|
||||
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved);
|
||||
void K_RemoveGrowShrink(player_t *player);
|
||||
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type);
|
||||
void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
void K_TumbleInterrupt(player_t *player);
|
||||
|
|
|
|||
|
|
@ -8,4 +8,11 @@ void Obj_HyudoroThink(mobj_t *actor);
|
|||
void Obj_HyudoroCenterThink(mobj_t *actor);
|
||||
void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher);
|
||||
|
||||
/* Shrink */
|
||||
void Obj_PohbeeThinker(mobj_t *pohbee);
|
||||
void Obj_PohbeeRemoved(mobj_t *pohbee);
|
||||
void Obj_ShrinkGunRemoved(mobj_t *gun);
|
||||
boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim);
|
||||
void Obj_CreateShrinkPohbees(player_t *owner);
|
||||
|
||||
#endif/*k_objects_H*/
|
||||
|
|
|
|||
410
src/k_pathfind.c
410
src/k_pathfind.c
|
|
@ -190,6 +190,10 @@ static boolean K_PathfindSetupValid(const pathfindsetup_t *const pathfindsetup)
|
|||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL gettraversable function.\n");
|
||||
}
|
||||
else if (pathfindsetup->getfinished == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL getfinished function.\n");
|
||||
}
|
||||
else if (pathfindsetup->getconnectednodes(pathfindsetup->startnodedata, &sourcenodenumconnectednodes) == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: Source node returned NULL connecting nodes.\n");
|
||||
|
|
@ -295,242 +299,244 @@ boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup
|
|||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: Pathfinding setup is not valid.\n");
|
||||
}
|
||||
else if (pathfindsetup->startnodedata == pathfindsetup->endnodedata)
|
||||
else
|
||||
{
|
||||
// At the destination, return a simple 1 node path
|
||||
pathfindnode_t singlenode = {0};
|
||||
singlenode.camefrom = NULL;
|
||||
singlenode.nodedata = pathfindsetup->endnodedata;
|
||||
singlenode.nodedata = pathfindsetup->startnodedata;
|
||||
singlenode.heapindex = SIZE_MAX;
|
||||
singlenode.hscore = 0U;
|
||||
singlenode.gscore = 0U;
|
||||
|
||||
K_ReconstructPath(path, &singlenode);
|
||||
|
||||
pathfindsuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bheap_t openset = {0};
|
||||
bheapitem_t poppedbheapitem = {0};
|
||||
pathfindnode_t *nodesarray = NULL;
|
||||
pathfindnode_t **closedset = NULL;
|
||||
pathfindnode_t *newnode = NULL;
|
||||
pathfindnode_t *currentnode = NULL;
|
||||
pathfindnode_t *connectingnode = NULL;
|
||||
void **connectingnodesdata = NULL;
|
||||
void *checknodedata = NULL;
|
||||
UINT32 *connectingnodecosts = NULL;
|
||||
size_t numconnectingnodes = 0U;
|
||||
size_t connectingnodeheapindex = 0U;
|
||||
size_t nodesarraycount = 0U;
|
||||
size_t closedsetcount = 0U;
|
||||
size_t i = 0U;
|
||||
UINT32 tentativegscore = 0U;
|
||||
|
||||
// Set the dynamic structure capacites to defaults if they are 0
|
||||
if (pathfindsetup->nodesarraycapacity == 0U)
|
||||
if (pathfindsetup->getfinished(&singlenode, pathfindsetup) == true)
|
||||
{
|
||||
pathfindsetup->nodesarraycapacity = DEFAULT_NODEARRAY_CAPACITY;
|
||||
// At the destination, return a simple 1 node path
|
||||
K_ReconstructPath(path, &singlenode);
|
||||
pathfindsuccess = true;
|
||||
}
|
||||
if (pathfindsetup->opensetcapacity == 0U)
|
||||
else
|
||||
{
|
||||
pathfindsetup->opensetcapacity = DEFAULT_OPENSET_CAPACITY;
|
||||
}
|
||||
if (pathfindsetup->closedsetcapacity == 0U)
|
||||
{
|
||||
pathfindsetup->closedsetcapacity = DEFAULT_CLOSEDSET_CAPACITY;
|
||||
}
|
||||
bheap_t openset = {0};
|
||||
bheapitem_t poppedbheapitem = {0};
|
||||
pathfindnode_t *nodesarray = NULL;
|
||||
pathfindnode_t **closedset = NULL;
|
||||
pathfindnode_t *newnode = NULL;
|
||||
pathfindnode_t *currentnode = NULL;
|
||||
pathfindnode_t *connectingnode = NULL;
|
||||
void **connectingnodesdata = NULL;
|
||||
void *checknodedata = NULL;
|
||||
UINT32 *connectingnodecosts = NULL;
|
||||
size_t numconnectingnodes = 0U;
|
||||
size_t connectingnodeheapindex = 0U;
|
||||
size_t nodesarraycount = 0U;
|
||||
size_t closedsetcount = 0U;
|
||||
size_t i = 0U;
|
||||
UINT32 tentativegscore = 0U;
|
||||
|
||||
// Allocate the necessary memory
|
||||
nodesarray = Z_Calloc(pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
if (nodesarray == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory allocating nodes array.");
|
||||
}
|
||||
closedset = Z_Calloc(pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||
if (closedset == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory allocating closed set.");
|
||||
}
|
||||
K_BHeapInit(&openset, pathfindsetup->opensetcapacity);
|
||||
|
||||
// Create the first node and add it to the open set
|
||||
newnode = &nodesarray[nodesarraycount];
|
||||
newnode->heapindex = SIZE_MAX;
|
||||
newnode->nodedata = pathfindsetup->startnodedata;
|
||||
newnode->camefrom = NULL;
|
||||
newnode->gscore = 0U;
|
||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||
nodesarraycount++;
|
||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||
|
||||
// update openset capacity if it changed
|
||||
if (openset.capacity != pathfindsetup->opensetcapacity)
|
||||
{
|
||||
pathfindsetup->opensetcapacity = openset.capacity;
|
||||
}
|
||||
|
||||
// Go through each node in the openset, adding new ones from each node to it
|
||||
// this continues until a path is found or there are no more nodes to check
|
||||
while (openset.count > 0U)
|
||||
{
|
||||
// pop the best node off of the openset
|
||||
K_BHeapPop(&openset, &poppedbheapitem);
|
||||
currentnode = (pathfindnode_t*)poppedbheapitem.data;
|
||||
|
||||
if (currentnode->nodedata == pathfindsetup->endnodedata)
|
||||
// Set the dynamic structure capacites to defaults if they are 0
|
||||
if (pathfindsetup->nodesarraycapacity == 0U)
|
||||
{
|
||||
pathfindsuccess = K_ReconstructPath(path, currentnode);
|
||||
break;
|
||||
pathfindsetup->nodesarraycapacity = DEFAULT_NODEARRAY_CAPACITY;
|
||||
}
|
||||
if (pathfindsetup->opensetcapacity == 0U)
|
||||
{
|
||||
pathfindsetup->opensetcapacity = DEFAULT_OPENSET_CAPACITY;
|
||||
}
|
||||
if (pathfindsetup->closedsetcapacity == 0U)
|
||||
{
|
||||
pathfindsetup->closedsetcapacity = DEFAULT_CLOSEDSET_CAPACITY;
|
||||
}
|
||||
|
||||
// Place the node we just popped into the closed set, as we are now evaluating it
|
||||
if (closedsetcount >= pathfindsetup->closedsetcapacity)
|
||||
// Allocate the necessary memory
|
||||
nodesarray = Z_Calloc(pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
if (nodesarray == NULL)
|
||||
{
|
||||
// Need to reallocate closedset to fit another node
|
||||
pathfindsetup->closedsetcapacity = pathfindsetup->closedsetcapacity * 2;
|
||||
closedset =
|
||||
Z_Realloc(closedset, pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||
if (closedset == NULL)
|
||||
I_Error("K_PathfindAStar: Out of memory allocating nodes array.");
|
||||
}
|
||||
closedset = Z_Calloc(pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||
if (closedset == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory allocating closed set.");
|
||||
}
|
||||
K_BHeapInit(&openset, pathfindsetup->opensetcapacity);
|
||||
|
||||
// Create the first node and add it to the open set
|
||||
newnode = &nodesarray[nodesarraycount];
|
||||
newnode->heapindex = SIZE_MAX;
|
||||
newnode->nodedata = pathfindsetup->startnodedata;
|
||||
newnode->camefrom = NULL;
|
||||
newnode->gscore = 0U;
|
||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||
nodesarraycount++;
|
||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||
|
||||
// update openset capacity if it changed
|
||||
if (openset.capacity != pathfindsetup->opensetcapacity)
|
||||
{
|
||||
pathfindsetup->opensetcapacity = openset.capacity;
|
||||
}
|
||||
|
||||
// Go through each node in the openset, adding new ones from each node to it
|
||||
// this continues until a path is found or there are no more nodes to check
|
||||
while (openset.count > 0U)
|
||||
{
|
||||
// pop the best node off of the openset
|
||||
K_BHeapPop(&openset, &poppedbheapitem);
|
||||
currentnode = (pathfindnode_t*)poppedbheapitem.data;
|
||||
|
||||
if (pathfindsetup->getfinished(currentnode, pathfindsetup) == true)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory reallocating closed set.");
|
||||
pathfindsuccess = K_ReconstructPath(path, currentnode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedset[closedsetcount] = currentnode;
|
||||
closedsetcount++;
|
||||
|
||||
// Get the needed data for the next nodes from the current node
|
||||
connectingnodesdata = pathfindsetup->getconnectednodes(currentnode->nodedata, &numconnectingnodes);
|
||||
connectingnodecosts = pathfindsetup->getconnectioncosts(currentnode->nodedata);
|
||||
|
||||
if (connectingnodesdata == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node data.\n");
|
||||
}
|
||||
else if (connectingnodecosts == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node costs.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// For each connecting node add it to the openset if it's unevaluated and not there,
|
||||
// skip it if it's in the closedset or not traversable
|
||||
for (i = 0; i < numconnectingnodes; i++)
|
||||
// Place the node we just popped into the closed set, as we are now evaluating it
|
||||
if (closedsetcount >= pathfindsetup->closedsetcapacity)
|
||||
{
|
||||
checknodedata = connectingnodesdata[i];
|
||||
|
||||
if (checknodedata == NULL)
|
||||
// Need to reallocate closedset to fit another node
|
||||
pathfindsetup->closedsetcapacity = pathfindsetup->closedsetcapacity * 2;
|
||||
closedset =
|
||||
Z_Realloc(closedset, pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||
if (closedset == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node has a NULL connecting node.\n");
|
||||
I_Error("K_PathfindAStar: Out of memory reallocating closed set.");
|
||||
}
|
||||
else
|
||||
}
|
||||
closedset[closedsetcount] = currentnode;
|
||||
closedsetcount++;
|
||||
|
||||
// Get the needed data for the next nodes from the current node
|
||||
connectingnodesdata = pathfindsetup->getconnectednodes(currentnode->nodedata, &numconnectingnodes);
|
||||
connectingnodecosts = pathfindsetup->getconnectioncosts(currentnode->nodedata);
|
||||
|
||||
if (connectingnodesdata == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node data.\n");
|
||||
}
|
||||
else if (connectingnodecosts == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node costs.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// For each connecting node add it to the openset if it's unevaluated and not there,
|
||||
// skip it if it's in the closedset or not traversable
|
||||
for (i = 0; i < numconnectingnodes; i++)
|
||||
{
|
||||
// skip this node if it isn't traversable
|
||||
if (pathfindsetup->gettraversable(checknodedata, currentnode->nodedata) == false)
|
||||
checknodedata = connectingnodesdata[i];
|
||||
|
||||
if (checknodedata == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Figure out what the gscore of this route for the connecting node is
|
||||
tentativegscore = currentnode->gscore + connectingnodecosts[i];
|
||||
|
||||
// find this data in the nodes array if it's been generated before
|
||||
connectingnode = K_NodesArrayContainsNodeData(nodesarray, checknodedata, nodesarraycount);
|
||||
|
||||
if (connectingnode != NULL)
|
||||
{
|
||||
// The connecting node has been seen before, so it must be in either the closedset (skip it)
|
||||
// or the openset (re-evaluate it's gscore)
|
||||
if (K_ClosedsetContainsNode(closedset, connectingnode, closedsetcount) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (tentativegscore < connectingnode->gscore)
|
||||
{
|
||||
// The node is not in the closedset, update it's gscore if this path to it is faster
|
||||
connectingnode->gscore = tentativegscore;
|
||||
connectingnode->camefrom = currentnode;
|
||||
|
||||
connectingnodeheapindex =
|
||||
K_BHeapContains(&openset, connectingnode, connectingnode->heapindex);
|
||||
if (connectingnodeheapindex != SIZE_MAX)
|
||||
{
|
||||
K_UpdateBHeapItemValue(
|
||||
&openset.array[connectingnodeheapindex], K_NodeGetFScore(connectingnode));
|
||||
}
|
||||
else
|
||||
{
|
||||
// SOMEHOW the node is not in either the closed set OR the open set
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node is not in either set.\n");
|
||||
}
|
||||
}
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node has a NULL connecting node.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Node is not created yet, so it hasn't been seen so far
|
||||
// Reallocate nodesarray if it's full
|
||||
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
|
||||
// skip this node if it isn't traversable
|
||||
if (pathfindsetup->gettraversable(checknodedata, currentnode->nodedata) == false)
|
||||
{
|
||||
pathfindnode_t *nodesarrayrealloc = NULL;
|
||||
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
|
||||
nodesarrayrealloc = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
|
||||
if (nodesarrayrealloc == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
|
||||
}
|
||||
|
||||
// Need to update pointers in closedset, openset, and node "camefrom" if nodesarray moved.
|
||||
if (nodesarray != nodesarrayrealloc)
|
||||
{
|
||||
size_t j = 0U;
|
||||
size_t arrayindex = 0U;
|
||||
for (j = 0U; j < closedsetcount; j++)
|
||||
{
|
||||
arrayindex = closedset[j] - nodesarray;
|
||||
closedset[j] = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
for (j = 0U; j < openset.count; j++)
|
||||
{
|
||||
arrayindex = ((pathfindnode_t *)(openset.array[j].data)) - nodesarray;
|
||||
openset.array[j].data = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
for (j = 0U; j < nodesarraycount; j++)
|
||||
{
|
||||
if (nodesarrayrealloc[j].camefrom != NULL)
|
||||
{
|
||||
arrayindex = nodesarrayrealloc[j].camefrom - nodesarray;
|
||||
nodesarrayrealloc[j].camefrom = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
}
|
||||
|
||||
arrayindex = currentnode - nodesarray;
|
||||
currentnode = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
|
||||
nodesarray = nodesarrayrealloc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the new node and add it to the nodes array and open set
|
||||
newnode = &nodesarray[nodesarraycount];
|
||||
newnode->heapindex = SIZE_MAX;
|
||||
newnode->nodedata = checknodedata;
|
||||
newnode->camefrom = currentnode;
|
||||
newnode->gscore = tentativegscore;
|
||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||
nodesarraycount++;
|
||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||
// Figure out what the gscore of this route for the connecting node is
|
||||
tentativegscore = currentnode->gscore + connectingnodecosts[i];
|
||||
|
||||
// find this data in the nodes array if it's been generated before
|
||||
connectingnode = K_NodesArrayContainsNodeData(nodesarray, checknodedata, nodesarraycount);
|
||||
|
||||
if (connectingnode != NULL)
|
||||
{
|
||||
// The connecting node has been seen before, so it must be in either the closedset (skip it)
|
||||
// or the openset (re-evaluate it's gscore)
|
||||
if (K_ClosedsetContainsNode(closedset, connectingnode, closedsetcount) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (tentativegscore < connectingnode->gscore)
|
||||
{
|
||||
// The node is not in the closedset, update it's gscore if this path to it is faster
|
||||
connectingnode->gscore = tentativegscore;
|
||||
connectingnode->camefrom = currentnode;
|
||||
|
||||
connectingnodeheapindex =
|
||||
K_BHeapContains(&openset, connectingnode, connectingnode->heapindex);
|
||||
if (connectingnodeheapindex != SIZE_MAX)
|
||||
{
|
||||
K_UpdateBHeapItemValue(
|
||||
&openset.array[connectingnodeheapindex], K_NodeGetFScore(connectingnode));
|
||||
}
|
||||
else
|
||||
{
|
||||
// SOMEHOW the node is not in either the closed set OR the open set
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node is not in either set.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Node is not created yet, so it hasn't been seen so far
|
||||
// Reallocate nodesarray if it's full
|
||||
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
|
||||
{
|
||||
pathfindnode_t *nodesarrayrealloc = NULL;
|
||||
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
|
||||
nodesarrayrealloc = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
|
||||
if (nodesarrayrealloc == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
|
||||
}
|
||||
|
||||
// Need to update pointers in closedset, openset, and node "camefrom" if nodesarray moved.
|
||||
if (nodesarray != nodesarrayrealloc)
|
||||
{
|
||||
size_t j = 0U;
|
||||
size_t arrayindex = 0U;
|
||||
for (j = 0U; j < closedsetcount; j++)
|
||||
{
|
||||
arrayindex = closedset[j] - nodesarray;
|
||||
closedset[j] = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
for (j = 0U; j < openset.count; j++)
|
||||
{
|
||||
arrayindex = ((pathfindnode_t *)(openset.array[j].data)) - nodesarray;
|
||||
openset.array[j].data = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
for (j = 0U; j < nodesarraycount; j++)
|
||||
{
|
||||
if (nodesarrayrealloc[j].camefrom != NULL)
|
||||
{
|
||||
arrayindex = nodesarrayrealloc[j].camefrom - nodesarray;
|
||||
nodesarrayrealloc[j].camefrom = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
}
|
||||
|
||||
arrayindex = currentnode - nodesarray;
|
||||
currentnode = &nodesarrayrealloc[arrayindex];
|
||||
}
|
||||
|
||||
nodesarray = nodesarrayrealloc;
|
||||
}
|
||||
|
||||
// Create the new node and add it to the nodes array and open set
|
||||
newnode = &nodesarray[nodesarraycount];
|
||||
newnode->heapindex = SIZE_MAX;
|
||||
newnode->nodedata = checknodedata;
|
||||
newnode->camefrom = currentnode;
|
||||
newnode->gscore = tentativegscore;
|
||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||
nodesarraycount++;
|
||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the memory
|
||||
K_BHeapFree(&openset);
|
||||
Z_Free(closedset);
|
||||
Z_Free(nodesarray);
|
||||
// Clean up the memory
|
||||
K_BHeapFree(&openset);
|
||||
Z_Free(closedset);
|
||||
Z_Free(nodesarray);
|
||||
}
|
||||
}
|
||||
|
||||
return pathfindsuccess;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ typedef UINT32(*getnodeheuristicfunc)(void*, void*);
|
|||
// function pointer for getting if a node is traversable from its base data
|
||||
typedef boolean(*getnodetraversablefunc)(void*, void*);
|
||||
|
||||
// function pointer for getting if a node is our pathfinding end point
|
||||
typedef boolean(*getpathfindfinishedfunc)(void*, void*);
|
||||
|
||||
|
||||
// A pathfindnode contains information about a node from the pathfinding
|
||||
// heapindex is only used within the pathfinding algorithm itself, and is always 0 after it is completed
|
||||
|
|
@ -58,10 +61,12 @@ typedef struct pathfindsetup_s {
|
|||
size_t nodesarraycapacity;
|
||||
void *startnodedata;
|
||||
void *endnodedata;
|
||||
UINT32 endgscore;
|
||||
getconnectednodesfunc getconnectednodes;
|
||||
getnodeconnectioncostsfunc getconnectioncosts;
|
||||
getnodeheuristicfunc getheuristic;
|
||||
getnodetraversablefunc gettraversable;
|
||||
getpathfindfinishedfunc getfinished;
|
||||
} pathfindsetup_t;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -57,16 +57,8 @@ SINT8 K_UsingPowerLevels(void)
|
|||
|
||||
void K_ClearClientPowerLevels(void)
|
||||
{
|
||||
UINT8 i, j;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
clientPowerAdd[i] = 0;
|
||||
|
||||
for (j = 0; j < PWRLV_NUMTYPES; j++)
|
||||
{
|
||||
clientpowerlevels[i][j] = 0;
|
||||
}
|
||||
}
|
||||
memset(clientpowerlevels, 0, sizeof clientpowerlevels);
|
||||
memset(clientPowerAdd, 0, sizeof clientPowerAdd);
|
||||
}
|
||||
|
||||
// Adapted from this: http://wiki.tockdom.com/wiki/Player_Rating
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ t_splash_t *K_GetSplashByIndex(size_t checkIndex)
|
|||
--------------------------------------------------*/
|
||||
t_splash_t *K_GetSplashByName(const char *checkName)
|
||||
{
|
||||
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
||||
size_t i;
|
||||
|
||||
if (numSplashDefs == 0)
|
||||
|
|
@ -102,7 +103,7 @@ t_splash_t *K_GetSplashByName(const char *checkName)
|
|||
{
|
||||
t_splash_t *s = &splashDefs[i];
|
||||
|
||||
if (stricmp(checkName, s->name) == 0)
|
||||
if (checkHash == s->hash && !strncmp(checkName, s->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
// Name matches.
|
||||
return s;
|
||||
|
|
@ -159,6 +160,7 @@ t_footstep_t *K_GetFootstepByIndex(size_t checkIndex)
|
|||
--------------------------------------------------*/
|
||||
t_footstep_t *K_GetFootstepByName(const char *checkName)
|
||||
{
|
||||
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
||||
size_t i;
|
||||
|
||||
if (numFootstepDefs == 0)
|
||||
|
|
@ -170,7 +172,7 @@ t_footstep_t *K_GetFootstepByName(const char *checkName)
|
|||
{
|
||||
t_footstep_t *fs = &footstepDefs[i];
|
||||
|
||||
if (stricmp(checkName, fs->name) == 0)
|
||||
if (checkHash == fs->hash && !strncmp(checkName, fs->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
// Name matches.
|
||||
return fs;
|
||||
|
|
@ -227,21 +229,20 @@ terrain_t *K_GetTerrainByIndex(size_t checkIndex)
|
|||
--------------------------------------------------*/
|
||||
terrain_t *K_GetTerrainByName(const char *checkName)
|
||||
{
|
||||
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
||||
size_t i;
|
||||
|
||||
if (numTerrainDefs == 0)
|
||||
if (numTerrainDefs > 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numTerrainDefs; i++)
|
||||
{
|
||||
terrain_t *t = &terrainDefs[i];
|
||||
|
||||
if (stricmp(checkName, t->name) == 0)
|
||||
for (i = 0; i < numTerrainDefs; i++)
|
||||
{
|
||||
// Name matches.
|
||||
return t;
|
||||
terrain_t *t = &terrainDefs[i];
|
||||
|
||||
if (checkHash == t->hash && !strncmp(checkName, t->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
// Name matches.
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,20 +266,19 @@ terrain_t *K_GetDefaultTerrain(void)
|
|||
--------------------------------------------------*/
|
||||
terrain_t *K_GetTerrainForTextureName(const char *checkName)
|
||||
{
|
||||
UINT32 checkHash = quickncasehash(checkName, 8);
|
||||
size_t i;
|
||||
|
||||
if (numTerrainFloorDefs == 0)
|
||||
if (numTerrainFloorDefs > 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numTerrainFloorDefs; i++)
|
||||
{
|
||||
t_floor_t *f = &terrainFloorDefs[i];
|
||||
|
||||
if (strncasecmp(checkName, f->textureName, 8) == 0)
|
||||
for (i = 0; i < numTerrainFloorDefs; i++)
|
||||
{
|
||||
return K_GetTerrainByIndex(f->terrainID);
|
||||
t_floor_t *f = &terrainFloorDefs[i];
|
||||
|
||||
if (checkHash == f->textureHash && !strncmp(checkName, f->textureName, 8))
|
||||
{
|
||||
return K_GetTerrainByIndex(f->terrainID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,15 +294,15 @@ terrain_t *K_GetTerrainForTextureName(const char *checkName)
|
|||
--------------------------------------------------*/
|
||||
terrain_t *K_GetTerrainForTextureNum(INT32 textureNum)
|
||||
{
|
||||
texture_t *tex = NULL;
|
||||
|
||||
if (textureNum < 0 || textureNum >= numtextures)
|
||||
if (textureNum >= 0 && textureNum < numtextures)
|
||||
{
|
||||
return NULL;
|
||||
texture_t *tex = textures[textureNum];
|
||||
return K_GetTerrainForTextureName(tex->name);
|
||||
}
|
||||
|
||||
tex = textures[textureNum];
|
||||
return K_GetTerrainForTextureName(tex->name);
|
||||
// This texture doesn't have a terrain directly applied to it,
|
||||
// so we fallback to the default terrain.
|
||||
return K_GetDefaultTerrain();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -1187,6 +1187,7 @@ static boolean K_DoTERRAINLumpParse(size_t num, void (*parser)(size_t, char *, c
|
|||
static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
||||
{
|
||||
char *tkn = M_GetToken((char *)data);
|
||||
UINT32 tknHash = 0;
|
||||
size_t pos = 0;
|
||||
size_t i;
|
||||
|
||||
|
|
@ -1211,11 +1212,13 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
{
|
||||
t_splash_t *s = NULL;
|
||||
|
||||
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
||||
|
||||
for (i = 0; i < numSplashDefs; i++)
|
||||
{
|
||||
s = &splashDefs[i];
|
||||
|
||||
if (stricmp(tkn, s->name) == 0)
|
||||
if (tknHash == s->hash && !strncmp(tkn, s->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -1227,6 +1230,8 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
s = &splashDefs[i];
|
||||
|
||||
strncpy(s->name, tkn, TERRAIN_NAME_LEN);
|
||||
s->hash = tknHash;
|
||||
|
||||
CONS_Printf("Created new Splash type '%s'\n", s->name);
|
||||
}
|
||||
|
||||
|
|
@ -1248,11 +1253,13 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
{
|
||||
t_footstep_t *fs = NULL;
|
||||
|
||||
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
||||
|
||||
for (i = 0; i < numFootstepDefs; i++)
|
||||
{
|
||||
fs = &footstepDefs[i];
|
||||
|
||||
if (stricmp(tkn, fs->name) == 0)
|
||||
if (tknHash == fs->hash && !strncmp(tkn, fs->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -1264,6 +1271,8 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
fs = &footstepDefs[i];
|
||||
|
||||
strncpy(fs->name, tkn, TERRAIN_NAME_LEN);
|
||||
fs->hash = tknHash;
|
||||
|
||||
CONS_Printf("Created new Footstep type '%s'\n", fs->name);
|
||||
}
|
||||
|
||||
|
|
@ -1285,11 +1294,13 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
{
|
||||
terrain_t *t = NULL;
|
||||
|
||||
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
||||
|
||||
for (i = 0; i < numTerrainDefs; i++)
|
||||
{
|
||||
t = &terrainDefs[i];
|
||||
|
||||
if (stricmp(tkn, t->name) == 0)
|
||||
if (tknHash == t->hash && !strncmp(tkn, t->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -1301,6 +1312,8 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
t = &terrainDefs[i];
|
||||
|
||||
strncpy(t->name, tkn, TERRAIN_NAME_LEN);
|
||||
t->hash = tknHash;
|
||||
|
||||
CONS_Printf("Created new Terrain type '%s'\n", t->name);
|
||||
}
|
||||
|
||||
|
|
@ -1333,11 +1346,13 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
{
|
||||
t_floor_t *f = NULL;
|
||||
|
||||
tknHash = quickncasehash(tkn, 8);
|
||||
|
||||
for (i = 0; i < numTerrainFloorDefs; i++)
|
||||
{
|
||||
f = &terrainFloorDefs[i];
|
||||
|
||||
if (stricmp(tkn, f->textureName) == 0)
|
||||
if (f->textureHash == tknHash && !strncmp(tkn, f->textureName, 8))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -1348,7 +1363,8 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
K_NewTerrainFloorDefs();
|
||||
f = &terrainFloorDefs[i];
|
||||
|
||||
strncpy(f->textureName, tkn, 9);
|
||||
strncpy(f->textureName, tkn, 8);
|
||||
f->textureHash = tknHash;
|
||||
}
|
||||
|
||||
Z_Free(tkn);
|
||||
|
|
@ -1398,11 +1414,13 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
{
|
||||
terrain_t *t = NULL;
|
||||
|
||||
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
||||
|
||||
for (i = 0; i < numTerrainDefs; i++)
|
||||
{
|
||||
t = &terrainDefs[i];
|
||||
|
||||
if (stricmp(tkn, t->name) == 0)
|
||||
if (tknHash == t->hash && !strncmp(tkn, t->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -1435,11 +1453,13 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size)
|
|||
{
|
||||
t_footstep_t *fs = NULL;
|
||||
|
||||
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
||||
|
||||
for (i = 0; i < numFootstepDefs; i++)
|
||||
{
|
||||
fs = &footstepDefs[i];
|
||||
|
||||
if (stricmp(tkn, fs->name) == 0)
|
||||
if (tknHash == fs->hash && !strncmp(tkn, fs->name, TERRAIN_NAME_LEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ typedef struct t_splash_s
|
|||
// These are particles spawned when hitting the floor.
|
||||
|
||||
char name[TERRAIN_NAME_LEN]; // Lookup name.
|
||||
UINT32 hash; // Lookup name's hash.
|
||||
|
||||
UINT16 mobjType; // Thing type. MT_NULL to not spawn anything.
|
||||
UINT16 sfx; // Sound to play.
|
||||
|
|
@ -48,6 +49,7 @@ typedef struct t_footstep_s
|
|||
// These are particles spawned when moving fast enough on a floor.
|
||||
|
||||
char name[TERRAIN_NAME_LEN]; // Lookup name.
|
||||
UINT32 hash; // Lookup name's hash.
|
||||
|
||||
UINT16 mobjType; // Thing type. MT_NULL to not spawn anything.
|
||||
UINT16 sfx; // Sound to play.
|
||||
|
|
@ -79,6 +81,7 @@ typedef struct terrain_s
|
|||
// These are all of the properties that the floor gets.
|
||||
|
||||
char name[TERRAIN_NAME_LEN]; // Lookup name.
|
||||
UINT32 hash; // Lookup name's hash.
|
||||
|
||||
size_t splashID; // Splash defintion ID.
|
||||
size_t footstepID; // Footstep defintion ID.
|
||||
|
|
@ -93,16 +96,14 @@ typedef struct terrain_s
|
|||
typedef struct t_floor_s
|
||||
{
|
||||
// Terrain floor definition.
|
||||
// Ties texture names to a .
|
||||
// Ties a texture name to a terrain definition.
|
||||
|
||||
// (Could be optimized by using texture IDs instead of names,
|
||||
// but was concerned because I recall sooomething about those not being netsafe?
|
||||
// Someone confirm if I just hallucinated that. :V)
|
||||
|
||||
char textureName[9]; // Floor texture name.
|
||||
char textureName[8]; // Floor texture name.
|
||||
UINT32 textureHash; // Floor texture hash.
|
||||
size_t terrainID; // Terrain definition ID.
|
||||
} t_floor_t;
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
size_t K_GetSplashHeapIndex(t_splash_t *splash);
|
||||
|
||||
|
|
@ -285,6 +286,7 @@ terrain_t *K_GetTerrainByIndex(size_t checkIndex);
|
|||
|
||||
terrain_t *K_GetTerrainByName(const char *checkName);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
terrain_t *K_GetDefaultTerrain(void);
|
||||
|
||||
|
|
|
|||
271
src/k_waypoint.c
271
src/k_waypoint.c
|
|
@ -1039,6 +1039,102 @@ static boolean K_WaypointPathfindTraversableNoShortcuts(void *data, void *prevda
|
|||
return traversable;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_WaypointPathfindReachedEnd(void *data, void *setupData)
|
||||
|
||||
Returns if the current waypoint data is our end point of our pathfinding.
|
||||
|
||||
Input Arguments:-
|
||||
data - Should point to a pathfindnode_t to compare
|
||||
setupData - Should point to the pathfindsetup_t to compare
|
||||
|
||||
Return:-
|
||||
True if the waypoint is the pathfind end point, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_WaypointPathfindReachedEnd(void *data, void *setupData)
|
||||
{
|
||||
boolean isEnd = false;
|
||||
|
||||
if (data == NULL || setupData == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindReachedEnd received NULL data.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindnode_t *node = (pathfindnode_t *)data;
|
||||
pathfindsetup_t *setup = (pathfindsetup_t *)setupData;
|
||||
|
||||
isEnd = (node->nodedata == setup->endnodedata);
|
||||
}
|
||||
|
||||
return isEnd;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData)
|
||||
|
||||
Returns if the current waypoint data reaches our end G score.
|
||||
|
||||
Input Arguments:-
|
||||
data - Should point to a pathfindnode_t to compare
|
||||
setupData - Should point to the pathfindsetup_t to compare
|
||||
|
||||
Return:-
|
||||
True if the waypoint reached the G score, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData)
|
||||
{
|
||||
boolean scoreReached = false;
|
||||
|
||||
if (data == NULL || setupData == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindReachedGScore received NULL data.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindnode_t *node = (pathfindnode_t *)data;
|
||||
pathfindsetup_t *setup = (pathfindsetup_t *)setupData;
|
||||
|
||||
scoreReached = (node->gscore >= setup->endgscore);
|
||||
}
|
||||
|
||||
return scoreReached;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_WaypointPathfindReachedGScoreSpawnable(void *data, void *setupData)
|
||||
|
||||
Returns if the current waypoint data reaches our end G score.
|
||||
|
||||
Input Arguments:-
|
||||
data - Should point to a pathfindnode_t to compare
|
||||
setupData - Should point to the pathfindsetup_t to compare
|
||||
|
||||
Return:-
|
||||
True if the waypoint reached the G score, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_WaypointPathfindReachedGScoreSpawnable(void *data, void *setupData)
|
||||
{
|
||||
boolean scoreReached = false;
|
||||
boolean spawnable = false;
|
||||
|
||||
if (data == NULL || setupData == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindReachedGScoreSpawnable received NULL data.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindnode_t *node = (pathfindnode_t *)data;
|
||||
pathfindsetup_t *setup = (pathfindsetup_t *)setupData;
|
||||
waypoint_t *wp = (waypoint_t *)node->nodedata;
|
||||
|
||||
scoreReached = (node->gscore >= setup->endgscore);
|
||||
spawnable = K_GetWaypointIsSpawnpoint(wp);
|
||||
}
|
||||
|
||||
return (scoreReached && spawnable);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindToWaypoint(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
|
|
@ -1087,18 +1183,19 @@ boolean K_PathfindToWaypoint(
|
|||
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedEnd;
|
||||
|
||||
if (huntbackwards)
|
||||
{
|
||||
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||
}
|
||||
|
||||
if (useshortcuts)
|
||||
{
|
||||
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||
}
|
||||
|
||||
|
||||
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||
|
|
@ -1108,6 +1205,173 @@ boolean K_PathfindToWaypoint(
|
|||
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||
pathfindsetup.getheuristic = heuristicfunc;
|
||||
pathfindsetup.gettraversable = traversablefunc;
|
||||
pathfindsetup.getfinished = finishedfunc;
|
||||
|
||||
pathfound = K_PathfindAStar(returnpath, &pathfindsetup);
|
||||
|
||||
K_UpdateOpensetBaseSize(pathfindsetup.opensetcapacity);
|
||||
K_UpdateClosedsetBaseSize(pathfindsetup.closedsetcapacity);
|
||||
K_UpdateNodesArrayBaseSize(pathfindsetup.nodesarraycapacity);
|
||||
}
|
||||
|
||||
return pathfound;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindThruCircuit(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PathfindThruCircuit(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
{
|
||||
boolean pathfound = false;
|
||||
|
||||
if (sourcewaypoint == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL sourcewaypoint in K_PathfindThruCircuit.\n");
|
||||
}
|
||||
else if (finishline == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL finishline in K_PathfindThruCircuit.\n");
|
||||
}
|
||||
else if (((huntbackwards == false) && (sourcewaypoint->numnextwaypoints == 0))
|
||||
|| ((huntbackwards == true) && (sourcewaypoint->numprevwaypoints == 0)))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC,
|
||||
"K_PathfindThruCircuit: sourcewaypoint with ID %d has no next waypoint\n",
|
||||
K_GetWaypointID(sourcewaypoint));
|
||||
}
|
||||
else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0))
|
||||
|| ((huntbackwards == true) && (finishline->numnextwaypoints == 0)))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC,
|
||||
"K_PathfindThruCircuit: finishline with ID %d has no previous waypoint\n",
|
||||
K_GetWaypointID(finishline));
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindsetup_t pathfindsetup = {0};
|
||||
getconnectednodesfunc nextnodesfunc = K_WaypointPathfindGetNext;
|
||||
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedGScore;
|
||||
|
||||
if (huntbackwards)
|
||||
{
|
||||
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||
}
|
||||
|
||||
if (useshortcuts)
|
||||
{
|
||||
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||
}
|
||||
|
||||
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||
pathfindsetup.startnodedata = sourcewaypoint;
|
||||
pathfindsetup.endnodedata = finishline;
|
||||
pathfindsetup.endgscore = traveldistance;
|
||||
pathfindsetup.getconnectednodes = nextnodesfunc;
|
||||
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||
pathfindsetup.getheuristic = heuristicfunc;
|
||||
pathfindsetup.gettraversable = traversablefunc;
|
||||
pathfindsetup.getfinished = finishedfunc;
|
||||
|
||||
pathfound = K_PathfindAStar(returnpath, &pathfindsetup);
|
||||
|
||||
K_UpdateOpensetBaseSize(pathfindsetup.opensetcapacity);
|
||||
K_UpdateClosedsetBaseSize(pathfindsetup.closedsetcapacity);
|
||||
K_UpdateNodesArrayBaseSize(pathfindsetup.nodesarraycapacity);
|
||||
}
|
||||
|
||||
return pathfound;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindThruCircuitSpawnable(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PathfindThruCircuitSpawnable(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
{
|
||||
boolean pathfound = false;
|
||||
|
||||
if (sourcewaypoint == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL sourcewaypoint in K_PathfindThruCircuitSpawnable.\n");
|
||||
}
|
||||
else if (finishline == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL finishline in K_PathfindThruCircuitSpawnable.\n");
|
||||
}
|
||||
else if (((huntbackwards == false) && (sourcewaypoint->numnextwaypoints == 0))
|
||||
|| ((huntbackwards == true) && (sourcewaypoint->numprevwaypoints == 0)))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC,
|
||||
"K_PathfindThruCircuitSpawnable: sourcewaypoint with ID %d has no next waypoint\n",
|
||||
K_GetWaypointID(sourcewaypoint));
|
||||
}
|
||||
else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0))
|
||||
|| ((huntbackwards == true) && (finishline->numnextwaypoints == 0)))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC,
|
||||
"K_PathfindThruCircuitSpawnable: finishline with ID %d has no previous waypoint\n",
|
||||
K_GetWaypointID(finishline));
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindsetup_t pathfindsetup = {0};
|
||||
getconnectednodesfunc nextnodesfunc = K_WaypointPathfindGetNext;
|
||||
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedGScoreSpawnable;
|
||||
|
||||
if (huntbackwards)
|
||||
{
|
||||
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||
}
|
||||
|
||||
if (useshortcuts)
|
||||
{
|
||||
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||
}
|
||||
|
||||
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||
pathfindsetup.startnodedata = sourcewaypoint;
|
||||
pathfindsetup.endnodedata = finishline;
|
||||
pathfindsetup.endgscore = traveldistance;
|
||||
pathfindsetup.getconnectednodes = nextnodesfunc;
|
||||
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||
pathfindsetup.getheuristic = heuristicfunc;
|
||||
pathfindsetup.gettraversable = traversablefunc;
|
||||
pathfindsetup.getfinished = finishedfunc;
|
||||
|
||||
pathfound = K_PathfindAStar(returnpath, &pathfindsetup);
|
||||
|
||||
|
|
@ -1183,18 +1447,19 @@ waypoint_t *K_GetNextWaypointToDestination(
|
|||
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedEnd;
|
||||
|
||||
if (huntbackwards)
|
||||
{
|
||||
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||
}
|
||||
|
||||
if (useshortcuts)
|
||||
{
|
||||
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||
}
|
||||
|
||||
|
||||
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||
|
|
@ -1204,6 +1469,7 @@ waypoint_t *K_GetNextWaypointToDestination(
|
|||
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||
pathfindsetup.getheuristic = heuristicfunc;
|
||||
pathfindsetup.gettraversable = traversablefunc;
|
||||
pathfindsetup.getfinished = finishedfunc;
|
||||
|
||||
pathfindsuccess = K_PathfindAStar(&pathtowaypoint, &pathfindsetup);
|
||||
|
||||
|
|
@ -1895,6 +2161,7 @@ boolean K_SetupWaypointList(void)
|
|||
// Loop through the waypointcap here so that all waypoints are added to the heap, and allow easier debugging
|
||||
for (waypointmobj = waypointcap; waypointmobj; waypointmobj = waypointmobj->tracer)
|
||||
{
|
||||
waypointmobj->cusval = (INT32)numwaypoints;
|
||||
K_SetupWaypoint(waypointmobj);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,67 @@ boolean K_PathfindToWaypoint(
|
|||
const boolean huntbackwards);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindThruCircuit(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
|
||||
Tries a pathfind to the finish line waypoint, similar to K_PathfindToWaypoint, but it will continue
|
||||
until it reaches the specified distance. The final path returned will only have the waypoints up to the
|
||||
specified distance.
|
||||
|
||||
Input Arguments:-
|
||||
sourcewaypoint - The waypoint to start searching from
|
||||
traveldistance - How far along the circuit it will try to pathfind.
|
||||
returnpath - The path_t that will contain the final found path
|
||||
useshortcuts - Whether to use waypoints that are marked as being shortcuts in the search
|
||||
huntbackwards - Goes through the waypoints backwards if true
|
||||
|
||||
Return:-
|
||||
True if a circuit path could be constructed, false if it couldn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_PathfindThruCircuit(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindThruCircuitSpawnable(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
|
||||
The same as K_PathfindThruCircuit, but continues until hitting a waypoint that
|
||||
can be respawned at.
|
||||
|
||||
Input Arguments:-
|
||||
sourcewaypoint - The waypoint to start searching from
|
||||
traveldistance - How far along the circuit it will try to pathfind.
|
||||
returnpath - The path_t that will contain the final found path
|
||||
useshortcuts - Whether to use waypoints that are marked as being shortcuts in the search
|
||||
huntbackwards - Goes through the waypoints backwards if true
|
||||
|
||||
Return:-
|
||||
True if a circuit path could be constructed, false if it couldn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_PathfindThruCircuitSpawnable(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
const UINT32 traveldistance,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetNextWaypointToDestination(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
|
|
|
|||
227
src/lua_hook.h
227
src/lua_hook.h
|
|
@ -1,7 +1,7 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2012-2016 by John "JTE" Muniz.
|
||||
// Copyright (C) 2012-2020 by Sonic Team Junior.
|
||||
// Copyright (C) 2012-2022 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
|
|
@ -12,115 +12,134 @@
|
|||
|
||||
#include "r_defs.h"
|
||||
#include "d_player.h"
|
||||
#include "s_sound.h"
|
||||
#include "d_event.h"
|
||||
|
||||
#include "lua_hudlib_drawlist.h"
|
||||
|
||||
enum hook {
|
||||
hook_NetVars=0,
|
||||
hook_MapChange,
|
||||
hook_MapLoad,
|
||||
hook_PlayerJoin,
|
||||
hook_PreThinkFrame,
|
||||
hook_ThinkFrame,
|
||||
hook_PostThinkFrame,
|
||||
hook_MobjSpawn,
|
||||
hook_MobjCollide,
|
||||
hook_MobjLineCollide,
|
||||
hook_MobjMoveCollide,
|
||||
hook_TouchSpecial,
|
||||
hook_MobjFuse,
|
||||
hook_MobjThinker,
|
||||
hook_BossThinker,
|
||||
hook_ShouldDamage,
|
||||
hook_MobjDamage,
|
||||
hook_MobjDeath,
|
||||
hook_BossDeath,
|
||||
hook_MobjRemoved,
|
||||
hook_JumpSpecial,
|
||||
hook_AbilitySpecial,
|
||||
hook_SpinSpecial,
|
||||
hook_JumpSpinSpecial,
|
||||
hook_BotTiccmd,
|
||||
hook_BotAI,
|
||||
hook_BotRespawn,
|
||||
hook_LinedefExecute,
|
||||
hook_PlayerMsg,
|
||||
hook_HurtMsg,
|
||||
hook_PlayerSpawn,
|
||||
hook_ShieldSpawn,
|
||||
hook_ShieldSpecial,
|
||||
hook_MobjMoveBlocked,
|
||||
hook_MapThingSpawn,
|
||||
hook_FollowMobj,
|
||||
hook_PlayerCanDamage,
|
||||
hook_PlayerQuit,
|
||||
hook_MusicChange,
|
||||
hook_TeamSwitch,
|
||||
hook_ViewpointSwitch,
|
||||
hook_PlayerThink,
|
||||
hook_ShouldJingleContinue,
|
||||
hook_GameQuit,
|
||||
hook_PlayerCmd,
|
||||
/*
|
||||
Do you know what an 'X Macro' is? Such a macro is called over each element of
|
||||
a list and expands the input. I use it for the hook lists because both an enum
|
||||
and array of hook names need to be kept in order. The X Macro handles this
|
||||
automatically.
|
||||
*/
|
||||
|
||||
// SRB2Kart
|
||||
hook_IntermissionThinker,
|
||||
hook_VoteThinker,
|
||||
#define MOBJ_HOOK_LIST(X) \
|
||||
X (MobjSpawn),/* P_SpawnMobj */\
|
||||
X (MobjCollide),/* PIT_CheckThing */\
|
||||
X (MobjLineCollide),/* ditto */\
|
||||
X (MobjMoveCollide),/* tritto */\
|
||||
X (TouchSpecial),/* P_TouchSpecialThing */\
|
||||
X (MobjFuse),/* when mobj->fuse runs out */\
|
||||
X (MobjThinker),/* P_MobjThinker, P_SceneryThinker */\
|
||||
X (BossThinker),/* P_GenericBossThinker */\
|
||||
X (ShouldDamage),/* P_DamageMobj (Should mobj take damage?) */\
|
||||
X (MobjDamage),/* P_DamageMobj (Mobj actually takes damage!) */\
|
||||
X (MobjDeath),/* P_KillMobj */\
|
||||
X (BossDeath),/* A_BossDeath */\
|
||||
X (MobjRemoved),/* P_RemoveMobj */\
|
||||
X (BotRespawn),/* B_CheckRespawn */\
|
||||
X (MobjMoveBlocked),/* P_XYMovement (when movement is blocked) */\
|
||||
X (MapThingSpawn),/* P_SpawnMapThing */\
|
||||
X (FollowMobj),/* P_PlayerAfterThink Smiles mobj-following */\
|
||||
|
||||
hook_MAX // last hook
|
||||
};
|
||||
extern const char *const hookNames[];
|
||||
#define HOOK_LIST(X) \
|
||||
X (NetVars),/* add to archive table (netsave) */\
|
||||
X (MapChange),/* (before map load) */\
|
||||
X (MapLoad),\
|
||||
X (PlayerJoin),/* Got_AddPlayer */\
|
||||
X (PreThinkFrame)/* frame (before mobj and player thinkers) */,\
|
||||
X (ThinkFrame),/* frame (after mobj and player thinkers) */\
|
||||
X (PostThinkFrame),/* frame (at end of tick, ie after overlays, precipitation, specials) */\
|
||||
X (JumpSpecial),/* P_DoJumpStuff (Any-jumping) */\
|
||||
X (AbilitySpecial),/* P_DoJumpStuff (Double-jumping) */\
|
||||
X (SpinSpecial),/* P_DoSpinAbility (Spin button effect) */\
|
||||
X (JumpSpinSpecial),/* P_DoJumpStuff (Spin button effect (mid-air)) */\
|
||||
X (BotTiccmd),/* B_BuildTiccmd */\
|
||||
X (PlayerMsg),/* chat messages */\
|
||||
X (HurtMsg),/* imhurttin */\
|
||||
X (PlayerSpawn),/* G_SpawnPlayer */\
|
||||
X (ShieldSpawn),/* P_SpawnShieldOrb */\
|
||||
X (ShieldSpecial),/* shield abilities */\
|
||||
X (PlayerCanDamage),/* P_PlayerCanDamage */\
|
||||
X (PlayerQuit),\
|
||||
X (IntermissionThinker),/* Y_Ticker */\
|
||||
X (TeamSwitch),/* team switching in... uh... *what* speak, spit it the fuck out */\
|
||||
X (ViewpointSwitch),/* spy mode (no trickstabs) */\
|
||||
X (SeenPlayer),/* MT_NAMECHECK */\
|
||||
X (PlayerThink),/* P_PlayerThink */\
|
||||
X (GameQuit),\
|
||||
X (PlayerCmd),/* building the player's ticcmd struct */\
|
||||
X (MusicChange),\
|
||||
X (VoteThinker),/* Y_VoteTicker */\
|
||||
|
||||
#define STRING_HOOK_LIST(X) \
|
||||
X (LinedefExecute),\
|
||||
X (ShouldJingleContinue),/* should jingle of the given music continue playing */\
|
||||
|
||||
#define HUD_HOOK_LIST(X) \
|
||||
X (game),\
|
||||
X (scores),/* emblems/multiplayer list */\
|
||||
X (title),/* titlescreen */\
|
||||
X (titlecard),\
|
||||
X (intermission),\
|
||||
|
||||
/*
|
||||
I chose to access the hook enums through a macro as well. This could provide
|
||||
a hint to lookup the macro's definition instead of the enum's definition.
|
||||
(Since each enumeration is not defined in the source code, but by the list
|
||||
macros above, it is not greppable.) The name passed to the macro can also be
|
||||
grepped and found in the lists above.
|
||||
*/
|
||||
|
||||
#define MOBJ_HOOK(name) mobjhook_ ## name
|
||||
#define HOOK(name) hook_ ## name
|
||||
#define HUD_HOOK(name) hudhook_ ## name
|
||||
#define STRING_HOOK(name) stringhook_ ## name
|
||||
|
||||
#define ENUM(X) enum { X ## _LIST (X) X(MAX) }
|
||||
|
||||
ENUM (MOBJ_HOOK);
|
||||
ENUM (HOOK);
|
||||
ENUM (HUD_HOOK);
|
||||
ENUM (STRING_HOOK);
|
||||
|
||||
#undef ENUM
|
||||
|
||||
/* dead simple, LUA_HOOK(GameQuit) */
|
||||
#define LUA_HOOK(type) LUA_HookVoid(HOOK(type))
|
||||
//#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type))
|
||||
|
||||
extern boolean hook_cmd_running;
|
||||
extern int hook_defrosting;
|
||||
|
||||
void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load)
|
||||
void LUAh_MapLoad(void); // Hook for map load
|
||||
void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer
|
||||
void LUAh_PreThinkFrame(void); // Hook for frame (before mobj and player thinkers)
|
||||
void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers)
|
||||
void LUAh_PostThinkFrame(void); // Hook for frame (at end of tick, ie after overlays, precipitation, specials)
|
||||
boolean LUAh_MobjHook(mobj_t *mo, enum hook which);
|
||||
boolean LUAh_PlayerHook(player_t *plr, enum hook which);
|
||||
#define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type
|
||||
UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
|
||||
UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which);
|
||||
#define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type
|
||||
#define LUAh_MobjLineCollide(thing, line) LUAh_MobjLineCollideHook(thing, line, hook_MobjLineCollide) // Hook for PIT_CheckThing by (thing) mobj type
|
||||
#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
|
||||
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
|
||||
#define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
|
||||
boolean LUAh_MobjThinker(mobj_t *mo); // Hook for P_MobjThinker or P_SceneryThinker by mobj type
|
||||
#define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type
|
||||
UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Should mobj take damage?)
|
||||
boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)
|
||||
boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for P_KillMobj by mobj type
|
||||
#define LUAh_BossDeath(mo) LUAh_MobjHook(mo, hook_BossDeath) // Hook for A_BossDeath by mobj type
|
||||
#define LUAh_MobjRemoved(mo) LUAh_MobjHook(mo, hook_MobjRemoved) // Hook for P_RemoveMobj by mobj type
|
||||
#define LUAh_JumpSpecial(player) LUAh_PlayerHook(player, hook_JumpSpecial) // Hook for P_DoJumpStuff (Any-jumping)
|
||||
#define LUAh_AbilitySpecial(player) LUAh_PlayerHook(player, hook_AbilitySpecial) // Hook for P_DoJumpStuff (Double-jumping)
|
||||
#define LUAh_SpinSpecial(player) LUAh_PlayerHook(player, hook_SpinSpecial) // Hook for P_DoSpinAbility (Spin button effect)
|
||||
#define LUAh_JumpSpinSpecial(player) LUAh_PlayerHook(player, hook_JumpSpinSpecial) // Hook for P_DoJumpStuff (Spin button effect (mid-air))
|
||||
boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd
|
||||
boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name
|
||||
boolean LUAh_BotRespawn(mobj_t *sonic, mobj_t *tails); // Hook for B_CheckRespawn
|
||||
boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors
|
||||
boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg, int mute); // Hook for chat messages
|
||||
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for hurt messages
|
||||
#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer
|
||||
void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player quitting
|
||||
boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping,
|
||||
UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes
|
||||
void LUA_HookVoid(int hook);
|
||||
void LUA_HookHUD(huddrawlist_h, int hook);
|
||||
|
||||
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them.
|
||||
int LUA_HookMobj(mobj_t *, int hook);
|
||||
int LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook);
|
||||
void LUA_HookInt(INT32 integer, int hook);
|
||||
void LUA_HookBool(boolean value, int hook);
|
||||
int LUA_HookPlayer(player_t *, int hook);
|
||||
int LUA_HookTiccmd(player_t *, ticcmd_t *, int hook);
|
||||
int LUA_HookKey(event_t *event, int hook); // Hooks for key events
|
||||
|
||||
void LUAh_IntermissionThinker(void); // Hook for Y_Ticker
|
||||
void LUAh_VoteThinker(void); // Hook for Y_VoteTicker
|
||||
|
||||
#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
|
||||
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
|
||||
boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following
|
||||
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage
|
||||
boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh....
|
||||
UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode
|
||||
#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink
|
||||
boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing
|
||||
void LUAh_GameQuit(boolean quitting); // Hook for game quitting
|
||||
void LUA_HookThinkFrame(void);
|
||||
int LUA_HookMobjLineCollide(mobj_t *, line_t *);
|
||||
int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher);
|
||||
int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype);
|
||||
int LUA_HookMobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype);
|
||||
int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype);
|
||||
int LUA_HookMobjMoveBlocked(mobj_t *, mobj_t *, line_t *);
|
||||
void LUA_HookLinedefExecute(line_t *, mobj_t *, sector_t *);
|
||||
int LUA_HookPlayerMsg(int source, int target, int flags, char *msg, int mute);
|
||||
int LUA_HookHurtMsg(player_t *, mobj_t *inflictor, mobj_t *source, UINT8 damagetype);
|
||||
int LUA_HookMapThingSpawn(mobj_t *, mapthing_t *);
|
||||
int LUA_HookFollowMobj(player_t *, mobj_t *);
|
||||
int LUA_HookPlayerCanDamage(player_t *, mobj_t *);
|
||||
void LUA_HookPlayerQuit(player_t *, kickreason_t);
|
||||
int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble);
|
||||
int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced);
|
||||
int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend);
|
||||
int LUA_HookShouldJingleContinue(player_t *, const char *musname);
|
||||
int LUA_HookMusicChange(const char *oldname, struct MusicChange *);
|
||||
|
|
|
|||
2750
src/lua_hooklib.c
2750
src/lua_hooklib.c
File diff suppressed because it is too large
Load diff
|
|
@ -47,10 +47,6 @@ extern boolean hud_running;
|
|||
|
||||
boolean LUA_HudEnabled(enum hud option);
|
||||
|
||||
void LUAh_GameHUD(player_t *stplyr, huddrawlist_h list);
|
||||
void LUAh_ScoresHUD(huddrawlist_h list);
|
||||
void LUAh_TitleHUD(huddrawlist_h list);
|
||||
void LUAh_TitleCardHUD(player_t *stplayr, huddrawlist_h list);
|
||||
void LUAh_IntermissionHUD(huddrawlist_h list);
|
||||
void LUA_SetHudHook(int hook, huddrawlist_h list);
|
||||
|
||||
#endif // __LUA_HUD_H__
|
||||
|
|
|
|||
238
src/lua_hudlib.c
238
src/lua_hudlib.c
|
|
@ -29,14 +29,13 @@
|
|||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
#include "lua_hud.h"
|
||||
#include "lua_hook.h"
|
||||
|
||||
#define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!");
|
||||
|
||||
boolean hud_running = false;
|
||||
static UINT8 hud_enabled[(hud_MAX/8)+1];
|
||||
|
||||
static UINT8 hudAvailable; // hud hooks field
|
||||
|
||||
static UINT8 camnum = 1;
|
||||
|
||||
// must match enum hud in lua_hud.h
|
||||
|
|
@ -79,21 +78,6 @@ static const char *const patch_opt[] = {
|
|||
"topoffset",
|
||||
NULL};
|
||||
|
||||
enum hudhook {
|
||||
hudhook_game = 0,
|
||||
hudhook_scores,
|
||||
hudhook_intermission,
|
||||
hudhook_title,
|
||||
hudhook_titlecard
|
||||
};
|
||||
static const char *const hudhook_opt[] = {
|
||||
"game",
|
||||
"scores",
|
||||
"intermission",
|
||||
"title",
|
||||
"titlecard",
|
||||
NULL};
|
||||
|
||||
// alignment types for v.drawString
|
||||
enum align {
|
||||
align_left = 0,
|
||||
|
|
@ -1249,6 +1233,8 @@ static luaL_Reg lib_draw[] = {
|
|||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int lib_draw_ref;
|
||||
|
||||
//
|
||||
// lib_hud
|
||||
//
|
||||
|
|
@ -1282,28 +1268,7 @@ static int lib_hudenabled(lua_State *L)
|
|||
}
|
||||
|
||||
// add a HUD element for rendering
|
||||
static int lib_hudadd(lua_State *L)
|
||||
{
|
||||
enum hudhook field;
|
||||
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
field = luaL_checkoption(L, 2, "game", hudhook_opt);
|
||||
|
||||
if (!lua_lumploading)
|
||||
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
|
||||
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "HUD");
|
||||
I_Assert(lua_istable(L, -1));
|
||||
lua_rawgeti(L, -1, field+2); // HUD[2+]
|
||||
I_Assert(lua_istable(L, -1));
|
||||
lua_remove(L, -2);
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1));
|
||||
|
||||
hudAvailable |= 1<<field;
|
||||
return 0;
|
||||
}
|
||||
extern int lib_hudadd(lua_State *L);
|
||||
|
||||
static luaL_Reg lib_hud[] = {
|
||||
{"enable", lib_hudenable},
|
||||
|
|
@ -1321,26 +1286,9 @@ int LUA_HudLib(lua_State *L)
|
|||
{
|
||||
memset(hud_enabled, 0xff, (hud_MAX/8)+1);
|
||||
|
||||
lua_newtable(L); // HUD registry table
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, lib_draw);
|
||||
lua_rawseti(L, -2, 1); // HUD[1] = lib_draw
|
||||
|
||||
lua_newtable(L);
|
||||
lua_rawseti(L, -2, 2); // HUD[2] = game rendering functions array
|
||||
|
||||
lua_newtable(L);
|
||||
lua_rawseti(L, -2, 3); // HUD[3] = scores rendering functions array
|
||||
|
||||
lua_newtable(L);
|
||||
lua_rawseti(L, -2, 4); // HUD[4] = intermission rendering functions array
|
||||
|
||||
lua_newtable(L);
|
||||
lua_rawseti(L, -2, 5); // HUD[5] = title rendering functions array
|
||||
|
||||
lua_newtable(L);
|
||||
lua_rawseti(L, -2, 6); // HUD[6] = title card rendering functions array
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, lib_draw);
|
||||
lib_draw_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
luaL_newmetatable(L, META_COLORMAP);
|
||||
lua_pushcfunction(L, colormap_get);
|
||||
|
|
@ -1371,170 +1319,28 @@ boolean LUA_HudEnabled(enum hud option)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Hook for HUD rendering
|
||||
void LUAh_GameHUD(player_t *stplayr, huddrawlist_h list)
|
||||
void LUA_SetHudHook(int hook, huddrawlist_h list)
|
||||
{
|
||||
if (!gL || !(hudAvailable & (1<<hudhook_game)))
|
||||
return;
|
||||
lua_getref(gL, lib_draw_ref);
|
||||
|
||||
lua_pushlightuserdata(gL, list);
|
||||
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
|
||||
|
||||
hud_running = true;
|
||||
lua_settop(gL, 0);
|
||||
switch (hook)
|
||||
{
|
||||
case HUD_HOOK(game):
|
||||
camnum = R_GetViewNumber();
|
||||
|
||||
lua_pushcfunction(gL, LUA_GetErrorMessage);
|
||||
LUA_PushUserdata(gL, stplyr, META_PLAYER);
|
||||
LUA_PushUserdata(gL, &camera[camnum], META_CAMERA);
|
||||
|
||||
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_rawgeti(gL, -1, 2+hudhook_game); // HUD[2] = rendering funcs
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
camnum++; // for compatibility
|
||||
break;
|
||||
|
||||
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_remove(gL, -3); // pop HUD
|
||||
LUA_PushUserdata(gL, stplayr, META_PLAYER);
|
||||
|
||||
camnum = R_GetViewNumber();
|
||||
LUA_PushUserdata(gL, &camera[camnum], META_CAMERA);
|
||||
camnum++; // for compatibility
|
||||
|
||||
lua_pushnil(gL);
|
||||
while (lua_next(gL, -5) != 0) {
|
||||
lua_pushvalue(gL, -5); // graphics library (HUD[1])
|
||||
lua_pushvalue(gL, -5); // stplayr
|
||||
lua_pushvalue(gL, -5); // camera
|
||||
LUA_Call(gL, 3, 0, 1);
|
||||
case HUD_HOOK(titlecard):
|
||||
LUA_PushUserdata(gL, stplyr, META_PLAYER);
|
||||
lua_pushinteger(gL, lt_ticker);
|
||||
lua_pushinteger(gL, (lt_endtime + TICRATE));
|
||||
break;
|
||||
}
|
||||
lua_settop(gL, 0);
|
||||
hud_running = false;
|
||||
}
|
||||
|
||||
void LUAh_ScoresHUD(huddrawlist_h list)
|
||||
{
|
||||
if (!gL || !(hudAvailable & (1<<hudhook_scores)))
|
||||
return;
|
||||
|
||||
lua_pushlightuserdata(gL, list);
|
||||
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
|
||||
|
||||
hud_running = true;
|
||||
lua_settop(gL, 0);
|
||||
|
||||
lua_pushcfunction(gL, LUA_GetErrorMessage);
|
||||
|
||||
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_rawgeti(gL, -1, 2+hudhook_scores); // HUD[3] = rendering funcs
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
|
||||
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_remove(gL, -3); // pop HUD
|
||||
lua_pushnil(gL);
|
||||
while (lua_next(gL, -3) != 0) {
|
||||
lua_pushvalue(gL, -3); // graphics library (HUD[1])
|
||||
LUA_Call(gL, 1, 0, 1);
|
||||
}
|
||||
lua_settop(gL, 0);
|
||||
hud_running = false;
|
||||
}
|
||||
|
||||
void LUAh_TitleHUD(huddrawlist_h list)
|
||||
{
|
||||
if (!gL || !(hudAvailable & (1<<hudhook_title)))
|
||||
return;
|
||||
|
||||
lua_pushlightuserdata(gL, list);
|
||||
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
|
||||
|
||||
hud_running = true;
|
||||
lua_settop(gL, 0);
|
||||
|
||||
lua_pushcfunction(gL, LUA_GetErrorMessage);
|
||||
|
||||
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_rawgeti(gL, -1, 2+hudhook_title); // HUD[5] = rendering funcs
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
|
||||
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_remove(gL, -3); // pop HUD
|
||||
lua_pushnil(gL);
|
||||
while (lua_next(gL, -3) != 0) {
|
||||
lua_pushvalue(gL, -3); // graphics library (HUD[1])
|
||||
LUA_Call(gL, 1, 0, 1);
|
||||
}
|
||||
lua_settop(gL, 0);
|
||||
hud_running = false;
|
||||
}
|
||||
|
||||
void LUAh_TitleCardHUD(player_t *stplayr, huddrawlist_h list)
|
||||
{
|
||||
if (!gL || !(hudAvailable & (1<<hudhook_titlecard)))
|
||||
return;
|
||||
|
||||
lua_pushlightuserdata(gL, list);
|
||||
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
|
||||
|
||||
hud_running = true;
|
||||
lua_settop(gL, 0);
|
||||
|
||||
lua_pushcfunction(gL, LUA_GetErrorMessage);
|
||||
|
||||
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_rawgeti(gL, -1, 2+hudhook_titlecard); // HUD[6] = rendering funcs
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
|
||||
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_remove(gL, -3); // pop HUD
|
||||
|
||||
LUA_PushUserdata(gL, stplayr, META_PLAYER);
|
||||
lua_pushinteger(gL, lt_ticker);
|
||||
lua_pushinteger(gL, (lt_endtime + TICRATE));
|
||||
lua_pushnil(gL);
|
||||
|
||||
while (lua_next(gL, -6) != 0) {
|
||||
lua_pushvalue(gL, -6); // graphics library (HUD[1])
|
||||
lua_pushvalue(gL, -6); // stplayr
|
||||
lua_pushvalue(gL, -6); // lt_ticker
|
||||
lua_pushvalue(gL, -6); // lt_endtime
|
||||
LUA_Call(gL, 4, 0, 1);
|
||||
}
|
||||
|
||||
lua_settop(gL, 0);
|
||||
hud_running = false;
|
||||
}
|
||||
|
||||
void LUAh_IntermissionHUD(huddrawlist_h list)
|
||||
{
|
||||
if (!gL || !(hudAvailable & (1<<hudhook_intermission)))
|
||||
return;
|
||||
|
||||
lua_pushlightuserdata(gL, list);
|
||||
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
|
||||
|
||||
hud_running = true;
|
||||
lua_settop(gL, 0);
|
||||
|
||||
lua_pushcfunction(gL, LUA_GetErrorMessage);
|
||||
|
||||
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_rawgeti(gL, -1, 2+hudhook_intermission); // HUD[4] = rendering funcs
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
|
||||
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
|
||||
I_Assert(lua_istable(gL, -1));
|
||||
lua_remove(gL, -3); // pop HUD
|
||||
lua_pushnil(gL);
|
||||
while (lua_next(gL, -3) != 0) {
|
||||
lua_pushvalue(gL, -3); // graphics library (HUD[1])
|
||||
LUA_Call(gL, 1, 0, 1);
|
||||
}
|
||||
lua_settop(gL, 0);
|
||||
hud_running = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ typedef struct drawitem_s {
|
|||
fixed_t sy;
|
||||
INT32 num;
|
||||
INT32 digits;
|
||||
const char *str;
|
||||
size_t stroffset; // offset into strbuf to get str
|
||||
UINT16 color;
|
||||
UINT8 strength;
|
||||
INT32 align;
|
||||
|
|
@ -129,6 +129,10 @@ void LUA_HUD_DestroyDrawList(huddrawlist_h list)
|
|||
{
|
||||
Z_Free(list->items);
|
||||
}
|
||||
if (list->strbuf)
|
||||
{
|
||||
Z_Free(list->strbuf);
|
||||
}
|
||||
Z_Free(list);
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +160,7 @@ static size_t AllocateDrawItem(huddrawlist_h list)
|
|||
// copy string to list's internal string buffer
|
||||
// lua can deallocate the string before we get to use it, so it's important to
|
||||
// keep our own copy
|
||||
static const char *CopyString(huddrawlist_h list, const char* str)
|
||||
static size_t CopyString(huddrawlist_h list, const char* str)
|
||||
{
|
||||
size_t lenstr;
|
||||
|
||||
|
|
@ -168,10 +172,13 @@ static const char *CopyString(huddrawlist_h list, const char* str)
|
|||
else list->strbuf_capacity *= 2;
|
||||
list->strbuf = (char*) Z_ReallocAlign(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL, 8);
|
||||
}
|
||||
const char *result = (const char *) &list->strbuf[list->strbuf_len];
|
||||
strncpy(&list->strbuf[list->strbuf_len], str, lenstr + 1);
|
||||
list->strbuf_len += lenstr + 1;
|
||||
return result;
|
||||
|
||||
{
|
||||
size_t old_len = list->strbuf_len;
|
||||
strncpy(&list->strbuf[old_len], str, lenstr + 1);
|
||||
list->strbuf_len += lenstr + 1;
|
||||
return old_len;
|
||||
}
|
||||
}
|
||||
|
||||
void LUA_HUD_AddDraw(
|
||||
|
|
@ -325,7 +332,7 @@ void LUA_HUD_AddDrawString(
|
|||
item->type = DI_DrawString;
|
||||
item->x = x;
|
||||
item->y = y;
|
||||
item->str = CopyString(list, str);
|
||||
item->stroffset = CopyString(list, str);
|
||||
item->flags = flags;
|
||||
item->align = align;
|
||||
}
|
||||
|
|
@ -360,7 +367,7 @@ void LUA_HUD_AddDrawTitleCardString(
|
|||
item->x = x;
|
||||
item->y = y;
|
||||
item->flags = flags;
|
||||
item->str = CopyString(list, str);
|
||||
item->stroffset = CopyString(list, str);
|
||||
item->bossmode = bossmode;
|
||||
item->timer = timer;
|
||||
item->threshold = threshold;
|
||||
|
|
@ -379,8 +386,8 @@ void LUA_HUD_AddDrawKartString(
|
|||
item->type = DI_DrawKartString;
|
||||
item->x = x;
|
||||
item->y = y;
|
||||
item->stroffset = CopyString(list, str);
|
||||
item->flags = flags;
|
||||
item->str = CopyString(list, str);
|
||||
}
|
||||
|
||||
void LUA_HUD_DrawList(huddrawlist_h list)
|
||||
|
|
@ -394,6 +401,7 @@ void LUA_HUD_DrawList(huddrawlist_h list)
|
|||
for (i = 0; i < list->items_len; i++)
|
||||
{
|
||||
drawitem_t *item = &list->items[i];
|
||||
const char *itemstr = &list->strbuf[item->stroffset];
|
||||
|
||||
switch (item->type)
|
||||
{
|
||||
|
|
@ -423,33 +431,33 @@ void LUA_HUD_DrawList(huddrawlist_h list)
|
|||
{
|
||||
// hu_font
|
||||
case align_left:
|
||||
V_DrawString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
case align_center:
|
||||
V_DrawCenteredString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawCenteredString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
case align_right:
|
||||
V_DrawRightAlignedString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawRightAlignedString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
// hu_font, 0.5x scale
|
||||
case align_small:
|
||||
V_DrawSmallString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawSmallString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
case align_smallcenter:
|
||||
V_DrawCenteredSmallString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawCenteredSmallString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
case align_smallright:
|
||||
V_DrawRightAlignedSmallString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawRightAlignedSmallString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
// tny_font
|
||||
case align_thin:
|
||||
V_DrawThinString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawThinString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
case align_thincenter:
|
||||
V_DrawCenteredThinString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawCenteredThinString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
case align_thinright:
|
||||
V_DrawRightAlignedThinString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawRightAlignedThinString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -457,10 +465,10 @@ void LUA_HUD_DrawList(huddrawlist_h list)
|
|||
V_DrawFadeScreen(item->color, item->strength);
|
||||
break;
|
||||
case DI_DrawTitleCardString:
|
||||
V_DrawTitleCardString(item->x, item->y, item->str, item->flags, item->bossmode, item->timer, item->threshold);
|
||||
V_DrawTitleCardString(item->x, item->y, itemstr, item->flags, item->bossmode, item->timer, item->threshold);
|
||||
break;
|
||||
case DI_DrawKartString:
|
||||
V_DrawKartString(item->x, item->y, item->flags, item->str);
|
||||
V_DrawKartString(item->x, item->y, item->flags, itemstr);
|
||||
break;
|
||||
default:
|
||||
I_Error("can't draw draw list item: invalid draw list item type");
|
||||
|
|
|
|||
|
|
@ -1687,7 +1687,7 @@ void LUA_Archive(UINT8 **p)
|
|||
|
||||
WRITEUINT32(*p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
|
||||
|
||||
LUAh_NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode
|
||||
LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode
|
||||
}
|
||||
|
||||
ArchiveTables(p);
|
||||
|
|
@ -1726,7 +1726,7 @@ void LUA_UnArchive(UINT8 **p)
|
|||
}
|
||||
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
|
||||
|
||||
LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode
|
||||
LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode
|
||||
}
|
||||
|
||||
UnArchiveTables(p);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
|
|||
void LUA_CVarChanged(void *cvar); // lua_consolelib.c
|
||||
int Lua_optoption(lua_State *L, int narg,
|
||||
const char *def, const char *const lst[]);
|
||||
void LUAh_NetArchiveHook(lua_CFunction archFunc);
|
||||
void LUA_HookNetArchive(lua_CFunction archFunc);
|
||||
|
||||
void LUA_PushTaggableObjectArray
|
||||
( lua_State *L,
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedInt(fixed_t a)
|
|||
*/
|
||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedDiv(fixed_t a, fixed_t b)
|
||||
{
|
||||
if ((abs(a) >> (FRACBITS-2)) >= abs(b))
|
||||
if ((abs(a / (FRACUNIT/4))) >= abs(b))
|
||||
return (a^b) < 0 ? INT32_MIN : INT32_MAX;
|
||||
|
||||
return FixedDiv2(a, b);
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
hyudoro.c
|
||||
shrink.c
|
||||
|
|
|
|||
782
src/objects/shrink.c
Normal file
782
src/objects/shrink.c
Normal file
|
|
@ -0,0 +1,782 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 2022 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file shrink.c
|
||||
/// \brief Shrink laser item code.
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_main.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../g_game.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../k_waypoint.h"
|
||||
|
||||
//
|
||||
// ███████╗██╗██╗░░██╗███╗░░░███╗███████╗
|
||||
// ██╔════╝██║╚██╗██╔╝████╗░████║██╔════╝
|
||||
// █████╗░░██║░╚███╔╝░██╔████╔██║█████╗░░
|
||||
// ██╔══╝░░██║░██╔██╗░██║╚██╔╝██║██╔══╝░░
|
||||
// ██║░░░░░██║██╔╝╚██╗██║░╚═╝░██║███████╗
|
||||
// ╚═╝░░░░░╚═╝╚═╝░░╚═╝╚═╝░░░░░╚═╝╚══════╝
|
||||
//
|
||||
// vertical flip
|
||||
//
|
||||
|
||||
#define POHBEE_HOVER (256 << FRACBITS)
|
||||
#define POHBEE_SPEED (128 << FRACBITS)
|
||||
#define POHBEE_TIME (30 * TICRATE)
|
||||
#define POHBEE_DIST (4096 << FRACBITS)
|
||||
|
||||
#define GUN_SWING (ANGLE_90 - ANG10)
|
||||
#define GUN_SWINGTIME (4 * TICRATE)
|
||||
|
||||
#define CHAIN_SIZE (52)
|
||||
|
||||
#define EXTRA_FOR_FIRST (7)
|
||||
|
||||
enum
|
||||
{
|
||||
POHBEE_MODE_SPAWN,
|
||||
POHBEE_MODE_ACT,
|
||||
POHBEE_MODE_DESPAWN,
|
||||
};
|
||||
|
||||
#define pohbee_mode(o) ((o)->cusval)
|
||||
#define pohbee_timer(o) ((o)->reactiontime)
|
||||
#define pohbee_waypoint_cur(o) ((o)->extravalue1)
|
||||
#define pohbee_waypoint_dest(o) ((o)->extravalue2)
|
||||
#define pohbee_height(o) ((o)->movefactor)
|
||||
|
||||
#define pohbee_owner(o) ((o)->target)
|
||||
#define pohbee_guns(o) ((o)->hnext)
|
||||
|
||||
#define gun_offset(o) ((o)->movecount)
|
||||
#define gun_numsegs(o) ((o)->extravalue1)
|
||||
|
||||
#define gun_pohbee(o) ((o)->target)
|
||||
#define gun_laser(o) ((o)->tracer)
|
||||
#define gun_chains(o) ((o)->hprev)
|
||||
|
||||
#define chain_index(o) ((o)->extravalue1)
|
||||
|
||||
enum
|
||||
{
|
||||
LASER_SHRINK,
|
||||
LASER_GROW,
|
||||
};
|
||||
|
||||
static skincolornum_t ShrinkLaserColor(mobj_t *pohbee)
|
||||
{
|
||||
UINT8 laserState = LASER_SHRINK;
|
||||
player_t *owner = NULL;
|
||||
|
||||
if (pohbee_owner(pohbee) != NULL && P_MobjWasRemoved(pohbee_owner(pohbee)) == false)
|
||||
{
|
||||
owner = pohbee_owner(pohbee)->player;
|
||||
}
|
||||
|
||||
if (owner != NULL && P_IsDisplayPlayer(owner) == true)
|
||||
{
|
||||
laserState = LASER_GROW;
|
||||
|
||||
if (r_splitscreen > 0 && (leveltime & 1))
|
||||
{
|
||||
// TODO: make this properly screen dependent,
|
||||
// instead of flashing.
|
||||
laserState = LASER_SHRINK;
|
||||
}
|
||||
}
|
||||
|
||||
switch (laserState)
|
||||
{
|
||||
default:
|
||||
case LASER_SHRINK:
|
||||
return SKINCOLOR_KETCHUP;
|
||||
|
||||
case LASER_GROW:
|
||||
return SKINCOLOR_SAPPHIRE;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean ShrinkLaserActive(mobj_t *pohbee)
|
||||
{
|
||||
return (pohbee_mode(pohbee) == POHBEE_MODE_ACT);
|
||||
}
|
||||
|
||||
static void PohbeeMoveTo(mobj_t *pohbee, fixed_t destx, fixed_t desty, fixed_t destz)
|
||||
{
|
||||
pohbee->momx = destx - pohbee->x;
|
||||
pohbee->momy = desty - pohbee->y;
|
||||
pohbee->momz = destz - pohbee->z;
|
||||
}
|
||||
|
||||
static fixed_t GenericDistance(
|
||||
fixed_t curx, fixed_t cury, fixed_t curz,
|
||||
fixed_t destx, fixed_t desty, fixed_t destz)
|
||||
{
|
||||
return P_AproxDistance(P_AproxDistance(destx - curx, desty - cury), destz - curz);
|
||||
}
|
||||
|
||||
static fixed_t PohbeeWaypointZ(mobj_t *pohbee, mobj_t *dest)
|
||||
{
|
||||
return dest->z + (pohbee_height(pohbee) + FixedMul(POHBEE_HOVER, mapobjectscale) * P_MobjFlip(dest));
|
||||
}
|
||||
|
||||
static void PohbeeSpawn(mobj_t *pohbee)
|
||||
{
|
||||
waypoint_t *curWaypoint = NULL;
|
||||
waypoint_t *destWaypoint = NULL;
|
||||
|
||||
fixed_t distLeft = INT32_MAX;
|
||||
fixed_t newX = pohbee->x;
|
||||
fixed_t newY = pohbee->y;
|
||||
fixed_t newZ = pohbee->z;
|
||||
|
||||
boolean finalize = false;
|
||||
|
||||
const boolean useshortcuts = false;
|
||||
const boolean huntbackwards = false;
|
||||
boolean pathfindsuccess = false;
|
||||
path_t pathtofinish = {0};
|
||||
size_t pathIndex = 0;
|
||||
|
||||
curWaypoint = K_GetWaypointFromIndex((size_t)pohbee_waypoint_cur(pohbee));
|
||||
destWaypoint = K_GetWaypointFromIndex((size_t)pohbee_waypoint_dest(pohbee));
|
||||
|
||||
if (curWaypoint == NULL || destWaypoint == NULL)
|
||||
{
|
||||
// Waypoints aren't valid.
|
||||
// Just transition into the next state.
|
||||
pohbee_mode(pohbee) = POHBEE_MODE_ACT;
|
||||
return;
|
||||
}
|
||||
|
||||
distLeft = FixedMul(POHBEE_SPEED, mapobjectscale);
|
||||
|
||||
while (distLeft > 0)
|
||||
{
|
||||
fixed_t wpX = curWaypoint->mobj->x;
|
||||
fixed_t wpY = curWaypoint->mobj->y;
|
||||
fixed_t wpZ = PohbeeWaypointZ(pohbee, curWaypoint->mobj);
|
||||
|
||||
fixed_t distToNext = GenericDistance(
|
||||
newX, newY, newZ,
|
||||
wpX, wpY, wpZ
|
||||
);
|
||||
|
||||
if (distToNext > distLeft)
|
||||
{
|
||||
// Only made it partially there.
|
||||
newX += FixedMul(FixedDiv(wpX - newX, distToNext), distLeft);
|
||||
newY += FixedMul(FixedDiv(wpY - newY, distToNext), distLeft);
|
||||
newZ += FixedMul(FixedDiv(wpZ - newZ, distToNext), distLeft);
|
||||
|
||||
distLeft = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close enough to the next waypoint,
|
||||
// move there and remove the distance.
|
||||
newX = wpX;
|
||||
newY = wpY;
|
||||
newZ = wpZ;
|
||||
|
||||
distLeft -= distToNext;
|
||||
|
||||
if (curWaypoint == destWaypoint)
|
||||
{
|
||||
// Reached the end.
|
||||
finalize = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create waypoint path to our destination.
|
||||
// Crazy over-engineered, just to catch when
|
||||
// waypoints are insanely close to each other :P
|
||||
if (pathfindsuccess == false)
|
||||
{
|
||||
pathfindsuccess = K_PathfindToWaypoint(
|
||||
curWaypoint, destWaypoint,
|
||||
&pathtofinish,
|
||||
useshortcuts, huntbackwards
|
||||
);
|
||||
|
||||
if (pathfindsuccess == false)
|
||||
{
|
||||
// Path isn't valid.
|
||||
// Just transition into the next state.
|
||||
finalize = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pathIndex++;
|
||||
|
||||
if (pathIndex >= pathtofinish.numnodes)
|
||||
{
|
||||
// Successfully reached the end of the path.
|
||||
finalize = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now moving to the next waypoint.
|
||||
curWaypoint = (waypoint_t *)pathtofinish.array[pathIndex].nodedata;
|
||||
pohbee_waypoint_cur(pohbee) = (INT32)K_GetWaypointHeapIndex(curWaypoint);
|
||||
}
|
||||
}
|
||||
|
||||
PohbeeMoveTo(pohbee, newX, newY, newZ);
|
||||
pohbee->angle = K_MomentumAngle(pohbee);
|
||||
|
||||
if (finalize == true)
|
||||
{
|
||||
// Move to next state
|
||||
pohbee_mode(pohbee) = POHBEE_MODE_ACT;
|
||||
}
|
||||
|
||||
if (pathfindsuccess == true)
|
||||
{
|
||||
Z_Free(pathtofinish.array);
|
||||
}
|
||||
}
|
||||
|
||||
static void PohbeeAct(mobj_t *pohbee)
|
||||
{
|
||||
pohbee_timer(pohbee)--;
|
||||
|
||||
if (pohbee_timer(pohbee) <= 0)
|
||||
{
|
||||
// Move to next state
|
||||
pohbee_mode(pohbee) = POHBEE_MODE_DESPAWN;
|
||||
pohbee->fuse = 5*TICRATE;
|
||||
}
|
||||
}
|
||||
|
||||
static void PohbeeDespawn(mobj_t *pohbee)
|
||||
{
|
||||
pohbee->momz = 16 * pohbee->scale * P_MobjFlip(pohbee);
|
||||
}
|
||||
|
||||
static void DoGunSwing(mobj_t *gun, mobj_t *pohbee)
|
||||
{
|
||||
const angle_t angle = gun->angle + ANGLE_90;
|
||||
const tic_t swingTimer = leveltime + gun_offset(gun);
|
||||
|
||||
const angle_t swingAmt = swingTimer * (ANGLE_MAX / GUN_SWINGTIME);
|
||||
const fixed_t swingCos = FINECOSINE(swingAmt >> ANGLETOFINESHIFT);
|
||||
|
||||
const angle_t pitch = -ANGLE_90 + FixedMul(swingCos, GUN_SWING);
|
||||
const fixed_t dist = gun_numsegs(gun) * CHAIN_SIZE * gun->scale;
|
||||
|
||||
fixed_t offsetX = FixedMul(
|
||||
dist, FixedMul(
|
||||
FINECOSINE(angle >> ANGLETOFINESHIFT),
|
||||
FINECOSINE(pitch >> ANGLETOFINESHIFT)
|
||||
)
|
||||
);
|
||||
|
||||
fixed_t offsetY = FixedMul(
|
||||
dist, FixedMul(
|
||||
FINESINE(angle >> ANGLETOFINESHIFT),
|
||||
FINECOSINE(pitch >> ANGLETOFINESHIFT)
|
||||
)
|
||||
);
|
||||
|
||||
fixed_t offsetZ = FixedMul(
|
||||
dist, FINESINE(pitch >> ANGLETOFINESHIFT)
|
||||
);
|
||||
|
||||
PohbeeMoveTo(gun, pohbee->x + offsetX, pohbee->y + offsetY, pohbee->z + offsetZ);
|
||||
}
|
||||
|
||||
static void ShrinkLaserThinker(mobj_t *pohbee, mobj_t *gun, mobj_t *laser)
|
||||
{
|
||||
const fixed_t gunX = gun->x + gun->momx;
|
||||
const fixed_t gunY = gun->y + gun->momy;
|
||||
const fixed_t gunZ = P_GetMobjFeet(gun) + gun->momz;
|
||||
|
||||
PohbeeMoveTo(laser, gunX, gunY, gun->floorz);
|
||||
|
||||
if (ShrinkLaserActive(pohbee) == true)
|
||||
{
|
||||
mobj_t *particle = NULL;
|
||||
|
||||
laser->renderflags &= ~RF_DONTDRAW;
|
||||
laser->color = gun->color;
|
||||
|
||||
if (leveltime & 1)
|
||||
{
|
||||
laser->spritexscale = 5*FRACUNIT/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
laser->spritexscale = FRACUNIT;
|
||||
}
|
||||
|
||||
laser->spriteyscale = FixedDiv(FixedDiv(gunZ - gun->floorz, mapobjectscale), laser->info->height);
|
||||
|
||||
particle = P_SpawnMobjFromMobj(
|
||||
laser,
|
||||
P_RandomRange(-16, 16) * FRACUNIT,
|
||||
P_RandomRange(-16, 16) * FRACUNIT,
|
||||
0,
|
||||
MT_SHRINK_PARTICLE
|
||||
);
|
||||
|
||||
P_SetTarget(&gun_pohbee(particle), pohbee);
|
||||
|
||||
particle->color = laser->color;
|
||||
|
||||
P_SetScale(particle, particle->scale * 2);
|
||||
particle->destscale = 0;
|
||||
|
||||
//particle->momz = 2 * particle->scale * P_MobjFlip(particle);
|
||||
}
|
||||
else
|
||||
{
|
||||
laser->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
static void DoGunChains(mobj_t *gun, mobj_t *pohbee)
|
||||
{
|
||||
const fixed_t gunX = gun->x + gun->momx;
|
||||
const fixed_t gunY = gun->y + gun->momy;
|
||||
const fixed_t gunZ = P_GetMobjHead(gun) + gun->momz;
|
||||
|
||||
const fixed_t beeX = pohbee->x + pohbee->momx;
|
||||
const fixed_t beeY = pohbee->y + pohbee->momy;
|
||||
const fixed_t beeZ = P_GetMobjFeet(pohbee) + pohbee->momz;
|
||||
|
||||
const fixed_t offsetX = (beeX - gunX) / gun_numsegs(gun);
|
||||
const fixed_t offsetY = (beeY - gunY) / gun_numsegs(gun);
|
||||
const fixed_t offsetZ = (beeZ - gunZ) / gun_numsegs(gun);
|
||||
|
||||
mobj_t *chain = NULL;
|
||||
|
||||
fixed_t curX = gunX + (offsetX / 2);
|
||||
fixed_t curY = gunY + (offsetY / 2);
|
||||
fixed_t curZ = gunZ + (offsetZ / 2);
|
||||
|
||||
chain = gun_chains(gun);
|
||||
while (chain != NULL && P_MobjWasRemoved(chain) == false)
|
||||
{
|
||||
PohbeeMoveTo(chain, curX, curY, curZ);
|
||||
|
||||
curX += offsetX;
|
||||
curY += offsetY;
|
||||
curZ += offsetZ;
|
||||
|
||||
chain = gun_chains(chain);
|
||||
}
|
||||
}
|
||||
|
||||
static void ShrinkGunThinker(mobj_t *gun)
|
||||
{
|
||||
mobj_t *pohbee = gun_pohbee(gun);
|
||||
|
||||
if (pohbee == NULL || P_MobjWasRemoved(pohbee) == true)
|
||||
{
|
||||
P_RemoveMobj(gun);
|
||||
return;
|
||||
}
|
||||
|
||||
gun->angle = pohbee->angle;
|
||||
gun->color = ShrinkLaserColor(pohbee);
|
||||
|
||||
DoGunSwing(gun, pohbee);
|
||||
|
||||
if (gun_laser(gun) != NULL && P_MobjWasRemoved(gun_laser(gun)) == false)
|
||||
{
|
||||
ShrinkLaserThinker(pohbee, gun, gun_laser(gun));
|
||||
}
|
||||
|
||||
DoGunChains(gun, pohbee);
|
||||
}
|
||||
|
||||
void Obj_PohbeeThinker(mobj_t *pohbee)
|
||||
{
|
||||
mobj_t *gun = NULL;
|
||||
|
||||
pohbee->momx = pohbee->momy = pohbee->momz = 0;
|
||||
|
||||
switch (pohbee_mode(pohbee))
|
||||
{
|
||||
case POHBEE_MODE_SPAWN:
|
||||
PohbeeSpawn(pohbee);
|
||||
break;
|
||||
|
||||
case POHBEE_MODE_ACT:
|
||||
PohbeeAct(pohbee);
|
||||
break;
|
||||
|
||||
case POHBEE_MODE_DESPAWN:
|
||||
PohbeeDespawn(pohbee);
|
||||
break;
|
||||
|
||||
default:
|
||||
// failsafe
|
||||
pohbee_mode(pohbee) = POHBEE_MODE_SPAWN;
|
||||
break;
|
||||
}
|
||||
|
||||
gun = pohbee_guns(pohbee);
|
||||
while (gun != NULL && P_MobjWasRemoved(gun) == false)
|
||||
{
|
||||
ShrinkGunThinker(gun);
|
||||
gun = pohbee_guns(gun);
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_PohbeeRemoved(mobj_t *pohbee)
|
||||
{
|
||||
mobj_t *gun = pohbee_guns(pohbee);
|
||||
|
||||
while (gun != NULL && P_MobjWasRemoved(gun) == false)
|
||||
{
|
||||
mobj_t *nextGun = pohbee_guns(gun);
|
||||
P_RemoveMobj(gun);
|
||||
gun = nextGun;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_ShrinkGunRemoved(mobj_t *gun)
|
||||
{
|
||||
mobj_t *chain = NULL;
|
||||
|
||||
if (gun_laser(gun) != NULL && P_MobjWasRemoved(gun_laser(gun)) == false)
|
||||
{
|
||||
P_RemoveMobj(gun_laser(gun));
|
||||
}
|
||||
|
||||
chain = gun_chains(gun);
|
||||
while (chain != NULL && P_MobjWasRemoved(chain) == false)
|
||||
{
|
||||
mobj_t *nextChain = gun_chains(chain);
|
||||
P_RemoveMobj(chain);
|
||||
chain = nextChain;
|
||||
}
|
||||
}
|
||||
|
||||
boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim)
|
||||
{
|
||||
mobj_t *pohbee = gun_pohbee(gun);
|
||||
mobj_t *owner = NULL;
|
||||
INT32 prevTimer = 0;
|
||||
|
||||
if (pohbee == NULL || P_MobjWasRemoved(pohbee) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ShrinkLaserActive(pohbee) == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (victim->player->shrinkLaserDelay > 0)
|
||||
{
|
||||
victim->player->shrinkLaserDelay = TICRATE;
|
||||
return true;
|
||||
}
|
||||
|
||||
victim->player->shrinkLaserDelay = TICRATE;
|
||||
|
||||
owner = pohbee_owner(pohbee);
|
||||
prevTimer = victim->player->growshrinktimer;
|
||||
|
||||
if (owner != NULL && victim == owner)
|
||||
{
|
||||
// Belongs to us. Give us Grow!
|
||||
if (prevTimer < 0)
|
||||
{
|
||||
// Take away Shrink.
|
||||
K_RemoveGrowShrink(victim->player);
|
||||
}
|
||||
else
|
||||
{
|
||||
victim->player->growshrinktimer += 3*TICRATE;
|
||||
S_StartSound(victim, sfx_kc5a);
|
||||
|
||||
if (prevTimer <= 0)
|
||||
{
|
||||
victim->scalespeed = mapobjectscale/TICRATE;
|
||||
victim->destscale = FixedMul(mapobjectscale, GROW_SCALE);
|
||||
|
||||
if (K_PlayerShrinkCheat(victim->player) == true)
|
||||
{
|
||||
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
if (victim->player->invincibilitytimer > 0)
|
||||
{
|
||||
; // invincibility has priority in P_RestoreMusic, no point in starting here
|
||||
}
|
||||
else if (P_IsLocalPlayer(victim->player) == true)
|
||||
{
|
||||
S_ChangeMusicSpecial("kgrow");
|
||||
}
|
||||
else //used to be "if (P_IsDisplayPlayer(victim->player) == false)"
|
||||
{
|
||||
S_StartSound(victim, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow));
|
||||
}
|
||||
|
||||
P_RestoreMusic(victim->player);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prevTimer > 0)
|
||||
{
|
||||
// Take away Grow.
|
||||
K_RemoveGrowShrink(victim->player);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start shrinking!
|
||||
victim->player->growshrinktimer -= 5*TICRATE;
|
||||
S_StartSound(victim, sfx_kc59);
|
||||
|
||||
if (prevTimer >= 0)
|
||||
{
|
||||
//K_DropItems(victim->player);
|
||||
|
||||
victim->scalespeed = mapobjectscale/TICRATE;
|
||||
victim->destscale = FixedMul(mapobjectscale, SHRINK_SCALE);
|
||||
|
||||
if (K_PlayerShrinkCheat(victim->player) == true)
|
||||
{
|
||||
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static waypoint_t *GetPohbeeWaypoint(waypoint_t *anchor, const UINT32 traveldist, const boolean huntbackwards)
|
||||
{
|
||||
const boolean useshortcuts = false;
|
||||
boolean pathfindsuccess = false;
|
||||
path_t pathtofinish = {0};
|
||||
waypoint_t *ret = NULL;
|
||||
|
||||
pathfindsuccess = K_PathfindThruCircuitSpawnable(
|
||||
anchor, traveldist,
|
||||
&pathtofinish,
|
||||
useshortcuts, huntbackwards
|
||||
);
|
||||
|
||||
if (pathfindsuccess == true)
|
||||
{
|
||||
ret = (waypoint_t *)pathtofinish.array[ pathtofinish.numnodes - 1 ].nodedata;
|
||||
Z_Free(pathtofinish.array);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = anchor;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static waypoint_t *GetPohbeeStart(waypoint_t *anchor)
|
||||
{
|
||||
const UINT32 traveldist = FixedMul(POHBEE_DIST >> 1, mapobjectscale) / FRACUNIT;
|
||||
const boolean huntbackwards = true;
|
||||
|
||||
return GetPohbeeWaypoint(anchor, traveldist, huntbackwards);
|
||||
}
|
||||
|
||||
static waypoint_t *GetPohbeeEnd(waypoint_t *anchor)
|
||||
{
|
||||
const UINT32 traveldist = FixedMul(POHBEE_DIST, mapobjectscale) / FRACUNIT;
|
||||
const boolean huntbackwards = false;
|
||||
|
||||
return GetPohbeeWaypoint(anchor, traveldist, huntbackwards);
|
||||
}
|
||||
|
||||
static void CreatePohbee(player_t *owner, waypoint_t *start, waypoint_t *end, UINT8 numLasers)
|
||||
{
|
||||
mobj_t *pohbee = NULL;
|
||||
|
||||
fixed_t size = 0;
|
||||
INT32 baseSegs = INT32_MAX;
|
||||
INT32 segVal = INT32_MAX;
|
||||
mobj_t *prevGun = NULL;
|
||||
|
||||
size_t i, j;
|
||||
|
||||
if (owner == NULL || owner->mo == NULL || P_MobjWasRemoved(owner->mo) == true
|
||||
|| start == NULL || end == NULL
|
||||
|| numLasers == 0)
|
||||
{
|
||||
// Invalid inputs
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate number of chain segments added per laser.
|
||||
size = FixedMul(end->mobj->radius, 3*FRACUNIT/2);
|
||||
segVal = max(1, 1 + ((size / start->mobj->scale) / CHAIN_SIZE) / numLasers);
|
||||
baseSegs = segVal * numLasers;
|
||||
|
||||
// Valid spawning conditions,
|
||||
// we can start creating each individual part.
|
||||
pohbee = P_SpawnMobjFromMobj(start->mobj, 0, 0, (baseSegs * CHAIN_SIZE * FRACUNIT) + POHBEE_HOVER * 3, MT_SHRINK_POHBEE);
|
||||
P_SetTarget(&pohbee_owner(pohbee), owner->mo);
|
||||
|
||||
pohbee_mode(pohbee) = POHBEE_MODE_SPAWN;
|
||||
pohbee_timer(pohbee) = POHBEE_TIME;
|
||||
pohbee_height(pohbee) = size;
|
||||
|
||||
pohbee_waypoint_cur(pohbee) = (INT32)K_GetWaypointHeapIndex(start);
|
||||
pohbee_waypoint_dest(pohbee) = (INT32)K_GetWaypointHeapIndex(end);
|
||||
|
||||
prevGun = pohbee;
|
||||
|
||||
for (i = 0; i < numLasers; i++)
|
||||
{
|
||||
const UINT8 numSegs = segVal * (i + 1);
|
||||
|
||||
mobj_t *gun = P_SpawnMobjFromMobj(pohbee, 0, 0, 0, MT_SHRINK_GUN);
|
||||
mobj_t *laser = NULL;
|
||||
mobj_t *prevChain = NULL;
|
||||
|
||||
P_SetTarget(&gun_pohbee(gun), pohbee);
|
||||
P_SetTarget(&pohbee_guns(prevGun), gun);
|
||||
|
||||
gun_numsegs(gun) = numSegs;
|
||||
gun_offset(gun) = P_RandomKey(GUN_SWINGTIME);
|
||||
|
||||
laser = P_SpawnMobjFromMobj(gun, 0, 0, 0, MT_SHRINK_LASER);
|
||||
P_SetTarget(&gun_laser(gun), laser);
|
||||
|
||||
prevChain = gun;
|
||||
for (j = 0; j < numSegs; j++)
|
||||
{
|
||||
mobj_t *chain = P_SpawnMobjFromMobj(gun, 0, 0, 0, MT_SHRINK_CHAIN);
|
||||
|
||||
P_SetTarget(&gun_chains(prevChain), chain);
|
||||
chain_index(chain) = j;
|
||||
|
||||
prevChain = chain;
|
||||
}
|
||||
|
||||
prevGun = gun;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_CreateShrinkPohbees(player_t *owner)
|
||||
{
|
||||
UINT8 ownerPos = 1;
|
||||
|
||||
struct {
|
||||
waypoint_t *start;
|
||||
waypoint_t *end;
|
||||
UINT8 lasers;
|
||||
boolean first;
|
||||
} pohbees[MAXPLAYERS];
|
||||
size_t numPohbees = 0;
|
||||
|
||||
size_t i, j;
|
||||
|
||||
if (owner == NULL || owner->mo == NULL || P_MobjWasRemoved(owner->mo) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ownerPos = owner->position;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
waypoint_t *endWaypoint = NULL;
|
||||
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
// Not valid.
|
||||
continue;
|
||||
}
|
||||
|
||||
player = &players[i];
|
||||
|
||||
if (player->spectator == true)
|
||||
{
|
||||
// Not playing.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->position > ownerPos)
|
||||
{
|
||||
// Too far behind.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->nextwaypoint == NULL)
|
||||
{
|
||||
// No waypoint?
|
||||
continue;
|
||||
}
|
||||
|
||||
endWaypoint = GetPohbeeEnd(player->nextwaypoint);
|
||||
|
||||
for (j = 0; j < numPohbees; j++)
|
||||
{
|
||||
if (pohbees[j].end == endWaypoint)
|
||||
{
|
||||
// Increment laser count for the already existing poh-bee,
|
||||
// if another one would occupy the same space.
|
||||
pohbees[j].lasers++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == numPohbees)
|
||||
{
|
||||
// Push a new poh-bee
|
||||
pohbees[j].start = GetPohbeeStart(player->nextwaypoint);
|
||||
pohbees[j].end = endWaypoint;
|
||||
pohbees[j].lasers = 1;
|
||||
|
||||
if (player->position == 1)
|
||||
{
|
||||
pohbees[j].first = true;
|
||||
}
|
||||
|
||||
numPohbees++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numPohbees; i++)
|
||||
{
|
||||
CreatePohbee(owner, pohbees[i].start, pohbees[i].end, pohbees[i].lasers);
|
||||
|
||||
if (pohbees[i].first == true)
|
||||
{
|
||||
// Add a chain of extra ones for 1st place.
|
||||
waypoint_t *prev = pohbees[i].end;
|
||||
|
||||
for (j = 0; j < EXTRA_FOR_FIRST; j++)
|
||||
{
|
||||
waypoint_t *new = GetPohbeeEnd(prev);
|
||||
CreatePohbee(owner, prev, new, 1);
|
||||
prev = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2474,7 +2474,7 @@ void A_LobShot(mobj_t *actor)
|
|||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2 >> 16;
|
||||
mobj_t *shot, *hitspot;
|
||||
mobj_t *shot;
|
||||
angle_t an;
|
||||
fixed_t z;
|
||||
fixed_t dist;
|
||||
|
|
@ -2502,11 +2502,6 @@ void A_LobShot(mobj_t *actor)
|
|||
shot->destscale = actor->scale;
|
||||
P_SetScale(shot, actor->scale);
|
||||
|
||||
// Keep track of where it's going to land
|
||||
hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL);
|
||||
hitspot->tics = airtime;
|
||||
P_SetTarget(&shot->tracer, hitspot);
|
||||
|
||||
P_SetTarget(&shot->target, actor); // where it came from
|
||||
|
||||
P_InitAngle(shot, actor->angle);
|
||||
|
|
@ -3142,20 +3137,18 @@ void A_SkullAttack(mobj_t *actor)
|
|||
actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90;
|
||||
else if (locvar1 == 3)
|
||||
{
|
||||
statenum_t oldspawnstate = mobjinfo[MT_NULL].spawnstate;
|
||||
UINT32 oldflags = mobjinfo[MT_NULL].flags;
|
||||
fixed_t oldradius = mobjinfo[MT_NULL].radius;
|
||||
fixed_t oldheight = mobjinfo[MT_NULL].height;
|
||||
mobj_t *check;
|
||||
statenum_t oldspawnstate = mobjinfo[MT_RAY].spawnstate;
|
||||
UINT32 oldflags = mobjinfo[MT_RAY].flags;
|
||||
fixed_t oldradius = mobjinfo[MT_RAY].radius;
|
||||
fixed_t oldheight = mobjinfo[MT_RAY].height;
|
||||
INT32 i, j;
|
||||
static INT32 k;/* static for (at least) GCC 9.1 weirdness */
|
||||
boolean allow;
|
||||
angle_t testang = 0;
|
||||
|
||||
mobjinfo[MT_NULL].spawnstate = S_INVISIBLE;
|
||||
mobjinfo[MT_NULL].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP;
|
||||
mobjinfo[MT_NULL].radius = mobjinfo[actor->type].radius;
|
||||
mobjinfo[MT_NULL].height = mobjinfo[actor->type].height;
|
||||
mobjinfo[MT_RAY].spawnstate = S_INVISIBLE;
|
||||
mobjinfo[MT_RAY].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP;
|
||||
mobjinfo[MT_RAY].radius = mobjinfo[actor->type].radius;
|
||||
mobjinfo[MT_RAY].height = mobjinfo[actor->type].height;
|
||||
|
||||
if (P_RandomChance(FRACUNIT/2)) // port priority 1?
|
||||
{
|
||||
|
|
@ -3168,15 +3161,12 @@ void A_SkullAttack(mobj_t *actor)
|
|||
j = 9;
|
||||
}
|
||||
|
||||
#define dostuff(q) check = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_NULL);\
|
||||
#define dostuff(q) \
|
||||
testang = actor->angle + ((i+(q))*ANG10);\
|
||||
allow = (P_TryMove(check,\
|
||||
P_ReturnThrustX(check, testang, dist + 2*actor->radius),\
|
||||
P_ReturnThrustY(check, testang, dist + 2*actor->radius),\
|
||||
true));\
|
||||
P_RemoveMobj(check);\
|
||||
if (allow)\
|
||||
break;
|
||||
if (P_CheckMove(actor,\
|
||||
P_ReturnThrustX(actor, testang, dist + 2*actor->radius),\
|
||||
P_ReturnThrustY(actor, testang, dist + 2*actor->radius),\
|
||||
true)) break;
|
||||
|
||||
if (P_RandomChance(FRACUNIT/2)) // port priority 2?
|
||||
{
|
||||
|
|
@ -3202,10 +3192,10 @@ void A_SkullAttack(mobj_t *actor)
|
|||
|
||||
#undef dostuff
|
||||
|
||||
mobjinfo[MT_NULL].spawnstate = oldspawnstate;
|
||||
mobjinfo[MT_NULL].flags = oldflags;
|
||||
mobjinfo[MT_NULL].radius = oldradius;
|
||||
mobjinfo[MT_NULL].height = oldheight;
|
||||
mobjinfo[MT_RAY].spawnstate = oldspawnstate;
|
||||
mobjinfo[MT_RAY].flags = oldflags;
|
||||
mobjinfo[MT_RAY].radius = oldradius;
|
||||
mobjinfo[MT_RAY].height = oldheight;
|
||||
}
|
||||
|
||||
an = actor->angle >> ANGLETOFINESHIFT;
|
||||
|
|
@ -3495,7 +3485,7 @@ void A_BossDeath(mobj_t *mo)
|
|||
}
|
||||
|
||||
bossjustdie:
|
||||
if (LUAh_BossDeath(mo))
|
||||
if (LUA_HookMobj(mo, MOBJ_HOOK(BossDeath)))
|
||||
return;
|
||||
else if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (special->flags & (MF_ENEMY|MF_BOSS) && special->flags2 & MF2_FRET)
|
||||
return;
|
||||
|
||||
if (LUAh_TouchSpecial(special, toucher) || P_MobjWasRemoved(special))
|
||||
if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special))
|
||||
return;
|
||||
|
||||
if ((special->flags & (MF_ENEMY|MF_BOSS)) && !(special->flags & MF_MISSILE))
|
||||
|
|
@ -973,7 +973,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
target->shadowscale = 0;
|
||||
}
|
||||
|
||||
if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target))
|
||||
if (LUA_HookMobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target))
|
||||
return;
|
||||
|
||||
//K_SetHitLagForObjects(target, inflictor, MAXHITLAGTICS, true);
|
||||
|
|
@ -1861,7 +1861,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
// Everything above here can't be forced.
|
||||
if (!metalrecording)
|
||||
{
|
||||
UINT8 shouldForce = LUAh_ShouldDamage(target, inflictor, source, damage, damagetype);
|
||||
UINT8 shouldForce = LUA_HookShouldDamage(target, inflictor, source, damage, damagetype);
|
||||
if (P_MobjWasRemoved(target))
|
||||
return (shouldForce == 1); // mobj was removed
|
||||
if (shouldForce == 1)
|
||||
|
|
@ -1887,7 +1887,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (!force && target->flags2 & MF2_FRET) // Currently flashing from being hit
|
||||
return false;
|
||||
|
||||
if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
return true;
|
||||
|
||||
if (target->health > 1)
|
||||
|
|
@ -1917,7 +1917,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (!P_KillPlayer(player, inflictor, source, damagetype))
|
||||
return false;
|
||||
}
|
||||
else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype))
|
||||
else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,6 +410,7 @@ boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing);
|
|||
boolean P_IsLineTripWire(const line_t *ld);
|
||||
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
|
||||
boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
|
||||
boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
|
||||
fixed_t P_BaseStepUp(void);
|
||||
fixed_t P_GetThingStepUp(mobj_t *thing);
|
||||
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
|
||||
|
|
|
|||
136
src/p_map.c
136
src/p_map.c
|
|
@ -32,6 +32,7 @@
|
|||
#include "hu_stuff.h" // SRB2kart
|
||||
#include "i_system.h" // SRB2kart
|
||||
#include "k_terrain.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
#include "r_splats.h"
|
||||
|
||||
|
|
@ -656,7 +657,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
}
|
||||
|
||||
{
|
||||
UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type
|
||||
UINT8 shouldCollide = LUA_Hook2Mobj(thing, tmthing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type
|
||||
if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing))
|
||||
return BMIT_CONTINUE; // one of them was removed???
|
||||
if (shouldCollide == 1)
|
||||
|
|
@ -664,7 +665,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
else if (shouldCollide == 2)
|
||||
return BMIT_CONTINUE; // force no collide
|
||||
|
||||
shouldCollide = LUAh_MobjMoveCollide(tmthing, thing); // checks hook for tmthing's type
|
||||
shouldCollide = LUA_Hook2Mobj(tmthing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for tmthing's type
|
||||
if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing))
|
||||
return BMIT_CONTINUE; // one of them was removed???
|
||||
if (shouldCollide == 1)
|
||||
|
|
@ -739,6 +740,81 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
|
||||
// SRB2kart 011617 - Colission[sic] code for kart items //{
|
||||
|
||||
if (thing->type == MT_SHRINK_GUN || thing->type == MT_SHRINK_PARTICLE)
|
||||
{
|
||||
if (tmthing->type != MT_PLAYER)
|
||||
{
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_SHRINK_GUN)
|
||||
{
|
||||
// Use special collision for the laser gun.
|
||||
// The laser sprite itself is just a visual,
|
||||
// the gun itself does the colliding for us.
|
||||
if (tmthing->z > thing->z)
|
||||
{
|
||||
return BMIT_CONTINUE; // overhead
|
||||
}
|
||||
|
||||
if (tmthing->z + tmthing->height < thing->floorz)
|
||||
{
|
||||
return BMIT_CONTINUE; // underneath
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
{
|
||||
return BMIT_CONTINUE; // overhead
|
||||
}
|
||||
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
{
|
||||
return BMIT_CONTINUE; // underneath
|
||||
}
|
||||
}
|
||||
|
||||
return Obj_ShrinkLaserCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||
}
|
||||
else if (tmthing->type == MT_SHRINK_GUN || tmthing->type == MT_SHRINK_PARTICLE)
|
||||
{
|
||||
if (thing->type != MT_PLAYER)
|
||||
{
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (tmthing->type == MT_SHRINK_GUN)
|
||||
{
|
||||
// Use special collision for the laser gun.
|
||||
// The laser sprite itself is just a visual,
|
||||
// the gun itself does the colliding for us.
|
||||
if (thing->z > tmthing->z)
|
||||
{
|
||||
return BMIT_CONTINUE; // overhead
|
||||
}
|
||||
|
||||
if (thing->z + thing->height < tmthing->floorz)
|
||||
{
|
||||
return BMIT_CONTINUE; // underneath
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
{
|
||||
return BMIT_CONTINUE; // overhead
|
||||
}
|
||||
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
{
|
||||
return BMIT_CONTINUE; // underneath
|
||||
}
|
||||
}
|
||||
|
||||
return Obj_ShrinkLaserCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||
}
|
||||
|
||||
if (tmthing->type == MT_SMK_ICEBLOCK)
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -1640,7 +1716,7 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld)
|
|||
blockingline = ld;
|
||||
|
||||
{
|
||||
UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, blockingline); // checks hook for thing's type
|
||||
UINT8 shouldCollide = LUA_HookMobjLineCollide(tmthing, blockingline); // checks hook for thing's type
|
||||
if (P_MobjWasRemoved(tmthing))
|
||||
return BMIT_CONTINUE; // one of them was removed???
|
||||
if (shouldCollide == 1)
|
||||
|
|
@ -2483,21 +2559,19 @@ fixed_t P_GetThingStepUp(mobj_t *thing)
|
|||
return maxstep;
|
||||
}
|
||||
|
||||
//
|
||||
// P_TryMove
|
||||
// Attempt to move to a new position.
|
||||
//
|
||||
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
||||
static boolean
|
||||
increment_move
|
||||
( mobj_t * thing,
|
||||
fixed_t x,
|
||||
fixed_t y,
|
||||
boolean allowdropoff,
|
||||
fixed_t * return_stairjank)
|
||||
{
|
||||
fixed_t tryx = thing->x;
|
||||
fixed_t tryy = thing->y;
|
||||
fixed_t oldx = tryx;
|
||||
fixed_t oldy = tryy;
|
||||
fixed_t radius = thing->radius;
|
||||
fixed_t thingtop;
|
||||
fixed_t startingonground = P_IsObjectOnGround(thing);
|
||||
fixed_t stairjank = 0;
|
||||
pslope_t *oldslope = thing->standingslope;
|
||||
floatok = false;
|
||||
|
||||
// reset this to 0 at the start of each trymove call as it's only used here
|
||||
|
|
@ -2643,7 +2717,45 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
}
|
||||
} while (tryx != x || tryy != y);
|
||||
|
||||
if (return_stairjank)
|
||||
*return_stairjank = stairjank;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// P_CheckMove
|
||||
// Check if a P_TryMove would be successful.
|
||||
//
|
||||
boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
||||
{
|
||||
boolean moveok;
|
||||
mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY);
|
||||
|
||||
hack->radius = thing->radius;
|
||||
hack->height = thing->height;
|
||||
|
||||
moveok = increment_move(hack, x, y, allowdropoff, NULL);
|
||||
P_RemoveMobj(hack);
|
||||
|
||||
return moveok;
|
||||
}
|
||||
|
||||
//
|
||||
// P_TryMove
|
||||
// Attempt to move to a new position.
|
||||
//
|
||||
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
||||
{
|
||||
fixed_t oldx = thing->x;
|
||||
fixed_t oldy = thing->y;
|
||||
fixed_t startingonground = P_IsObjectOnGround(thing);
|
||||
fixed_t stairjank = 0;
|
||||
pslope_t *oldslope = thing->standingslope;
|
||||
|
||||
// The move is ok!
|
||||
if (!increment_move(thing, x, y, allowdropoff, &stairjank))
|
||||
return false;
|
||||
|
||||
// If it's a pushable object, check if anything is
|
||||
// standing on top and move it, too.
|
||||
|
|
|
|||
59
src/p_mobj.c
59
src/p_mobj.c
|
|
@ -1574,7 +1574,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
// blocked move
|
||||
moved = false;
|
||||
|
||||
if (LUAh_MobjMoveBlocked(mo))
|
||||
if (LUA_HookMobjMoveBlocked(mo, tmhitthing, blockingline))
|
||||
{
|
||||
if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
|
|
@ -3976,7 +3976,7 @@ static void P_RingThinker(mobj_t *mobj)
|
|||
|
||||
if (!mobj->fuse)
|
||||
{
|
||||
if (!LUAh_MobjFuse(mobj))
|
||||
if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse)))
|
||||
{
|
||||
mobj->renderflags &= ~RF_DONTDRAW;
|
||||
spark = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SIGNSPARKLE); // Spawn a fancy sparkle
|
||||
|
|
@ -5356,7 +5356,7 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj)
|
|||
|
||||
static void P_MobjSceneryThink(mobj_t *mobj)
|
||||
{
|
||||
if (LUAh_MobjThinker(mobj))
|
||||
if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)))
|
||||
return;
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
return;
|
||||
|
|
@ -6218,7 +6218,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->fuse--;
|
||||
if (!mobj->fuse)
|
||||
{
|
||||
if (!LUAh_MobjFuse(mobj))
|
||||
if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse)))
|
||||
P_RemoveMobj(mobj);
|
||||
return;
|
||||
}
|
||||
|
|
@ -6238,7 +6238,7 @@ static boolean P_MobjPushableThink(mobj_t *mobj)
|
|||
|
||||
static boolean P_MobjBossThink(mobj_t *mobj)
|
||||
{
|
||||
if (LUAh_BossThinker(mobj))
|
||||
if (LUA_HookMobj(mobj, MOBJ_HOOK(BossThinker)))
|
||||
{
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
return false;
|
||||
|
|
@ -7840,6 +7840,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
Obj_HyudoroCenterThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_SHRINK_POHBEE:
|
||||
{
|
||||
Obj_PohbeeThinker(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_ROCKETSNEAKER:
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
{
|
||||
|
|
@ -9159,7 +9164,7 @@ static boolean P_FuseThink(mobj_t *mobj)
|
|||
if (mobj->fuse)
|
||||
return true;
|
||||
|
||||
if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj))
|
||||
if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse)) || P_MobjWasRemoved(mobj))
|
||||
;
|
||||
else if (mobj->info->flags & MF_MONITOR)
|
||||
{
|
||||
|
|
@ -9391,13 +9396,13 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
// Check for a Lua thinker first
|
||||
if (!mobj->player)
|
||||
{
|
||||
if (LUAh_MobjThinker(mobj) || P_MobjWasRemoved(mobj))
|
||||
if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)) || P_MobjWasRemoved(mobj))
|
||||
return;
|
||||
}
|
||||
else if (!mobj->player->spectator)
|
||||
{
|
||||
// You cannot short-circuit the player thinker like you can other thinkers.
|
||||
LUAh_MobjThinker(mobj);
|
||||
LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker));
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
return;
|
||||
}
|
||||
|
|
@ -9888,7 +9893,24 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
const mobjinfo_t *info = &mobjinfo[type];
|
||||
SINT8 sc = -1;
|
||||
state_t *st;
|
||||
mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
|
||||
mobj_t *mobj;
|
||||
|
||||
if (type == MT_NULL)
|
||||
{
|
||||
#if 0
|
||||
#ifdef PARANOIA
|
||||
I_Error("Tried to spawn MT_NULL\n");
|
||||
#endif
|
||||
return NULL;
|
||||
#endif
|
||||
// Hack: Some code assumes that P_SpawnMobj can never return NULL
|
||||
// So replace MT_NULL with MT_RAY in the meantime
|
||||
// Remove when dealt properly
|
||||
CONS_Debug(DBG_GAMELOGIC, "Tried to spawn MT_NULL, using MT_RAY\n");
|
||||
type = MT_RAY;
|
||||
}
|
||||
|
||||
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
|
||||
|
||||
// this is officially a mobj, declared as soon as possible.
|
||||
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
|
||||
|
|
@ -9989,7 +10011,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
|
||||
// DANGER! This can cause P_SpawnMobj to return NULL!
|
||||
// Avoid using P_RemoveMobj on the newly created mobj in "MobjSpawn" Lua hooks!
|
||||
if (LUAh_MobjSpawn(mobj))
|
||||
if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjSpawn)))
|
||||
{
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
return NULL;
|
||||
|
|
@ -10328,7 +10350,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
mobj_t *side = P_SpawnMobj(mobj->x + FINECOSINE((ang>>ANGLETOFINESHIFT) & FINEMASK),
|
||||
mobj->y + FINESINE((ang>>ANGLETOFINESHIFT) & FINEMASK), mobj->z, MT_DAYTONAPINETREE_SIDE);
|
||||
P_InitAngle(side, ang);
|
||||
side->target = mobj;
|
||||
P_SetTarget(&side->target, mobj);
|
||||
side->threshold = i;
|
||||
}
|
||||
break;
|
||||
|
|
@ -10589,7 +10611,7 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
return; // something already removing this mobj.
|
||||
|
||||
mobj->thinker.function.acp1 = (actionf_p1)P_RemoveThinkerDelayed; // shh. no recursing.
|
||||
LUAh_MobjRemoved(mobj);
|
||||
LUA_HookMobj(mobj, MOBJ_HOOK(MobjRemoved));
|
||||
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; // needed for P_UnsetThingPosition, etc. to work.
|
||||
|
||||
// Rings only, please!
|
||||
|
|
@ -10634,6 +10656,16 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
P_SetTarget(&mobj->player->followmobj, NULL);
|
||||
}
|
||||
|
||||
if (mobj->type == MT_SHRINK_POHBEE)
|
||||
{
|
||||
Obj_PohbeeRemoved(mobj);
|
||||
}
|
||||
|
||||
if (mobj->type == MT_SHRINK_GUN)
|
||||
{
|
||||
Obj_ShrinkGunRemoved(mobj);
|
||||
}
|
||||
|
||||
mobj->health = 0; // Just because
|
||||
|
||||
// unlink from sector and block lists
|
||||
|
|
@ -10745,6 +10777,7 @@ void P_RemoveSavegameMobj(mobj_t *mobj)
|
|||
|
||||
// free block
|
||||
P_RemoveThinker((thinker_t *)mobj);
|
||||
R_RemoveMobjInterpolator(mobj);
|
||||
}
|
||||
|
||||
static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
|
||||
|
|
@ -12186,7 +12219,7 @@ static void P_SnapToFinishLine(mobj_t *mobj)
|
|||
|
||||
static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle)
|
||||
{
|
||||
boolean override = LUAh_MapThingSpawn(mobj, mthing);
|
||||
boolean override = LUA_HookMapThingSpawn(mobj, mthing);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ typedef enum
|
|||
MF_AMBIENT = 1<<10,
|
||||
// Slide this object when it hits a wall.
|
||||
MF_SLIDEME = 1<<11,
|
||||
// Player cheat.
|
||||
// Don't collide with walls or solid objects. Two MF_NOCLIP objects can't touch each other at all!
|
||||
MF_NOCLIP = 1<<12,
|
||||
// Allow moves to any height, no gravity. For active floaters.
|
||||
MF_FLOAT = 1<<13,
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ static void P_NetArchivePlayers(void)
|
|||
|
||||
WRITEUINT8(save_p, players[i].stairjank);
|
||||
|
||||
WRITEUINT8(save_p, players[i].shrinkLaserDelay);
|
||||
|
||||
// respawnvars_t
|
||||
WRITEUINT8(save_p, players[i].respawn.state);
|
||||
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].respawn.wp));
|
||||
|
|
@ -654,6 +656,8 @@ static void P_NetUnArchivePlayers(void)
|
|||
|
||||
players[i].stairjank = READUINT8(save_p);
|
||||
|
||||
players[i].shrinkLaserDelay = READUINT8(save_p);
|
||||
|
||||
// respawnvars_t
|
||||
players[i].respawn.state = READUINT8(save_p);
|
||||
players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save_p);
|
||||
|
|
@ -4193,21 +4197,21 @@ static void P_RelinkPointers(void)
|
|||
{
|
||||
temp = (UINT32)(size_t)mobj->hnext;
|
||||
mobj->hnext = NULL;
|
||||
if (!(mobj->hnext = P_FindNewPosition(temp)))
|
||||
if (!P_SetTarget(&mobj->hnext, P_FindNewPosition(temp)))
|
||||
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 (!(mobj->hprev = P_FindNewPosition(temp)))
|
||||
if (!P_SetTarget(&mobj->hprev, P_FindNewPosition(temp)))
|
||||
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 (!(mobj->itnext = P_FindNewPosition(temp)))
|
||||
if (!P_SetTarget(&mobj->itnext, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->terrain)
|
||||
|
|
@ -4423,7 +4427,7 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride)
|
|||
|
||||
static void P_NetArchiveMisc(boolean resending)
|
||||
{
|
||||
INT32 i;
|
||||
size_t i;
|
||||
|
||||
WRITEUINT32(save_p, ARCHIVEBLOCK_MISC);
|
||||
|
||||
|
|
@ -4552,11 +4556,25 @@ static void P_NetArchiveMisc(boolean resending)
|
|||
WRITEUINT8(save_p, 0x2f);
|
||||
else
|
||||
WRITEUINT8(save_p, 0x2e);
|
||||
|
||||
WRITEUINT32(save_p, livestudioaudience_timer);
|
||||
|
||||
// Only the server uses this, but it
|
||||
// needs synched for remote admins anyway.
|
||||
WRITEUINT32(save_p, schedule_len);
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
WRITEINT16(save_p, task->basetime);
|
||||
WRITEINT16(save_p, task->timer);
|
||||
WRITESTRING(save_p, task->command);
|
||||
}
|
||||
}
|
||||
|
||||
static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
||||
{
|
||||
INT32 i;
|
||||
size_t i;
|
||||
size_t numTasks;
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_MISC)
|
||||
I_Error("Bad $$$.sav at archive block Misc");
|
||||
|
|
@ -4700,6 +4718,26 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
|||
if (READUINT8(save_p) == 0x2f)
|
||||
paused = true;
|
||||
|
||||
livestudioaudience_timer = READUINT32(save_p);
|
||||
|
||||
// Only the server uses this, but it
|
||||
// needs synched for remote admins anyway.
|
||||
Schedule_Clear();
|
||||
|
||||
numTasks = READUINT32(save_p);
|
||||
for (i = 0; i < numTasks; i++)
|
||||
{
|
||||
INT16 basetime;
|
||||
INT16 timer;
|
||||
char command[MAXTEXTCMD];
|
||||
|
||||
basetime = READINT16(save_p);
|
||||
timer = READINT16(save_p);
|
||||
READSTRING(save_p, command);
|
||||
|
||||
Schedule_Add(basetime, timer, command);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
#include "md5.h" // map MD5
|
||||
|
||||
// for LUAh_MapLoad
|
||||
// for MapLoad hook
|
||||
#include "lua_script.h"
|
||||
#include "lua_hook.h"
|
||||
|
||||
|
|
@ -4455,7 +4455,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
}
|
||||
P_PreTicker(2);
|
||||
P_MapStart(); // just in case MapLoad modifies tmthing
|
||||
LUAh_MapLoad();
|
||||
LUA_HookInt(gamemap, HOOK(MapLoad));
|
||||
P_MapEnd(); // just in case MapLoad modifies tmthing
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#include "v_video.h" // V_ALLOWLOWERCASE
|
||||
#include "m_misc.h"
|
||||
#include "m_cond.h" //unlock triggers
|
||||
#include "lua_hook.h" // LUAh_LinedefExecute
|
||||
#include "lua_hook.h" // LUA_HookLinedefExecute
|
||||
#include "f_finale.h" // control text prompt
|
||||
#include "r_skins.h" // skins
|
||||
|
||||
|
|
@ -3032,7 +3032,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
|||
|
||||
case 443: // Calls a named Lua function
|
||||
if (line->stringargs[0])
|
||||
LUAh_LinedefExecute(line, mo, callsec);
|
||||
LUA_HookLinedefExecute(line, mo, callsec);
|
||||
else
|
||||
CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in arg0str)\n", sizeu1(line-lines));
|
||||
break;
|
||||
|
|
|
|||
14
src/p_tick.c
14
src/p_tick.c
|
|
@ -581,7 +581,7 @@ void P_Ticker(boolean run)
|
|||
ps_lua_mobjhooks = 0;
|
||||
ps_checkposition_calls = 0;
|
||||
|
||||
LUAh_PreThinkFrame();
|
||||
LUA_HOOK(PreThinkFrame);
|
||||
|
||||
ps_playerthink_time = I_GetPreciseTime();
|
||||
|
||||
|
|
@ -654,7 +654,7 @@ void P_Ticker(boolean run)
|
|||
}
|
||||
|
||||
ps_lua_thinkframe_time = I_GetPreciseTime();
|
||||
LUAh_ThinkFrame();
|
||||
LUA_HOOK(ThinkFrame);
|
||||
ps_lua_thinkframe_time = I_GetPreciseTime() - ps_lua_thinkframe_time;
|
||||
}
|
||||
|
||||
|
|
@ -721,7 +721,7 @@ void P_Ticker(boolean run)
|
|||
G_WriteAllGhostTics();
|
||||
|
||||
if (cv_recordmultiplayerdemos.value && (demo.savemode == DSM_NOTSAVING || demo.savemode == DSM_WILLAUTOSAVE))
|
||||
if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && G_PlayerInputDown(0, gc_y, 0))
|
||||
if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && !menuactive && (G_PlayerInputDown(0, gc_b, 0) || G_PlayerInputDown(0, gc_x, 0)))
|
||||
demo.savemode = DSM_TITLEENTRY;
|
||||
}
|
||||
else if (demo.playback) // Use Ghost data for consistency checks.
|
||||
|
|
@ -748,7 +748,7 @@ void P_Ticker(boolean run)
|
|||
// Always move the camera.
|
||||
P_RunChaseCameras();
|
||||
|
||||
LUAh_PostThinkFrame();
|
||||
LUA_HOOK(PostThinkFrame);
|
||||
|
||||
if (run)
|
||||
{
|
||||
|
|
@ -802,7 +802,7 @@ void P_PreTicker(INT32 frames)
|
|||
K_KartUpdatePosition(&players[i]);
|
||||
|
||||
// OK! Now that we got all of that sorted, players can think!
|
||||
LUAh_PreThinkFrame();
|
||||
LUA_HOOK(PreThinkFrame);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
|
|
@ -825,7 +825,7 @@ void P_PreTicker(INT32 frames)
|
|||
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
P_PlayerAfterThink(&players[i]);
|
||||
|
||||
LUAh_ThinkFrame();
|
||||
LUA_HOOK(ThinkFrame);
|
||||
|
||||
// Run shield positioning
|
||||
P_RunOverlays();
|
||||
|
|
@ -833,7 +833,7 @@ void P_PreTicker(INT32 frames)
|
|||
P_UpdateSpecials();
|
||||
P_RespawnSpecials();
|
||||
|
||||
LUAh_PostThinkFrame();
|
||||
LUA_HOOK(PostThinkFrame);
|
||||
|
||||
R_UpdateLevelInterpolators();
|
||||
R_UpdateViewInterpolation();
|
||||
|
|
|
|||
44
src/p_user.c
44
src/p_user.c
|
|
@ -665,7 +665,7 @@ boolean P_EvaluateMusicStatus(UINT16 status, const char *musname)
|
|||
break;
|
||||
|
||||
case JT_OTHER: // Other state
|
||||
result = LUAh_ShouldJingleContinue(&players[i], musname);
|
||||
result = LUA_HookShouldJingleContinue(&players[i], musname);
|
||||
break;
|
||||
|
||||
case JT_NONE: // Null state
|
||||
|
|
@ -1197,7 +1197,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
|
|||
ghost->sprite2 = mobj->sprite2;
|
||||
ghost->frame = mobj->frame;
|
||||
ghost->tics = -1;
|
||||
ghost->renderflags |= tr_trans50 << RF_TRANSSHIFT;
|
||||
ghost->renderflags = (mobj->renderflags & ~RF_TRANSMASK)|RF_TRANS50;
|
||||
ghost->fuse = ghost->info->damage;
|
||||
ghost->skin = mobj->skin;
|
||||
ghost->standingslope = mobj->standingslope;
|
||||
|
|
@ -1207,6 +1207,11 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
|
|||
ghost->sprzoff = mobj->sprzoff;
|
||||
ghost->rollangle = mobj->rollangle;
|
||||
|
||||
ghost->spritexscale = mobj->spritexscale;
|
||||
ghost->spriteyscale = mobj->spriteyscale;
|
||||
ghost->spritexoffset = mobj->spritexoffset;
|
||||
ghost->spriteyoffset = mobj->spriteyoffset;
|
||||
|
||||
if (mobj->flags2 & MF2_OBJECTFLIP)
|
||||
ghost->flags |= MF2_OBJECTFLIP;
|
||||
|
||||
|
|
@ -3044,6 +3049,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
subsector_t *newsubsec;
|
||||
#endif
|
||||
|
||||
fixed_t playerScale = FixedDiv(player->mo->scale, mapobjectscale);
|
||||
fixed_t scaleDiff = playerScale - FRACUNIT;
|
||||
fixed_t cameraScale = mapobjectscale;
|
||||
|
||||
thiscam->old_x = thiscam->x;
|
||||
thiscam->old_y = thiscam->y;
|
||||
thiscam->old_z = thiscam->z;
|
||||
|
|
@ -3132,8 +3141,11 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
return true;
|
||||
}
|
||||
|
||||
thiscam->radius = 20*mapobjectscale;
|
||||
thiscam->height = 16*mapobjectscale;
|
||||
// Adjust camera to match Grow/Shrink
|
||||
cameraScale = FixedMul(cameraScale, FRACUNIT + (scaleDiff / 3));
|
||||
|
||||
thiscam->radius = 20*cameraScale;
|
||||
thiscam->height = 16*cameraScale;
|
||||
|
||||
// Don't run while respawning from a starpost
|
||||
// Inu 4/8/13 Why not?!
|
||||
|
|
@ -3159,8 +3171,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
camspeed = cv_cam_speed[num].value;
|
||||
camstill = cv_cam_still[num].value;
|
||||
camrotate = cv_cam_rotate[num].value;
|
||||
camdist = FixedMul(cv_cam_dist[num].value, mapobjectscale);
|
||||
camheight = FixedMul(cv_cam_height[num].value, mapobjectscale);
|
||||
camdist = FixedMul(cv_cam_dist[num].value, cameraScale);
|
||||
camheight = FixedMul(cv_cam_height[num].value, cameraScale);
|
||||
|
||||
if (timeover)
|
||||
{
|
||||
|
|
@ -3171,8 +3183,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
{
|
||||
const INT32 introcam = (introtime - leveltime);
|
||||
camrotate += introcam*5;
|
||||
camdist += (introcam * mapobjectscale)*3;
|
||||
camheight += (introcam * mapobjectscale)*2;
|
||||
camdist += (introcam * cameraScale)*3;
|
||||
camheight += (introcam * cameraScale)*2;
|
||||
}
|
||||
else if (player->exiting) // SRB2Kart: Leave the camera behind while exiting, for dramatic effect!
|
||||
camstill = true;
|
||||
|
|
@ -3236,7 +3248,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
|
||||
// sets ideal cam pos
|
||||
{
|
||||
const fixed_t speedthreshold = 48*mapobjectscale;
|
||||
const fixed_t speedthreshold = 48*cameraScale;
|
||||
const fixed_t olddist = P_AproxDistance(mo->x - thiscam->x, mo->y - thiscam->y);
|
||||
|
||||
fixed_t lag, distoffset;
|
||||
|
|
@ -3541,7 +3553,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
|
||||
// point viewed by the camera
|
||||
// this point is just 64 unit forward the player
|
||||
dist = 64*mapobjectscale;
|
||||
dist = 64*cameraScale;
|
||||
viewpointx = mo->x + FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist) + xpan;
|
||||
viewpointy = mo->y + FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist) + ypan;
|
||||
|
||||
|
|
@ -3684,7 +3696,7 @@ boolean P_SpectatorJoinGame(player_t *player)
|
|||
else
|
||||
changeto = (P_RandomFixed() & 1) + 1;
|
||||
|
||||
if (!LUAh_TeamSwitch(player, changeto, true, false, false))
|
||||
if (!LUA_HookTeamSwitch(player, changeto, true, false, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3710,7 +3722,7 @@ boolean P_SpectatorJoinGame(player_t *player)
|
|||
{
|
||||
if (localplayertable[i] == (player-players))
|
||||
{
|
||||
LUAh_ViewpointSwitch(player, player, true);
|
||||
LUA_HookViewpointSwitch(player, player, true);
|
||||
displayplayers[i] = (player-players);
|
||||
break;
|
||||
}
|
||||
|
|
@ -4220,7 +4232,7 @@ void P_PlayerThink(player_t *player)
|
|||
|
||||
if (player->playerstate == PST_DEAD)
|
||||
{
|
||||
LUAh_PlayerThink(player);
|
||||
LUA_HookPlayer(player, HOOK(PlayerThink));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -4269,7 +4281,7 @@ void P_PlayerThink(player_t *player)
|
|||
else
|
||||
player->mo->renderflags &= ~RF_GHOSTLYMASK;
|
||||
P_DeathThink(player);
|
||||
LUAh_PlayerThink(player);
|
||||
LUA_HookPlayer(player, HOOK(PlayerThink));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4474,7 +4486,7 @@ void P_PlayerThink(player_t *player)
|
|||
if (player->carry == CR_SLIDING)
|
||||
player->carry = CR_NONE;
|
||||
|
||||
LUAh_PlayerThink(player);
|
||||
LUA_HookPlayer(player, HOOK(PlayerThink));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -4581,7 +4593,7 @@ void P_PlayerAfterThink(player_t *player)
|
|||
|
||||
if (player->followmobj)
|
||||
{
|
||||
if (LUAh_FollowMobj(player, player->followmobj) || P_MobjWasRemoved(player->followmobj))
|
||||
if (LUA_HookFollowMobj(player, player->followmobj) || P_MobjWasRemoved(player->followmobj))
|
||||
{;}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
297
src/r_bbox.c
Normal file
297
src/r_bbox.c
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2021 by Sonic Team Junior.
|
||||
// Copyright (C) 2022 by Kart Krew.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file r_bbox.c
|
||||
/// \brief Boundary box (cube) renderer
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "command.h"
|
||||
#include "r_local.h"
|
||||
#include "screen.h" // cv_renderhitbox
|
||||
#include "v_video.h" // V_DrawFill
|
||||
|
||||
enum {
|
||||
RENDERHITBOX_OFF,
|
||||
RENDERHITBOX_TANGIBLE,
|
||||
RENDERHITBOX_ALL,
|
||||
RENDERHITBOX_INTANGIBLE,
|
||||
RENDERHITBOX_RINGS,
|
||||
};
|
||||
|
||||
static CV_PossibleValue_t renderhitbox_cons_t[] = {
|
||||
{RENDERHITBOX_OFF, "Off"},
|
||||
{RENDERHITBOX_TANGIBLE, "Tangible"},
|
||||
{RENDERHITBOX_ALL, "All"},
|
||||
{RENDERHITBOX_INTANGIBLE, "Intangible"},
|
||||
{RENDERHITBOX_RINGS, "Rings"},
|
||||
{0}};
|
||||
|
||||
consvar_t cv_renderhitbox = CVAR_INIT ("renderhitbox", "Off", 0, renderhitbox_cons_t, NULL);
|
||||
|
||||
struct bbox_col {
|
||||
INT32 x;
|
||||
INT32 y;
|
||||
INT32 h;
|
||||
};
|
||||
|
||||
struct bbox_config {
|
||||
fixed_t height;
|
||||
fixed_t tz;
|
||||
struct bbox_col col[4];
|
||||
UINT8 color;
|
||||
};
|
||||
|
||||
static inline void
|
||||
raster_bbox_seg
|
||||
( INT32 x,
|
||||
fixed_t y,
|
||||
fixed_t h,
|
||||
UINT8 pixel)
|
||||
{
|
||||
y /= FRACUNIT;
|
||||
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
|
||||
h = y + (FixedCeil(abs(h)) / FRACUNIT);
|
||||
|
||||
if (h >= viewheight)
|
||||
h = viewheight;
|
||||
|
||||
while (y < h)
|
||||
{
|
||||
topleft[x + y * vid.width] = pixel;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_bbox_col
|
||||
( struct bbox_config * bb,
|
||||
int p,
|
||||
fixed_t tx,
|
||||
fixed_t ty)
|
||||
{
|
||||
struct bbox_col *col = &bb->col[p];
|
||||
|
||||
fixed_t xscale, yscale;
|
||||
|
||||
if (ty < FRACUNIT) // projection breaks down here
|
||||
ty = FRACUNIT;
|
||||
|
||||
xscale = FixedDiv(projection[viewssnum], ty);
|
||||
yscale = FixedDiv(projectiony[viewssnum], ty);
|
||||
|
||||
col->x = (centerxfrac + FixedMul(tx, xscale)) / FRACUNIT;
|
||||
col->y = (centeryfrac - FixedMul(bb->tz, yscale));
|
||||
col->h = FixedMul(bb->height, yscale);
|
||||
|
||||
// Using this function is TOO EASY!
|
||||
V_DrawFill(
|
||||
viewwindowx + col->x,
|
||||
viewwindowy + col->y / FRACUNIT, 1,
|
||||
col->h / FRACUNIT, V_NOSCALESTART | bb->color);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_bbox_row
|
||||
( struct bbox_config * bb,
|
||||
int p1,
|
||||
int p2)
|
||||
{
|
||||
struct bbox_col
|
||||
*a = &bb->col[p1],
|
||||
*b = &bb->col[p2];
|
||||
|
||||
INT32 x1, x2; // left, right
|
||||
INT32 dx; // width
|
||||
|
||||
fixed_t y1, y2; // top, bottom
|
||||
fixed_t s1, s2; // top and bottom increment
|
||||
|
||||
if (a->x > b->x)
|
||||
{
|
||||
struct bbox_col *c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
|
||||
x1 = a->x;
|
||||
x2 = b->x;
|
||||
|
||||
if (x2 >= viewwidth)
|
||||
x2 = viewwidth - 1;
|
||||
|
||||
if (x1 == x2 || x1 >= viewwidth || x2 < 0)
|
||||
return;
|
||||
|
||||
dx = x2 - x1;
|
||||
|
||||
y1 = a->y;
|
||||
y2 = b->y;
|
||||
s1 = (y2 - y1) / dx;
|
||||
|
||||
y2 = y1 + a->h;
|
||||
s2 = ((b->y + b->h) - y2) / dx;
|
||||
|
||||
// FixedCeil needs a minimum!!! :D :D
|
||||
|
||||
if (s1 == 0)
|
||||
s1 = 1;
|
||||
|
||||
if (s2 == 0)
|
||||
s2 = 1;
|
||||
|
||||
if (x1 < 0)
|
||||
{
|
||||
y1 -= x1 * s1;
|
||||
y2 -= x1 * s2;
|
||||
x1 = 0;
|
||||
}
|
||||
|
||||
while (x1 < x2)
|
||||
{
|
||||
raster_bbox_seg(x1, y1, s1, bb->color);
|
||||
raster_bbox_seg(x1, y2, s2, bb->color);
|
||||
|
||||
y1 += s1;
|
||||
y2 += s2;
|
||||
|
||||
x1++;
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 R_GetBoundingBoxColor(mobj_t *thing)
|
||||
{
|
||||
UINT32 flags = thing->flags;
|
||||
|
||||
if (thing->player)
|
||||
return 255; // 0FF
|
||||
|
||||
if (flags & (MF_NOCLIPTHING))
|
||||
return 7; // BFBFBF
|
||||
|
||||
if (flags & (MF_SPECIAL))
|
||||
return 73; // FF0
|
||||
|
||||
if (flags & (MF_BOSS|MF_MISSILE|MF_ENEMY|MF_PAIN))
|
||||
return 35; // F00
|
||||
|
||||
if (flags & (MF_NOCLIP))
|
||||
return 152; // 00F
|
||||
|
||||
return 0; // FFF
|
||||
}
|
||||
|
||||
void R_DrawThingBoundingBox(vissprite_t *vis)
|
||||
{
|
||||
// radius offsets
|
||||
fixed_t rs = vis->scale;
|
||||
fixed_t rc = vis->xscale;
|
||||
|
||||
// translated coordinates
|
||||
fixed_t tx = vis->gx;
|
||||
fixed_t ty = vis->gy;
|
||||
|
||||
struct bbox_config bb = {
|
||||
.height = vis->thingheight,
|
||||
.tz = vis->texturemid,
|
||||
.color = R_GetBoundingBoxColor(vis->mobj),
|
||||
};
|
||||
|
||||
// 1--3
|
||||
// | |
|
||||
// 0--2
|
||||
|
||||
// left
|
||||
|
||||
draw_bbox_col(&bb, 0, tx, ty); // bottom
|
||||
draw_bbox_col(&bb, 1, tx - rc, ty + rs); // top
|
||||
|
||||
// right
|
||||
|
||||
tx += rs;
|
||||
ty += rc;
|
||||
|
||||
draw_bbox_col(&bb, 2, tx, ty); // bottom
|
||||
draw_bbox_col(&bb, 3, tx - rc, ty + rs); // top
|
||||
|
||||
// connect all four columns
|
||||
|
||||
draw_bbox_row(&bb, 0, 1);
|
||||
draw_bbox_row(&bb, 1, 3);
|
||||
draw_bbox_row(&bb, 3, 2);
|
||||
draw_bbox_row(&bb, 2, 0);
|
||||
}
|
||||
|
||||
static boolean is_tangible (mobj_t *thing)
|
||||
{
|
||||
// These objects can never touch another
|
||||
if (thing->flags & (MF_NOCLIPTHING))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// These objects probably do nothing! :D
|
||||
if ((thing->flags & (MF_SPECIAL|MF_SOLID|MF_SHOOTABLE
|
||||
|MF_PUSHABLE|MF_BOSS|MF_MISSILE|MF_SPRING
|
||||
|MF_MONITOR|MF_ENEMY|MF_PAIN|MF_STICKY
|
||||
|MF_PICKUPFROMBELOW)) == 0U)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean R_ThingBoundingBoxVisible(mobj_t *thing)
|
||||
{
|
||||
INT32 cvmode = cv_renderhitbox.value;
|
||||
|
||||
if (thing->type == MT_WAYPOINT)
|
||||
{
|
||||
// Waypoints debugger serves this purpose
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thing == r_viewmobj)
|
||||
{
|
||||
// Rendering bbox right on top causes anomalies
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (cvmode)
|
||||
{
|
||||
case RENDERHITBOX_OFF:
|
||||
return false;
|
||||
|
||||
case RENDERHITBOX_ALL:
|
||||
return true;
|
||||
|
||||
case RENDERHITBOX_INTANGIBLE:
|
||||
return !is_tangible(thing);
|
||||
|
||||
case RENDERHITBOX_TANGIBLE:
|
||||
// Exclude rings from here, lots of them!
|
||||
if (thing->type == MT_RING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_tangible(thing);
|
||||
|
||||
case RENDERHITBOX_RINGS:
|
||||
return (thing->type == MT_RING);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
160
src/r_things.c
160
src/r_things.c
|
|
@ -1449,6 +1449,104 @@ static void R_ProjectDropShadow(
|
|||
objectsdrawn++;
|
||||
}
|
||||
|
||||
static void R_ProjectBoundingBox(mobj_t *thing, vissprite_t *vis)
|
||||
{
|
||||
fixed_t gx, gy;
|
||||
fixed_t tx, tz;
|
||||
|
||||
vissprite_t *box;
|
||||
|
||||
// uncapped/interpolation
|
||||
interpmobjstate_t interp = {0};
|
||||
|
||||
if (!R_ThingBoundingBoxVisible(thing))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// do interpolation
|
||||
if (R_UsingFrameInterpolation() && !paused)
|
||||
{
|
||||
R_InterpolateMobjState(thing, rendertimefrac, &interp);
|
||||
}
|
||||
else
|
||||
{
|
||||
R_InterpolateMobjState(thing, FRACUNIT, &interp);
|
||||
}
|
||||
|
||||
// 1--3
|
||||
// | |
|
||||
// 0--2
|
||||
|
||||
// start in the (0) corner
|
||||
gx = interp.x - thing->radius - viewx;
|
||||
gy = interp.y - thing->radius - viewy;
|
||||
|
||||
tz = FixedMul(gx, viewcos) + FixedMul(gy, viewsin);
|
||||
|
||||
// thing is behind view plane?
|
||||
// if parent vis is visible, ignore this
|
||||
if (!vis && (tz < FixedMul(MINZ, interp.scale)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tx = FixedMul(gx, viewsin) - FixedMul(gy, viewcos);
|
||||
|
||||
// too far off the side?
|
||||
if (!vis && abs(tx) > FixedMul(tz, fovtan[viewssnum])<<2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
box = R_NewVisSprite();
|
||||
box->mobj = thing;
|
||||
box->mobjflags = thing->flags;
|
||||
box->thingheight = thing->height;
|
||||
box->cut = SC_BBOX;
|
||||
|
||||
box->gx = tx;
|
||||
box->gy = tz;
|
||||
|
||||
box->scale = 2 * FixedMul(thing->radius, viewsin);
|
||||
box->xscale = 2 * FixedMul(thing->radius, viewcos);
|
||||
|
||||
box->pz = interp.z;
|
||||
box->pzt = box->pz + box->thingheight;
|
||||
|
||||
box->gzt = box->pzt;
|
||||
box->gz = box->pz;
|
||||
box->texturemid = box->gzt - viewz;
|
||||
|
||||
if (vis)
|
||||
{
|
||||
box->x1 = vis->x1;
|
||||
box->x2 = vis->x2;
|
||||
box->szt = vis->szt;
|
||||
box->sz = vis->sz;
|
||||
|
||||
box->sortscale = vis->sortscale; // link sorting to sprite
|
||||
box->dispoffset = vis->dispoffset + 5;
|
||||
|
||||
box->cut |= SC_LINKDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed_t xscale = FixedDiv(projection[viewssnum], tz);
|
||||
fixed_t yscale = FixedDiv(projectiony[viewssnum], tz);
|
||||
fixed_t top = (centeryfrac - FixedMul(box->texturemid, yscale));
|
||||
|
||||
box->x1 = (centerxfrac + FixedMul(box->gx, xscale)) / FRACUNIT;
|
||||
box->x2 = box->x1;
|
||||
|
||||
box->szt = top / FRACUNIT;
|
||||
box->sz = (top + FixedMul(box->thingheight, yscale)) / FRACUNIT;
|
||||
|
||||
box->sortscale = yscale;
|
||||
box->dispoffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// R_ProjectSprite
|
||||
// Generates a vissprite for a thing
|
||||
|
|
@ -1690,8 +1788,14 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
if (spriterotangle
|
||||
&& !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))
|
||||
{
|
||||
rollangle = R_GetRollAngle(vflip
|
||||
? InvAngle(spriterotangle) : spriterotangle);
|
||||
if ((papersprite && ang >= ANGLE_180) != vflip)
|
||||
{
|
||||
rollangle = R_GetRollAngle(InvAngle(spriterotangle));
|
||||
}
|
||||
else
|
||||
{
|
||||
rollangle = R_GetRollAngle(spriterotangle);
|
||||
}
|
||||
rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle);
|
||||
|
||||
if (rotsprite != NULL)
|
||||
|
|
@ -2195,6 +2299,8 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz);
|
||||
}
|
||||
|
||||
R_ProjectBoundingBox(oldthing, vis);
|
||||
|
||||
// Debug
|
||||
++objectsdrawn;
|
||||
}
|
||||
|
|
@ -2429,8 +2535,26 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
|
|||
limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale;
|
||||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||||
{
|
||||
if (R_ThingVisibleWithinDist(thing, limit_dist))
|
||||
R_ProjectSprite(thing);
|
||||
if (R_ThingWithinDist(thing, limit_dist))
|
||||
{
|
||||
const INT32 oldobjectsdrawn = objectsdrawn;
|
||||
|
||||
if (R_ThingVisible(thing))
|
||||
{
|
||||
R_ProjectSprite(thing);
|
||||
}
|
||||
|
||||
// I'm so smart :^)
|
||||
if (objectsdrawn == oldobjectsdrawn)
|
||||
{
|
||||
/*
|
||||
Object is invisible OR is off screen but
|
||||
render its bbox even if the latter because
|
||||
radius could be bigger than sprite.
|
||||
*/
|
||||
R_ProjectBoundingBox(thing, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
|
||||
|
|
@ -2503,6 +2627,10 @@ static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 e
|
|||
if (dsfirst->cut & SC_SHADOW)
|
||||
continue;
|
||||
|
||||
// don't connect to your bounding box!
|
||||
if (dsfirst->cut & SC_BBOX)
|
||||
continue;
|
||||
|
||||
// don't connect if it's not the tracer
|
||||
if (dsfirst->mobj != ds->mobj)
|
||||
continue;
|
||||
|
|
@ -2946,7 +3074,9 @@ static void R_DrawSprite(vissprite_t *spr)
|
|||
mfloorclip = spr->clipbot;
|
||||
mceilingclip = spr->cliptop;
|
||||
|
||||
if (spr->cut & SC_SPLAT)
|
||||
if (spr->cut & SC_BBOX)
|
||||
R_DrawThingBoundingBox(spr);
|
||||
else if (spr->cut & SC_SPLAT)
|
||||
R_DrawFloorSplat(spr);
|
||||
else
|
||||
R_DrawVisSprite(spr);
|
||||
|
|
@ -3245,6 +3375,12 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
|
|||
INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1;
|
||||
INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2;
|
||||
|
||||
if (spr->cut & SC_BBOX)
|
||||
{
|
||||
// Do not clip bounding boxes
|
||||
continue;
|
||||
}
|
||||
|
||||
if (x2 < cx)
|
||||
{
|
||||
drawsegs_xrange = drawsegs_xranges[1].items;
|
||||
|
|
@ -3283,18 +3419,14 @@ boolean R_ThingVisible (mobj_t *thing)
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean R_ThingVisibleWithinDist (mobj_t *thing,
|
||||
fixed_t limit_dist)
|
||||
boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist)
|
||||
{
|
||||
fixed_t approx_dist;
|
||||
const fixed_t dist = R_PointToDist(thing->x, thing->y);
|
||||
|
||||
if (! R_ThingVisible(thing))
|
||||
return false;
|
||||
|
||||
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
|
||||
|
||||
if (limit_dist && approx_dist > limit_dist)
|
||||
if (limit_dist && dist > limit_dist)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,12 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel);
|
|||
void R_InitSprites(void);
|
||||
void R_ClearSprites(void);
|
||||
|
||||
UINT8 R_GetBoundingBoxColor(mobj_t *thing);
|
||||
boolean R_ThingBoundingBoxVisible(mobj_t *thing);
|
||||
|
||||
boolean R_ThingVisible (mobj_t *thing);
|
||||
|
||||
boolean R_ThingVisibleWithinDist (mobj_t *thing,
|
||||
boolean R_ThingWithinDist (mobj_t *thing,
|
||||
fixed_t draw_dist);
|
||||
|
||||
boolean R_PrecipThingVisible (precipmobj_t *precipthing,
|
||||
|
|
@ -134,6 +137,7 @@ typedef enum
|
|||
SC_SPLAT = 1<<11,
|
||||
// srb2kart
|
||||
SC_SEMIBRIGHT = 1<<12,
|
||||
SC_BBOX = 1<<13,
|
||||
// masks
|
||||
SC_CUTMASK = SC_TOP|SC_BOTTOM,
|
||||
SC_FLAGMASK = ~SC_CUTMASK
|
||||
|
|
@ -220,6 +224,8 @@ extern UINT32 visspritecount;
|
|||
void R_ClipSprites(drawseg_t* dsstart, portal_t* portal);
|
||||
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal);
|
||||
|
||||
void R_DrawThingBoundingBox(vissprite_t *spr);
|
||||
|
||||
UINT8 *R_GetSpriteTranslation(vissprite_t *vis);
|
||||
|
||||
// ----------
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "m_cond.h" // for conditionsets
|
||||
#include "lua_hook.h" // MusicChange hook
|
||||
#include "k_boss.h" // bossinfo
|
||||
#include "byteptr.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
// 3D Sound Interface
|
||||
|
|
@ -43,6 +44,8 @@ CV_PossibleValue_t soundvolume_cons_t[] = {{0, "MIN"}, {MAX_VOLUME, "MAX"}, {0,
|
|||
static void SetChannelsNum(void);
|
||||
static void Command_Tunes_f(void);
|
||||
static void Command_RestartAudio_f(void);
|
||||
static void Command_PlaySound(void);
|
||||
static void Got_PlaySound(UINT8 **p, INT32 playernum);
|
||||
|
||||
// Sound system toggles
|
||||
static void GameSounds_OnChange(void);
|
||||
|
|
@ -268,6 +271,8 @@ void S_RegisterSoundStuff(void)
|
|||
|
||||
COM_AddCommand("tunes", Command_Tunes_f);
|
||||
COM_AddCommand("restartaudio", Command_RestartAudio_f);
|
||||
COM_AddCommand("playsound", Command_PlaySound);
|
||||
RegisterNetXCmd(XD_PLAYSOUND, Got_PlaySound);
|
||||
}
|
||||
|
||||
static void SetChannelsNum(void)
|
||||
|
|
@ -2121,6 +2126,15 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
|
|||
{
|
||||
char newmusic[7];
|
||||
|
||||
struct MusicChange hook_param = {
|
||||
newmusic,
|
||||
&mflags,
|
||||
&looping,
|
||||
&position,
|
||||
&prefadems,
|
||||
&fadeinms
|
||||
};
|
||||
|
||||
if (S_MusicDisabled()
|
||||
|| demo.rewinding // Don't mess with music while rewinding!
|
||||
|| demo.title) // SRB2Kart: Demos don't interrupt title screen music
|
||||
|
|
@ -2128,7 +2142,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
|
|||
|
||||
strncpy(newmusic, mmusic, 7);
|
||||
|
||||
if (LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms))
|
||||
if (LUA_HookMusicChange(music_name, &hook_param))
|
||||
return;
|
||||
|
||||
newmusic[6] = 0;
|
||||
|
|
@ -2470,6 +2484,71 @@ static void Command_RestartAudio_f(void)
|
|||
S_ChangeMusicInternal("titles", looptitle);
|
||||
}
|
||||
|
||||
static void Command_PlaySound(void)
|
||||
{
|
||||
const char *sound;
|
||||
const size_t argc = COM_Argc();
|
||||
sfxenum_t sfx = NUMSFX;
|
||||
UINT8 buf[4];
|
||||
UINT8 *buf_p = buf;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
CONS_Printf("playsound <name/num>: Plays a sound effect for the entire server.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Printf("This can only be used by the server host.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sound = COM_Argv(1);
|
||||
if (*sound >= '0' && *sound <= '9')
|
||||
{
|
||||
sfx = atoi(sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (sfx = 0; sfx < sfxfree; sfx++)
|
||||
{
|
||||
if (S_sfx[sfx].name && fasticmp(sound, S_sfx[sfx].name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sfx < 0 || sfx >= NUMSFX)
|
||||
{
|
||||
CONS_Printf("Could not find sound effect named \"sfx_%s\".\n", sound);
|
||||
return;
|
||||
}
|
||||
|
||||
WRITEINT32(buf_p, sfx);
|
||||
SendNetXCmd(XD_PLAYSOUND, buf, buf_p - buf);
|
||||
}
|
||||
|
||||
static void Got_PlaySound(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
INT32 sound_id = READINT32(*cp);
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum)) // hacked client, or disasterous bug
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal playsound received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sound_id < 0 || sound_id >= NUMSFX)
|
||||
{
|
||||
// bad sound effect, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sound_id);
|
||||
}
|
||||
|
||||
void GameSounds_OnChange(void)
|
||||
{
|
||||
if (M_CheckParm("-nosound") || M_CheckParm("-noaudio"))
|
||||
|
|
|
|||
|
|
@ -243,6 +243,16 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst);
|
|||
// Music Playback
|
||||
//
|
||||
|
||||
/* this is for the sake of the hook */
|
||||
struct MusicChange {
|
||||
char * newname;
|
||||
UINT16 * mflags;
|
||||
boolean * looping;
|
||||
UINT32 * position;
|
||||
UINT32 * prefadems;
|
||||
UINT32 * fadeinms;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MUS_SPECIAL = 1,/* powerups--invincibility, grow */
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ extern CV_PossibleValue_t cv_renderer_t[];
|
|||
extern INT32 scr_bpp;
|
||||
extern UINT8 *scr_borderpatch; // patch used to fill the view borders
|
||||
|
||||
extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen;
|
||||
extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_renderhitbox, cv_fullscreen;
|
||||
extern consvar_t cv_vhseffect, cv_shittyscreen;
|
||||
|
||||
// wait for page flipping to end or not
|
||||
|
|
|
|||
|
|
@ -106,8 +106,10 @@ rendermode_t chosenrendermode = render_none; // set by command line arguments
|
|||
|
||||
boolean highcolor = false;
|
||||
|
||||
static void Impl_SetVsync(void);
|
||||
|
||||
// synchronize page flipping with screen refresh
|
||||
consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
|
||||
consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Impl_SetVsync);
|
||||
static consvar_t cv_stretch = CVAR_INIT ("stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL);
|
||||
static consvar_t cv_alwaysgrabmouse = CVAR_INIT ("alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL);
|
||||
|
||||
|
|
@ -1041,7 +1043,7 @@ void I_GetEvent(void)
|
|||
#endif
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
LUAh_GameQuit(true);
|
||||
LUA_HookBool(true, HOOK(GameQuit));
|
||||
I_Quit();
|
||||
break;
|
||||
}
|
||||
|
|
@ -2002,3 +2004,11 @@ UINT32 I_GetRefreshRate(void)
|
|||
// trouble querying mode over and over again.
|
||||
return refresh_rate;
|
||||
}
|
||||
|
||||
static void Impl_SetVsync(void)
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST(2,0,18)
|
||||
if (renderer)
|
||||
SDL_RenderSetVSync(renderer, cv_vidwait.value);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1114,6 +1114,9 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
|
||||
{"ffbonc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Shout message sound effect
|
||||
{"sysmsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Server notification"},
|
||||
|
||||
// SRB2Kart - Engine sounds
|
||||
// Engine class A
|
||||
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
|
|
@ -1179,6 +1179,9 @@ typedef enum
|
|||
// Fast fall bounce
|
||||
sfx_ffbonc,
|
||||
|
||||
// Shout message sound effect
|
||||
sfx_sysmsg,
|
||||
|
||||
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
|
||||
// Engine class A - Low Speed, Low Weight
|
||||
sfx_krta00,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include "lua_hudlib_drawlist.h"
|
||||
#include "lua_hud.h"
|
||||
#include "lua_hook.h"
|
||||
|
||||
// SRB2Kart
|
||||
#include "k_hud.h" // SRB2kart
|
||||
|
|
@ -965,7 +966,7 @@ luahook:
|
|||
if (renderisnewtic)
|
||||
{
|
||||
LUA_HUD_ClearDrawList(luahuddrawlist_titlecard);
|
||||
LUAh_TitleCardHUD(stplyr, luahuddrawlist_titlecard);
|
||||
LUA_HookHUD(luahuddrawlist_titlecard, HUD_HOOK(titlecard));
|
||||
}
|
||||
LUA_HUD_DrawList(luahuddrawlist_titlecard);
|
||||
}
|
||||
|
|
@ -1012,7 +1013,7 @@ static void ST_overlayDrawer(void)
|
|||
if (renderisnewtic)
|
||||
{
|
||||
LUA_HUD_ClearDrawList(luahuddrawlist_game);
|
||||
LUAh_GameHUD(stplyr, luahuddrawlist_game);
|
||||
LUA_HookHUD(luahuddrawlist_game, HUD_HOOK(game));
|
||||
}
|
||||
LUA_HUD_DrawList(luahuddrawlist_game);
|
||||
}
|
||||
|
|
@ -1217,7 +1218,7 @@ void ST_Drawer(void)
|
|||
switch (demo.savemode)
|
||||
{
|
||||
case DSM_NOTSAVING:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Look Backward: Save replay");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "(B) or (X): Save replay");
|
||||
break;
|
||||
|
||||
case DSM_WILLAUTOSAVE:
|
||||
|
|
|
|||
|
|
@ -2560,6 +2560,30 @@ void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, con
|
|||
V_DrawThinStringAtFixed(x, y, option, string);
|
||||
}
|
||||
|
||||
// Draws a number using the PING font thingy.
|
||||
// TODO: Merge number drawing functions into one with "font name" selection.
|
||||
|
||||
INT32 V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap)
|
||||
{
|
||||
INT32 w = SHORT(fontv[PINGNUM_FONT].font[0]->width); // this SHOULD always be 5 but I guess custom graphics exist.
|
||||
|
||||
if (flags & V_NOSCALESTART)
|
||||
w *= vid.dupx;
|
||||
|
||||
if (num < 0)
|
||||
num = -num;
|
||||
|
||||
// draw the number
|
||||
do
|
||||
{
|
||||
x -= (w-1); // Oni wanted their outline to intersect.
|
||||
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, fontv[PINGNUM_FONT].font[num%10], colormap);
|
||||
num /= 10;
|
||||
} while (num);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void V_DrawCenteredKartString(INT32 x, INT32 y, INT32 option, const char *string)
|
||||
{
|
||||
x -= V_KartStringWidth(string, option)/2;
|
||||
|
|
@ -2683,28 +2707,6 @@ void V_DrawProfileNum(INT32 x, INT32 y, INT32 flags, UINT8 num)
|
|||
} while (--digits);
|
||||
}
|
||||
|
||||
// Draws a number using the PING font thingy.
|
||||
// TODO: Merge number drawing functions into one with "font name" selection.
|
||||
|
||||
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap)
|
||||
{
|
||||
INT32 w = SHORT(fontv[PINGNUM_FONT].font[0]->width); // this SHOULD always be 5 but I guess custom graphics exist.
|
||||
|
||||
if (flags & V_NOSCALESTART)
|
||||
w *= vid.dupx;
|
||||
|
||||
if (num < 0)
|
||||
num = -num;
|
||||
|
||||
// draw the number
|
||||
do
|
||||
{
|
||||
x -= (w-1); // Oni wanted their outline to intersect.
|
||||
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, fontv[PINGNUM_FONT].font[num%10], colormap);
|
||||
num /= 10;
|
||||
} while (num);
|
||||
}
|
||||
|
||||
// Find max height of the string
|
||||
//
|
||||
INT32 V_LevelNameHeight(const char *string)
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits)
|
|||
|
||||
// Draw ping numbers. Used by the scoreboard and that one ping option. :P
|
||||
// This is a separate function because IMO lua should have access to it as well.
|
||||
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap);
|
||||
INT32 V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap);
|
||||
|
||||
void V_DrawProfileNum(INT32 x, INT32 y, INT32 flags, UINT8 num);
|
||||
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ void Y_IntermissionDrawer(void)
|
|||
if (renderisnewtic)
|
||||
{
|
||||
LUA_HUD_ClearDrawList(luahuddrawlist_intermission);
|
||||
LUAh_IntermissionHUD(luahuddrawlist_intermission);
|
||||
LUA_HookHUD(luahuddrawlist_intermission, HUD_HOOK(intermission));
|
||||
}
|
||||
LUA_HUD_DrawList(luahuddrawlist_intermission);
|
||||
|
||||
|
|
@ -591,7 +591,7 @@ skiptallydrawer:
|
|||
switch (demo.savemode)
|
||||
{
|
||||
case DSM_NOTSAVING:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "(B): Save replay");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "(B) or (X): Save replay");
|
||||
break;
|
||||
|
||||
case DSM_SAVED:
|
||||
|
|
@ -632,7 +632,7 @@ void Y_Ticker(void)
|
|||
|
||||
if (demo.recording)
|
||||
{
|
||||
if (demo.savemode == DSM_NOTSAVING && G_PlayerInputDown(0, gc_y, 0))
|
||||
if (demo.savemode == DSM_NOTSAVING && !menuactive && (G_PlayerInputDown(0, gc_b, 0) || G_PlayerInputDown(0, gc_x, 0)))
|
||||
demo.savemode = DSM_TITLEENTRY;
|
||||
|
||||
if (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE)
|
||||
|
|
@ -643,7 +643,7 @@ void Y_Ticker(void)
|
|||
if (paused || P_AutoPause())
|
||||
return;
|
||||
|
||||
LUAh_IntermissionThinker();
|
||||
LUA_HOOK(IntermissionThinker);
|
||||
|
||||
intertic++;
|
||||
|
||||
|
|
@ -883,6 +883,7 @@ void Y_StartIntermission(void)
|
|||
K_CashInPowerLevels();
|
||||
}
|
||||
|
||||
Automate_Run(AEV_INTERMISSIONSTART);
|
||||
bgpatch = W_CachePatchName("MENUBG", PU_STATIC);
|
||||
widebgpatch = W_CachePatchName("WEIRDRES", PU_STATIC);
|
||||
|
||||
|
|
@ -1258,7 +1259,7 @@ void Y_VoteTicker(void)
|
|||
if (paused || P_AutoPause() || !voteclient.loaded)
|
||||
return;
|
||||
|
||||
LUAh_VoteThinker();
|
||||
LUA_HOOK(VoteThinker);
|
||||
|
||||
votetic++;
|
||||
|
||||
|
|
@ -1474,6 +1475,7 @@ void Y_VoteTicker(void)
|
|||
void Y_StartVote(void)
|
||||
{
|
||||
INT32 i = 0;
|
||||
boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules
|
||||
|
||||
votetic = -1;
|
||||
|
||||
|
|
@ -1482,8 +1484,8 @@ void Y_StartVote(void)
|
|||
I_Error("voteendtic is dirty");
|
||||
#endif
|
||||
|
||||
widebgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCW" : "INTERSCW"), PU_STATIC);
|
||||
bgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCR" : "INTERSCR"), PU_STATIC);
|
||||
widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC);
|
||||
bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC);
|
||||
cursor = W_CachePatchName("M_CURSOR", PU_STATIC);
|
||||
cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC);
|
||||
cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC);
|
||||
|
|
@ -1515,8 +1517,8 @@ void Y_StartVote(void)
|
|||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
// set up the encore
|
||||
levelinfo[i].encore = (votelevels[i][1] & 0x80);
|
||||
votelevels[i][1] &= ~0x80;
|
||||
levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE);
|
||||
votelevels[i][1] &= ~VOTEMODIFIER_ENCORE;
|
||||
|
||||
// set up the levelstring
|
||||
if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0])
|
||||
|
|
@ -1557,6 +1559,7 @@ void Y_StartVote(void)
|
|||
}
|
||||
|
||||
voteclient.loaded = true;
|
||||
Automate_Run(AEV_VOTESTART);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue