mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-28 02:32:48 +00:00
Merge branch 'monkey-input' of git.do.srb2.org:KartKrew/Kart into monkey-input
This commit is contained in:
commit
030d3d0656
57 changed files with 1369 additions and 511 deletions
|
|
@ -338,6 +338,8 @@ static bool ACS_CountThing(mobj_t *mobj, mobjtype_t type)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Unused, but it's here if you need it.
|
||||
#if 0
|
||||
/*--------------------------------------------------
|
||||
static bool ACS_ActivatorIsLocal(ACSVM::Thread *thread)
|
||||
|
||||
|
|
@ -365,6 +367,7 @@ static bool ACS_ActivatorIsLocal(ACSVM::Thread *thread)
|
|||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------
|
||||
static UINT32 ACS_SectorThingCounter(sector_t *sec, mtag_t thingTag, bool (*filter)(mobj_t *))
|
||||
|
|
@ -823,8 +826,10 @@ bool CallFunc_EndPrint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo
|
|||
(void)argV;
|
||||
(void)argC;
|
||||
|
||||
if (ACS_ActivatorIsLocal(thread) == true)
|
||||
HU_DoTitlecardCEcho(thread->printBuf.data());
|
||||
auto& info = static_cast<Thread*>(thread)->info;
|
||||
|
||||
if (P_MobjWasRemoved(info.mo) == false && info.mo->player != nullptr)
|
||||
HU_DoTitlecardCEcho(info.mo->player, thread->printBuf.data(), true);
|
||||
|
||||
thread->printBuf.drop();
|
||||
return false;
|
||||
|
|
@ -1203,7 +1208,7 @@ bool CallFunc_EndPrintBold(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM
|
|||
(void)argV;
|
||||
(void)argC;
|
||||
|
||||
HU_DoTitlecardCEcho(thread->printBuf.data());
|
||||
HU_DoTitlecardCEcho(nullptr, thread->printBuf.data(), true);
|
||||
|
||||
thread->printBuf.drop();
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -777,15 +777,17 @@ static void COM_CEcho_f(void)
|
|||
size_t i;
|
||||
char cechotext[1024] = "";
|
||||
|
||||
for (i = 1; i < COM_Argc(); i++)
|
||||
strncpy(cechotext, COM_Argv(1), sizeof(cechotext)-1);
|
||||
|
||||
for (i = 2; i < COM_Argc(); i++)
|
||||
{
|
||||
strncat(cechotext, COM_Argv(i), sizeof(cechotext)-1);
|
||||
strncat(cechotext, " ", sizeof(cechotext)-1);
|
||||
strncat(cechotext, COM_Argv(i), sizeof(cechotext)-1);
|
||||
}
|
||||
|
||||
cechotext[sizeof(cechotext) - 1] = '\0';
|
||||
|
||||
HU_DoCEcho(cechotext);
|
||||
HU_DoTitlecardCEcho(NULL, cechotext, true);
|
||||
}
|
||||
|
||||
/** Sets drawing flags for the CECHO command.
|
||||
|
|
|
|||
|
|
@ -502,6 +502,7 @@ consvar_t cv_kicktime = Server("kicktime", "20").values(CV_Unsigned);
|
|||
|
||||
void MasterServer_OnChange(void);
|
||||
consvar_t cv_masterserver = Server("masterserver", "https://ms.kartkrew.org/ms/api").onchange(MasterServer_OnChange);
|
||||
consvar_t cv_masterserver_nagattempts = Server("masterserver_nagattempts", "5").values(CV_Unsigned);
|
||||
|
||||
void MasterServer_Debug_OnChange (void);
|
||||
consvar_t cv_masterserver_debug = Server("masterserver_debug", "Off").on_off().onchange(MasterServer_Debug_OnChange);
|
||||
|
|
@ -540,13 +541,14 @@ consvar_t cv_server_contact = Server("server_contact", "").onchange_noinit(Updat
|
|||
consvar_t cv_servername = Server("servername", "Ring Racers server").onchange_noinit(Update_parameters);
|
||||
|
||||
void M_SortServerList(void);
|
||||
consvar_t cv_serversort = Server("serversort", "Ping").dont_save().onchange(M_SortServerList).values({
|
||||
{0,"Ping"},
|
||||
{1,"AVG. Power Level"},
|
||||
{2,"Most Players"},
|
||||
{3,"Least Players"},
|
||||
{4,"Max Player Slots"},
|
||||
{5,"Gametype"},
|
||||
consvar_t cv_serversort = Server("serversort", "Recommended").dont_save().onchange(M_SortServerList).values({
|
||||
{-1, "Recommended"},
|
||||
{ 0, "Ping"},
|
||||
{ 1, "AVG. Power Level"},
|
||||
{ 2, "Most Players"},
|
||||
{ 3, "Least Players"},
|
||||
{ 4, "Max Player Slots"},
|
||||
{ 5, "Gametype"},
|
||||
});
|
||||
|
||||
// show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping)
|
||||
|
|
|
|||
104
src/d_clisrv.c
104
src/d_clisrv.c
|
|
@ -1550,6 +1550,10 @@ static void SendAskInfo(INT32 node)
|
|||
|
||||
serverelem_t serverlist[MAXSERVERLIST];
|
||||
UINT32 serverlistcount = 0;
|
||||
UINT32 serverlistultimatecount = 0;
|
||||
|
||||
static boolean resendserverlistnode[MAXNETNODES];
|
||||
static tic_t serverlistepoch;
|
||||
|
||||
static void SL_ClearServerList(INT32 connectedserver)
|
||||
{
|
||||
|
|
@ -1562,6 +1566,8 @@ static void SL_ClearServerList(INT32 connectedserver)
|
|||
serverlist[i].node = 0;
|
||||
}
|
||||
serverlistcount = 0;
|
||||
|
||||
memset(resendserverlistnode, 0, sizeof resendserverlistnode);
|
||||
}
|
||||
|
||||
static UINT32 SL_SearchServer(INT32 node)
|
||||
|
|
@ -1574,32 +1580,37 @@ static UINT32 SL_SearchServer(INT32 node)
|
|||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
|
||||
static boolean SL_InsertServer(serverinfo_pak* info, SINT8 node)
|
||||
{
|
||||
UINT32 i;
|
||||
|
||||
resendserverlistnode[node] = false;
|
||||
|
||||
// search if not already on it
|
||||
i = SL_SearchServer(node);
|
||||
if (i == UINT32_MAX)
|
||||
{
|
||||
// not found add it
|
||||
if (serverlistcount >= MAXSERVERLIST)
|
||||
return; // list full
|
||||
return false; // list full
|
||||
|
||||
if (info->_255 != 255)
|
||||
return;/* old packet format */
|
||||
return false;/* old packet format */
|
||||
|
||||
if (info->packetversion != PACKETVERSION)
|
||||
return;/* old new packet format */
|
||||
return false;/* old new packet format */
|
||||
|
||||
if (info->version != VERSION)
|
||||
return; // Not same version.
|
||||
return false; // Not same version.
|
||||
|
||||
if (info->subversion != SUBVERSION)
|
||||
return; // Close, but no cigar.
|
||||
return false; // Close, but no cigar.
|
||||
|
||||
if (strcmp(info->application, SRB2APPLICATION))
|
||||
return;/* that's a different mod */
|
||||
return false;/* that's a different mod */
|
||||
|
||||
if (info->modifiedgame != (mpmenu.room == 1))
|
||||
return false;/* CORE vs MODDED! */
|
||||
|
||||
i = serverlistcount++;
|
||||
}
|
||||
|
|
@ -1609,6 +1620,8 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
|
|||
|
||||
// resort server list
|
||||
M_SortServerList();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CL_QueryServerList (msg_server_t *server_list)
|
||||
|
|
@ -1617,6 +1630,8 @@ void CL_QueryServerList (msg_server_t *server_list)
|
|||
|
||||
CL_UpdateServerList();
|
||||
|
||||
serverlistepoch = I_GetTime();
|
||||
|
||||
for (i = 0; server_list[i].header.buffer[0]; i++)
|
||||
{
|
||||
// Make sure MS version matches our own, to
|
||||
|
|
@ -1629,19 +1644,43 @@ void CL_QueryServerList (msg_server_t *server_list)
|
|||
if (node == -1)
|
||||
break; // no more node free
|
||||
SendAskInfo(node);
|
||||
// Force close the connection so that servers can't eat
|
||||
// up nodes forever if we never get a reply back from them
|
||||
// (usually when they've not forwarded their ports).
|
||||
//
|
||||
// Don't worry, we'll get in contact with the working
|
||||
// servers again when they send SERVERINFO to us later!
|
||||
//
|
||||
// (Note: as a side effect this probably means every
|
||||
// server in the list will probably be using the same node (e.g. node 1),
|
||||
// not that it matters which nodes they use when
|
||||
// the connections are closed afterwards anyway)
|
||||
// -- Monster Iestyn 12/11/18
|
||||
Net_CloseConnection(node|FORCECLOSE);
|
||||
|
||||
resendserverlistnode[node] = true;
|
||||
// Leave this node open. It'll be closed if the
|
||||
// request times out (CL_TimeoutServerList).
|
||||
}
|
||||
}
|
||||
|
||||
serverlistultimatecount = i;
|
||||
}
|
||||
|
||||
#define SERVERLISTRESENDRATE NEWTICRATE
|
||||
|
||||
void CL_TimeoutServerList(void)
|
||||
{
|
||||
if (netgame && serverlistultimatecount > serverlistcount)
|
||||
{
|
||||
const tic_t timediff = I_GetTime() - serverlistepoch;
|
||||
const tic_t timetoresend = timediff % SERVERLISTRESENDRATE;
|
||||
const boolean timedout = timediff > connectiontimeout;
|
||||
|
||||
if (timedout || (timediff > 0 && timetoresend == 0))
|
||||
{
|
||||
INT32 node;
|
||||
|
||||
for (node = 1; node < MAXNETNODES; ++node)
|
||||
{
|
||||
if (resendserverlistnode[node])
|
||||
{
|
||||
if (timedout)
|
||||
Net_CloseConnection(node|FORCECLOSE);
|
||||
else
|
||||
SendAskInfo(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (timedout)
|
||||
serverlistultimatecount = serverlistcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3875,22 +3914,14 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
|
|||
|
||||
CONS_Debug(DBG_NETPLAY, "addplayer: %d %d\n", node, newplayernum);
|
||||
|
||||
{
|
||||
// Clear player before joining, lest some things get set incorrectly
|
||||
CL_ClearPlayer(newplayernum);
|
||||
G_DestroyParty(newplayernum);
|
||||
G_AddPlayer(newplayernum);
|
||||
//G_SpectatePlayerOnJoin(newplayernum); -- caused desyncs in this spot :(
|
||||
|
||||
playeringame[newplayernum] = true;
|
||||
G_AddPlayer(newplayernum);
|
||||
|
||||
if (newplayernum+1 > doomcom->numslots)
|
||||
doomcom->numslots = (INT16)(newplayernum+1);
|
||||
}
|
||||
if (newplayernum+1 > doomcom->numslots)
|
||||
doomcom->numslots = (INT16)(newplayernum+1);
|
||||
|
||||
newplayer = &players[newplayernum];
|
||||
|
||||
newplayer->jointime = 0;
|
||||
|
||||
READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME);
|
||||
READMEM(*p, players[newplayernum].public_key, PUBKEYLENGTH);
|
||||
READMEM(*p, clientpowerlevels[newplayernum], sizeof(((serverplayer_t *)0)->powerlevels));
|
||||
|
|
@ -4195,6 +4226,11 @@ boolean SV_SpawnServer(void)
|
|||
I_NetOpenSocket();
|
||||
}
|
||||
|
||||
if (cv_advertise.value)
|
||||
{
|
||||
RegisterServer();
|
||||
}
|
||||
|
||||
ourIP = 0;
|
||||
STUN_bind(GotOurIP);
|
||||
}
|
||||
|
|
@ -4617,7 +4653,9 @@ static void HandleServerInfo(SINT8 node)
|
|||
memcpy(servername, netbuffer->u.serverinfo.servername, MAXSERVERNAME);
|
||||
CopyCaretColors(netbuffer->u.serverinfo.servername, servername, MAXSERVERNAME);
|
||||
|
||||
SL_InsertServer(&netbuffer->u.serverinfo, node);
|
||||
// If we have cause to reject it, it's not worth observing.
|
||||
if (SL_InsertServer(&netbuffer->u.serverinfo, node) == false)
|
||||
serverlistultimatecount--;
|
||||
}
|
||||
|
||||
static void PT_WillResendGamestate(void)
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ struct serverelem_t
|
|||
};
|
||||
|
||||
extern serverelem_t serverlist[MAXSERVERLIST];
|
||||
extern UINT32 serverlistcount;
|
||||
extern UINT32 serverlistcount, serverlistultimatecount;
|
||||
extern INT32 mapchangepending;
|
||||
|
||||
// Points inside doomcom
|
||||
|
|
@ -595,6 +595,7 @@ void CL_ClearPlayer(INT32 playernum);
|
|||
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
|
||||
void CL_QueryServerList(msg_server_t *list);
|
||||
void CL_UpdateServerList(void);
|
||||
void CL_TimeoutServerList(void);
|
||||
// Is there a game running
|
||||
boolean Playing(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -1193,14 +1193,13 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
|
|||
&& LUA_HookTeamSwitch(&players[playernum], 0, false, false, false)) // fiiiine, lua can except it
|
||||
{
|
||||
P_DamageMobj(players[playernum].mo, NULL, NULL, 1, DMG_SPECTATOR);
|
||||
players[playernum].playerstate = PST_REBORN;
|
||||
|
||||
players[playernum].pflags &= ~PF_WANTSTOJOIN;
|
||||
players[playernum].spectator = true;
|
||||
if (players[i].spectator)
|
||||
{
|
||||
HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false);
|
||||
|
||||
HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false);
|
||||
|
||||
FinalisePlaystateChange(playernum);
|
||||
FinalisePlaystateChange(playernum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3452,6 +3451,22 @@ static void Command_ServerTeamChange_f(void)
|
|||
SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue));
|
||||
}
|
||||
|
||||
void P_SetPlayerSpectator(INT32 playernum)
|
||||
{
|
||||
//Make sure you're in the right gametype.
|
||||
if (!G_GametypeHasTeams() && !G_GametypeHasSpectators())
|
||||
return;
|
||||
|
||||
// Don't duplicate efforts.
|
||||
if (players[playernum].spectator)
|
||||
return;
|
||||
|
||||
players[playernum].spectator = true;
|
||||
players[playernum].pflags &= ~PF_WANTSTOJOIN;
|
||||
|
||||
players[playernum].playerstate = PST_REBORN;
|
||||
}
|
||||
|
||||
//todo: This and the other teamchange functions are getting too long and messy. Needs cleaning.
|
||||
static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
|
|
@ -3523,55 +3538,38 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
//Safety first!
|
||||
// (not respawning spectators here...)
|
||||
wasspectator = (players[playernum].spectator == true);
|
||||
|
||||
if (!wasspectator && gamestate == GS_LEVEL)
|
||||
{
|
||||
if (players[playernum].mo)
|
||||
{
|
||||
P_DamageMobj(players[playernum].mo, NULL, NULL, 1,
|
||||
(NetPacket.packet.newteam ? DMG_INSTAKILL : DMG_SPECTATOR));
|
||||
}
|
||||
//else
|
||||
if (!NetPacket.packet.newteam)
|
||||
{
|
||||
players[playernum].playerstate = PST_REBORN;
|
||||
}
|
||||
}
|
||||
|
||||
players[playernum].pflags &= ~PF_WANTSTOJOIN;
|
||||
if (!wasspectator)
|
||||
{
|
||||
if (gamestate == GS_LEVEL && players[playernum].mo)
|
||||
{
|
||||
// The following will call P_SetPlayerSpectator if successful
|
||||
P_DamageMobj(players[playernum].mo, NULL, NULL, 1, DMG_SPECTATOR);
|
||||
}
|
||||
|
||||
//...but because the above could return early under some contexts, we try again here
|
||||
P_SetPlayerSpectator(playernum);
|
||||
}
|
||||
|
||||
//Now that we've done our error checking and killed the player
|
||||
//if necessary, put the player on the correct team/status.
|
||||
boolean nochangeoccourred = false;
|
||||
|
||||
if (NetPacket.packet.newteam != 0)
|
||||
{
|
||||
// This serves us in both teamchange contexts.
|
||||
players[playernum].pflags |= PF_WANTSTOJOIN;
|
||||
}
|
||||
|
||||
if (G_GametypeHasTeams())
|
||||
{
|
||||
if (!NetPacket.packet.newteam)
|
||||
{
|
||||
players[playernum].ctfteam = 0;
|
||||
players[playernum].spectator = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
players[playernum].ctfteam = NetPacket.packet.newteam;
|
||||
players[playernum].pflags |= PF_WANTSTOJOIN; //players[playernum].spectator = false;
|
||||
nochangeoccourred = true;
|
||||
}
|
||||
}
|
||||
else if (G_GametypeHasSpectators())
|
||||
{
|
||||
if (!NetPacket.packet.newteam)
|
||||
players[playernum].spectator = true;
|
||||
else
|
||||
{
|
||||
players[playernum].pflags |= PF_WANTSTOJOIN; //players[playernum].spectator = false;
|
||||
nochangeoccourred = true;
|
||||
}
|
||||
// This one is, of course, specific.
|
||||
players[playernum].ctfteam = NetPacket.packet.newteam;
|
||||
}
|
||||
|
||||
if (NetPacket.packet.autobalance)
|
||||
|
|
@ -3599,20 +3597,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
else if (NetPacket.packet.newteam == 0 && !wasspectator)
|
||||
HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); // "entered the game" text was moved to P_SpectatorJoinGame
|
||||
|
||||
/*if (G_GametypeHasTeams())
|
||||
{
|
||||
if (NetPacket.packet.newteam)
|
||||
{
|
||||
UINT8 i;
|
||||
for (i = 0; i <= splitscreen; i++)
|
||||
{
|
||||
if (playernum == g_localplayers[i]) //CTF and Team Match colors.
|
||||
CV_SetValue(&cv_playercolor[i], NetPacket.packet.newteam + 5); - -this calculation is totally wrong
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (gamestate != GS_LEVEL || nochangeoccourred == true)
|
||||
if (gamestate != GS_LEVEL || wasspectator == true)
|
||||
return;
|
||||
|
||||
FinalisePlaystateChange(playernum);
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ void D_SetupVote(void);
|
|||
void D_ModifyClientVote(UINT8 player, SINT8 voted);
|
||||
void D_PickVote(void);
|
||||
void ObjectPlace_OnChange(void);
|
||||
void P_SetPlayerSpectator(INT32 playernum);
|
||||
boolean IsPlayerAdmin(INT32 playernum);
|
||||
void SetAdminPlayer(INT32 playernum);
|
||||
void ClearAdminPlayers(void);
|
||||
|
|
|
|||
|
|
@ -5809,6 +5809,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_BATTLEUFO_BEAM",
|
||||
|
||||
"MT_POWERUP_AURA",
|
||||
|
||||
"MT_SCRIPT_THING",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
|
|||
I_OsPolling();
|
||||
I_UpdateNoBlit();
|
||||
|
||||
if (drawMenu)
|
||||
if (drawMenu && rendermode != render_none)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
I_lock_mutex(&k_menu_mutex);
|
||||
|
|
|
|||
39
src/g_demo.c
39
src/g_demo.c
|
|
@ -228,10 +228,7 @@ void G_ReadDemoExtraData(void)
|
|||
{
|
||||
if (!playeringame[p])
|
||||
{
|
||||
CL_ClearPlayer(p);
|
||||
playeringame[p] = true;
|
||||
G_AddPlayer(p);
|
||||
players[p].spectator = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXAVAILABILITY; i++)
|
||||
|
|
@ -253,28 +250,34 @@ void G_ReadDemoExtraData(void)
|
|||
|
||||
switch (i) {
|
||||
case DXD_PST_PLAYING:
|
||||
if (players[p].bot)
|
||||
if (players[p].spectator == true)
|
||||
{
|
||||
players[p].spectator = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
players[p].pflags |= PF_WANTSTOJOIN;
|
||||
if (players[p].bot)
|
||||
{
|
||||
players[p].spectator = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
players[p].pflags |= PF_WANTSTOJOIN;
|
||||
}
|
||||
}
|
||||
//CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime);
|
||||
break;
|
||||
|
||||
case DXD_PST_SPECTATING:
|
||||
players[p].pflags &= ~PF_WANTSTOJOIN; // double-fuck you
|
||||
if (players[p].spectator != true)
|
||||
if (players[p].spectator)
|
||||
{
|
||||
//CONS_Printf("player %s is spectating on tic %d\n", player_names[p], leveltime);
|
||||
players[p].spectator = true;
|
||||
if (players[p].mo)
|
||||
P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_INSTAKILL);
|
||||
else
|
||||
players[p].playerstate = PST_REBORN;
|
||||
players[p].pflags &= ~PF_WANTSTOJOIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (players[p].mo)
|
||||
{
|
||||
P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_SPECTATOR);
|
||||
}
|
||||
P_SetPlayerSpectator(p);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DXD_PST_LEFT:
|
||||
|
|
@ -3420,7 +3423,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
if (!playeringame[displayplayers[0]] || players[displayplayers[0]].spectator)
|
||||
displayplayers[0] = consoleplayer = serverplayer = p;
|
||||
|
||||
playeringame[p] = true;
|
||||
G_AddPlayer(p);
|
||||
players[p].spectator = spectator;
|
||||
|
||||
if (flags & DEMO_KICKSTART)
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ extern UINT8 demo_writerng;
|
|||
#define DXD_COLOR 0x10 // color changed
|
||||
#define DXD_FOLLOWER 0x20 // follower was changed
|
||||
|
||||
#define DXD_ADDPLAYER (DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER)
|
||||
|
||||
#define DXD_WEAPONPREF 0x80 // netsynced playsim settings were changed
|
||||
|
||||
#define DXD_PST_PLAYING 0x01
|
||||
|
|
|
|||
59
src/g_game.c
59
src/g_game.c
|
|
@ -1146,7 +1146,7 @@ void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate)
|
|||
else
|
||||
{
|
||||
// Podium: writetextmap is finished. Yay!
|
||||
HU_DoTitlecardCEcho(va("Congratulations,\\%s!\\Check the console!", cv_playername[0].string));
|
||||
HU_DoTitlecardCEcho(NULL, va("Congratulations,\\%s!\\Check the console!", cv_playername[0].string), true);
|
||||
|
||||
livestudioaudience_timer = 0;
|
||||
LiveStudioAudience();
|
||||
|
|
@ -1276,6 +1276,10 @@ boolean G_IsTitleCardAvailable(void)
|
|||
if (gametyperules & GTR_SPECIALSTART)
|
||||
return false;
|
||||
|
||||
// ALso.
|
||||
if (K_PodiumSequence() == true)
|
||||
return false;
|
||||
|
||||
// The title card is available.
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2827,9 +2831,6 @@ void G_DoReborn(INT32 playernum)
|
|||
{
|
||||
player_t *player = &players[playernum];
|
||||
|
||||
// Make sure objectplace is OFF when you first start the level!
|
||||
OP_ResetObjectplace();
|
||||
|
||||
{
|
||||
// respawn at the start
|
||||
mobj_t *oldmo = NULL;
|
||||
|
|
@ -2850,11 +2851,53 @@ void G_DoReborn(INT32 playernum)
|
|||
}
|
||||
}
|
||||
|
||||
// These are the barest esentials.
|
||||
// This func probably doesn't even need to know if the player is a bot.
|
||||
void G_AddPlayer(INT32 playernum)
|
||||
{
|
||||
player_t *p = &players[playernum];
|
||||
p->playerstate = PST_REBORN;
|
||||
demo_extradata[playernum] |= DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER; // Set everything
|
||||
CL_ClearPlayer(playernum);
|
||||
G_DestroyParty(playernum);
|
||||
|
||||
playeringame[playernum] = true;
|
||||
|
||||
player_t *newplayer = &players[playernum];
|
||||
|
||||
newplayer->playerstate = PST_REBORN;
|
||||
newplayer->jointime = 0;
|
||||
|
||||
demo_extradata[playernum] |= DXD_ADDPLAYER;
|
||||
}
|
||||
|
||||
void G_SpectatePlayerOnJoin(INT32 playernum)
|
||||
{
|
||||
// This is only ever called shortly after the above.
|
||||
// That calls CL_ClearPlayer, so spectator is false by default
|
||||
|
||||
if (!netgame && !G_GametypeHasTeams() && !G_GametypeHasSpectators())
|
||||
return;
|
||||
|
||||
// These are handled automatically elsewhere
|
||||
if (demo.playback || players[playernum].bot)
|
||||
return;
|
||||
|
||||
UINT8 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
|
||||
// Spectators are of no consequence
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
|
||||
// Prevent splitscreen hosters/joiners from only adding 1 player at a time in empty servers (this will also catch yourself)
|
||||
if (!players[i].jointime)
|
||||
continue;
|
||||
|
||||
// A ha! An established player! It's time to spectate
|
||||
players[playernum].spectator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void G_BeginLevelExit(void)
|
||||
|
|
@ -3273,7 +3316,7 @@ boolean G_GametypeHasSpectators(void)
|
|||
#ifdef DEVELOP
|
||||
return true;
|
||||
#endif
|
||||
return (netgame || (multiplayer && demo.netgame));
|
||||
return (netgame || (demo.playback && demo.netgame));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive);
|
|||
void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive);
|
||||
|
||||
void G_AddPlayer(INT32 playernum);
|
||||
void G_SpectatePlayerOnJoin(INT32 playernum);
|
||||
|
||||
void G_SetExitGameFlag(void);
|
||||
void G_ClearExitGameFlag(void);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
/*
|
||||
Documentation available here.
|
||||
|
||||
<https://ms.kartkrew.org/tools/api/2/>
|
||||
<https://ms.kartkrew.org/tools/api/2.2/>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CURL
|
||||
|
|
@ -441,7 +441,12 @@ HMS_fetch_servers (msg_server_t *list, int query_id)
|
|||
break;
|
||||
#endif
|
||||
|
||||
//#define MSERVTESTALONE
|
||||
#ifdef MSERVTESTALONE
|
||||
strcpy(list[i].ip, "127.0.0.1"); // MS test without needing a second person to host
|
||||
#else
|
||||
strlcpy(list[i].ip, address, sizeof list[i].ip);
|
||||
#endif
|
||||
strlcpy(list[i].port, port, sizeof list[i].port);
|
||||
|
||||
if (contact)
|
||||
|
|
@ -511,6 +516,40 @@ HMS_compare_mod_version (char *buffer, size_t buffer_size)
|
|||
return ok;
|
||||
}
|
||||
|
||||
const char *
|
||||
HMS_fetch_rules (char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct HMS_buffer *hms;
|
||||
|
||||
hms = HMS_connect("rules");
|
||||
|
||||
if (! hms)
|
||||
return NULL;
|
||||
|
||||
boolean ok = HMS_do(hms);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
char *p = strstr(hms->buffer, "\n\n");
|
||||
|
||||
if (p)
|
||||
{
|
||||
p[1] = '\0';
|
||||
|
||||
strlcpy(buffer, hms->buffer, buffer_size);
|
||||
}
|
||||
else
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
HMS_end(hms);
|
||||
|
||||
if (!ok)
|
||||
return NULL;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char *
|
||||
Strip_trailing_slashes (char *api)
|
||||
{
|
||||
|
|
|
|||
145
src/hu_stuff.c
145
src/hu_stuff.c
|
|
@ -62,6 +62,7 @@
|
|||
#include "r_fps.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "y_inter.h" // Y_PlayerStandingsDrawer
|
||||
#include "g_party.h"
|
||||
|
||||
// coords are scaled
|
||||
#define HU_INPUTX 0
|
||||
|
|
@ -157,10 +158,15 @@ static tic_t cechotimer = 0;
|
|||
static tic_t cechoduration = 5*TICRATE;
|
||||
static INT32 cechoflags = 0;
|
||||
|
||||
static char tcechotext[1024]; // buffer for the titlecard text
|
||||
static tic_t tcechotimer = 0; // goes up by 1 each frame this is active
|
||||
static tic_t tcechoduration = 0; // Set automatically
|
||||
struct tcecho_state
|
||||
{
|
||||
char text[1024]; // buffer for the titlecard text
|
||||
tic_t start; // gametic that the message started
|
||||
tic_t duration; // Set automatically
|
||||
};
|
||||
|
||||
#define NUM_TCECHO_STATES (1 + MAXSPLITSCREENPLAYERS)
|
||||
static struct tcecho_state g_tcecho[NUM_TCECHO_STATES];
|
||||
|
||||
static tic_t resynch_ticker = 0;
|
||||
|
||||
|
|
@ -283,6 +289,12 @@ void HU_Init(void)
|
|||
PR ("GTFN");
|
||||
REG;
|
||||
|
||||
PR ("4GTOL");
|
||||
REG;
|
||||
|
||||
PR ("4GTFN");
|
||||
REG;
|
||||
|
||||
DIG (1);
|
||||
|
||||
DIM (0, 10);
|
||||
|
|
@ -960,13 +972,6 @@ void HU_Ticker(void)
|
|||
|
||||
if (cechotimer)
|
||||
cechotimer--;
|
||||
|
||||
if (tcechotimer)
|
||||
{
|
||||
tcechotimer++;
|
||||
if (tcechotimer > tcechoduration)
|
||||
tcechotimer = 0;
|
||||
}
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
{
|
||||
|
|
@ -1829,12 +1834,31 @@ static void HU_DrawCEcho(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void HU_DrawTitlecardCEcho(void)
|
||||
static tic_t HU_TitlecardCEchoElapsed(const struct tcecho_state *state)
|
||||
{
|
||||
if (tcechotimer)
|
||||
return max(gametic, state->start) - state->start;
|
||||
}
|
||||
|
||||
static void HU_DrawTitlecardCEcho(size_t num)
|
||||
{
|
||||
const struct tcecho_state *state = &g_tcecho[num];
|
||||
|
||||
tic_t elapsed = HU_TitlecardCEchoElapsed(state);
|
||||
UINT8 viewnum = max(1, num) - 1;
|
||||
boolean p4 = (num != 0 && r_splitscreen);
|
||||
|
||||
// If the splitscreens were somehow decreased in the
|
||||
// middle of drawing this, don't draw it.
|
||||
if (viewnum > r_splitscreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (elapsed < state->duration)
|
||||
{
|
||||
INT32 i = 0;
|
||||
INT32 y = (BASEVIDHEIGHT/2)-16;
|
||||
INT32 x = BASEVIDWIDTH/2;
|
||||
INT32 y = BASEVIDHEIGHT/2;
|
||||
INT32 pnumlines = 0;
|
||||
INT32 timeroffset = 0;
|
||||
|
||||
|
|
@ -1842,11 +1866,28 @@ static void HU_DrawTitlecardCEcho(void)
|
|||
char *echoptr;
|
||||
char temp[1024];
|
||||
|
||||
for (i = 0; tcechotext[i] != '\0'; ++i)
|
||||
if (tcechotext[i] == '\\')
|
||||
for (i = 0; state->text[i] != '\0'; ++i)
|
||||
if (state->text[i] == '\\')
|
||||
pnumlines++;
|
||||
|
||||
y -= (pnumlines-1)*16;
|
||||
if (p4)
|
||||
{
|
||||
if (r_splitscreen == 1) // 2P
|
||||
{
|
||||
y -= (1 - (viewnum * 2)) * (y / 2);
|
||||
}
|
||||
else // 3P / 4P
|
||||
{
|
||||
x -= (1 - ((viewnum % 2) * 2)) * (x / 2);
|
||||
y -= (1 - ((viewnum / 2) * 2)) * (y / 2);
|
||||
}
|
||||
|
||||
y -= 11 + ((pnumlines-1) * 9);
|
||||
}
|
||||
else
|
||||
{
|
||||
y -= 18 + ((pnumlines-1) * 16);
|
||||
}
|
||||
|
||||
// Prevent crashing because I'm sick of this
|
||||
if (y < 0)
|
||||
|
|
@ -1856,13 +1897,13 @@ static void HU_DrawTitlecardCEcho(void)
|
|||
return;
|
||||
}
|
||||
|
||||
strcpy(temp, tcechotext);
|
||||
strcpy(temp, state->text);
|
||||
echoptr = &temp[0];
|
||||
|
||||
while (*echoptr != '\0')
|
||||
{
|
||||
INT32 w;
|
||||
INT32 timer = (INT32)(tcechotimer - timeroffset);
|
||||
INT32 ofs;
|
||||
INT32 timer = (INT32)(elapsed - timeroffset);
|
||||
|
||||
if (timer <= 0)
|
||||
return; // we don't care.
|
||||
|
|
@ -1874,10 +1915,10 @@ static void HU_DrawTitlecardCEcho(void)
|
|||
|
||||
*line = '\0';
|
||||
|
||||
w = V_TitleCardStringWidth(echoptr);
|
||||
V_DrawTitleCardString(BASEVIDWIDTH/2 -w/2, y, echoptr, 0, false, timer, TICRATE*4);
|
||||
ofs = V_CenteredTitleCardStringOffset(echoptr, p4);
|
||||
V_DrawTitleCardString(x - ofs, y, echoptr, 0, false, timer, TICRATE*4, p4);
|
||||
|
||||
y += 32;
|
||||
y += p4 ? 18 : 32;
|
||||
|
||||
// offset the timer for the next line.
|
||||
timeroffset += strlen(echoptr);
|
||||
|
|
@ -2037,9 +2078,23 @@ drawontop:
|
|||
|
||||
if (cechotimer)
|
||||
HU_DrawCEcho();
|
||||
|
||||
if (tcechotimer)
|
||||
HU_DrawTitlecardCEcho();
|
||||
|
||||
const struct tcecho_state *firststate = &g_tcecho[0];
|
||||
|
||||
// Server messages overwrite player-specific messages
|
||||
if (HU_TitlecardCEchoElapsed(firststate) < firststate->duration)
|
||||
{
|
||||
HU_DrawTitlecardCEcho(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 1; i < NUM_TCECHO_STATES; ++i)
|
||||
{
|
||||
HU_DrawTitlecardCEcho(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
|
@ -2576,17 +2631,41 @@ void HU_DoCEcho(const char *msg)
|
|||
// No need to bother clearing the buffer or anything.
|
||||
void HU_ClearTitlecardCEcho(void)
|
||||
{
|
||||
tcechotimer = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NUM_TCECHO_STATES; ++i)
|
||||
{
|
||||
g_tcecho[i].duration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar but for titlecard CEcho and also way less convoluted because I have no clue whatever the fuck they were trying above.
|
||||
void HU_DoTitlecardCEcho(const char *msg)
|
||||
void HU_DoTitlecardCEcho(player_t *player, const char *msg, boolean interrupt)
|
||||
{
|
||||
if (player && !P_IsDisplayPlayer(player))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct tcecho_state *state = &g_tcecho[0];
|
||||
|
||||
if (player)
|
||||
{
|
||||
state = &g_tcecho[1 + G_PartyPosition(player - players)];
|
||||
}
|
||||
|
||||
// If this message should not interrupt an existing
|
||||
// message. Check if another message is already running.
|
||||
if (!interrupt && HU_TitlecardCEchoElapsed(state) < state->duration)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
I_OutputMsg("%s\n", msg); // print to log
|
||||
|
||||
strncpy(tcechotext, msg, sizeof(tcechotext));
|
||||
strncat(tcechotext, "\\", sizeof(tcechotext) - strlen(tcechotext) - 1);
|
||||
tcechotext[sizeof(tcechotext) - 1] = '\0';
|
||||
tcechotimer = 1;
|
||||
tcechoduration = TICRATE*6 + strlen(tcechotext);
|
||||
|
||||
strncpy(state->text, msg, sizeof(state->text));
|
||||
strncat(state->text, "\\", sizeof(state->text) - strlen(state->text) - 1);
|
||||
state->text[sizeof(state->text) - 1] = '\0';
|
||||
state->start = gametic;
|
||||
state->duration = TICRATE*6 + strlen(state->text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ enum
|
|||
X (GTOL),
|
||||
X (GTFN),
|
||||
|
||||
X (GTOL4),
|
||||
X (GTFN4),
|
||||
|
||||
X (TALLNUM),
|
||||
X (NIGHTSNUM),
|
||||
X (PINGNUM),
|
||||
|
|
@ -163,7 +166,7 @@ void HU_SetCEchoFlags(INT32 flags);
|
|||
void HU_DoCEcho(const char *msg);
|
||||
|
||||
// Titlecard CECHO shite
|
||||
void HU_DoTitlecardCEcho(const char *msg);
|
||||
void HU_DoTitlecardCEcho(player_t *player, const char *msg, boolean interrupt);
|
||||
void HU_ClearTitlecardCEcho(void);
|
||||
|
||||
void DoSayCommand(char *message, SINT8 target, UINT8 flags, UINT8 source);
|
||||
|
|
|
|||
27
src/info.c
27
src/info.c
|
|
@ -30312,6 +30312,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SCRIPT_THING
|
||||
4096, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
16*FRACUNIT, // radius
|
||||
16*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
skincolor_t skincolors[MAXSKINCOLORS] = {
|
||||
|
|
|
|||
|
|
@ -6999,6 +6999,8 @@ typedef enum mobj_type
|
|||
|
||||
MT_POWERUP_AURA,
|
||||
|
||||
MT_SCRIPT_THING,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
|
|
@ -127,10 +127,7 @@ void K_CheckBumpers(void)
|
|||
{
|
||||
if (nobumpers > 0 && nobumpers >= numingame)
|
||||
{
|
||||
// TODO: this would make a great debug feature for release
|
||||
#ifndef DEVELOP
|
||||
P_DoAllPlayersExit(PF_NOCONTEST, false);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -142,9 +139,9 @@ void K_CheckBumpers(void)
|
|||
|
||||
if (numingame <= 1)
|
||||
{
|
||||
if ((gametyperules & GTR_PRISONS) && (K_CanChangeRules(true) == true))
|
||||
if ((gametyperules & GTR_PRISONS) && !battleprisons && (K_CanChangeRules(true) == true))
|
||||
{
|
||||
// Reset map to turn on battle capsules
|
||||
// Reset map to turn on battle prisons
|
||||
if (server)
|
||||
D_MapChange(gamemap, gametype, encoremode, true, 0, false, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,12 +47,8 @@ void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e st
|
|||
{
|
||||
CONS_Debug(DBG_NETPLAY, "addbot: %d\n", newplayernum);
|
||||
|
||||
// Clear player before joining, lest some things get set incorrectly
|
||||
CL_ClearPlayer(newplayernum);
|
||||
G_DestroyParty(newplayernum);
|
||||
|
||||
playeringame[newplayernum] = true;
|
||||
G_AddPlayer(newplayernum);
|
||||
|
||||
if (newplayernum+1 > doomcom->numslots)
|
||||
doomcom->numslots = (INT16)(newplayernum+1);
|
||||
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ void K_InitGrandPrixBots(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
players[i].spectator = true; // force spectate for all other players, if they happen to exist?
|
||||
P_SetPlayerSpectator(i); // force spectate for all other players, if they happen to exist?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -391,6 +391,11 @@ void K_UpdateGrandPrixBots(void)
|
|||
players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE);
|
||||
}
|
||||
|
||||
if (grandprixinfo.wonround == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the rival.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4332,6 +4332,9 @@ static void K_drawKartFinish(boolean finish)
|
|||
|
||||
if (finish)
|
||||
{
|
||||
if (gametyperules & GTR_SPECIALSTART)
|
||||
return;
|
||||
|
||||
timer = stplyr->karthud[khud_finish];
|
||||
kptodraw = kp_racefinish;
|
||||
minsplitstationary = 2;
|
||||
|
|
|
|||
31
src/k_kart.c
31
src/k_kart.c
|
|
@ -3921,7 +3921,7 @@ void K_StumblePlayer(player_t *player)
|
|||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
|
||||
// Reset slope.
|
||||
player->mo->pitch = player->mo->roll = 0;
|
||||
P_ResetPitchRoll(player->mo);
|
||||
}
|
||||
|
||||
boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir)
|
||||
|
|
@ -3939,6 +3939,14 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool
|
|||
return false;
|
||||
}
|
||||
|
||||
if (fromAir && player->airtime < STUMBLE_AIRTIME
|
||||
&& player->airtime > 1) // ACHTUNG HACK, sorry. Ground-to-ground transitions sometimes have 1-tic airtime because collision blows
|
||||
{
|
||||
// Short airtime with no reaction window, probably a track traversal setpiece.
|
||||
// Don't punish for these.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((player->mo->pitch == oldPitch)
|
||||
&& (player->mo->roll == oldRoll))
|
||||
{
|
||||
|
|
@ -4102,6 +4110,9 @@ void K_UpdateStumbleIndicator(player_t *player)
|
|||
mobj->renderflags &= ~RF_HORIZONTALFLIP;
|
||||
}
|
||||
|
||||
if (air && player->airtime < STUMBLE_AIRTIME)
|
||||
delta = 0;
|
||||
|
||||
steepRange = ANGLE_90 - steepVal;
|
||||
delta = max(0, abs(delta) - ((signed)steepVal));
|
||||
trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * (NUMTRANSMAPS - 2)) + (FRACUNIT/2)) / FRACUNIT;
|
||||
|
|
@ -4252,7 +4263,7 @@ static void K_HandleTumbleBounce(player_t *player)
|
|||
player->tumbleHeight = 10;
|
||||
player->pflags |= PF_TUMBLELASTBOUNCE;
|
||||
player->mo->rollangle = 0; // p_user.c will stop rotating the player automatically
|
||||
player->mo->pitch = player->mo->roll = 0; // Prevent Kodachrome Void infinite
|
||||
P_ResetPitchRoll(player->mo); // Prevent Kodachrome Void infinite
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6155,8 +6166,7 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound)
|
|||
mo->momz = FixedDiv(mo->momz, FixedSqrt(3*FRACUNIT));
|
||||
}
|
||||
|
||||
mo->pitch = 0;
|
||||
mo->roll = 0;
|
||||
P_ResetPitchRoll(mo);
|
||||
|
||||
if (sound)
|
||||
{
|
||||
|
|
@ -8256,7 +8266,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->incontrol = 0;
|
||||
player->incontrol++;
|
||||
}
|
||||
|
||||
|
||||
player->incontrol = min(player->incontrol, 5*TICRATE);
|
||||
player->incontrol = max(player->incontrol, -5*TICRATE);
|
||||
|
||||
|
|
@ -10447,16 +10457,18 @@ static void K_KartSpindash(player_t *player)
|
|||
{
|
||||
if (player->pflags & PF_NOFASTFALL)
|
||||
return;
|
||||
// Update fastfall.
|
||||
player->fastfall = player->mo->momz;
|
||||
player->spindash = 0;
|
||||
|
||||
if (player->fastfallBase == 0)
|
||||
if (player->fastfall == 0)
|
||||
{
|
||||
// Factors 3D momentum.
|
||||
player->fastfallBase = FixedHypot(player->speed, player->mo->momz);
|
||||
}
|
||||
|
||||
// Update fastfall.
|
||||
player->fastfall = player->mo->momz;
|
||||
player->spindash = 0;
|
||||
P_ResetPitchRoll(player->mo);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (player->fastfall != 0)
|
||||
|
|
@ -10584,7 +10596,6 @@ boolean K_FastFallBounce(player_t *player)
|
|||
player->mo->momz = bounce * P_MobjFlip(player->mo);
|
||||
|
||||
player->fastfall = 0;
|
||||
player->fastfallBase = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,10 @@ Make sure this matches the actual number of states
|
|||
|
||||
#define RR_PROJECTILE_FUSE (8*TICRATE)
|
||||
|
||||
#define STUMBLE_STEEP_VAL ANG60
|
||||
#define STUMBLE_STEEP_VAL_AIR (ANG30 + ANG10)
|
||||
// 2023-08-26 +ang20 to Sal's OG values to make them friendlier - Tyron
|
||||
#define STUMBLE_STEEP_VAL (ANG60 + ANG20)
|
||||
#define STUMBLE_STEEP_VAL_AIR (ANG30 + ANG10 + ANG20)
|
||||
#define STUMBLE_AIRTIME TICRATE
|
||||
|
||||
#define MAXRINGVOLUME 255
|
||||
#define MINRINGVOLUME 100
|
||||
|
|
|
|||
11
src/k_menu.h
11
src/k_menu.h
|
|
@ -29,8 +29,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SERVERLISTDEBUG
|
||||
|
||||
// flags for items in the menu
|
||||
// menu handle (what we do when key is pressed
|
||||
#define IT_TYPE 14 // (2+4+8)
|
||||
|
|
@ -831,7 +829,6 @@ extern struct mpmenu_s {
|
|||
// See M_OptSelectTick, it'll make more sense there. Sorry if this is a bit of a mess!
|
||||
|
||||
UINT8 room;
|
||||
boolean roomforced;
|
||||
tic_t ticker;
|
||||
|
||||
UINT8 servernum;
|
||||
|
|
@ -842,6 +839,9 @@ extern struct mpmenu_s {
|
|||
|
||||
} mpmenu;
|
||||
|
||||
void M_PleaseWait(void);
|
||||
void M_PopupMasterServerRules(void);
|
||||
|
||||
// Time Attack
|
||||
void M_PrepareTimeAttack(INT32 choice);
|
||||
void M_StartTimeAttack(INT32 choice);
|
||||
|
|
@ -895,11 +895,6 @@ void Fetch_servers_thread (int *id);
|
|||
void M_RefreshServers(INT32 choice);
|
||||
void M_ServersMenu(INT32 choice);
|
||||
|
||||
// for debugging purposes...
|
||||
#ifdef SERVERLISTDEBUG
|
||||
void M_ServerListFillDebug(void);
|
||||
#endif
|
||||
|
||||
// Options menu:
|
||||
|
||||
// mode descriptions for video mode menu
|
||||
|
|
|
|||
101
src/k_menudraw.c
101
src/k_menudraw.c
|
|
@ -3086,6 +3086,23 @@ void M_DrawTimeAttack(void)
|
|||
|
||||
// NOTE: This is pretty rigid and only intended for use with the multiplayer options menu which has *3* choices.
|
||||
|
||||
static void M_DrawMasterServerReminder(void)
|
||||
{
|
||||
// Did you change the Server Browser address? Have a little reminder.
|
||||
|
||||
INT32 mservflags = 0;
|
||||
if (CV_IsSetToDefault(&cv_masterserver))
|
||||
mservflags = highlightflags;
|
||||
else
|
||||
mservflags = warningflags;
|
||||
|
||||
INT32 y = BASEVIDHEIGHT - 24;
|
||||
|
||||
V_DrawFadeFill(0, y-1, BASEVIDWIDTH, 10+1, 0, 31, 5);
|
||||
V_DrawCenteredThinString(BASEVIDWIDTH/2, y,
|
||||
mservflags, va("List via \"%s\"", cv_masterserver.string));
|
||||
}
|
||||
|
||||
static void M_MPOptDrawer(menu_t *m, INT16 extend[3][3])
|
||||
{
|
||||
// This is a copypaste of the generic gamemode menu code with a few changes.
|
||||
|
|
@ -3149,6 +3166,7 @@ void M_DrawMPOptSelect(void)
|
|||
M_DrawEggaChannel();
|
||||
M_DrawMenuTooltips();
|
||||
M_MPOptDrawer(&PLAY_MP_OptSelectDef, mpmenu.modewinextend);
|
||||
M_DrawMasterServerReminder();
|
||||
}
|
||||
|
||||
// Multiplayer mode option select: HOST GAME!
|
||||
|
|
@ -3400,14 +3418,79 @@ void M_DrawMPRoomSelect(void)
|
|||
|
||||
// Draw buttons:
|
||||
|
||||
if (!mpmenu.roomforced || mpmenu.room == 0)
|
||||
V_DrawFixedPatch(160<<FRACBITS, 100<<FRACBITS, FRACUNIT, mpmenu.room ? (5<<V_ALPHASHIFT) : 0, butt1[(mpmenu.room) ? 1 : 0], NULL);
|
||||
V_DrawFixedPatch(160<<FRACBITS, 90<<FRACBITS, FRACUNIT, mpmenu.room ? (5<<V_ALPHASHIFT) : 0, butt1[(mpmenu.room) ? 1 : 0], NULL);
|
||||
|
||||
if (!mpmenu.roomforced || mpmenu.room == 1)
|
||||
V_DrawFixedPatch(160<<FRACBITS, 100<<FRACBITS, FRACUNIT, (!mpmenu.room) ? (5<<V_ALPHASHIFT) : 0, butt2[(!mpmenu.room) ? 1 : 0], NULL);
|
||||
V_DrawFixedPatch(160<<FRACBITS, 90<<FRACBITS, FRACUNIT, (!mpmenu.room) ? (5<<V_ALPHASHIFT) : 0, butt2[(!mpmenu.room) ? 1 : 0], NULL);
|
||||
|
||||
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL);
|
||||
V_DrawCenteredThinString(BASEVIDWIDTH/2, 12, 0, "Select today's type of play!");
|
||||
|
||||
M_DrawMasterServerReminder();
|
||||
}
|
||||
|
||||
// SERVER BROWSER
|
||||
static void M_DrawServerCountAndHorizontalBar(void)
|
||||
{
|
||||
const char *text;
|
||||
INT32 y = currentMenu->y+STRINGHEIGHT;
|
||||
|
||||
const char throbber[4] = {'-', '\\', '|', '/'};
|
||||
UINT8 throbindex = (mpmenu.ticker/4) % 4;
|
||||
|
||||
switch (M_GetWaitingMode())
|
||||
{
|
||||
case M_WAITING_VERSION:
|
||||
text = "Checking for updates...";
|
||||
break;
|
||||
|
||||
case M_WAITING_SERVERS:
|
||||
text = "Loading server list...";
|
||||
break;
|
||||
|
||||
default:
|
||||
if (serverlistultimatecount > serverlistcount)
|
||||
{
|
||||
text = va("%d/%d server%s found...",
|
||||
serverlistcount,
|
||||
serverlistultimatecount,
|
||||
serverlistultimatecount == 1 ? "" : "s"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throbindex = UINT8_MAX; // No throbber!
|
||||
text = va("%d server%s found",
|
||||
serverlistcount,
|
||||
serverlistcount == 1 ? "" : "s"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (throbindex == UINT8_MAX)
|
||||
{
|
||||
V_DrawRightAlignedString(
|
||||
BASEVIDWIDTH - currentMenu->x,
|
||||
y,
|
||||
highlightflags,
|
||||
text
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawRightAlignedString(
|
||||
BASEVIDWIDTH - currentMenu->x - 12, y,
|
||||
highlightflags,
|
||||
text
|
||||
);
|
||||
|
||||
V_DrawCenteredString( // Only clean way to center the throbber without exposing character width
|
||||
BASEVIDWIDTH - currentMenu->x - 4, y,
|
||||
highlightflags,
|
||||
va("%c", throbber[throbindex])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void M_DrawMPServerBrowser(void)
|
||||
{
|
||||
patch_t *text1 = W_CachePatchName("MENUBGT1", PU_CACHE);
|
||||
|
|
@ -3503,11 +3586,19 @@ void M_DrawMPServerBrowser(void)
|
|||
V_DrawFill(0, 53, 320, 1, 31);
|
||||
V_DrawFill(0, 55, 320, 1, 31);
|
||||
|
||||
V_DrawCenteredGamemodeString(160, 2, 0, 0, "Server Browser");
|
||||
const char *headertext;
|
||||
if (M_SecretUnlocked(SECRET_ADDONS, true))
|
||||
headertext = va("%s Servers", mpmenu.room ? "Modded" : "Core");
|
||||
else
|
||||
headertext = "Server Browser";
|
||||
V_DrawCenteredGamemodeString(160, 2, 0, 0, headertext);
|
||||
|
||||
// normal menu options
|
||||
M_DrawGenericMenu();
|
||||
|
||||
// And finally, the overlay bar!
|
||||
M_DrawServerCountAndHorizontalBar();
|
||||
M_DrawMasterServerReminder();
|
||||
}
|
||||
|
||||
// OPTIONS MENU
|
||||
|
|
|
|||
|
|
@ -94,6 +94,21 @@ gp_rank_e K_PodiumGrade(void)
|
|||
return podiumData.grade;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumHasEmerald(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PodiumHasEmerald(void)
|
||||
{
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return podiumData.rank.specialWon;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetPodiumPosition(player_t *player)
|
||||
|
||||
|
|
@ -284,6 +299,7 @@ boolean K_StartCeremony(void)
|
|||
|
||||
G_SetGametype(GT_RACE);
|
||||
G_DoLoadLevelEx(false, GS_CEREMONY);
|
||||
wipegamestate = GS_CEREMONY; // I don't know what else to do here
|
||||
|
||||
r_splitscreen = 0; // Only one screen for the ceremony
|
||||
R_ExecuteSetViewSize();
|
||||
|
|
|
|||
|
|
@ -69,6 +69,20 @@ boolean K_PodiumRanking(void);
|
|||
gp_rank_e K_PodiumGrade(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumHasEmerald(void)
|
||||
|
||||
Returns whether the Emerald or Prize was collected.
|
||||
|
||||
Input Arguments:-
|
||||
N/A
|
||||
|
||||
Return:-
|
||||
true if the Emerald/Prize was collected during the GP, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PodiumHasEmerald(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetPodiumPosition(player_t *player);
|
||||
|
||||
|
|
|
|||
|
|
@ -3515,9 +3515,12 @@ static int lib_getTimeMicros(lua_State *L)
|
|||
|
||||
static int lib_startTitlecardCecho(lua_State *L)
|
||||
{
|
||||
const char *str = luaL_checkstring(L, 1);
|
||||
HU_DoTitlecardCEcho(str);
|
||||
|
||||
player_t *player = lua_isnil(L, 1) ? NULL : *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
const char *str = luaL_checkstring(L, 2);
|
||||
boolean interrupt = lua_optboolean(L, 3);
|
||||
|
||||
HU_DoTitlecardCEcho(player, str, interrupt);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -948,6 +948,7 @@ static int libd_drawTitleCardString(lua_State *L)
|
|||
boolean rightalign = lua_optboolean(L, 5);
|
||||
INT32 timer = luaL_optinteger(L, 6, 0);
|
||||
INT32 threshold = luaL_optinteger(L, 7, 0);
|
||||
boolean p4 = lua_optboolean(L, 8);
|
||||
huddrawlist_h list;
|
||||
|
||||
flags &= ~V_PARAMMASK; // Don't let crashes happen.
|
||||
|
|
@ -958,9 +959,9 @@ static int libd_drawTitleCardString(lua_State *L)
|
|||
lua_pop(L, 1);
|
||||
|
||||
if (LUA_HUD_IsDrawListValid(list))
|
||||
LUA_HUD_AddDrawTitleCardString(list, x, y, flags, str, rightalign, timer, threshold);
|
||||
LUA_HUD_AddDrawTitleCardString(list, x, y, flags, str, rightalign, timer, threshold, p4);
|
||||
else
|
||||
V_DrawTitleCardString(x, y, str, flags, rightalign, timer, threshold);
|
||||
V_DrawTitleCardString(x, y, str, flags, rightalign, timer, threshold, p4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -989,9 +990,10 @@ static int libd_drawKartString(lua_State *L)
|
|||
static int libd_titleCardStringWidth(lua_State *L)
|
||||
{
|
||||
const char *str = luaL_checkstring(L, 1);
|
||||
boolean p4 = lua_optboolean(L, 2);
|
||||
HUDONLY
|
||||
|
||||
lua_pushinteger(L, V_TitleCardStringWidth(str));
|
||||
lua_pushinteger(L, V_TitleCardStringWidth(str, p4));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ typedef struct drawitem_s {
|
|||
INT32 timer;
|
||||
INT32 threshold;
|
||||
boolean bossmode;
|
||||
boolean p4;
|
||||
} drawitem_t;
|
||||
|
||||
// The internal structure of a drawlist.
|
||||
|
|
@ -358,7 +359,8 @@ void LUA_HUD_AddDrawTitleCardString(
|
|||
const char *str,
|
||||
boolean bossmode,
|
||||
INT32 timer,
|
||||
INT32 threshold
|
||||
INT32 threshold,
|
||||
boolean p4
|
||||
)
|
||||
{
|
||||
size_t i = AllocateDrawItem(list);
|
||||
|
|
@ -371,6 +373,7 @@ void LUA_HUD_AddDrawTitleCardString(
|
|||
item->bossmode = bossmode;
|
||||
item->timer = timer;
|
||||
item->threshold = threshold;
|
||||
item->p4 = p4;
|
||||
}
|
||||
|
||||
void LUA_HUD_AddDrawKartString(
|
||||
|
|
@ -465,7 +468,7 @@ void LUA_HUD_DrawList(huddrawlist_h list)
|
|||
V_DrawFadeScreen(item->color, item->strength);
|
||||
break;
|
||||
case DI_DrawTitleCardString:
|
||||
V_DrawTitleCardString(item->x, item->y, itemstr, item->flags, item->bossmode, item->timer, item->threshold);
|
||||
V_DrawTitleCardString(item->x, item->y, itemstr, item->flags, item->bossmode, item->timer, item->threshold, item->p4);
|
||||
break;
|
||||
case DI_DrawKartString:
|
||||
V_DrawTimerString(item->x, item->y, item->flags, itemstr);
|
||||
|
|
|
|||
|
|
@ -111,7 +111,8 @@ void LUA_HUD_AddDrawTitleCardString(
|
|||
const char *str,
|
||||
boolean bossmode,
|
||||
INT32 timer,
|
||||
INT32 threshold
|
||||
INT32 threshold,
|
||||
boolean p4
|
||||
);
|
||||
void LUA_HUD_AddDrawKartString(
|
||||
huddrawlist_h list,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ menuitem_t OPTIONS_VideoOGL[] =
|
|||
{IT_STRING | IT_CVAR, "Texture Quality", "Texture depth. Higher values are recommended.",
|
||||
NULL, {.cvar = &cv_scr_depth}, 0, 0},
|
||||
|
||||
/*
|
||||
{IT_STRING | IT_CVAR, "Texture Filter", "Texture Filter. Nearest is recommended.",
|
||||
NULL, {.cvar = &cv_glfiltermode}, 0, 0},
|
||||
*/
|
||||
|
||||
{IT_STRING | IT_CVAR, "Anisotropic", "Lower values will improve performance at a minor quality loss.",
|
||||
NULL, {.cvar = &cv_glanisotropicmode}, 0, 0},
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "../k_menu.h"
|
||||
#include "../m_cond.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../mserv.h" // cv_masterserver
|
||||
|
||||
#if defined (TESTERS)
|
||||
#define IT_STRING_CALL_NOTESTERS IT_DISABLED
|
||||
|
|
@ -11,13 +12,74 @@
|
|||
#define IT_STRING_CALL_NOTESTERS (IT_STRING | IT_CALL)
|
||||
#endif // TESTERS
|
||||
|
||||
static boolean firstDismissedNagThisBoot = true;
|
||||
|
||||
static void M_HandleMasterServerResetChoice(INT32 ch)
|
||||
{
|
||||
if (ch == MA_YES)
|
||||
{
|
||||
CV_Set(&cv_masterserver, cv_masterserver.defaultvalue);
|
||||
CV_Set(&cv_masterserver_nagattempts, cv_masterserver_nagattempts.defaultvalue);
|
||||
S_StartSound(NULL, sfx_s221);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstDismissedNagThisBoot)
|
||||
{
|
||||
if (cv_masterserver_nagattempts.value > 0)
|
||||
{
|
||||
CV_SetValue(&cv_masterserver_nagattempts, cv_masterserver_nagattempts.value - 1);
|
||||
}
|
||||
firstDismissedNagThisBoot = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_PreMPHostInitChoice(INT32 ch)
|
||||
{
|
||||
M_HandleMasterServerResetChoice(ch);
|
||||
M_MPHostInit(0);
|
||||
}
|
||||
|
||||
static void M_PreMPHostInit(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
|
||||
if (!CV_IsSetToDefault(&cv_masterserver) && cv_masterserver_nagattempts.value > 0)
|
||||
{
|
||||
M_StartMessage("Server Browser Alert", M_GetText("Hey! You've changed the game's\naddress for the Server Browser.\n\nYou won't be able to host games on\nthe official Server Browser.\n\nUnless you're from the future, this\nprobably isn't what you want.\n"), &M_PreMPHostInitChoice, MM_YESNO, "Fix and continue", "I changed the URL intentionally");
|
||||
return;
|
||||
}
|
||||
|
||||
M_MPHostInit(0);
|
||||
}
|
||||
|
||||
static void M_PreMPRoomSelectInitChoice(INT32 ch)
|
||||
{
|
||||
M_HandleMasterServerResetChoice(ch);
|
||||
M_MPRoomSelectInit(0);
|
||||
}
|
||||
|
||||
static void M_PreMPRoomSelectInit(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
|
||||
if (!CV_IsSetToDefault(&cv_masterserver) && cv_masterserver_nagattempts.value > 0)
|
||||
{
|
||||
M_StartMessage("Server Browser Alert", M_GetText("Hey! You've changed the game's\naddress for the Server Browser.\n\nYou won't be able to see games from\nthe official Server Browser.\n\nUnless you're from the future, this\nprobably isn't what you want.\n"), &M_PreMPRoomSelectInitChoice, MM_YESNO, "Fix and continue", "I changed the URL intentionally");
|
||||
return;
|
||||
}
|
||||
|
||||
M_MPRoomSelectInit(0);
|
||||
}
|
||||
|
||||
menuitem_t PLAY_MP_OptSelect[] =
|
||||
{
|
||||
{IT_STRING_CALL_NOTESTERS, "Host Game", "Start your own online game!",
|
||||
NULL, {.routine = M_MPHostInit}, 0, 0},
|
||||
NULL, {.routine = M_PreMPHostInit}, 0, 0},
|
||||
|
||||
{IT_STRING_CALL_NOTESTERS, "Server Browser", "Search for game servers to play in.",
|
||||
NULL, {.routine = M_MPRoomSelectInit}, 0, 0},
|
||||
NULL, {.routine = M_PreMPRoomSelectInit}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.",
|
||||
NULL, {.routine = M_MPJoinIPInit}, 0, 0},
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "../k_menu.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../mserv.h"
|
||||
|
||||
// MULTIPLAYER HOST SCREEN -- see mhost_e
|
||||
menuitem_t PLAY_MP_Host[] =
|
||||
|
|
@ -43,13 +45,41 @@ menu_t PLAY_MP_HostDef = {
|
|||
NULL
|
||||
};
|
||||
|
||||
void M_PopupMasterServerRules(void)
|
||||
{
|
||||
#ifdef MASTERSERVER
|
||||
if (cv_advertise.value && (serverrunning || currentMenu == &PLAY_MP_HostDef))
|
||||
{
|
||||
char *rules = GetMasterServerRules();
|
||||
|
||||
if (rules != NULL)
|
||||
{
|
||||
M_StartMessage("Server List Rules", rules, NULL, MM_NOTHING, NULL, NULL);
|
||||
Z_Free(rules);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void M_MPHostInit(INT32 choice)
|
||||
{
|
||||
|
||||
(void)choice;
|
||||
mpmenu.modewinextend[0][0] = 1;
|
||||
M_SetupNextMenu(&PLAY_MP_HostDef, true);
|
||||
itemOn = mhost_go;
|
||||
|
||||
Get_rules();
|
||||
// There's one downside to doing it this way:
|
||||
// if you turn advertise on via the console,
|
||||
// then access this menu for the first time,
|
||||
// no rules will pop up because they haven't
|
||||
// arrived yet.
|
||||
M_PopupMasterServerRules();
|
||||
// HOWEVER, this menu popup isn't for people
|
||||
// who know how to use the Developer Console.
|
||||
// People who CAN do that should already know
|
||||
// what kind of service they're connecting to.
|
||||
// (it'll still appear in the logs later, too!)
|
||||
}
|
||||
|
||||
void M_HandleHostMenuGametype(INT32 choice)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "../i_system.h" // I_OsPolling
|
||||
#include "../i_video.h" // I_UpdateNoBlit
|
||||
#include "../m_misc.h" // NUMLOGIP
|
||||
#include "../f_finale.h" // g_wipeskiprender
|
||||
|
||||
menuitem_t PLAY_MP_JoinIP[] =
|
||||
{
|
||||
|
|
@ -56,6 +57,21 @@ void M_MPJoinIPInit(INT32 choice)
|
|||
M_SetupNextMenu(&PLAY_MP_JoinIPDef, true);
|
||||
}
|
||||
|
||||
void M_PleaseWait(void)
|
||||
{
|
||||
if (rendermode == render_none)
|
||||
return;
|
||||
|
||||
g_wipeskiprender = true;
|
||||
|
||||
M_DrawTextBox(56, BASEVIDHEIGHT/2-12, 24, 2);
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "PLEASE WAIT...");
|
||||
I_OsPolling();
|
||||
I_UpdateNoBlit();
|
||||
if (rendermode == render_soft)
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
}
|
||||
|
||||
// Attempts to join a given IP from the menu.
|
||||
void M_JoinIP(const char *ipa)
|
||||
{
|
||||
|
|
@ -67,13 +83,7 @@ void M_JoinIP(const char *ipa)
|
|||
|
||||
COM_BufAddText(va("connect \"%s\"\n", ipa));
|
||||
|
||||
// A little "please wait" message.
|
||||
M_DrawTextBox(56, BASEVIDHEIGHT/2-12, 24, 2);
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Connecting to server...");
|
||||
I_OsPolling();
|
||||
I_UpdateNoBlit();
|
||||
if (rendermode == render_soft)
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
M_PleaseWait();
|
||||
}
|
||||
|
||||
boolean M_JoinIPInputs(INT32 ch)
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@ void M_MPRoomSelect(INT32 choice)
|
|||
M_ServersMenu(0);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
else if (mpmenu.roomforced == false
|
||||
&& menucmd[pid].dpad_lr != 0)
|
||||
else if (menucmd[pid].dpad_lr != 0)
|
||||
{
|
||||
mpmenu.room ^= 1;
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
|
|
@ -59,12 +58,28 @@ void M_MPRoomSelectTick(void)
|
|||
void M_MPRoomSelectInit(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
|
||||
if (modifiedgame)
|
||||
{
|
||||
M_StartMessage("Server Browser & Add-Ons", M_GetText("You have add-ons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\n\n\"Dr. Robotnik's Ring Racers\" will\nautomatically add everything\nyou need when you join.\n"), NULL, MM_NOTHING, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// The following behaviour is affected by modifiedgame despite the above restriction.
|
||||
// It's a sanity check were that to be removed, wheither by us or by a modified client.
|
||||
// "wheither"? That typo rules, I'm keeping that ~toast 280823
|
||||
|
||||
mpmenu.room = (modifiedgame == true) ? 1 : 0;
|
||||
mpmenu.roomforced = ((modifiedgame == true) || (!M_SecretUnlocked(SECRET_ADDONS, true)));
|
||||
mpmenu.ticker = 0;
|
||||
mpmenu.servernum = 0;
|
||||
mpmenu.scrolln = 0;
|
||||
mpmenu.slide = 0;
|
||||
|
||||
if ((modifiedgame == true) || (M_SecretUnlocked(SECRET_ADDONS, true) == false))
|
||||
{
|
||||
M_ServersMenu(0);
|
||||
return;
|
||||
}
|
||||
|
||||
M_SetupNextMenu(&PLAY_MP_RoomSelectDef, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@
|
|||
|
||||
#include "../k_menu.h"
|
||||
#include "../v_video.h"
|
||||
#include "../i_system.h" // I_OsPolling
|
||||
#include "../i_video.h" // I_UpdateNoBlit
|
||||
#include "../s_sound.h"
|
||||
|
||||
//#define SERVERLISTDEBUG
|
||||
|
||||
#ifdef SERVERLISTDEBUG
|
||||
#include "../m_random.h"
|
||||
|
||||
void M_ServerListFillDebug(void);
|
||||
#endif
|
||||
|
||||
menuitem_t PLAY_MP_ServerBrowser[] =
|
||||
|
|
@ -16,8 +19,8 @@ menuitem_t PLAY_MP_ServerBrowser[] =
|
|||
{IT_STRING | IT_CVAR, "SORT BY", NULL, // tooltip MUST be null.
|
||||
NULL, {.cvar = &cv_serversort}, 0, 0},
|
||||
|
||||
{IT_STRING, "REFRESH", NULL,
|
||||
NULL, {NULL}, 0, 0},
|
||||
{IT_STRING | IT_CALL, "REFRESH", NULL,
|
||||
NULL, {.routine = &M_RefreshServers}, 0, 0},
|
||||
|
||||
{IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0},
|
||||
};
|
||||
|
|
@ -42,28 +45,6 @@ menu_t PLAY_MP_ServerBrowserDef = {
|
|||
// for server fetch threads...
|
||||
M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
|
||||
|
||||
// depending on mpmenu.room, either allows only unmodded servers or modded ones. Remove others from the list.
|
||||
// we do this by iterating backwards.
|
||||
static void M_CleanServerList(void)
|
||||
{
|
||||
UINT8 i = serverlistcount;
|
||||
|
||||
while (i)
|
||||
{
|
||||
|
||||
if (serverlist[i].info.modifiedgame != mpmenu.room)
|
||||
{
|
||||
// move everything after this index 1 slot down...
|
||||
if (i != serverlistcount)
|
||||
memcpy(&serverlist[i], &serverlist[i+1], sizeof(serverelem_t)*(serverlistcount-i));
|
||||
|
||||
serverlistcount--;
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
M_SetWaitingMode (int mode)
|
||||
{
|
||||
|
|
@ -180,31 +161,19 @@ void M_RefreshServers(INT32 choice)
|
|||
{
|
||||
(void)choice;
|
||||
|
||||
// Display a little "please wait" message.
|
||||
M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers...");
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
|
||||
I_OsPolling();
|
||||
I_UpdateNoBlit();
|
||||
if (rendermode == render_soft)
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
CL_UpdateServerList();
|
||||
|
||||
#ifdef SERVERLISTDEBUG
|
||||
M_ServerListFillDebug();
|
||||
#else /*SERVERLISTDEBUG*/
|
||||
#ifdef MASTERSERVER
|
||||
#ifdef HAVE_THREADS
|
||||
Spawn_masterserver_thread("fetch-servers", Fetch_servers_thread);
|
||||
#else/*HAVE_THREADS*/
|
||||
Fetch_servers_thread(NULL);
|
||||
#endif/*HAVE_THREADS*/
|
||||
#else/*MASTERSERVER*/
|
||||
CL_UpdateServerList();
|
||||
#endif/*MASTERSERVER*/
|
||||
|
||||
#ifdef SERVERLISTDEBUG
|
||||
M_ServerListFillDebug();
|
||||
#endif
|
||||
M_CleanServerList();
|
||||
M_SortServerList();
|
||||
|
||||
#endif /*SERVERLISTDEBUG*/
|
||||
}
|
||||
|
||||
#ifdef UPDATE_ALERT
|
||||
|
|
@ -253,13 +222,21 @@ void M_ServersMenu(INT32 choice)
|
|||
// modified game check: no longer handled
|
||||
// we don't request a restart unless the filelist differs
|
||||
|
||||
CL_UpdateServerList();
|
||||
|
||||
mpmenu.ticker = 0;
|
||||
mpmenu.servernum = 0;
|
||||
mpmenu.scrolln = 0;
|
||||
mpmenu.slide = 0;
|
||||
|
||||
PLAY_MP_ServerBrowserDef.prevMenu = currentMenu;
|
||||
M_SetupNextMenu(&PLAY_MP_ServerBrowserDef, false);
|
||||
itemOn = 0;
|
||||
|
||||
#ifdef SERVERLISTDEBUG
|
||||
M_ServerListFillDebug();
|
||||
#else /*SERVERLISTDEBUG*/
|
||||
|
||||
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
|
||||
I_lock_mutex(&ms_QueryId_mutex);
|
||||
{
|
||||
|
|
@ -289,12 +266,7 @@ void M_ServersMenu(INT32 choice)
|
|||
M_RefreshServers(0);
|
||||
#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
|
||||
|
||||
#ifdef SERVERLISTDEBUG
|
||||
M_ServerListFillDebug();
|
||||
#endif
|
||||
|
||||
M_CleanServerList();
|
||||
M_SortServerList();
|
||||
#endif /*SERVERLISTDEBUG*/
|
||||
}
|
||||
|
||||
#ifdef SERVERLISTDEBUG
|
||||
|
|
@ -304,29 +276,31 @@ void M_ServerListFillDebug(void)
|
|||
{
|
||||
UINT8 i = 0;
|
||||
|
||||
serverlistcount = 10;
|
||||
serverlistcount = 40;
|
||||
memset(serverlist, 0, sizeof(serverlist)); // zero out the array for convenience...
|
||||
|
||||
for (i = 0; i < serverlistcount; i++)
|
||||
{
|
||||
// We don't really care about the server node for this, let's just fill in the info so that we have a visual...
|
||||
serverlist[i].info.numberofplayer = min(i, 8);
|
||||
serverlist[i].info.maxplayer = 8;
|
||||
serverlist[i].info.maxplayer = M_RandomRange(8, 16);
|
||||
UINT8 val = i % 16;
|
||||
serverlist[i].info.numberofplayer = min(val, serverlist[i].info.maxplayer);
|
||||
|
||||
serverlist[i].info.avgpwrlv = P_RandomRange(PR_UNDEFINED, 500, 1500);
|
||||
serverlist[i].info.time = P_RandomRange(PR_UNDEFINED, 1, 8); // ping
|
||||
serverlist[i].info.avgpwrlv = M_RandomRange(500, 1500);
|
||||
serverlist[i].info.time = M_RandomRange(1, 8); // ping
|
||||
|
||||
strcpy(serverlist[i].info.servername, va("Serv %d", i+1));
|
||||
|
||||
strcpy(serverlist[i].info.gametypename, i & 1 ? "Race" : "Battle");
|
||||
|
||||
P_RandomRange(PR_UNDEFINED, 0, 5); // change results...
|
||||
serverlist[i].info.kartvars = P_RandomRange(PR_UNDEFINED, 0, 3) & SV_SPEEDMASK;
|
||||
serverlist[i].info.kartvars = M_RandomRange(0, 3) & SV_SPEEDMASK;
|
||||
|
||||
serverlist[i].info.modifiedgame = P_RandomRange(PR_UNDEFINED, 0, 1);
|
||||
serverlist[i].info.modifiedgame = M_RandomRange(0, 1);
|
||||
|
||||
CONS_Printf("Serv %d | %d...\n", i, serverlist[i].info.modifiedgame);
|
||||
}
|
||||
|
||||
M_SortServerList();
|
||||
}
|
||||
|
||||
#endif // SERVERLISTDEBUG
|
||||
|
|
@ -339,7 +313,7 @@ static int ServerListEntryComparator_##key(const void *entry1, const void *entry
|
|||
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; \
|
||||
if (sa->info.key != sb->info.key) \
|
||||
return sa->info.key - sb->info.key; \
|
||||
return strcmp(sa->info.servername, sb->info.servername); \
|
||||
return sa->info.time - sb->info.time; \
|
||||
}
|
||||
|
||||
// This does descending instead of ascending.
|
||||
|
|
@ -349,15 +323,22 @@ static int ServerListEntryComparator_##key##_reverse(const void *entry1, const v
|
|||
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; \
|
||||
if (sb->info.key != sa->info.key) \
|
||||
return sb->info.key - sa->info.key; \
|
||||
return strcmp(sb->info.servername, sa->info.servername); \
|
||||
return sa->info.time - sb->info.time; \
|
||||
}
|
||||
|
||||
SERVER_LIST_ENTRY_COMPARATOR(time)
|
||||
//SERVER_LIST_ENTRY_COMPARATOR(time) -- done seperately due to the usual tiebreaker being time
|
||||
SERVER_LIST_ENTRY_COMPARATOR(numberofplayer)
|
||||
SERVER_LIST_ENTRY_COMPARATOR_REVERSE(numberofplayer)
|
||||
SERVER_LIST_ENTRY_COMPARATOR_REVERSE(maxplayer)
|
||||
SERVER_LIST_ENTRY_COMPARATOR(avgpwrlv)
|
||||
|
||||
static int ServerListEntryComparator_time(const void *entry1, const void *entry2)
|
||||
{
|
||||
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2;
|
||||
if (sa->info.time != sb->info.time)
|
||||
return sa->info.time - sb->info.time;
|
||||
return strcmp(sa->info.servername, sb->info.servername);
|
||||
}
|
||||
|
||||
static int ServerListEntryComparator_gametypename(const void *entry1, const void *entry2)
|
||||
{
|
||||
|
|
@ -365,13 +346,51 @@ static int ServerListEntryComparator_gametypename(const void *entry1, const void
|
|||
int c;
|
||||
if (( c = strcasecmp(sa->info.gametypename, sb->info.gametypename) ))
|
||||
return c;
|
||||
return strcmp(sa->info.servername, sb->info.servername); \
|
||||
return sa->info.time - sb->info.time;
|
||||
}
|
||||
|
||||
static int ServerListEntryComparator_recommended(const void *entry1, const void *entry2)
|
||||
{
|
||||
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2;
|
||||
|
||||
INT32 saseedval = sa->info.numberofplayer;
|
||||
INT32 sbseedval = sb->info.numberofplayer;
|
||||
|
||||
// Tyron wrote the following on 25072022:
|
||||
// "sort should be two parts
|
||||
// top part of the list is "all non-empty servers sorted by reverse playercount", with servers above a certain reported ping marked as bad connection or whatever
|
||||
// bottom part of the list is all empty servers sorted by ping"
|
||||
// toast is implementing on 27082023, over a year later, because
|
||||
// "fixing server join flow" is saner to do near the end
|
||||
|
||||
{
|
||||
const UINT8 SERVER_EMPTY = 1;
|
||||
|
||||
// The intent with this nudge is to show you
|
||||
// good games you could get a memorable Duel in,
|
||||
// with the possibility to really katamari into
|
||||
// something more substantial.
|
||||
// By comparison, empty games are not nearly as
|
||||
// fun to get going, so let's lower their SEO.
|
||||
if (!saseedval)
|
||||
saseedval = MAXPLAYERS + SERVER_EMPTY;
|
||||
if (!sbseedval)
|
||||
sbseedval = MAXPLAYERS + SERVER_EMPTY;
|
||||
}
|
||||
|
||||
if (saseedval != sbseedval)
|
||||
return saseedval - sbseedval;
|
||||
|
||||
return sa->info.time - sb->info.time;
|
||||
}
|
||||
|
||||
void M_SortServerList(void)
|
||||
{
|
||||
switch(cv_serversort.value)
|
||||
{
|
||||
case -1:
|
||||
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_recommended);
|
||||
break;
|
||||
case 0: // Ping.
|
||||
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_time);
|
||||
break;
|
||||
|
|
@ -397,89 +416,115 @@ void M_SortServerList(void)
|
|||
// Server browser inputs & ticker
|
||||
void M_MPServerBrowserTick(void)
|
||||
{
|
||||
mpmenu.ticker++;
|
||||
mpmenu.slide /= 2;
|
||||
|
||||
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
|
||||
I_lock_mutex(&ms_ServerList_mutex);
|
||||
{
|
||||
if (ms_ServerList)
|
||||
{
|
||||
CL_QueryServerList(ms_ServerList);
|
||||
free(ms_ServerList);
|
||||
ms_ServerList = NULL;
|
||||
}
|
||||
}
|
||||
I_unlock_mutex(ms_ServerList_mutex);
|
||||
#endif
|
||||
|
||||
CL_TimeoutServerList();
|
||||
}
|
||||
|
||||
// Input handler for server browser.
|
||||
boolean M_ServerBrowserInputs(INT32 ch)
|
||||
{
|
||||
UINT8 pid = 0;
|
||||
UINT8 maxscroll = serverlistcount-(SERVERSPERPAGE/2);
|
||||
INT16 maxscroll = serverlistcount - (SERVERSPERPAGE/2) - 2; // Why? Because
|
||||
if (maxscroll < 0)
|
||||
maxscroll = 0;
|
||||
|
||||
const INT16 serverbrowserOn = (currentMenu->numitems - 1);
|
||||
|
||||
(void) ch;
|
||||
|
||||
if (!itemOn && menucmd[pid].dpad_ud < 0)
|
||||
{
|
||||
M_PrevOpt(); // go to itemOn 2
|
||||
if (serverlistcount)
|
||||
{
|
||||
UINT8 prevscroll = mpmenu.scrolln;
|
||||
// Return the MS listing to the bottom.
|
||||
INT32 prevscroll = mpmenu.scrolln;
|
||||
|
||||
mpmenu.servernum = serverlistcount;
|
||||
mpmenu.servernum = serverlistcount-1;
|
||||
mpmenu.scrolln = maxscroll;
|
||||
mpmenu.slide = SERVERSPACE * (prevscroll - mpmenu.scrolln);
|
||||
mpmenu.slide = SERVERSPACE * (prevscroll - (INT32)mpmenu.scrolln);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemOn = 1; // Sike! If there are no servers, go to refresh instead.
|
||||
M_PrevOpt(); // Double apply
|
||||
}
|
||||
|
||||
return true; // overwrite behaviour.
|
||||
}
|
||||
else if (itemOn == 2) // server browser itself...
|
||||
else if (itemOn == (serverbrowserOn - 1) && menucmd[pid].dpad_ud > 0 && !serverlistcount)
|
||||
{
|
||||
// we have to manually do that here.
|
||||
if (M_MenuBackPressed(pid))
|
||||
M_NextOpt(); // Double apply
|
||||
}
|
||||
else if (itemOn == serverbrowserOn) // server browser itself...
|
||||
{
|
||||
#ifndef SERVERLISTDEBUG
|
||||
if (M_MenuConfirmPressed(pid))
|
||||
{
|
||||
M_GoBack(0);
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
COM_BufAddText(va("connect node %d\n", serverlist[mpmenu.servernum].node));
|
||||
|
||||
M_PleaseWait();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (menucmd[pid].dpad_ud > 0) // down
|
||||
if (menucmd[pid].dpad_ud > 0) // down
|
||||
{
|
||||
if (mpmenu.servernum >= serverlistcount-1)
|
||||
{
|
||||
UINT8 prevscroll = mpmenu.scrolln;
|
||||
mpmenu.servernum = 0;
|
||||
mpmenu.scrolln = 0;
|
||||
mpmenu.slide = SERVERSPACE * (prevscroll - mpmenu.scrolln);
|
||||
|
||||
M_NextOpt(); // Go back to the top of the real menu.
|
||||
}
|
||||
else
|
||||
if ((UINT32)(mpmenu.servernum+1) < serverlistcount)
|
||||
{
|
||||
// Listing scroll down
|
||||
mpmenu.servernum++;
|
||||
if (mpmenu.scrolln < maxscroll && mpmenu.servernum > SERVERSPERPAGE/2)
|
||||
{
|
||||
mpmenu.scrolln++;
|
||||
mpmenu.slide += SERVERSPACE;
|
||||
}
|
||||
}
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the MS listing to the top.
|
||||
INT32 prevscroll = mpmenu.scrolln;
|
||||
|
||||
mpmenu.servernum = 0;
|
||||
mpmenu.scrolln = 0;
|
||||
mpmenu.slide = SERVERSPACE * (prevscroll - (INT32)mpmenu.scrolln);
|
||||
}
|
||||
else if (menucmd[pid].dpad_ud < 0)
|
||||
{
|
||||
|
||||
if (!mpmenu.servernum)
|
||||
if (mpmenu.servernum)
|
||||
{
|
||||
M_PrevOpt();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mpmenu.servernum <= serverlistcount-(SERVERSPERPAGE/2) && mpmenu.scrolln)
|
||||
// Listing scroll up
|
||||
if (mpmenu.servernum <= (INT16)maxscroll && mpmenu.scrolln)
|
||||
{
|
||||
mpmenu.scrolln--;
|
||||
mpmenu.slide -= SERVERSPACE;
|
||||
}
|
||||
|
||||
mpmenu.servernum--;
|
||||
}
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true; // Overwrite behaviour.
|
||||
}
|
||||
return false; // use normal behaviour.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,19 +31,20 @@ static inline size_t M_StringHeight(const char *string)
|
|||
void M_StartMessage(const char *header, const char *string, void (*routine)(INT32), menumessagetype_t itemtype, const char *confirmstr, const char *defaultstr)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
static char *message = NULL;
|
||||
Z_Free(message);
|
||||
DEBFILE(string);
|
||||
|
||||
message = V_ScaledWordWrap(
|
||||
BASEVIDWIDTH << FRACBITS,
|
||||
char *message = V_ScaledWordWrap(
|
||||
(BASEVIDWIDTH - 8) << FRACBITS,
|
||||
FRACUNIT, FRACUNIT, FRACUNIT,
|
||||
0,
|
||||
HU_FONT,
|
||||
string
|
||||
);
|
||||
|
||||
strncpy(menumessage.message, string, MAXMENUMESSAGE);
|
||||
strncpy(menumessage.message, message, MAXMENUMESSAGE);
|
||||
|
||||
Z_Free(message);
|
||||
|
||||
menumessage.header = header;
|
||||
menumessage.flags = itemtype;
|
||||
menumessage.routine = routine;
|
||||
|
|
@ -84,7 +85,7 @@ void M_StartMessage(const char *header, const char *string, void (*routine)(INT3
|
|||
// oogh my god this was replaced in 2023
|
||||
|
||||
menumessage.x = (8 * MAXSTRINGLENGTH) - 1;
|
||||
menumessage.y = M_StringHeight(message);
|
||||
menumessage.y = M_StringHeight(menumessage.message);
|
||||
|
||||
M_SetMenuDelay(pid); // Set menu delay to avoid setting off any of the handlers.
|
||||
}
|
||||
|
|
|
|||
98
src/mserv.c
98
src/mserv.c
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "doomstat.h"
|
||||
#include "doomdef.h"
|
||||
#include "console.h" // con_startup
|
||||
#include "command.h"
|
||||
#include "i_threads.h"
|
||||
#include "mserv.h"
|
||||
|
|
@ -40,6 +41,8 @@ static boolean MSUpdateAgain;
|
|||
|
||||
static time_t MSLastPing;
|
||||
|
||||
static char *MSRules;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
static I_mutex MSMutex;
|
||||
static I_cond MSCond;
|
||||
|
|
@ -157,6 +160,43 @@ static void Command_Listserv_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
static boolean firstmsrules = false;
|
||||
|
||||
static void
|
||||
Get_masterserver_rules (boolean checkfirst)
|
||||
{
|
||||
char rules[256];
|
||||
|
||||
if (checkfirst)
|
||||
{
|
||||
boolean MSRulesExist;
|
||||
|
||||
Lock_state();
|
||||
MSRulesExist = (MSRules != NULL);
|
||||
Unlock_state();
|
||||
|
||||
if (MSRulesExist)
|
||||
return;
|
||||
}
|
||||
|
||||
if (HMS_fetch_rules(rules, sizeof rules))
|
||||
{
|
||||
Lock_state();
|
||||
Z_Free(MSRules);
|
||||
MSRules = Z_StrDup(rules);
|
||||
|
||||
if (MSRegistered == true)
|
||||
{
|
||||
CONS_Printf("\n");
|
||||
CONS_Alert(CONS_NOTICE, "%s\n", rules);
|
||||
}
|
||||
|
||||
firstmsrules = true;
|
||||
|
||||
Unlock_state();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Finish_registration (void)
|
||||
{
|
||||
|
|
@ -175,6 +215,17 @@ Finish_registration (void)
|
|||
}
|
||||
Unlock_state();
|
||||
|
||||
char *rules = GetMasterServerRules();
|
||||
if (rules == NULL)
|
||||
{
|
||||
Get_masterserver_rules(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf("\n");
|
||||
CONS_Alert(CONS_NOTICE, "%s\n", rules);
|
||||
}
|
||||
|
||||
if (registered)
|
||||
CONS_Printf("Master server registration successful.\n");
|
||||
}
|
||||
|
|
@ -257,6 +308,15 @@ Finish_unlist (void)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Finish_masterserver_change (char *api)
|
||||
{
|
||||
HMS_set_api(api);
|
||||
|
||||
if (!con_startup)
|
||||
Get_masterserver_rules(false);
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
static int *
|
||||
Server_id (void)
|
||||
|
|
@ -350,7 +410,14 @@ Change_masterserver_thread (char *api)
|
|||
}
|
||||
Unlock_state();
|
||||
|
||||
HMS_set_api(api);
|
||||
Finish_masterserver_change(api);
|
||||
}
|
||||
|
||||
static void
|
||||
Get_masterserver_rules_thread (void)
|
||||
{
|
||||
// THIS FUNC has its own lock check in it
|
||||
Get_masterserver_rules(true);
|
||||
}
|
||||
#endif/*HAVE_THREADS*/
|
||||
|
||||
|
|
@ -397,6 +464,17 @@ void UnregisterServer(void)
|
|||
#endif/*MASTERSERVER*/
|
||||
}
|
||||
|
||||
char *GetMasterServerRules(void)
|
||||
{
|
||||
char *rules;
|
||||
|
||||
Lock_state();
|
||||
rules = MSRules ? Z_StrDup(MSRules) : NULL;
|
||||
Unlock_state();
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
static boolean
|
||||
Online (void)
|
||||
{
|
||||
|
|
@ -447,7 +525,21 @@ Set_api (const char *api)
|
|||
strdup(api)
|
||||
);
|
||||
#else
|
||||
HMS_set_api(strdup(api));
|
||||
Finish_masterserver_change(strdup(api));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Get_rules (void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
I_spawn_thread(
|
||||
"get-masterserver-rules",
|
||||
(I_thread_fn)Get_masterserver_rules_thread,
|
||||
NULL
|
||||
);
|
||||
#else
|
||||
Get_masterserver_rules(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -521,6 +613,8 @@ void Advertise_OnChange(void)
|
|||
#ifdef HAVE_DISCORDRPC
|
||||
DRPC_UpdatePresence();
|
||||
#endif
|
||||
|
||||
M_PopupMasterServerRules();
|
||||
}
|
||||
|
||||
#ifdef DEVELOP
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ struct msg_ban_t
|
|||
// ================================ GLOBALS ===============================
|
||||
|
||||
extern consvar_t cv_masterserver, cv_servername;
|
||||
extern consvar_t cv_masterserver_nagattempts;
|
||||
extern consvar_t cv_server_contact;
|
||||
extern consvar_t cv_masterserver_update_rate;
|
||||
extern consvar_t cv_masterserver_timeout;
|
||||
|
|
@ -77,6 +78,8 @@ extern I_mutex ms_ServerList_mutex;
|
|||
void RegisterServer(void);
|
||||
void UnregisterServer(void);
|
||||
|
||||
void Get_rules(void);
|
||||
|
||||
void MasterClient_Ticker(void);
|
||||
|
||||
msg_server_t *GetShortServersList(int id);
|
||||
|
|
@ -84,6 +87,8 @@ msg_server_t *GetShortServersList(int id);
|
|||
char *GetMODVersion(int id);
|
||||
#endif
|
||||
|
||||
char *GetMasterServerRules(void);
|
||||
|
||||
void AddMServCommands(void);
|
||||
|
||||
/* HTTP */
|
||||
|
|
@ -94,6 +99,7 @@ int HMS_update (void);
|
|||
void HMS_list_servers (void);
|
||||
msg_server_t * HMS_fetch_servers (msg_server_t *list, int id);
|
||||
int HMS_compare_mod_version (char *buffer, size_t size_of_buffer);
|
||||
const char * HMS_fetch_rules (char *buffer, size_t size_of_buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ static void DashRingLaunch(player_t *player, mobj_t *ring)
|
|||
player->dashRingPushTics = DASHRING_PUSH_TICS;
|
||||
|
||||
player->mo->rollangle = 0;
|
||||
P_ResetPitchRoll(player->mo);
|
||||
player->flashing = 0;
|
||||
player->fastfall = 0;
|
||||
K_TumbleInterrupt(player);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "../r_skins.h"
|
||||
#include "../k_hitlag.h"
|
||||
#include "../acs/interface.h"
|
||||
#include "../hu_stuff.h"
|
||||
|
||||
#define UFO_BASE_SPEED (42 * FRACUNIT) // UFO's slowest speed.
|
||||
#define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration
|
||||
|
|
@ -453,6 +454,8 @@ static void UFOMove(mobj_t *ufo)
|
|||
|
||||
// Disable player
|
||||
P_DoAllPlayersExit(PF_NOCONTEST, false);
|
||||
|
||||
HU_DoTitlecardCEcho(NULL, "TOO LATE...", false);
|
||||
}
|
||||
|
||||
if (pathfindsuccess == true)
|
||||
|
|
|
|||
|
|
@ -1556,7 +1556,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
P_PlayDeathSound(target);
|
||||
}
|
||||
|
||||
if (K_Cooperative())
|
||||
// Prisons Free Play: don't eliminate P1 for
|
||||
// spectating. Because in Free Play, this player
|
||||
// can enter the game again, and these flags would
|
||||
// make them intangible.
|
||||
if (K_Cooperative() && !target->player->spectator)
|
||||
{
|
||||
target->player->pflags |= PF_ELIMINATED;
|
||||
|
||||
|
|
@ -2052,30 +2056,34 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
|
|||
|
||||
static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type)
|
||||
{
|
||||
if (player->respawn.state != RESPAWNST_NONE)
|
||||
if (type == DMG_SPECTATOR && (G_GametypeHasTeams() || G_GametypeHasSpectators()))
|
||||
{
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
P_SetPlayerSpectator(player-players);
|
||||
}
|
||||
|
||||
if (!player->exiting && (specialstageinfo.valid == true || modeattacking & ATTACKING_SPB))
|
||||
else
|
||||
{
|
||||
// TODO: this would make a great debug feature for release
|
||||
#ifdef DEVELOP
|
||||
if (type != DMG_SPECTATOR)
|
||||
if (player->respawn.state != RESPAWNST_NONE)
|
||||
{
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->exiting)
|
||||
{
|
||||
player->mo->destscale = 1;
|
||||
player->mo->flags |= MF_NOCLIPTHING;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
HU_DoTitlecardCEcho(player, "FALL OUT!", false);
|
||||
P_DoPlayerExit(player, PF_NOCONTEST);
|
||||
}
|
||||
else if (modeattacking & ATTACKING_SPB)
|
||||
{
|
||||
P_DoPlayerExit(player, PF_NOCONTEST);
|
||||
}
|
||||
#else
|
||||
P_DoPlayerExit(player, PF_NOCONTEST);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (player->exiting)
|
||||
{
|
||||
player->mo->destscale = 1;
|
||||
player->mo->flags |= MF_NOCLIPTHING;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
|
|
@ -2578,7 +2586,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
player->fastfall = 0;
|
||||
player->fastfallBase = 0;
|
||||
player->ringboost = 0;
|
||||
player->glanceDir = 0;
|
||||
player->pflags &= ~PF_GAINAX;
|
||||
|
|
|
|||
|
|
@ -569,6 +569,7 @@ void P_ExplodeMissile(mobj_t *mo);
|
|||
void P_CheckGravity(mobj_t *mo, boolean affect);
|
||||
void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope);
|
||||
void P_SetPitchRoll(mobj_t *mo, angle_t pitch, angle_t yaw);
|
||||
void P_ResetPitchRoll(mobj_t *mo);
|
||||
fixed_t P_ScaleFromMap(fixed_t n, fixed_t scale);
|
||||
fixed_t P_GetMobjHead(const mobj_t *);
|
||||
fixed_t P_GetMobjFeet(const mobj_t *);
|
||||
|
|
|
|||
131
src/p_mobj.c
131
src/p_mobj.c
|
|
@ -1333,7 +1333,7 @@ void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope)
|
|||
}
|
||||
else
|
||||
{
|
||||
mo->pitch = mo->roll = 0;
|
||||
P_ResetPitchRoll(mo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1348,6 +1348,15 @@ void P_SetPitchRoll(mobj_t *mo, angle_t pitch, angle_t yaw)
|
|||
mo->pitch = FixedMul(pitch, FINECOSINE (yaw));
|
||||
}
|
||||
|
||||
//
|
||||
// P_ResetPitchRoll
|
||||
//
|
||||
void P_ResetPitchRoll(mobj_t *mo)
|
||||
{
|
||||
mo->pitch = 0;
|
||||
mo->roll = 0;
|
||||
}
|
||||
|
||||
#define STOPSPEED (FRACUNIT)
|
||||
|
||||
//
|
||||
|
|
@ -6716,6 +6725,49 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
case MT_ARKARROW:
|
||||
Obj_ArkArrowThink(mobj);
|
||||
break;
|
||||
case MT_SCRIPT_THING:
|
||||
{
|
||||
if (mobj->thing_args[2] != 0)
|
||||
{
|
||||
// turned off
|
||||
break;
|
||||
}
|
||||
|
||||
UINT8 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player_t *player = &players[i];
|
||||
if (P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fixed_t dist = R_PointToDist2(
|
||||
mobj->x, mobj->y,
|
||||
player->mo->x, player->mo->y
|
||||
);
|
||||
|
||||
if (dist < mobj->thing_args[0] * FRACUNIT)
|
||||
{
|
||||
P_ActivateThingSpecial(mobj, player->mo);
|
||||
|
||||
if (mobj->thing_args[1] == 0)
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MT_VWREF:
|
||||
case MT_VWREB:
|
||||
{
|
||||
|
|
@ -7191,7 +7243,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
case MT_FLOATINGITEM:
|
||||
{
|
||||
mobj->pitch = mobj->roll = 0;
|
||||
P_ResetPitchRoll(mobj);
|
||||
if (mobj->flags & MF_NOCLIPTHING)
|
||||
{
|
||||
if (P_CheckDeathPitCollide(mobj))
|
||||
|
|
@ -11778,61 +11830,24 @@ void P_RespawnSpecials(void)
|
|||
//
|
||||
void P_SpawnPlayer(INT32 playernum)
|
||||
{
|
||||
UINT8 i, pcount = 0; // MAXPLAYERS if exiting
|
||||
UINT8 i;
|
||||
player_t *p = &players[playernum];
|
||||
mobj_t *mobj;
|
||||
|
||||
boolean justjoined = (p->jointime <= 1);
|
||||
|
||||
if (p->playerstate == PST_REBORN)
|
||||
{
|
||||
G_PlayerReborn(playernum, (p->jointime <= 1));
|
||||
G_PlayerReborn(playernum, justjoined);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (i == playernum)
|
||||
continue;
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
if (players[i].exiting)
|
||||
{
|
||||
pcount = MAXPLAYERS;
|
||||
break;
|
||||
}
|
||||
if (players[i].jointime <= 1) // Prevent splitscreen hosters/joiners from only adding 1 player at a time in empty servers
|
||||
continue;
|
||||
pcount++;
|
||||
}
|
||||
if (justjoined)
|
||||
G_SpectatePlayerOnJoin(playernum);
|
||||
|
||||
// spawn as spectator determination
|
||||
if (multiplayer && demo.playback)
|
||||
{
|
||||
; // Don't mess with spectator values since the demo setup handles them already.
|
||||
}
|
||||
else if (p->bot)
|
||||
{
|
||||
if (K_PodiumSequence() == true)
|
||||
; // This is too late to correct spectator status. Whatever state we're in at this point, our (dog) bed is made.
|
||||
else if (!(gametyperules & GTR_BOTS)
|
||||
|| (grandprixinfo.gp == true
|
||||
&& grandprixinfo.eventmode != GPEVENT_NONE))
|
||||
{
|
||||
// Bots aren't supposed to be here.
|
||||
p->spectator = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No point in a spectating bot!
|
||||
p->spectator = false;
|
||||
}
|
||||
}
|
||||
else if (netgame && p->jointime <= 1 && pcount)
|
||||
{
|
||||
p->spectator = true;
|
||||
}
|
||||
else if (multiplayer && !netgame)
|
||||
if (G_GametypeHasTeams())
|
||||
{
|
||||
// If you're in a team game and you don't have a team assigned yet...
|
||||
if (G_GametypeHasTeams() && p->ctfteam == 0)
|
||||
if (!p->spectator && p->ctfteam == 0)
|
||||
{
|
||||
changeteam_union NetPacket;
|
||||
UINT16 usvalue;
|
||||
|
|
@ -11842,9 +11857,6 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
// yes even in splitscreen mode
|
||||
p->spectator = true;
|
||||
|
||||
if (playernum&1) p->skincolor = skincolor_redteam;
|
||||
else p->skincolor = skincolor_blueteam;
|
||||
|
||||
// but immediately send a team change packet.
|
||||
NetPacket.packet.playernum = playernum;
|
||||
NetPacket.packet.verification = true;
|
||||
|
|
@ -11853,22 +11865,6 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
usvalue = SHORT(NetPacket.value.l|NetPacket.value.b);
|
||||
SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue));
|
||||
}
|
||||
else // Otherwise, never spectator.
|
||||
{
|
||||
// TODO: this would make a great debug feature for release
|
||||
#ifndef DEVELOP
|
||||
p->spectator = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (G_GametypeHasTeams())
|
||||
{
|
||||
// Fix stupid non spectator spectators.
|
||||
if (!p->spectator && !p->ctfteam)
|
||||
{
|
||||
p->spectator = true;
|
||||
}
|
||||
|
||||
// Fix team colors.
|
||||
// This code isn't being done right somewhere else. Oh well.
|
||||
|
|
@ -11967,8 +11963,7 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
S_StartSound(body, sfx_s1af);
|
||||
}
|
||||
|
||||
// I'm not refactoring the loop at the top of this file.
|
||||
pcount = 0;
|
||||
UINT8 pcount = 0;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7835,6 +7835,9 @@ static void P_InitPlayers(void)
|
|||
UINT8 i;
|
||||
INT32 skin = -1;
|
||||
|
||||
// Make sure objectplace is OFF when you first start the level!
|
||||
OP_ResetObjectplace();
|
||||
|
||||
// Are we forcing a character?
|
||||
if (gametype == GT_TUTORIAL)
|
||||
{
|
||||
|
|
@ -7871,14 +7874,7 @@ static void P_InitPlayers(void)
|
|||
// followercolor can be left alone for hopefully obvious reasons
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_CIRCUIT) && K_PodiumSequence() == false)
|
||||
{
|
||||
G_DoReborn(i);
|
||||
}
|
||||
else // gametype is race
|
||||
{
|
||||
G_SpawnPlayer(i);
|
||||
}
|
||||
G_SpawnPlayer(i);
|
||||
|
||||
players[i].xtralife = 0; // extra lives do not ever carry over from the previous round
|
||||
}
|
||||
|
|
@ -8245,8 +8241,17 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
}
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_SPECIALSTART)
|
||||
if (K_PodiumHasEmerald())
|
||||
{
|
||||
// Special Stage out
|
||||
if (ranspecialwipe != 2)
|
||||
S_StartSound(NULL, sfx_s3k6a);
|
||||
levelfadecol = 0;
|
||||
wipetype = wipe_encore_towhite;
|
||||
}
|
||||
else if (gametyperules & GTR_SPECIALSTART)
|
||||
{
|
||||
// Special Stage in
|
||||
if (ranspecialwipe != 2)
|
||||
S_StartSound(NULL, sfx_s3kaf);
|
||||
levelfadecol = 0;
|
||||
|
|
@ -8254,6 +8259,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
}
|
||||
else if (skipstats == 1)
|
||||
{
|
||||
// MapWarp
|
||||
if (ranspecialwipe != 2)
|
||||
S_StartSound(NULL, sfx_s3k73);
|
||||
levelfadecol = 0;
|
||||
|
|
@ -8261,11 +8267,13 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
}
|
||||
else if (encoremode)
|
||||
{
|
||||
// Encore
|
||||
levelfadecol = 0;
|
||||
wipetype = wipe_encore_towhite;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default
|
||||
levelfadecol = 31;
|
||||
}
|
||||
|
||||
|
|
@ -8547,7 +8555,7 @@ void P_PostLoadLevel(void)
|
|||
K_InitGrandPrixBots();
|
||||
grandprixinfo.initalize = false;
|
||||
}
|
||||
else if (grandprixinfo.wonround == true)
|
||||
else
|
||||
{
|
||||
K_UpdateGrandPrixBots();
|
||||
grandprixinfo.wonround = false;
|
||||
|
|
|
|||
12
src/p_spec.c
12
src/p_spec.c
|
|
@ -1987,7 +1987,15 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
|
||||
player->starpostnum = 0;
|
||||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
if (gametyperules & GTR_SPECIALSTART)
|
||||
{
|
||||
if (player->laps > numlaps)
|
||||
{
|
||||
// Warp out
|
||||
S_StartSound(NULL, sfx_s3kb3);
|
||||
}
|
||||
}
|
||||
else if (P_IsDisplayPlayer(player))
|
||||
{
|
||||
if (numlaps > 1 && player->laps == numlaps) // final lap
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
|
@ -2053,6 +2061,8 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
if (!(specialstageinfo.ufo == NULL || P_MobjWasRemoved(specialstageinfo.ufo)))
|
||||
{
|
||||
applyflags |= PF_NOCONTEST;
|
||||
|
||||
HU_DoTitlecardCEcho(player, "EMPTY\\HANDED?", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
17
src/p_user.c
17
src/p_user.c
|
|
@ -484,12 +484,10 @@ void P_ResetPlayer(player_t *player)
|
|||
player->trickpanel = 0;
|
||||
player->glanceDir = 0;
|
||||
player->fastfall = 0;
|
||||
player->fastfallBase = 0;
|
||||
|
||||
if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false)
|
||||
{
|
||||
player->mo->pitch = 0;
|
||||
player->mo->roll = 0;
|
||||
P_ResetPitchRoll(player->mo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1296,7 +1294,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
{
|
||||
K_UpdateAllPlayerPositions();
|
||||
|
||||
if (cv_kartvoices.value)
|
||||
if (cv_kartvoices.value && !(gametyperules & GTR_SPECIALSTART))
|
||||
{
|
||||
if (P_IsDisplayPlayer(player))
|
||||
{
|
||||
|
|
@ -1326,7 +1324,9 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
G_BeginLevelExit();
|
||||
}
|
||||
|
||||
if (grandprixinfo.gp == true && player->bot == false && losing == false)
|
||||
if (grandprixinfo.gp == true
|
||||
&& (roundqueue.size && roundqueue.position < roundqueue.size) // Not the last map of GP
|
||||
&& player->bot == false && losing == false)
|
||||
{
|
||||
const UINT8 lifethreshold = 20;
|
||||
|
||||
|
|
@ -1407,6 +1407,11 @@ void P_DoAllPlayersExit(pflags_t flags, boolean trygivelife)
|
|||
// You've already finished, don't play again
|
||||
;
|
||||
}
|
||||
else if (gametyperules & GTR_SPECIALSTART)
|
||||
{
|
||||
// Warp out
|
||||
S_StartSound(NULL, sfx_s3kb3);
|
||||
}
|
||||
else if (musiccountdown == 0)
|
||||
{
|
||||
// Other people finish
|
||||
|
|
@ -3504,7 +3509,7 @@ boolean P_SpectatorJoinGame(player_t *player)
|
|||
// Pressing fire assigns you to a team that needs players if allowed.
|
||||
// Partial code reproduction from p_tick.c autobalance code.
|
||||
// a surprise tool that will help us later...
|
||||
if (G_GametypeHasTeams())
|
||||
if (G_GametypeHasTeams() && player->ctfteam == 0)
|
||||
{
|
||||
INT32 z, numplayersred = 0, numplayersblue = 0;
|
||||
|
||||
|
|
|
|||
50
src/r_draw.c
50
src/r_draw.c
|
|
@ -200,7 +200,13 @@ CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
|
|||
|
||||
#define TRANSTAB_AMTMUL10 (255.0f / 10.0f)
|
||||
|
||||
static void R_GenerateBlendTables(void);
|
||||
struct GenerateBlendTables_State
|
||||
{
|
||||
RGBA_t *masterPalette;
|
||||
RGBA_t *gammaCorrectedPalette;
|
||||
};
|
||||
|
||||
static void R_GenerateBlendTables_Core(struct GenerateBlendTables_State *state);
|
||||
static void R_GenerateTranslucencyTable(UINT8 *table, RGBA_t* sourcepal, int style, UINT8 blendamt);
|
||||
|
||||
static void R_AllocateBlendTables(void)
|
||||
|
|
@ -221,8 +227,13 @@ static void R_AllocateBlendTables(void)
|
|||
#ifdef HAVE_THREADS
|
||||
static void R_GenerateBlendTables_Thread(void *userdata)
|
||||
{
|
||||
(void)userdata;
|
||||
R_GenerateBlendTables();
|
||||
struct GenerateBlendTables_State *state = userdata;
|
||||
|
||||
R_GenerateBlendTables_Core(state);
|
||||
|
||||
free(state->masterPalette);
|
||||
free(state->gammaCorrectedPalette);
|
||||
free(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -247,16 +258,29 @@ void R_InitTranslucencyTables(void)
|
|||
W_ReadLump(W_GetNumForName("TRANS90"), transtables+0x80000);
|
||||
|
||||
R_AllocateBlendTables();
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
I_spawn_thread("blend-tables",
|
||||
R_GenerateBlendTables_Thread, NULL);
|
||||
#else
|
||||
R_GenerateBlendTables();
|
||||
#endif
|
||||
}
|
||||
|
||||
void R_GenerateBlendTables(void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
// Allocate copies for the worker thread since the originals can be freed in the main thread.
|
||||
struct GenerateBlendTables_State *state = malloc(sizeof *state);
|
||||
size_t palsize = 256 * sizeof(RGBA_t);
|
||||
|
||||
state->masterPalette = memcpy(malloc(palsize), pMasterPalette, palsize);
|
||||
state->gammaCorrectedPalette = memcpy(malloc(palsize), pGammaCorrectedPalette, palsize);
|
||||
|
||||
I_spawn_thread("blend-tables",
|
||||
R_GenerateBlendTables_Thread, state);
|
||||
#else
|
||||
struct GenerateBlendTables_State state = {pMasterPalette, pGammaCorrectedPalette};
|
||||
|
||||
R_GenerateBlendTables_Core(&state);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void R_GenerateBlendTables_Core(struct GenerateBlendTables_State *state)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
|
|
@ -265,12 +289,12 @@ void R_GenerateBlendTables(void)
|
|||
const size_t offs = (0x10000 * i);
|
||||
const UINT8 alpha = (TRANSTAB_AMTMUL10 * ((float)(10-i)));
|
||||
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_add] + offs, pGammaCorrectedPalette, AST_ADD, alpha);
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_subtract] + offs, pMasterPalette, AST_SUBTRACT, alpha); // intentionally uses pMasterPalette
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, pGammaCorrectedPalette, AST_REVERSESUBTRACT, alpha);
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_add] + offs, state->gammaCorrectedPalette, AST_ADD, alpha);
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_subtract] + offs, state->masterPalette, AST_SUBTRACT, alpha); // intentionally uses pMasterPalette
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, state->gammaCorrectedPalette, AST_REVERSESUBTRACT, alpha);
|
||||
}
|
||||
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_modulate], pGammaCorrectedPalette, AST_MODULATE, 0);
|
||||
R_GenerateTranslucencyTable(blendtables[blendtab_modulate], state->gammaCorrectedPalette, AST_MODULATE, 0);
|
||||
}
|
||||
|
||||
void R_GenerateTranslucencyTable(UINT8 *table, RGBA_t* sourcepal, int style, UINT8 blendamt)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ enum
|
|||
extern UINT8 *blendtables[NUMBLENDMAPS];
|
||||
|
||||
void R_InitTranslucencyTables(void);
|
||||
void R_GenerateBlendTables(void);
|
||||
|
||||
UINT8 *R_GetTranslucencyTable(INT32 alphalevel);
|
||||
UINT8 *R_GetBlendTable(int style, INT32 alphalevel);
|
||||
|
|
|
|||
|
|
@ -1466,7 +1466,7 @@ static void copy_to_skin (struct ParseSpriteInfoState *parser, INT32 skinnum)
|
|||
}
|
||||
}
|
||||
|
||||
static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean all)
|
||||
static boolean R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean all)
|
||||
{
|
||||
char *sprinfoToken;
|
||||
size_t sprinfoTokenLength;
|
||||
|
|
@ -1487,12 +1487,15 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite frame should be");
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where sprite frame should be\n");
|
||||
return false;
|
||||
}
|
||||
sprinfoTokenLength = strlen(sprinfoToken);
|
||||
if (sprinfoTokenLength != 1)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Invalid frame \"%s\"",sprinfoToken);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Invalid frame \"%s\"\n",sprinfoToken);
|
||||
Z_Free(sprinfoToken);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
frameChar = sprinfoToken;
|
||||
|
|
@ -1504,7 +1507,10 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
// Left Curly Brace
|
||||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
I_Error("Error parsing SPRTINFO lump: Missing sprite info");
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Missing sprite info\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(sprinfoToken,"{")==0)
|
||||
|
|
@ -1513,7 +1519,8 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite info should be");
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where sprite info should be\n");
|
||||
return false;
|
||||
}
|
||||
while (strcmp(sprinfoToken,"}")!=0)
|
||||
{
|
||||
|
|
@ -1550,7 +1557,8 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite info or right curly brace should be");
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where sprite info or right curly brace should be\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1574,7 +1582,11 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
INT32 i;
|
||||
|
||||
if (!parser->foundskins)
|
||||
I_Error("Error parsing SPRTINFO lump: No skins specified in this sprite2 definition");
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: No skins specified in this sprite2 definition\n");
|
||||
Z_Free(bright);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parser->foundskins < 0)
|
||||
{
|
||||
|
|
@ -1607,6 +1619,8 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
M_Memcpy(&spriteinfo[parser->sprnum], parser->info, sizeof(spriteinfo_t));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1614,7 +1628,7 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean
|
|||
//
|
||||
// Parse a SPRTINFO lump.
|
||||
//
|
||||
static void R_ParseSpriteInfo(boolean spr2)
|
||||
static boolean R_ParseSpriteInfo(boolean spr2)
|
||||
{
|
||||
char *sprinfoToken;
|
||||
size_t sprinfoTokenLength;
|
||||
|
|
@ -1634,7 +1648,8 @@ static void R_ParseSpriteInfo(boolean spr2)
|
|||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be");
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strcmp(sprinfoToken, "*")) // All sprites
|
||||
|
|
@ -1646,7 +1661,9 @@ static void R_ParseSpriteInfo(boolean spr2)
|
|||
sprinfoTokenLength = strlen(sprinfoToken);
|
||||
if (sprinfoTokenLength != 4)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long\n",sprinfoToken);
|
||||
Z_Free(sprinfoToken);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1666,7 +1683,10 @@ static void R_ParseSpriteInfo(boolean spr2)
|
|||
for (i = 0; i <= NUMSPRITES; i++)
|
||||
{
|
||||
if (i == NUMSPRITES)
|
||||
I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unknown sprite name \"%s\"\n", newSpriteName);
|
||||
return false;
|
||||
}
|
||||
if (!memcmp(newSpriteName,sprnames[i],4))
|
||||
{
|
||||
parser.sprnum = i;
|
||||
|
|
@ -1679,7 +1699,10 @@ static void R_ParseSpriteInfo(boolean spr2)
|
|||
for (i = 0; i <= NUMPLAYERSPRITES; i++)
|
||||
{
|
||||
if (i == NUMPLAYERSPRITES)
|
||||
I_Error("Error parsing SPRTINFO lump: Unknown sprite2 name \"%s\"", newSpriteName);
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unknown sprite2 name \"%s\"\n", newSpriteName);
|
||||
return false;
|
||||
}
|
||||
if (!memcmp(newSpriteName,spr2names[i],4))
|
||||
{
|
||||
parser.spr2num = i;
|
||||
|
|
@ -1695,22 +1718,33 @@ static void R_ParseSpriteInfo(boolean spr2)
|
|||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where open curly brace for sprite \"%s\" should be",newSpriteName);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where open curly brace for sprite \"%s\" should be\n",newSpriteName);
|
||||
Z_Free(parser.info);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean error = false;
|
||||
|
||||
if (strcmp(sprinfoToken,"{")==0)
|
||||
{
|
||||
Z_Free(sprinfoToken);
|
||||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where definition for sprite \"%s\" should be",newSpriteName);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where definition for sprite \"%s\" should be\n",newSpriteName);
|
||||
Z_Free(parser.info);
|
||||
return false;
|
||||
}
|
||||
while (strcmp(sprinfoToken,"}")!=0)
|
||||
{
|
||||
if (stricmp(sprinfoToken, "SKIN")==0)
|
||||
{
|
||||
if (!spr2)
|
||||
I_Error("Error parsing SPRTINFO lump: \"SKIN\" token found outside of a sprite2 definition");
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: \"SKIN\" token found outside of a sprite2 definition\n");
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Z_Free(sprinfoToken);
|
||||
R_ParseSpriteInfoSkin(&parser);
|
||||
|
|
@ -1718,31 +1752,46 @@ static void R_ParseSpriteInfo(boolean spr2)
|
|||
else if (stricmp(sprinfoToken, "FRAME")==0)
|
||||
{
|
||||
Z_Free(sprinfoToken);
|
||||
R_ParseSpriteInfoFrame(&parser, PARSER_FRAME);
|
||||
if (!R_ParseSpriteInfoFrame(&parser, PARSER_FRAME))
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (stricmp(sprinfoToken, "DEFAULT")==0)
|
||||
{
|
||||
Z_Free(sprinfoToken);
|
||||
R_ParseSpriteInfoFrame(&parser, PARSER_DEFAULT);
|
||||
if (!R_ParseSpriteInfoFrame(&parser, PARSER_DEFAULT))
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unknown keyword \"%s\" in sprite %s",sprinfoToken,newSpriteName);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unknown keyword \"%s\" in sprite %s\n",sprinfoToken,newSpriteName);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
sprinfoToken = M_GetToken(NULL);
|
||||
if (sprinfoToken == NULL)
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite info or right curly brace for sprite \"%s\" should be",newSpriteName);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unexpected end of file where sprite info or right curly brace for sprite \"%s\" should be\n",newSpriteName);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("Error parsing SPRTINFO lump: Expected \"{\" for sprite \"%s\", got \"%s\"",newSpriteName,sprinfoToken);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Expected \"{\" for sprite \"%s\", got \"%s\"\n",newSpriteName,sprinfoToken);
|
||||
error = true;
|
||||
}
|
||||
Z_Free(sprinfoToken);
|
||||
Z_Free(parser.info);
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1777,13 +1826,20 @@ void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum)
|
|||
sprinfoToken = M_GetToken(sprinfoText);
|
||||
while (sprinfoToken != NULL)
|
||||
{
|
||||
boolean error = true;
|
||||
|
||||
if (!stricmp(sprinfoToken, "SPRITE"))
|
||||
R_ParseSpriteInfo(false);
|
||||
error = !R_ParseSpriteInfo(false);
|
||||
else if (!stricmp(sprinfoToken, "SPRITE2"))
|
||||
R_ParseSpriteInfo(true);
|
||||
error = !R_ParseSpriteInfo(true);
|
||||
else
|
||||
I_Error("Error parsing SPRTINFO lump: Unknown keyword \"%s\"", sprinfoToken);
|
||||
CONS_Alert(CONS_WARNING, "Error parsing SPRTINFO lump: Unknown keyword \"%s\"\n", sprinfoToken);
|
||||
|
||||
Z_Free(sprinfoToken);
|
||||
|
||||
if (error)
|
||||
break;
|
||||
|
||||
sprinfoToken = M_GetToken(NULL);
|
||||
}
|
||||
Z_Free((void *)sprinfoText);
|
||||
|
|
|
|||
|
|
@ -943,10 +943,10 @@ void ST_drawTitleCard(void)
|
|||
// Everything else...
|
||||
if (bossinfo.enemyname)
|
||||
{
|
||||
bx = V_TitleCardStringWidth(bossinfo.enemyname);
|
||||
bx = V_TitleCardStringWidth(bossinfo.enemyname, false);
|
||||
|
||||
// Name.
|
||||
V_DrawTitleCardString((BASEVIDWIDTH - bx)/2, 75, bossinfo.enemyname, 0, true, bossinfo.titleshow, lt_exitticker);
|
||||
V_DrawTitleCardString((BASEVIDWIDTH - bx)/2, 75, bossinfo.enemyname, 0, true, bossinfo.titleshow, lt_exitticker, false);
|
||||
|
||||
// Under-bar.
|
||||
{
|
||||
|
|
@ -1067,10 +1067,10 @@ void ST_drawTitleCard(void)
|
|||
V_DrawFixedPatch(eggx2*FRACUNIT, eggy2*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccirclebottom, NULL);
|
||||
|
||||
// Now the level name.
|
||||
V_DrawTitleCardString((actnum) ? 265 : 280, 60, lvlttl, V_SNAPTORIGHT, false, lt_ticker, TTANIMENDTHRESHOLD);
|
||||
V_DrawTitleCardString((actnum) ? 265 : 280, 60, lvlttl, V_SNAPTORIGHT, false, lt_ticker, TTANIMENDTHRESHOLD, false);
|
||||
|
||||
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
|
||||
V_DrawTitleCardString((actnum) ? 265 : 280, 60+32, strlen(zonttl) ? zonttl : "ZONE", V_SNAPTORIGHT, false, lt_ticker - strlen(lvlttl), TTANIMENDTHRESHOLD);
|
||||
V_DrawTitleCardString((actnum) ? 265 : 280, 60+32, strlen(zonttl) ? zonttl : "ZONE", V_SNAPTORIGHT, false, lt_ticker - strlen(lvlttl), TTANIMENDTHRESHOLD, false);
|
||||
|
||||
// the act has a similar graphic animation, but we'll handle it here since it's only like 2 graphics lmfao.
|
||||
if (actnum && actnum < 10)
|
||||
|
|
|
|||
165
src/v_video.cpp
165
src/v_video.cpp
|
|
@ -1852,50 +1852,155 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercase, UINT8 *co
|
|||
);
|
||||
}
|
||||
|
||||
// V_TitleCardStringWidth
|
||||
// Get the string's width using the titlecard font.
|
||||
INT32 V_TitleCardStringWidth(const char *str)
|
||||
template <bool Centered>
|
||||
static INT32 Internal_TitleCardStringOffset(const char *str, boolean p4)
|
||||
{
|
||||
int bg_font = GTOL_FONT;
|
||||
int fg_font = GTFN_FONT;
|
||||
|
||||
if (p4)
|
||||
{
|
||||
bg_font = GTOL4_FONT;
|
||||
fg_font = GTFN4_FONT;
|
||||
}
|
||||
|
||||
INT32 xoffs = 0;
|
||||
const char *ch = str;
|
||||
char c;
|
||||
patch_t *pp;
|
||||
|
||||
for (;;ch++)
|
||||
// Returns true if it reached the end, false if interrupted.
|
||||
auto scan = [&](auto keep_going)
|
||||
{
|
||||
if (!*ch)
|
||||
break;
|
||||
|
||||
if (*ch == '\n')
|
||||
for (;;ch++)
|
||||
{
|
||||
xoffs = 0;
|
||||
continue;
|
||||
if (*ch == '\n')
|
||||
{
|
||||
xoffs = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!keep_going(*ch))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
c = *ch;
|
||||
c = toupper(c);
|
||||
c -= LT_FONTSTART;
|
||||
|
||||
// check if character exists, if not, it's a space.
|
||||
if (c < 0 || c >= LT_FONTSIZE || !fontv[bg_font].font[(INT32)c])
|
||||
{
|
||||
xoffs += p4 ? 5 : 10;
|
||||
continue;
|
||||
}
|
||||
|
||||
pp = fontv[fg_font].font[(INT32)c];
|
||||
|
||||
xoffs += pp->width - (p4 ? 3 : 5);
|
||||
}
|
||||
|
||||
c = *ch;
|
||||
c = toupper(c);
|
||||
c -= LT_FONTSTART;
|
||||
return true;
|
||||
};
|
||||
|
||||
// check if character exists, if not, it's a space.
|
||||
if (c < 0 || c >= LT_FONTSIZE || !fontv[GTOL_FONT].font[(INT32)c])
|
||||
do
|
||||
{
|
||||
// For the sake of centering, don't count spaces or
|
||||
// punctuation at each end of a line.
|
||||
// TODO: This should ideally be more sophisticated:
|
||||
// - Check patch width directly for monospace or
|
||||
// punctuation that isn't necessarily thin.
|
||||
// - Apply to all centered string drawing.
|
||||
if constexpr (Centered)
|
||||
{
|
||||
xoffs += 10;
|
||||
continue;
|
||||
// Count leading fluff
|
||||
if (!scan([](int c) { return c && !isalnum(c); }))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!*ch)
|
||||
{
|
||||
// ALL fluff, so center it normally.
|
||||
break;
|
||||
}
|
||||
|
||||
// xoffs gets halved later, which centers the
|
||||
// string. If we don't want leading fluff to push
|
||||
// everything to the right, its full width needs
|
||||
// to be subtracted, so it's doubled here to
|
||||
// cancel out the division.
|
||||
xoffs *= 2;
|
||||
|
||||
INT32 trim = -1;
|
||||
|
||||
bool reached_end = scan(
|
||||
[&trim, &xoffs](int c)
|
||||
{
|
||||
if (isalnum(c))
|
||||
{
|
||||
trim = -1;
|
||||
}
|
||||
else if (trim < 0)
|
||||
{
|
||||
trim = xoffs;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
);
|
||||
|
||||
// Discount trailing fluff
|
||||
if (reached_end && trim >= 0)
|
||||
{
|
||||
xoffs = trim;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scan([](int c) { return c; });
|
||||
}
|
||||
|
||||
pp = fontv[GTFN_FONT].font[(INT32)c];
|
||||
|
||||
xoffs += pp->width-5;
|
||||
}
|
||||
while (*(ch++));
|
||||
|
||||
return xoffs;
|
||||
if constexpr (Centered)
|
||||
{
|
||||
return xoffs / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return xoffs;
|
||||
}
|
||||
}
|
||||
|
||||
// V_TitleCardStringWidth
|
||||
// Get the string's width using the titlecard font.
|
||||
INT32 V_TitleCardStringWidth(const char *str, boolean p4)
|
||||
{
|
||||
return Internal_TitleCardStringOffset<false>(str, p4);
|
||||
}
|
||||
|
||||
// V_CenteredTitleCardStringOffset
|
||||
// Subtract this offset from an X coordinate to center the string around that point.
|
||||
INT32 V_CenteredTitleCardStringOffset(const char *str, boolean p4)
|
||||
{
|
||||
return Internal_TitleCardStringOffset<true>(str, p4);
|
||||
}
|
||||
|
||||
// V_DrawTitleCardScreen.
|
||||
// see v_video.h's prototype for more information.
|
||||
//
|
||||
void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boolean bossmode, INT32 timer, INT32 threshold)
|
||||
void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boolean bossmode, INT32 timer, INT32 threshold, boolean p4)
|
||||
{
|
||||
int bg_font = GTOL_FONT;
|
||||
int fg_font = GTFN_FONT;
|
||||
|
||||
if (p4)
|
||||
{
|
||||
bg_font = GTOL4_FONT;
|
||||
fg_font = GTFN4_FONT;
|
||||
}
|
||||
|
||||
INT32 xoffs = 0;
|
||||
INT32 yoffs = 0;
|
||||
|
|
@ -1916,7 +2021,7 @@ void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boole
|
|||
x -= 2; // Account for patch width...
|
||||
|
||||
if (flags & V_SNAPTORIGHT)
|
||||
x -= V_TitleCardStringWidth(str);
|
||||
x -= V_TitleCardStringWidth(str, p4);
|
||||
|
||||
|
||||
for (;;ch++, i++)
|
||||
|
|
@ -1933,7 +2038,7 @@ void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boole
|
|||
if (*ch == '\n')
|
||||
{
|
||||
xoffs = x;
|
||||
yoffs += 32;
|
||||
yoffs += p4 ? 18 : 32;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1944,14 +2049,14 @@ void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boole
|
|||
c -= LT_FONTSTART;
|
||||
|
||||
// check if character exists, if not, it's a space.
|
||||
if (c < 0 || c >= LT_FONTSIZE || !fontv[GTFN_FONT].font[(INT32)c])
|
||||
if (c < 0 || c >= LT_FONTSIZE || !fontv[fg_font].font[(INT32)c])
|
||||
{
|
||||
xoffs += 10;
|
||||
xoffs += p4 ? 5 : 10;
|
||||
continue;
|
||||
}
|
||||
|
||||
ol = fontv[GTOL_FONT].font[(INT32)c];
|
||||
pp = fontv[GTFN_FONT].font[(INT32)c];
|
||||
ol = fontv[bg_font].font[(INT32)c];
|
||||
pp = fontv[fg_font].font[(INT32)c];
|
||||
|
||||
if (bossmode)
|
||||
{
|
||||
|
|
@ -2004,7 +2109,7 @@ void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boole
|
|||
V_DrawStretchyFixedPatch((x + xoffs)*FRACUNIT + offs, (y+yoffs)*FRACUNIT, abs(scalex), FRACUNIT, flags|flipflag, pp, NULL);
|
||||
}
|
||||
|
||||
xoffs += pp->width -5;
|
||||
xoffs += pp->width - (p4 ? 3 : 5);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -347,10 +347,13 @@ void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, con
|
|||
// threshold: when the letters start disappearing (leave to 0 to disable) (both are INT32 in case you supply negative values...)
|
||||
// NOTE: This function ignores most conventional string flags (V_RETURN8, V_FORCEUPPERCASE ...)
|
||||
// NOTE: This font only works with uppercase letters.
|
||||
void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boolean bossmode, INT32 timer, INT32 threshold);
|
||||
void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boolean bossmode, INT32 timer, INT32 threshold, boolean p4);
|
||||
|
||||
// returns thr width of a string drawn using the above function.
|
||||
INT32 V_TitleCardStringWidth(const char *str);
|
||||
INT32 V_TitleCardStringWidth(const char *str, boolean p4);
|
||||
|
||||
// offset that can be subtracted to center align.
|
||||
INT32 V_CenteredTitleCardStringOffset(const char *str, boolean p4);
|
||||
|
||||
// Draw tall nums, used for menu, HUD, intermission
|
||||
void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#define SRB2VERSION "2.0"/* this must be the first line, for cmake !! */
|
||||
#define SRB2VERSION "1.0"/* this must be the first line, for cmake !! */
|
||||
|
||||
// The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ).
|
||||
// DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
|
||||
|
|
|
|||
|
|
@ -1462,7 +1462,7 @@ void Y_IntermissionDrawer(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
headerwidth = V_TitleCardStringWidth(data.headerstring);
|
||||
headerwidth = V_TitleCardStringWidth(data.headerstring, false);
|
||||
|
||||
headerx = (BASEVIDWIDTH - headerwidth)/2;
|
||||
headery = 17;
|
||||
|
|
@ -1490,7 +1490,7 @@ void Y_IntermissionDrawer(void)
|
|||
V_DrawMappedPatch(x + roundx, 39, 0, roundpatch, NULL);
|
||||
}
|
||||
|
||||
V_DrawTitleCardString(x + headerx, headery, data.headerstring, 0, false, 0, 0);
|
||||
V_DrawTitleCardString(x + headerx, headery, data.headerstring, 0, false, 0, 0, false);
|
||||
}
|
||||
|
||||
// Returns early if there's no players to draw
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue