Compare commits
67
Commits
threadstuff
...
nettest1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36cb5624be | ||
|
|
ed1554de24 | ||
|
|
df4222e8dc | ||
|
|
2e4a11fc64 | ||
|
|
70f4b20161 | ||
|
|
0be50629c4 | ||
|
|
bee9aaee63 | ||
|
|
0184bd2779 | ||
|
|
2f410e59c7 | ||
|
|
ff258858c8 | ||
|
|
7bfb22d10d | ||
|
|
47960e5c17 | ||
|
|
c5f569eedc | ||
|
|
586cb358ba | ||
|
|
65b157cac0 | ||
|
|
0c864503a3 | ||
|
|
2f57137d11 | ||
|
|
13d4f9e7d7 | ||
|
|
c38d7c1672 | ||
|
|
0ddbaeb2a2 | ||
|
|
1e2ddebced | ||
|
|
acf1254494 | ||
|
|
007094e6d2 | ||
|
|
9c0f9b0637 | ||
|
|
cf0475dd94 | ||
|
|
afe57f1d05 | ||
|
|
a7b5df6793 | ||
|
|
a8eb9b2485 | ||
|
|
7fd123d604 | ||
|
|
0644ecd0c3 | ||
|
|
37cd0a596e | ||
|
|
499177c4b9 | ||
|
|
961e08ab75 | ||
|
|
178a59d3a1 | ||
|
|
6a4dc84a1f | ||
|
|
9930675c93 | ||
|
|
697f6994c9 | ||
|
|
5284ba6935 | ||
|
|
55752f3d68 | ||
|
|
2a69fa8f45 | ||
|
|
7c0c584c06 | ||
|
|
f3fea02e77 | ||
|
|
47e3616b4a | ||
|
|
f8a0eefa1a | ||
|
|
6bc4102dfd | ||
|
|
2cec2a5135 | ||
|
|
8d3a9abda3 | ||
|
|
f596bf07d5 | ||
|
|
75a4614acc | ||
|
|
4fb02a2175 | ||
|
|
0b315a8364 | ||
|
|
a5a43ec7a9 | ||
|
|
f783819278 | ||
|
|
8d6ca2646d | ||
|
|
a6e48de9a3 | ||
|
|
7c7d0ba9c3 | ||
|
|
eb631e1b09 | ||
|
|
d0da83e5cb | ||
|
|
9f9c81696d | ||
|
|
76f9907288 | ||
|
|
e3050c64bc | ||
|
|
607e0468ef | ||
|
|
f7fb8a1897 | ||
|
|
9ce1e0b0bc | ||
|
|
3957c04a9b | ||
|
|
e11fec1408 | ||
|
|
a2339b7a66 |
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -37,51 +37,51 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{72B01ACA-7A1A-4F7B-ACEF-2607299CF052}</ProjectGuid>
|
||||
<RootNamespace>libpng</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -37,51 +37,51 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{73A5729C-7323-41D4-AB48-8A03C9F81603}</ProjectGuid>
|
||||
<RootNamespace>zlib</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
@@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "s_openal", "src\hardware\s_
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Srb2Win", "src\sdl\Srb2SDL-vc10.vcxproj", "{61BA7D3C-F77D-4D31-B718-1177FE482CF2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Srb2DebugServer", "Srb2DebugServer\Srb2DebugServer.vcxproj", "{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM = Debug|ARM
|
||||
@@ -115,6 +117,18 @@ Global
|
||||
{61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|Win32.Build.0 = Release|Win32
|
||||
{61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|x64.ActiveCfg = Release|x64
|
||||
{61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|x64.Build.0 = Release|x64
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Debug|ARM64.ActiveCfg = Debug|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Debug|x64.Build.0 = Debug|x64
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Release|ARM64.ActiveCfg = Release|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Release|Win32.Build.0 = Release|Win32
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Release|x64.ActiveCfg = Release|x64
|
||||
{2C3C45EC-A621-4845-AAEB-9CB82A6D32B4}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
+4
-2
@@ -1364,6 +1364,7 @@ badinput:
|
||||
//
|
||||
|
||||
static boolean serverloading = false;
|
||||
static boolean serverloadingstealth = false;
|
||||
|
||||
static void Got_NetVar(UINT8 **p, INT32 playernum)
|
||||
{
|
||||
@@ -1391,7 +1392,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
|
||||
cvar = CV_FindNetVar(netid);
|
||||
svalue = (char *)*p;
|
||||
SKIPSTRING(*p);
|
||||
stealth = READUINT8(*p);
|
||||
stealth = READUINT8(*p) || (serverloading && serverloadingstealth);
|
||||
|
||||
if (!cvar)
|
||||
{
|
||||
@@ -1448,13 +1449,14 @@ void CV_SaveNetVars(UINT8 **p, boolean isdemorecording)
|
||||
WRITEUINT16(count_p, count);
|
||||
}
|
||||
|
||||
void CV_LoadNetVars(UINT8 **p)
|
||||
void CV_LoadNetVars(UINT8 **p, boolean onlyIfChanged)
|
||||
{
|
||||
consvar_t *cvar;
|
||||
UINT16 count;
|
||||
|
||||
// prevent "invalid command received"
|
||||
serverloading = true;
|
||||
serverloadingstealth = onlyIfChanged;
|
||||
|
||||
for (cvar = consvar_vars; cvar; cvar = cvar->next)
|
||||
if (cvar->flags & CV_NETVAR)
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ void CV_SaveVariables(FILE *f);
|
||||
|
||||
// load/save gamesate (load and save option and for network join in game)
|
||||
void CV_SaveNetVars(UINT8 **p, boolean isdemorecording);
|
||||
void CV_LoadNetVars(UINT8 **p);
|
||||
void CV_LoadNetVars(UINT8 **p, boolean onlyIfChanged);
|
||||
|
||||
// reset cheat netvars after cheats is deactivated
|
||||
void CV_ResetCheatNetVars(void);
|
||||
|
||||
+2
-1
@@ -49,6 +49,7 @@ static boolean con_started = false; // console has been initialised
|
||||
boolean con_startup = false; // true at game startup, screen need refreshing
|
||||
static boolean con_forcepic = true; // at startup toggle console translucency when first off
|
||||
boolean con_recalc; // set true when screen size has changed
|
||||
boolean con_muted = false;
|
||||
|
||||
static tic_t con_tick; // console ticker for anim or blinking prompt cursor
|
||||
// con_scrollup should use time (currenttime - lasttime)..
|
||||
@@ -1163,7 +1164,7 @@ static void CON_Print(char *msg)
|
||||
INT32 controlchars = 0; // for color changing
|
||||
char color = '\x80'; // keep color across lines
|
||||
|
||||
if (msg == NULL)
|
||||
if (msg == NULL || con_muted)
|
||||
return;
|
||||
|
||||
if (*msg == '\3') // chat text, makes ding sound
|
||||
|
||||
@@ -26,6 +26,9 @@ extern boolean con_recalc;
|
||||
|
||||
extern boolean con_startup;
|
||||
|
||||
// no messages will be printed while the console is muted
|
||||
extern boolean con_muted;
|
||||
|
||||
// top clip value for view render: do not draw part of view hidden by console
|
||||
extern INT32 con_clipviewtop;
|
||||
|
||||
|
||||
+777
-19
@@ -82,6 +82,7 @@ boolean nodownload = false;
|
||||
static boolean serverrunning = false;
|
||||
INT32 serverplayer = 0;
|
||||
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
|
||||
char netDebugText[10000];
|
||||
|
||||
// Server specific vars
|
||||
UINT8 playernode[MAXPLAYERS];
|
||||
@@ -144,6 +145,27 @@ char connectedservername[MAXSERVERNAME];
|
||||
/// \todo WORK!
|
||||
boolean acceptnewnode = true;
|
||||
|
||||
// Net simulation stuff
|
||||
savestate_t gameStateBuffer[BACKUPTICS];
|
||||
boolean gameStateBufferIsValid[BACKUPTICS];
|
||||
|
||||
ticcmd_t gameTicBuffer[BACKUPTICS][MAXPLAYERS];
|
||||
ticcmd_t localTicBuffer[BACKUPTICS];
|
||||
|
||||
boolean issimulation = false;
|
||||
|
||||
boolean rewindingWow = false;
|
||||
int rewindingTarget = 0;
|
||||
|
||||
steadyplayer_t steadyplayers[MAXPLAYERS];
|
||||
|
||||
void EncodeTiccmdTime(ticcmd_t* ticcmd, tic_t time);
|
||||
tic_t DecodeTiccmdTime(const ticcmd_t* ticcmd);
|
||||
|
||||
static void AdjustSimulatedTiccmdInputs(ticcmd_t* cmds);
|
||||
|
||||
static void RunSimulations();
|
||||
|
||||
// engine
|
||||
|
||||
// Must be a power of two
|
||||
@@ -1711,7 +1733,7 @@ static void CL_LoadReceivedSavegame(void)
|
||||
automapactive = false;
|
||||
|
||||
// load a base level
|
||||
if (P_LoadNetGame())
|
||||
if (P_LoadNetGame(false))
|
||||
{
|
||||
CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)));
|
||||
if (strlen(mapheaderinfo[gamemap-1]->lvlttl) > 0)
|
||||
@@ -3357,6 +3379,8 @@ static inline void SV_GenContext(void)
|
||||
}
|
||||
}
|
||||
|
||||
void SOCK_FlushDelayBuffers(boolean);
|
||||
|
||||
//
|
||||
// D_QuitNetGame
|
||||
// Called before quitting to leave a net game
|
||||
@@ -3391,6 +3415,9 @@ void D_QuitNetGame(void)
|
||||
HSendPacket(servernode, true, 0, 0);
|
||||
}
|
||||
|
||||
// don't wait
|
||||
SOCK_FlushDelayBuffers(true);
|
||||
|
||||
D_CloseConnection();
|
||||
ClearAdminPlayers();
|
||||
|
||||
@@ -4125,7 +4152,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
||||
|
||||
scp = netbuffer->u.servercfg.varlengthinputs;
|
||||
CV_LoadPlayerNames(&scp);
|
||||
CV_LoadNetVars(&scp);
|
||||
CV_LoadNetVars(&scp, false);
|
||||
#ifdef JOININGAME
|
||||
/// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook?
|
||||
/// Shouldn't them be downloaded even at intermission time?
|
||||
@@ -4778,16 +4805,11 @@ static INT16 Consistancy(void)
|
||||
ret += P_GetRandSeed();
|
||||
|
||||
#ifdef MOBJCONSISTANCY
|
||||
if (!thinkercap.next)
|
||||
{
|
||||
DEBFILE(va("Consistancy = %u\n", ret));
|
||||
return ret;
|
||||
}
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)th;
|
||||
@@ -4891,6 +4913,7 @@ static INT16 Consistancy(void)
|
||||
ret -= mo->sprite;
|
||||
ret += mo->frame;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -4935,8 +4958,11 @@ static void CL_SendClientCmd(void)
|
||||
}
|
||||
else if (gamestate != GS_NULL)
|
||||
{
|
||||
ticcmd_t adjustedCmd = localcmds;
|
||||
packetsize = sizeof (clientcmd_pak);
|
||||
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
|
||||
//AdjustSimulatedTiccmdInputs(&adjustedCmd); // adjust ticcmds for simulations
|
||||
|
||||
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &adjustedCmd, 1);
|
||||
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
|
||||
|
||||
if (splitscreen || botingame) // Send a special packet with 2 cmd for splitscreen
|
||||
@@ -5123,6 +5149,188 @@ static void SV_SendTics(void)
|
||||
supposedtics[0] = maketic;
|
||||
}
|
||||
|
||||
void EncodeTiccmdTime(ticcmd_t* ticcmd, tic_t time)
|
||||
{
|
||||
#ifdef ENCODE_TICCMD_TIMES
|
||||
ticcmd->aiming = (ticcmd->aiming & ~TICCMD_TIMEMASK_AIMING) | (time & TICCMD_TIMEMASK_AIMING);
|
||||
ticcmd->angleturn = (ticcmd->angleturn & ~(TICCMD_TIMEMASK_ANGLE<<1)) | (((time>>TICCMD_TIMEBITS_AIMING) & TICCMD_TIMEMASK_ANGLE) << 1); // <<1 due to TICCMD_RECEIVED :/
|
||||
#endif
|
||||
}
|
||||
|
||||
tic_t DecodeTiccmdTime(const ticcmd_t* ticcmd)
|
||||
{
|
||||
#ifdef ENCODE_TICCMD_TIMES
|
||||
return (ticcmd->aiming & TICCMD_TIMEMASK_AIMING) + (((ticcmd->angleturn & (TICCMD_TIMEMASK_ANGLE<<1)) >> 1) << TICCMD_TIMEBITS_AIMING);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
angle_t FixedAngleBetween(fixed_t srcX, fixed_t srcY, fixed_t destX, fixed_t destY)
|
||||
{
|
||||
return atan2(FIXED_TO_FLOAT(srcY - destY), FIXED_TO_FLOAT(srcX - destX)) * 0xFFFFFFFF / (2.0f*3.14159f) + 0x80000000;
|
||||
}
|
||||
|
||||
fixed_t FixedLength(fixed_t x, fixed_t y, fixed_t z)
|
||||
{
|
||||
return FLOAT_TO_FIXED(sqrt(FIXED_TO_FLOAT(x) * FIXED_TO_FLOAT(x) + FIXED_TO_FLOAT(y) * FIXED_TO_FLOAT(y) + FIXED_TO_FLOAT(z) * FIXED_TO_FLOAT(z)));
|
||||
}
|
||||
|
||||
fixed_t FixedLength2(fixed_t x, fixed_t y)
|
||||
{
|
||||
return FLOAT_TO_FIXED(sqrt(FIXED_TO_FLOAT(x) * FIXED_TO_FLOAT(x) + FIXED_TO_FLOAT(y) * FIXED_TO_FLOAT(y)));
|
||||
}
|
||||
|
||||
fixed_t FixedDistance(fixed_t aX, fixed_t aY, fixed_t aZ, fixed_t bX, fixed_t bY, fixed_t bZ)
|
||||
{
|
||||
return FixedLength(bX - aX, bY - aY, bZ - aZ);
|
||||
}
|
||||
|
||||
fixed_t FixedDistance2(fixed_t aX, fixed_t aY, fixed_t bX, fixed_t bY)
|
||||
{
|
||||
return FixedLength2(bX - aX, bY - aY);
|
||||
}
|
||||
|
||||
static ticcmd_t lastCmds;
|
||||
|
||||
//Kart doesnt have FPS shootouts, so this is unneeded
|
||||
/*
|
||||
void CorrectPlayerTargeting(ticcmd_t* cmds)
|
||||
{
|
||||
if (!players[consoleplayer].mo || !cv_netsteadyplayers.value || simtic == gametic)
|
||||
return;
|
||||
|
||||
boolean hasPressedAttack = (cmds->buttons & BT_ATTACK) && (!(lastCmds.buttons & BT_ATTACK)
|
||||
|| (players[consoleplayer].currentweapon == WEP_AUTO && players[consoleplayer].rings > 0));
|
||||
|
||||
if (hasPressedAttack)
|
||||
{
|
||||
// find the most likely targeted player by measuring the angle between them
|
||||
steadyplayer_t* mostLikelyPlayer = NULL;
|
||||
INT16 smallestDifference = 0x8000;
|
||||
INT16 smallestVDifference = 0x8000;
|
||||
mobj_t* myself = players[consoleplayer].mo;
|
||||
int gameHist = max((int)(simtic-gametic) - cv_netsteadyplayers.value, 0); // current hist time that the players have been positioned at on the screen
|
||||
int simHist = simtic - gametic; // max simulated hist time
|
||||
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
steadyplayer_t* player = &steadyplayers[i];
|
||||
if (playeringame[i] && players[i].mo && i != consoleplayer)
|
||||
{
|
||||
fixed_t curX = player->histx[gameHist], curY = player->histy[gameHist], curZ = player->histz[gameHist];
|
||||
INT16 difference = (INT16)(FixedAngleBetween(myself->x, myself->y, curX, curY)>>FRACBITS) - cmds->angleturn;
|
||||
INT16 vDifference = -(INT16)(FixedAngleBetween(0, curZ, FixedDistance2(curX, curY, myself->x, myself->y), myself->z)>>FRACBITS) - cmds->aiming;
|
||||
|
||||
if (abs(difference) + abs(vDifference) < abs(smallestDifference) + abs(smallestVDifference))
|
||||
{
|
||||
smallestDifference = difference;
|
||||
smallestVDifference = vDifference;
|
||||
mostLikelyPlayer = &steadyplayers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mostLikelyPlayer != NULL)
|
||||
{
|
||||
fixed_t curX = mostLikelyPlayer->histx[gameHist], curY = mostLikelyPlayer->histy[gameHist], curZ = mostLikelyPlayer->histz[gameHist];
|
||||
fixed_t simX = mostLikelyPlayer->histx[simHist], simY = mostLikelyPlayer->histy[simHist], simZ = mostLikelyPlayer->histz[simHist];
|
||||
|
||||
if (players[consoleplayer].currentweapon == WEP_RAIL)
|
||||
{
|
||||
// rail rings are simple: offset the aim towards the player's new position compared to their old one
|
||||
// distanceRatio increases/reduces the player's accuracy based on the distance change (e.g. big close Sonic to little faraway Sonic)
|
||||
fixed_t distanceRatio = FixedDiv(FixedDistance(myself->x, myself->y, myself->z, simX, simY, simZ), FixedDistance(myself->x, myself->y, myself->z, curX, curY, curZ));
|
||||
|
||||
cmds->angleturn = (INT16)(FixedAngleBetween(myself->x, myself->y, simX, simY) >> FRACBITS) - FixedDiv(smallestDifference, distanceRatio);
|
||||
cmds->aiming = -(INT16)(FixedAngleBetween(0, simZ, FixedDistance2(simX, simY, myself->x, myself->y), myself->z) >> FRACBITS) -
|
||||
FixedDiv(smallestVDifference, distanceRatio);
|
||||
}
|
||||
else
|
||||
{
|
||||
// other rings are a bit more complex, we want to guess where the enemy will be and use that angle offset instead.
|
||||
// calculate the player's new position and try to aim towards that
|
||||
fixed_t ringSpeed = mobjinfo[MT_REDRING].speed;
|
||||
fixed_t ringRadius = -(60<<FRACBITS) * (simtic - gametic); // if the ring was fired in any direction, this is the distance it would travel currently
|
||||
fixed_t enemyX = curX, enemyY = curY, enemyZ = curZ;
|
||||
tic_t wowtic = min(gametic, simtic - cv_netsteadyplayers.value);
|
||||
fixed_t originalDistance = FixedDistance(myself->x, myself->y, myself->z, enemyX, enemyY, enemyZ);
|
||||
fixed_t currentDistance = originalDistance;
|
||||
INT16 difference = 0;
|
||||
INT16 vDifference = 0;
|
||||
|
||||
while (ringRadius < currentDistance)
|
||||
{
|
||||
// move the enemy
|
||||
if (wowtic < simtic)
|
||||
{
|
||||
enemyX = mostLikelyPlayer->histx[wowtic - gametic]; // we have a simulation for this!
|
||||
enemyY = mostLikelyPlayer->histy[wowtic - gametic];
|
||||
enemyZ = mostLikelyPlayer->histz[wowtic - gametic];
|
||||
}
|
||||
else
|
||||
{
|
||||
// we ran out of simulations so just extrapolate the player's previous position
|
||||
enemyX += mostLikelyPlayer->histx[simtic - gametic] - mostLikelyPlayer->histx[simtic - gametic - 1];
|
||||
enemyY += mostLikelyPlayer->histy[simtic - gametic] - mostLikelyPlayer->histy[simtic - gametic - 1];
|
||||
enemyZ += mostLikelyPlayer->histz[simtic - gametic] - mostLikelyPlayer->histz[simtic - gametic - 1];
|
||||
}
|
||||
|
||||
currentDistance = FixedDistance(myself->x, myself->y, myself->z, enemyX, enemyY, enemyZ);
|
||||
|
||||
// if we had no lag, would the ring have reached the enemy by now?
|
||||
if (ringRadius + (60<<FRACBITS)*(int)(simtic - gametic) >= currentDistance && difference == 0 && vDifference == 0)
|
||||
{
|
||||
// capture the player's current angle offset/accuracy here
|
||||
difference = (INT16)(FixedAngleBetween(myself->x, myself->y, enemyX, enemyY) >> FRACBITS) - cmds->angleturn;
|
||||
vDifference = -(INT16)(FixedAngleBetween(0, enemyZ,
|
||||
FixedDistance2(enemyX, enemyY, myself->x, myself->y), myself->z) >> FRACBITS) - cmds->aiming;
|
||||
}
|
||||
|
||||
ringRadius += ringSpeed;
|
||||
wowtic++;
|
||||
}
|
||||
|
||||
// aim towards it I guess lol
|
||||
fixed_t distanceRatio = FixedDiv(currentDistance, originalDistance);
|
||||
|
||||
cmds->angleturn = (INT16)(FixedAngleBetween(myself->x, myself->y, enemyX, enemyY)>>FRACBITS) - FixedDiv(difference, distanceRatio);
|
||||
cmds->aiming = -(INT16)(FixedAngleBetween(0, enemyZ, FixedDistance2(enemyX, enemyY, myself->x, myself->y), myself->z) >> FRACBITS) - FixedDiv(vDifference, distanceRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static void AdjustSimulatedTiccmdInputs(ticcmd_t* cmds)
|
||||
{
|
||||
if (server || simtic == gametic)
|
||||
return;
|
||||
|
||||
INT16 oldAngle = cmds->angleturn;
|
||||
|
||||
//Kart doesnt have match mode where this is relevant
|
||||
//if (gamestate == GS_LEVEL && cv_netsteadyplayers.value && !cv_netslingdelay.value)
|
||||
// CorrectPlayerTargeting(cmds);
|
||||
|
||||
if (cmds->angleturn != oldAngle)
|
||||
{
|
||||
// If the aiming angles are different, readjust movements to go towards the player's original intended direction
|
||||
angle_t difference = (cmds->angleturn - oldAngle) << 16;
|
||||
char oldSidemove = cmds->sidemove, oldForwardmove = cmds->forwardmove;
|
||||
|
||||
cmds->sidemove = (FixedMul((fixed_t)(oldSidemove<<FRACBITS), FINECOSINE(difference>>ANGLETOFINESHIFT))
|
||||
+ FixedMul((fixed_t)(oldForwardmove<<FRACBITS), FINESINE(difference>>ANGLETOFINESHIFT))) >> FRACBITS;
|
||||
cmds->forwardmove = (FixedMul((fixed_t)(oldSidemove<<FRACBITS), -FINESINE(difference>>ANGLETOFINESHIFT))
|
||||
+ FixedMul((fixed_t)(oldForwardmove<<FRACBITS), FINECOSINE(difference>>ANGLETOFINESHIFT))) >> FRACBITS;
|
||||
|
||||
cmds->sidemove = min(max(cmds->sidemove, -50), 50);
|
||||
cmds->forwardmove = min(max(cmds->forwardmove, -50), 50);
|
||||
}
|
||||
|
||||
lastCmds = *cmds;
|
||||
}
|
||||
|
||||
//
|
||||
// TryRunTics
|
||||
//
|
||||
@@ -5146,6 +5354,8 @@ static void Local_Maketic(INT32 realtics)
|
||||
}
|
||||
}
|
||||
|
||||
EncodeTiccmdTime(&localcmds, I_GetTime());
|
||||
|
||||
localcmds.angleturn |= TICCMD_RECEIVED;
|
||||
}
|
||||
|
||||
@@ -5213,6 +5423,41 @@ static void SV_Maketic(void)
|
||||
maketic++;
|
||||
}
|
||||
|
||||
// Overview for the new programmer and the programmer who probably isn't new, but doesn't have a clue what his code does becuase he didn't comment it ;)
|
||||
// oh dayum did I just get called out by my old comment
|
||||
/*
|
||||
gametic is always the real tic as received from the server, plus one. the simulator does not change this!
|
||||
smoothedTic is the time that we are using as a basis to cancel out jitter. this may be slightly <= gametic.
|
||||
liveTic is the real time of the game from startup, used to record our commands
|
||||
simTic is the gametic we've simulated to. if this == gametic, we haven't simulated any
|
||||
gameStateBuffer[gametic] is the game state before 'gametic' executes
|
||||
*/
|
||||
tic_t liveTic;
|
||||
|
||||
int serverJitter;
|
||||
int rttJitter;
|
||||
int estimatedRTT;
|
||||
int minRTT;
|
||||
int maxRTT;
|
||||
int maxLiveTicOffset;
|
||||
int minLiveTicOffset;
|
||||
int recommendedSimulateTics = 0; // simulateTics recommendation based on the last known 'stable' RTT (range <= 2). Used for avoiding spike lag future-past-teleports.
|
||||
int smoothingDelay;
|
||||
UINT64 saveStateBenchmark = 0;
|
||||
UINT64 loadStateBenchmark = 0;
|
||||
int netUpdateFudge; // our last net update fudge
|
||||
|
||||
tic_t lastSavestateClearedTic;
|
||||
|
||||
#define MAXOFFSETHISTORY 35
|
||||
int ticTimeOffsetHistory[MAXOFFSETHISTORY];
|
||||
|
||||
void MakeNetDebugString();
|
||||
void DetermineNetConditions();
|
||||
static void PerformDebugRewinds();
|
||||
boolean FindMatchingTics(int* liveTicOut, int* gameTicOut);
|
||||
boolean CompareTiccmd(const ticcmd_t* a, const ticcmd_t* b);
|
||||
|
||||
void TryRunTics(tic_t realtics)
|
||||
{
|
||||
// the machine has lagged but it is not so bad
|
||||
@@ -5234,6 +5479,10 @@ void TryRunTics(tic_t realtics)
|
||||
D_MapChange(-1, 0, encoremode, false, 2, false, fromlevelselect); // finish the map change
|
||||
}
|
||||
|
||||
// Get packets from the server
|
||||
unsigned long long int frame = (I_GetTimeUs() * NEWTICRATE / 1000000);
|
||||
netUpdateFudge = (I_GetTimeUs() - frame * 1000000 / NEWTICRATE) * 100 * NEWTICRATE / 1000000; // record the timefudge where the net update typically occurs
|
||||
|
||||
NetUpdate();
|
||||
|
||||
if (demo.playback)
|
||||
@@ -5269,40 +5518,549 @@ void TryRunTics(tic_t realtics)
|
||||
return;
|
||||
}
|
||||
|
||||
if (neededtic > gametic)
|
||||
// record the actual local controls
|
||||
boolean canSimulate = (gamestate == GS_LEVEL)
|
||||
&& leveltime >= TICRATE*4
|
||||
&& gametic >= TICRATE
|
||||
&& !countdown2 //SRB2Kart: No simulating after everyone has finished ... it breaks stuff
|
||||
&& (cv_simulate.value && !server) //SRB2Kart: make it impossible to sim before the start of the race
|
||||
&& !resynch_local_inprogress && gametic >= lastSavestateClearedTic + TICRATE;
|
||||
boolean recordingStates = canSimulate;
|
||||
|
||||
if (simtic > gametic && !canSimulate)
|
||||
{
|
||||
// if we can't simulate anymore, we ought to reload and invalidate the savestates
|
||||
if (gameStateBufferIsValid[gametic % BACKUPTICS])
|
||||
P_LoadGameState(&gameStateBuffer[gametic % BACKUPTICS]);
|
||||
else
|
||||
CONS_Printf("Problem: game state buffer inaccessible! (simtic %d gametic %d)\n", simtic, gametic);
|
||||
|
||||
simtic = gametic;
|
||||
CONS_Printf("Clearing savestates due to !canSim\n");
|
||||
InvalidateSavestates();
|
||||
}
|
||||
|
||||
PerformDebugRewinds();
|
||||
|
||||
liveTic = I_GetTime();
|
||||
|
||||
// record the actual local controls for this frame
|
||||
for (tic_t i = 0; i < realtics; i++)
|
||||
localTicBuffer[(liveTic - i) % BACKUPTICS] = localcmds;
|
||||
|
||||
// Run the real game as received from the server
|
||||
if (neededtic > gametic && !resynch_local_inprogress)
|
||||
{
|
||||
if (advancedemo)
|
||||
D_StartTitle();
|
||||
else
|
||||
// run the count * tics
|
||||
{
|
||||
// Load the real state if it exists
|
||||
if (simtic != gametic && gameStateBufferIsValid[gametic % BACKUPTICS])
|
||||
{
|
||||
P_LoadGameState(&gameStateBuffer[gametic % BACKUPTICS]);
|
||||
|
||||
if (Consistancy() != consistancy[gametic%BACKUPTICS])
|
||||
CONS_Printf("oops, consistency error, even I got that one!\n");
|
||||
}
|
||||
else if (simtic != gametic && !gameStateBufferIsValid[gametic % BACKUPTICS])
|
||||
CONS_Printf("Problem: game state buffer inaccessible but a simulation happened!!\n");
|
||||
|
||||
// run the tics up to the real game tic
|
||||
while (neededtic > gametic)
|
||||
{
|
||||
DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
|
||||
|
||||
targetsimtic = gametic + 1;
|
||||
|
||||
G_Ticker((gametic % NEWTICRATERATIO) == 0);
|
||||
ExtraDataTicker();
|
||||
gametic++;
|
||||
simtic = gametic; // game state is reset, we wanna resimulate from here
|
||||
|
||||
consistancy[gametic%BACKUPTICS] = Consistancy();
|
||||
|
||||
if (recordingStates)
|
||||
{
|
||||
// store this real state
|
||||
P_SaveGameState(&gameStateBuffer[gametic % BACKUPTICS]);
|
||||
|
||||
gameStateBufferIsValid[gametic % BACKUPTICS] = true;
|
||||
|
||||
// store the ticcmds used during this game tic
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
gameTicBuffer[gametic % BACKUPTICS][i] = netcmds[(gametic - 1) % BACKUPTICS][i];
|
||||
}
|
||||
|
||||
// Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame.
|
||||
if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth out the game state according to the network
|
||||
// \todo rather than re-loading an older state, we could just buffer the tics instead of running them above
|
||||
if (cv_netsmoothing.value)
|
||||
{
|
||||
smoothedTic = liveTic - maxLiveTicOffset - 1;
|
||||
|
||||
if (gameStateBufferIsValid[(smoothedTic + BACKUPTICS) % BACKUPTICS] && smoothedTic != gametic)
|
||||
P_LoadGameState(&gameStateBuffer[(smoothedTic + BACKUPTICS) % BACKUPTICS]);
|
||||
|
||||
simtic = smoothedTic;
|
||||
}
|
||||
else
|
||||
smoothedTic = gametic;
|
||||
|
||||
// collect net condition data
|
||||
DetermineNetConditions();
|
||||
|
||||
// Simulate the game locally
|
||||
if (canSimulate)
|
||||
RunSimulations();
|
||||
|
||||
// we're gonna need more debugs...
|
||||
MakeNetDebugString();
|
||||
}
|
||||
|
||||
UINT64 simStartTime;
|
||||
UINT64 simEndTime;
|
||||
|
||||
static void RunSimulations()
|
||||
{
|
||||
if (!gameStateBufferIsValid[gametic % BACKUPTICS])
|
||||
return; // do not simulate if we cannot guarantee a recovery
|
||||
|
||||
static int lastsimtic = 0;
|
||||
|
||||
int tastyFudge = 0;
|
||||
// hack: don't treat duplicate tics as extra round-trip time
|
||||
for (int j = 1; j < 3; j++)
|
||||
{
|
||||
hu_stopped = true;
|
||||
if (CompareTiccmd(&gameTicBuffer[gametic % BACKUPTICS][consoleplayer], &gameTicBuffer[(gametic - j) % BACKUPTICS][consoleplayer]))
|
||||
tastyFudge++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int numDesiredSimulateTics = min(recommendedSimulateTics, cv_simulatetics.value);
|
||||
int nextTargetSimTic = min(min(gametic + estimatedRTT - tastyFudge, smoothedTic + numDesiredSimulateTics), simtic + MAXSIMULATIONS);
|
||||
|
||||
if (nextTargetSimTic >= 0)
|
||||
targetsimtic = nextTargetSimTic;
|
||||
|
||||
int numToSimulate = targetsimtic - simtic;
|
||||
|
||||
if (numToSimulate > 0) // only touch objects if we're definitely going to simulate and rewind!
|
||||
{
|
||||
// record steadyplayers' real game position and their simulated position
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo && i != consoleplayer)
|
||||
{
|
||||
if (simtic == smoothedTic) // this is their real position
|
||||
{
|
||||
steadyplayers[i].histx[0] = players[i].mo->x;
|
||||
steadyplayers[i].histy[0] = players[i].mo->y;
|
||||
steadyplayers[i].histz[0] = players[i].mo->z;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_UnsetThingPosition(players[i].mo);
|
||||
// restore the players' simulated position before simulating more
|
||||
players[i].mo->x = steadyplayers[i].histx[simtic - smoothedTic];
|
||||
players[i].mo->y = steadyplayers[i].histy[simtic - smoothedTic];
|
||||
players[i].mo->z = steadyplayers[i].histz[simtic - smoothedTic];
|
||||
P_SetThingPosition(players[i].mo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// and cull distant thinkers if enabled
|
||||
if (cv_simulateculldistance.value > 0)
|
||||
{
|
||||
thinker_t* current;
|
||||
fixed_t minDistance = cv_simulateculldistance.value << FRACBITS;
|
||||
mobj_t* playerMos[MAXPLAYERS];
|
||||
int numPlayers = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo)
|
||||
{
|
||||
playerMos[numPlayers++] = players[i].mo;
|
||||
}
|
||||
}
|
||||
|
||||
for (current = thlist[THINK_MOBJ].next; current != &thlist[THINK_MOBJ]; current = current->next)
|
||||
{
|
||||
for (i = 0; i < numPlayers; i++)
|
||||
{
|
||||
if (P_AproxDistance(playerMos[i]->x - ((mobj_t*)current)->x, playerMos[i]->y - ((mobj_t*)current)->y) < minDistance)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == numPlayers)
|
||||
{
|
||||
// cull this mobj
|
||||
((mobj_t*)current)->isculled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simulate the rest o da future
|
||||
issimulation = true;
|
||||
con_muted = true;
|
||||
|
||||
simStartTime = I_GetTimeUs();
|
||||
|
||||
for (int i = 0; i < numToSimulate; i++)
|
||||
{
|
||||
// control other players (just use their previous control for now)
|
||||
for (int j = 0; j < MAXPLAYERS; j++)
|
||||
{
|
||||
if (playeringame[j] && j != consoleplayer)
|
||||
netcmds[gametic % BACKUPTICS][j] = gameTicBuffer[(min(simtic + 1, gametic) + BACKUPTICS) % BACKUPTICS][j];
|
||||
}
|
||||
|
||||
// control the local player
|
||||
if (simtic + i < gametic) // game is smoothed, take tics from the _actual_ received state
|
||||
netcmds[gametic % BACKUPTICS][consoleplayer] = gameTicBuffer[(simtic + 1) % BACKUPTICS][consoleplayer];
|
||||
else
|
||||
netcmds[gametic % BACKUPTICS][consoleplayer] = localTicBuffer[(liveTic - estimatedRTT + i + 1 + BACKUPTICS) % BACKUPTICS];
|
||||
|
||||
G_Ticker(true); // tic a bunch of times lol see what happens lolol
|
||||
simtic++;
|
||||
|
||||
// record simulated players' positions
|
||||
for (int j = 0; j < MAXPLAYERS; j++)
|
||||
{
|
||||
if (playeringame[j] && players[j].mo && j != consoleplayer)
|
||||
{
|
||||
// Update steadyplayers' simulated positions
|
||||
steadyplayers[j].histx[simtic - smoothedTic] = players[j].mo->x;
|
||||
steadyplayers[j].histy[simtic - smoothedTic] = players[j].mo->y;
|
||||
steadyplayers[j].histz[simtic - smoothedTic] = players[j].mo->z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issimulation = false;
|
||||
con_muted = false;
|
||||
|
||||
// Finalise steadyplayers
|
||||
if (numToSimulate > 0)
|
||||
{
|
||||
int histIndex = max((int)(simtic - smoothedTic) - cv_netsteadyplayers.value, 0); // up to cv_netsteadyplayers.value behind the simulation
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo && i != consoleplayer && !players[i].spectator)
|
||||
{
|
||||
// Set the player's positions to the preferred simulation index (or perhaps just their original position)
|
||||
// and store it in simx/simy/simz too for trails
|
||||
P_UnsetThingPosition(players[i].mo);
|
||||
players[i].mo->x = steadyplayers[i].histx[histIndex];
|
||||
players[i].mo->y = steadyplayers[i].histy[histIndex];
|
||||
players[i].mo->z = steadyplayers[i].histz[histIndex];
|
||||
P_SetThingPosition(players[i].mo);
|
||||
|
||||
// fill any holes in the simulation history (due to frame skips)
|
||||
for (int j = (int)max(lastsimtic + 1, (int)simtic - 5); j <= (int)simtic; j++)
|
||||
{
|
||||
steadyplayers[i].simx[j % BACKUPTICS] = steadyplayers[i].histx[histIndex];
|
||||
steadyplayers[i].simy[j % BACKUPTICS] = steadyplayers[i].histy[histIndex];
|
||||
steadyplayers[i].simz[j % BACKUPTICS] = steadyplayers[i].histz[histIndex];
|
||||
}
|
||||
|
||||
// Generate trails
|
||||
if (cv_nettrails.value)
|
||||
{
|
||||
int trailLifetime = cv_nettrails.value;
|
||||
|
||||
for (int s = 0; s < trailLifetime; s++)
|
||||
{
|
||||
// If there is a big discrepency between the player's current position and their last one, spawn a trail showing their movements
|
||||
fixed_t prevx = steadyplayers[i].simx[(simtic - s - 1) % BACKUPTICS], prevy = steadyplayers[i].simy[(simtic - s - 1) % BACKUPTICS],
|
||||
prevz = steadyplayers[i].simz[(simtic - s - 1) % BACKUPTICS];
|
||||
fixed_t curx = steadyplayers[i].simx[(simtic - s) % BACKUPTICS], cury = steadyplayers[i].simy[(simtic - s) % BACKUPTICS],
|
||||
curz = steadyplayers[i].simz[(simtic - s) % BACKUPTICS];
|
||||
fixed_t distance = max(abs(curx - prevx), max(abs(cury - prevy), abs(curz - prevz)));
|
||||
fixed_t stepDistance = 60 << FRACBITS; // distance between trail steps
|
||||
fixed_t activationDistance = 60 << FRACBITS; // distance between trail steps
|
||||
|
||||
// If player is changing direction quickly in a net simulation, create a ghost trail
|
||||
if (distance > activationDistance)
|
||||
{
|
||||
fixed_t numSteps = FixedDiv(distance, stepDistance) & ~FRACMASK;
|
||||
fixed_t currentStep; // between 0 and 1
|
||||
fixed_t step = FixedDiv(1 << FRACBITS, numSteps + 1);
|
||||
|
||||
for (currentStep = step; currentStep < (1 << FRACBITS); currentStep += step)
|
||||
{
|
||||
mobj_t* ghost = P_SpawnGhostMobj(players[i].mo);
|
||||
|
||||
ghost->x = prevx + FixedMul(curx - prevx, currentStep);
|
||||
ghost->y = prevy + FixedMul(cury - prevy, currentStep);
|
||||
ghost->z = prevz + FixedMul(curz - prevz, currentStep);
|
||||
ghost->frame = (ghost->frame & FF_TRANSMASK) | ((6 - s) << FF_TRANSSHIFT);
|
||||
ghost->fuse = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move steadyplayer shields and signs
|
||||
if (cv_netsteadyplayers.value)
|
||||
{
|
||||
mobj_t* mobj;
|
||||
player_t* redflagplayer = NULL;
|
||||
player_t* blueflagplayer = NULL;
|
||||
|
||||
#define ADJUSTPOSITION(obj, player) do { \
|
||||
P_UnsetThingPosition(obj); \
|
||||
obj->x += steadyplayers[player].histx[histIndex] - steadyplayers[player].histx[simtic - gametic]; \
|
||||
obj->y += steadyplayers[player].histy[histIndex] - steadyplayers[player].histy[simtic - gametic]; \
|
||||
obj->z += steadyplayers[player].histz[histIndex] - steadyplayers[player].histz[simtic - gametic]; \
|
||||
P_SetThingPosition(obj); \
|
||||
} while(0)
|
||||
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
if (players[i].gotflag & GF_REDFLAG)
|
||||
redflagplayer = &players[i];
|
||||
if (players[i].gotflag & GF_BLUEFLAG)
|
||||
blueflagplayer = &players[i];
|
||||
}
|
||||
|
||||
// if (players[i].followmobj)
|
||||
// ADJUSTPOSITION(players[i].followmobj, i);
|
||||
}
|
||||
|
||||
for (mobj = (mobj_t*)thlist[THINK_MOBJ].next; mobj != (mobj_t*)&thlist[THINK_MOBJ]; mobj = (mobj_t*)mobj->thinker.next)
|
||||
{
|
||||
// if (mobj->flags2 & MF2_SHIELD && mobj->target != NULL && mobj->target->player != NULL && mobj->target != players[consoleplayer].mo)
|
||||
// ADJUSTPOSITION(mobj, mobj->target->player - players);
|
||||
// else if (mobj->type == MT_BLUEFLAG && blueflagplayer)
|
||||
// ADJUSTPOSITION(mobj, blueflagplayer - players);
|
||||
// else if (mobj->type == MT_REDFLAG && redflagplayer)
|
||||
// ADJUSTPOSITION(mobj, redflagplayer - players);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simEndTime = I_GetTimeUs();
|
||||
|
||||
lastsimtic = simtic;
|
||||
rendergametic = gametic;
|
||||
}
|
||||
|
||||
void InvalidateSavestates()
|
||||
{
|
||||
if (simtic > gametic)
|
||||
CONS_Printf("Warning: Savestates were invalidated during a simulation!!\n");
|
||||
|
||||
for (int i = 0; i < MAXSIMULATIONS; i++)
|
||||
gameStateBufferIsValid[i] = false;
|
||||
|
||||
lastSavestateClearedTic = gametic;
|
||||
}
|
||||
|
||||
int rttBuffer[70];
|
||||
int rttBufferIndex = 0;
|
||||
int rttBufferMax = 70;
|
||||
|
||||
void DetermineNetConditions()
|
||||
{
|
||||
// Refresh the time offset between real time and server time
|
||||
minLiveTicOffset = INT_MAX;
|
||||
maxLiveTicOffset = INT_MIN;
|
||||
|
||||
ticTimeOffsetHistory[liveTic % MAXOFFSETHISTORY] = (int)liveTic - (int)gametic;
|
||||
|
||||
// Find the net jitter based on the last 20 frames
|
||||
for (int i = 0; i < MAXOFFSETHISTORY; i++)
|
||||
{
|
||||
minLiveTicOffset = min(minLiveTicOffset, ticTimeOffsetHistory[i]);
|
||||
maxLiveTicOffset = max(maxLiveTicOffset, ticTimeOffsetHistory[i]);
|
||||
}
|
||||
|
||||
serverJitter = min(5, maxLiveTicOffset - minLiveTicOffset);
|
||||
|
||||
// Estimate the RTT (once used awkward tic matching stuff, now uses sneaky encoded angles)
|
||||
#ifndef ENCODE_TICCMD_TIMES
|
||||
if (!(gametic % 35))
|
||||
{
|
||||
int matchingLiveTic, matchingGameTic;
|
||||
if (FindMatchingTics(&matchingLiveTic, &matchingGameTic) && matchingLiveTic - matchingGameTic < BACKUPTICS - 2)
|
||||
{
|
||||
estimatedRTT = matchingLiveTic - matchingGameTic;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int j = 1; j < TICCMD_TIME_SIZE - 1; j++)
|
||||
{
|
||||
if (CompareTiccmd(&gameTicBuffer[gametic % BACKUPTICS][consoleplayer], &localTicBuffer[(liveTic - j + BACKUPTICS) % BACKUPTICS]))
|
||||
{
|
||||
estimatedRTT = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// estimate RTT jitter
|
||||
minRTT = INT_MAX;
|
||||
maxRTT = INT_MIN;
|
||||
|
||||
rttBuffer[rttBufferIndex] = estimatedRTT;
|
||||
rttBufferIndex = (rttBufferIndex + 1) % rttBufferMax;
|
||||
|
||||
for (int i = 0; i < rttBufferMax; i++)
|
||||
{
|
||||
minRTT = min(minRTT, rttBuffer[i]);
|
||||
maxRTT = max(maxRTT, rttBuffer[i]);
|
||||
}
|
||||
|
||||
rttJitter = maxRTT - minRTT;
|
||||
|
||||
// stable server conditions? (but not just a big lag spike?)
|
||||
if (rttJitter <= 2 && maxRTT < BACKUPTICS - 1)
|
||||
{
|
||||
// we know roughly how much we should simulate then!
|
||||
recommendedSimulateTics = maxRTT + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void PerformDebugRewinds()
|
||||
{
|
||||
if (rewindingWow && rewindingTarget > 0 && gameStateBufferIsValid[(gametic - rewindingTarget) % BACKUPTICS])
|
||||
{
|
||||
P_LoadGameState(&gameStateBuffer[(gametic - rewindingTarget) % BACKUPTICS]);
|
||||
|
||||
for (int i = 0; i < rewindingTarget; i++)
|
||||
{
|
||||
netcmds[gametic%BACKUPTICS][consoleplayer] = gameTicBuffer[(gametic - rewindingTarget + i) % BACKUPTICS][consoleplayer];
|
||||
G_Ticker(true);
|
||||
}
|
||||
|
||||
/* Ping Update except better:
|
||||
We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out.
|
||||
If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave.
|
||||
rewindingWow = false;
|
||||
}
|
||||
|
||||
Why do we do that? Well, I'm a person with unfortunately sometimes unstable internet and happen to keep getting kicked very unconveniently for very short high spikes. (700+ ms)
|
||||
Because my spikes are so high, the average ping is exponentially higher too (700s really add up...!) which leads me to getting kicked for a short burst of spiking.
|
||||
With this change here, this doesn't happen anymore as it checks if my ping has been CONSISTENTLY bad for long enough before killing me.
|
||||
if (gameStateBufferIsValid[gametic % BACKUPTICS] && cv_debugsimulaterewind.value > 0 && players[consoleplayer].mo) {
|
||||
short consis = Consistancy();
|
||||
|
||||
for (int i = 0; i < cv_debugsimulaterewind.value; i++)
|
||||
G_Ticker(true);
|
||||
|
||||
P_LoadGameState(&gameStateBuffer[gametic % BACKUPTICS]);
|
||||
|
||||
if (Consistancy() != consis)
|
||||
CONS_Printf("General consistency error...\n");
|
||||
}
|
||||
}
|
||||
|
||||
extern UINT32 saveTimes[12];
|
||||
extern UINT32 loadTimes[12];
|
||||
|
||||
void MakeNetDebugString()
|
||||
{
|
||||
netDebugText[0] = 0;
|
||||
|
||||
for (int i = min(maxRTT + 4, 16); i >= 0; i--)
|
||||
{
|
||||
if (simtic - (tic_t)i <= gametic) {
|
||||
char missed[2] = "+";
|
||||
|
||||
if (DecodeTiccmdTime(&(gameTicBuffer[(simtic - i) % BACKUPTICS][consoleplayer])) !=
|
||||
(DecodeTiccmdTime(&(gameTicBuffer[(simtic - i - 1) % BACKUPTICS][consoleplayer])) + 1) % TICCMD_TIME_SIZE)
|
||||
missed[0] = 'X'; // missed tic
|
||||
|
||||
// show tics and matches
|
||||
sprintf(&netDebugText[strlen(netDebugText)],
|
||||
"%s srv: %02d%slcl: %02d%s\n",
|
||||
missed,
|
||||
DecodeTiccmdTime(&(gameTicBuffer[(simtic - i) % BACKUPTICS][consoleplayer])),
|
||||
(i == gametic ? "<" : " "),
|
||||
(liveTic - i) & (TICCMD_TIME_SIZE-1),
|
||||
(i == estimatedRTT ? "<" : " "));
|
||||
}
|
||||
else {
|
||||
sprintf(&netDebugText[strlen(netDebugText)],
|
||||
"____ %02d_lcl: %02d%s\n",
|
||||
0,
|
||||
//(i == matchingGameTic ? "<" : " "),
|
||||
DecodeTiccmdTime(&localTicBuffer[(liveTic - i) % BACKUPTICS]),
|
||||
(i == estimatedRTT ? "<" : " "));
|
||||
}
|
||||
}
|
||||
|
||||
static tic_t lastSim = 0;
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\n\nJitter: %d", serverJitter);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nEstRTT: %d", estimatedRTT);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nGame: %d", gametic);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nSim: %d", simtic);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nSim-Game: %d", simtic - gametic);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nSimDelta: %d", simtic - lastSim);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nLive: %d", liveTic);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nTime save/load: %.2f/%.2f", (float)saveStateBenchmark/1000.0f, (float)loadStateBenchmark/1000.0f);
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nTotal +ms: %d", (int)((simEndTime - simStartTime + saveStateBenchmark + loadStateBenchmark) / 1000));
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nseed: %d", P_GetRandSeed());
|
||||
lastSim = simtic;
|
||||
|
||||
unsigned int rtts[20] = { 0 };
|
||||
for (int i = 0; i < rttBufferMax; i++)
|
||||
{
|
||||
if (rttBuffer[i] < 20)
|
||||
rtts[rttBuffer[i]]++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
if (rtts[i] > 0)
|
||||
sprintf(&netDebugText[strlen(netDebugText)], "\nRTT %i: %i", i, rtts[i] * 100 / rttBufferMax);
|
||||
}
|
||||
}
|
||||
|
||||
// startTic and endTics are tics going back in time from the current liveTic
|
||||
boolean FindMatchingTics(int* liveTicOut, int* gameTicOut) {
|
||||
int latestGameTic = INT_MAX;
|
||||
|
||||
for (int i = 0; i < BACKUPTICS; i++) {
|
||||
// display estimated matching frames
|
||||
for (int j = 0; j < BACKUPTICS - 1; j++) {
|
||||
// if this and the previous tic were different (interesting delta), and this matches some point in the tic buffer, say wow and use that towel
|
||||
if (!CompareTiccmd(&localTicBuffer[(liveTic - i + BACKUPTICS) % BACKUPTICS], &localTicBuffer[(liveTic - i - 1 + BACKUPTICS) % BACKUPTICS])
|
||||
&& CompareTiccmd(&localTicBuffer[(liveTic - i + BACKUPTICS) % BACKUPTICS], &gameTicBuffer[(smoothedTic - j + BACKUPTICS) % BACKUPTICS][consoleplayer])
|
||||
&& CompareTiccmd(&localTicBuffer[(liveTic - i - 1 + BACKUPTICS) % BACKUPTICS], &gameTicBuffer[(smoothedTic - j - 1 + BACKUPTICS) % BACKUPTICS][consoleplayer]))
|
||||
{
|
||||
if (j < latestGameTic && i >= j) { // i >= j: uses >= because gameTicBuffer[gametic] is actually the controls used in the -last- tic
|
||||
latestGameTic = j;
|
||||
*liveTicOut = i;
|
||||
*gameTicOut = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (latestGameTic != INT_MAX);
|
||||
}
|
||||
|
||||
boolean CompareTiccmd(const ticcmd_t* a, const ticcmd_t* b)
|
||||
{
|
||||
return a->aiming == b->aiming && (a->angleturn&~TICCMD_RECEIVED) == (b->angleturn&~TICCMD_RECEIVED) && a->buttons == b->buttons
|
||||
&& a->forwardmove == b->forwardmove && a->sidemove == b->sidemove;
|
||||
}
|
||||
|
||||
/*
|
||||
Ping Update except better:
|
||||
We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out.
|
||||
If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave.
|
||||
*/
|
||||
|
||||
static INT32 pingtimeout[MAXPLAYERS];
|
||||
|
||||
@@ -38,6 +38,18 @@
|
||||
// Networking and tick handling related.
|
||||
#define BACKUPTICS 32
|
||||
#define MAXTEXTCMD 256
|
||||
|
||||
// How many time bits to encode into ticcmds (aiming and angle components, respectively)
|
||||
#define ENCODE_TICCMD_TIMES
|
||||
#define TICCMD_TIMEBITS_AIMING 3
|
||||
#define TICCMD_TIMEBITS_ANGLE 2
|
||||
#define TICCMD_TIMEMASK_AIMING (~(0xFFFFFFFF<<TICCMD_TIMEBITS_AIMING))
|
||||
#define TICCMD_TIMEMASK_ANGLE (~(0xFFFFFFFF<<TICCMD_TIMEBITS_ANGLE))
|
||||
#define TICCMD_TIME_SIZE (1<<(TICCMD_TIMEBITS_AIMING+TICCMD_TIMEBITS_ANGLE))
|
||||
|
||||
// Maximum number of client-side simulations allowed. A simulation is a version of the game state extrapolated some frames ahead to cancel out network latency
|
||||
#define MAXSIMULATIONS (TICCMD_TIME_SIZE-1)
|
||||
|
||||
//
|
||||
// Packet structure
|
||||
//
|
||||
@@ -521,6 +533,17 @@ typedef enum
|
||||
|
||||
} kickreason_t;
|
||||
|
||||
// Player movement histories for simulated gamestates
|
||||
typedef struct
|
||||
{
|
||||
// stores historical simulated positions where 0 is the real game position and simtic-gametic is the latest simulated position
|
||||
fixed_t histx[MAXSIMULATIONS + 1], histy[MAXSIMULATIONS + 1], histz[MAXSIMULATIONS + 1];
|
||||
|
||||
// stores the final simulated position for each simulated gametic
|
||||
fixed_t simx[BACKUPTICS], simy[BACKUPTICS], simz[BACKUPTICS];
|
||||
|
||||
} steadyplayer_t;
|
||||
|
||||
extern boolean server;
|
||||
#define client (!server)
|
||||
extern boolean dedicated; // For dedicated server
|
||||
@@ -529,6 +552,9 @@ extern boolean acceptnewnode;
|
||||
extern SINT8 servernode;
|
||||
extern char connectedservername[MAXSERVERNAME];
|
||||
|
||||
extern boolean issimulation; // whether the currently executed tic is part of a simulated gamestate
|
||||
extern steadyplayer_t steadyplayers[MAXPLAYERS];
|
||||
|
||||
void Command_Ping_f(void);
|
||||
extern tic_t connectiontimeout;
|
||||
extern tic_t jointimeout;
|
||||
@@ -580,6 +606,9 @@ void D_QuitNetGame(void);
|
||||
//? How many ticks to run?
|
||||
void TryRunTics(tic_t realtic);
|
||||
|
||||
// Invalidates save states used in simulations
|
||||
void InvalidateSavestates();
|
||||
|
||||
// extra data for lmps
|
||||
// these functions scare me. they contain magic.
|
||||
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
|
||||
|
||||
@@ -153,6 +153,8 @@ char srb2path[256] = ".";
|
||||
boolean usehome = true;
|
||||
const char *pandf = "%s" PATHSEP "%s";
|
||||
|
||||
extern char netDebugText[10000];
|
||||
|
||||
//
|
||||
// EVENT HANDLING
|
||||
//
|
||||
@@ -591,6 +593,27 @@ static void D_Display(void)
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s);
|
||||
}
|
||||
|
||||
if (cv_netsimstat.value && netDebugText[0] != 0)
|
||||
{
|
||||
const char* str = netDebugText;
|
||||
int y = 0;
|
||||
|
||||
while (str != NULL)
|
||||
{
|
||||
char temp[1024];
|
||||
const char* nextStr = strstr(str + 1, "\n");
|
||||
int len = nextStr ? nextStr - str : strlen(str);
|
||||
|
||||
memcpy(temp, str, len);
|
||||
temp[len] = 0;
|
||||
|
||||
V_DrawRightAlignedSmallString(BASEVIDWIDTH, y, V_YELLOWMAP, temp);
|
||||
|
||||
y += 5;
|
||||
str = nextStr ? nextStr + 1 : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cv_shittyscreen.value)
|
||||
V_DrawVhsEffect(cv_shittyscreen.value == 2);
|
||||
|
||||
|
||||
@@ -1452,6 +1452,9 @@ void D_CloseConnection(void)
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
Net_CloseConnection(i|FORCECLOSE);
|
||||
|
||||
// don't delay this!
|
||||
SOCK_FlushDelayBuffers(true);
|
||||
|
||||
InitAck();
|
||||
|
||||
if (I_NetCloseSocket)
|
||||
|
||||
+239
-13
@@ -116,6 +116,11 @@ static void KartSpeed_OnChange(void);
|
||||
static void KartEncore_OnChange(void);
|
||||
static void KartComeback_OnChange(void);
|
||||
static void KartEliminateLast_OnChange(void);
|
||||
static void Command_Savestate(void);
|
||||
static void Command_Loadstate(void);
|
||||
static void Command_Rewind(void);
|
||||
static void Command_Saveloadtest(void);
|
||||
static void Command_Autotimefudge(void);
|
||||
|
||||
#ifdef NETGAME_DEVMODE
|
||||
static void Fishcake_OnChange(void);
|
||||
@@ -432,6 +437,7 @@ consvar_t cv_allowexitlevel = {"allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL
|
||||
|
||||
consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_netsimstat = { "netsimstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
|
||||
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_nettimeout = {"nettimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
@@ -468,6 +474,44 @@ boolean forceresetplayers = false;
|
||||
boolean deferencoremode = false;
|
||||
UINT8 splitscreen = 0;
|
||||
boolean circuitmap = true; // SRB2kart
|
||||
|
||||
consvar_t cv_simulate = { "simulate", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t simulateTics_cons_t[] = { {0, "MIN"}, {MAXSIMULATIONS - 1, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_simulatetics = { "simtics", "MAX", 0, simulateTics_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t simulateculldistance_cons_t[] = { {0, "MIN"}, {10000, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_simulateculldistance = { "simcull", "MIN", 0, simulateculldistance_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t netsteadyplayers_cons_t[] = { {0, "MIN"}, {MAXSIMULATIONS - 1, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_netsteadyplayers = { "simsteadyplayers", "0", 0, netsteadyplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t nettrails_cons_t[] = { {0, "MIN"}, {5, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_nettrails = { "simtrails", "5", 0, nettrails_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
consvar_t cv_netslingdelay = { "simslingdelay", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t netdelay_cons_t[] = { {0, "MIN"}, {250, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_netdelay = { "netdelay", "0", 0, netdelay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t netjitter_cons_t[] = { {0, "MIN"}, {5, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_netjitter = { "netjitter", "0", 0, netdelay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
consvar_t cv_netsmoothing = { "netsmoothing", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
consvar_t cv_netspikes = { "netspikes", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t debugsimulaterewind_cons_t[] = { {0, "MIN"}, {BACKUPTICS - 1, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_debugsimulaterewind = { "debugsimulaterewind", "0", 0, debugsimulaterewind_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
static CV_PossibleValue_t timefudge_cons_t[] = { {0, "MIN"}, {100, "MAX"}, {0, NULL} };
|
||||
consvar_t cv_timefudge = { "timefudge", "0", 0, timefudge_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
|
||||
|
||||
char timedemo_name[256];
|
||||
boolean timedemo_csv;
|
||||
char timedemo_csv_id[256];
|
||||
boolean timedemo_quit;
|
||||
|
||||
INT32 adminplayers[MAXPLAYERS];
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename net text commands
|
||||
@@ -611,6 +655,26 @@ void D_RegisterServerCommands(void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// experimental load/save game state for possible rewinding in netgames
|
||||
COM_AddCommand("savestate", Command_Savestate);
|
||||
COM_AddCommand("loadstate", Command_Loadstate);
|
||||
COM_AddCommand("rewind", Command_Rewind);
|
||||
COM_AddCommand("saveloadtest", Command_Saveloadtest);
|
||||
COM_AddCommand("autotimefudge", Command_Autotimefudge);
|
||||
|
||||
CV_RegisterVar(&cv_simulate);
|
||||
CV_RegisterVar(&cv_simulatetics);
|
||||
CV_RegisterVar(&cv_simulateculldistance);
|
||||
CV_RegisterVar(&cv_netdelay);
|
||||
CV_RegisterVar(&cv_netjitter);
|
||||
CV_RegisterVar(&cv_netsmoothing);
|
||||
CV_RegisterVar(&cv_netspikes);
|
||||
CV_RegisterVar(&cv_netsteadyplayers);
|
||||
CV_RegisterVar(&cv_debugsimulaterewind);
|
||||
CV_RegisterVar(&cv_timefudge);
|
||||
CV_RegisterVar(&cv_nettrails);
|
||||
CV_RegisterVar(&cv_netslingdelay);
|
||||
|
||||
// for master server connection
|
||||
AddMServCommands();
|
||||
|
||||
@@ -712,6 +776,151 @@ void D_RegisterServerCommands(void)
|
||||
CV_RegisterVar(&cv_dummyconsvar);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Louis' nasty test bed
|
||||
// =========================================================================
|
||||
#include "p_saveg.h"
|
||||
UINT8* savedState = NULL;
|
||||
|
||||
static void Command_Savestate(void)
|
||||
{
|
||||
CONS_Printf("Saving game state!\n");
|
||||
|
||||
savedState = (UINT8 *)malloc(1024*768 /* lol, 1998 screen resolution */);
|
||||
if (!savedState)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Wtf this machine is weak\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Leave room for the uncompressed length.
|
||||
save_p = savedState;
|
||||
|
||||
P_SaveNetGame();
|
||||
}
|
||||
|
||||
static void Command_Loadstate(void)
|
||||
{
|
||||
save_p = savedState;
|
||||
|
||||
P_LoadNetGame(true);
|
||||
|
||||
// try and execute 10 ticcmds...
|
||||
|
||||
CONS_Printf("Loading game state!\n");
|
||||
}
|
||||
|
||||
extern boolean rewindingWow;
|
||||
extern int rewindingTarget;
|
||||
extern boolean memleak;
|
||||
|
||||
static void Command_Rewind(void)
|
||||
{
|
||||
rewindingWow = true;
|
||||
rewindingTarget = COM_Argc() > 1 ? atoi(COM_Argv(1)) : 0;
|
||||
}
|
||||
|
||||
void MemShow() {
|
||||
Z_CheckHeap(-1);
|
||||
CONS_Printf("\x82%s", M_GetText("Memory Info\n"));
|
||||
CONS_Printf(M_GetText("Total heap used : %7s KB\n"), sizeu1(Z_TagsUsage(0, INT32_MAX)>>10));
|
||||
CONS_Printf(M_GetText("Static : %7s KB\n"), sizeu1(Z_TagUsage(PU_STATIC) >> 10));
|
||||
CONS_Printf(M_GetText("Static (sound) : %7s KB\n"), sizeu1(Z_TagUsage(PU_SOUND) >> 10));
|
||||
CONS_Printf(M_GetText("Static (music) : %7s KB\n"), sizeu1(Z_TagUsage(PU_MUSIC) >> 10));
|
||||
CONS_Printf(M_GetText("Locked cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_CACHE) >> 10));
|
||||
CONS_Printf(M_GetText("Level : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVEL) >> 10));
|
||||
CONS_Printf(M_GetText("Special thinker : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVSPEC) >> 10));
|
||||
CONS_Printf(M_GetText("All purgable : %7s KB\n"),
|
||||
sizeu1(Z_TagsUsage(PU_PURGELEVEL, INT32_MAX) >> 10));
|
||||
}
|
||||
|
||||
static savestate_t save;
|
||||
static void Command_Saveloadtest(void)
|
||||
{
|
||||
memleak = true;
|
||||
|
||||
MemShow();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
P_SaveGameState(&save);
|
||||
P_LoadGameState(&save);
|
||||
}
|
||||
|
||||
MemShow();
|
||||
|
||||
memleak = false;
|
||||
}
|
||||
|
||||
#include "i_net.h"
|
||||
|
||||
extern int netUpdateFudge;
|
||||
static void Command_Autotimefudge(void)
|
||||
{
|
||||
UINT64 startTime = I_GetTimeUs();
|
||||
static UINT64 packetTimeFudge[512];
|
||||
int numReceivedPackets = 0;
|
||||
int numSampleTics = 14;
|
||||
int i;
|
||||
|
||||
if (server)
|
||||
{
|
||||
if (netgame)
|
||||
{
|
||||
CONS_Printf("Servers do not need a time fudge! Heck, why are you hosting with this exe anyway? You don't need to ;)\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// New experimental version! Run a precise while loop that picks up packets instantly
|
||||
while (I_GetTimeUs() - startTime < ((UINT64)numSampleTics * 1000000 / NEWTICRATE))
|
||||
{
|
||||
I_NetGet();
|
||||
if (doomcom->remotenode != -1 && I_GetTimeUs() - startTime > (unsigned long long)2*1000000/NEWTICRATE) // wait a couple frames before recording
|
||||
{
|
||||
unsigned long long frame = I_GetTimeUs() * NEWTICRATE / 1000000;
|
||||
packetTimeFudge[numReceivedPackets++] = (I_GetTimeUs() - frame * 1000000 / NEWTICRATE) * 100 * NEWTICRATE / 1000000
|
||||
- netUpdateFudge; // gets the time fudge offset (0-100)
|
||||
}
|
||||
}
|
||||
|
||||
if (numReceivedPackets > 0)
|
||||
{
|
||||
int minOffset = 100, maxOffset = 0, averageOffset = 0;
|
||||
int newTimeFudge;
|
||||
int estimatedRange;
|
||||
|
||||
for (i = 0; i < numReceivedPackets; i++)
|
||||
{
|
||||
minOffset = min(minOffset, packetTimeFudge[i]);
|
||||
maxOffset = max(maxOffset, packetTimeFudge[i]);
|
||||
}
|
||||
|
||||
if (maxOffset - minOffset > 50)
|
||||
{
|
||||
// say maxOffset = 90 and minOffset = 20, we want the average to be 30...
|
||||
maxOffset = maxOffset - 100;
|
||||
|
||||
if (minOffset > maxOffset)
|
||||
{
|
||||
int swap = maxOffset;
|
||||
maxOffset = minOffset;
|
||||
minOffset = swap;
|
||||
}
|
||||
}
|
||||
|
||||
estimatedRange = maxOffset - minOffset;
|
||||
averageOffset = (maxOffset + minOffset) / 2;
|
||||
|
||||
CONS_Printf("%i packets, min: %d max: %d avg: %d est. range: %d (mynetupdate: %i)\n", numReceivedPackets, minOffset, maxOffset, averageOffset,
|
||||
estimatedRange, netUpdateFudge);
|
||||
|
||||
newTimeFudge = (cv_timefudge.value + averageOffset + 50) % 100;
|
||||
CONS_Printf("New time fudge: %i%%\n", newTimeFudge);
|
||||
|
||||
CV_SetValue(&cv_timefudge, newTimeFudge);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// CLIENT STARTUP
|
||||
// =========================================================================
|
||||
@@ -814,6 +1023,7 @@ void D_RegisterClientCommands(void)
|
||||
CV_RegisterVar(&cv_rollingdemos);
|
||||
CV_RegisterVar(&cv_netstat);
|
||||
CV_RegisterVar(&cv_netticbuffer);
|
||||
CV_RegisterVar(&cv_netsimstat);
|
||||
|
||||
#ifdef NETGAME_DEVMODE
|
||||
CV_RegisterVar(&cv_fishcake);
|
||||
@@ -4675,6 +4885,8 @@ void ItemFinder_OnChange(void)
|
||||
* \sa cv_pointlimit, TimeLimit_OnChange
|
||||
* \author Graue <graue@oceanbase.org>
|
||||
*/
|
||||
static int lastpointlimit;
|
||||
|
||||
static void PointLimit_OnChange(void)
|
||||
{
|
||||
// Don't allow pointlimit in Single Player/Co-Op/Race!
|
||||
@@ -4685,15 +4897,20 @@ static void PointLimit_OnChange(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (cv_pointlimit.value)
|
||||
if (cv_pointlimit.value != lastpointlimit)
|
||||
{
|
||||
CONS_Printf(M_GetText("Levels will end after %s scores %d point%s.\n"),
|
||||
G_GametypeHasTeams() ? M_GetText("a team") : M_GetText("someone"),
|
||||
cv_pointlimit.value,
|
||||
cv_pointlimit.value > 1 ? "s" : "");
|
||||
if (cv_pointlimit.value)
|
||||
{
|
||||
CONS_Printf(M_GetText("Levels will end after %s scores %d point%s.\n"),
|
||||
G_GametypeHasTeams() ? M_GetText("a team") : M_GetText("someone"),
|
||||
cv_pointlimit.value,
|
||||
cv_pointlimit.value > 1 ? "s" : "");
|
||||
}
|
||||
else if (netgame || multiplayer)
|
||||
CONS_Printf(M_GetText("Point limit disabled\n"));
|
||||
}
|
||||
else if (netgame || multiplayer)
|
||||
CONS_Printf(M_GetText("Point limit disabled\n"));
|
||||
|
||||
lastpointlimit = cv_pointlimit.value;
|
||||
}
|
||||
|
||||
static void NumLaps_OnChange(void)
|
||||
@@ -4742,19 +4959,28 @@ static void TimeLimit_OnChange(void)
|
||||
|
||||
if (cv_timelimit.value != 0)
|
||||
{
|
||||
CONS_Printf(M_GetText("Levels will end after %d minute%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
|
||||
timelimitintics = cv_timelimit.value * 60 * TICRATE;
|
||||
UINT32 newtimelimit = cv_timelimit.value * 60 * TICRATE;
|
||||
|
||||
//add hidetime for tag too!
|
||||
if (G_TagGametype())
|
||||
timelimitintics += hidetime * TICRATE;
|
||||
newtimelimit += hidetime * TICRATE;
|
||||
|
||||
if (newtimelimit != timelimitintics)
|
||||
{
|
||||
CONS_Printf(M_GetText("Levels will end after %d minute%s.\n"), cv_timelimit.value, cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
|
||||
|
||||
timelimitintics = newtimelimit; // ...and slightly modified by LX 12-11-2019 <3
|
||||
}
|
||||
|
||||
// Note the deliberate absence of any code preventing
|
||||
// pointlimit and timelimit from being set simultaneously.
|
||||
// Some people might like to use them together. It works.
|
||||
}
|
||||
else if (netgame || multiplayer)
|
||||
else if ((netgame || multiplayer) && timelimitintics > 0)
|
||||
{
|
||||
timelimitintics = 0;
|
||||
CONS_Printf(M_GetText("Time limit disabled\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/** Adjusts certain settings to match a changed gametype.
|
||||
@@ -5376,8 +5602,8 @@ static void Command_Archivetest_f(void)
|
||||
|
||||
// assign mobjnum
|
||||
i = 1;
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
|
||||
((mobj_t *)th)->mobjnum = i++;
|
||||
|
||||
// allocate buffer
|
||||
|
||||
@@ -83,6 +83,7 @@ extern consvar_t cv_teamscramble;
|
||||
extern consvar_t cv_scrambleonchange;
|
||||
|
||||
extern consvar_t cv_netstat;
|
||||
extern consvar_t cv_netsimstat;
|
||||
#ifdef WALLSPLATS
|
||||
extern consvar_t cv_splats;
|
||||
#endif
|
||||
@@ -147,6 +148,19 @@ extern consvar_t cv_maxping;
|
||||
extern consvar_t cv_pingtimeout;
|
||||
extern consvar_t cv_showping;
|
||||
|
||||
extern consvar_t cv_simulate;
|
||||
extern consvar_t cv_simulatetics;
|
||||
extern consvar_t cv_simulateculldistance;
|
||||
extern consvar_t cv_netdelay;
|
||||
extern consvar_t cv_netjitter;
|
||||
extern consvar_t cv_netsmoothing;
|
||||
extern consvar_t cv_netspikes;
|
||||
extern consvar_t cv_netsteadyplayers;
|
||||
extern consvar_t cv_debugsimulaterewind;
|
||||
extern consvar_t cv_timefudge;
|
||||
extern consvar_t cv_nettrails;
|
||||
extern consvar_t cv_netslingdelay;
|
||||
|
||||
extern consvar_t cv_skipmapcheck;
|
||||
|
||||
extern consvar_t cv_sleep;
|
||||
|
||||
@@ -500,6 +500,9 @@ extern UINT32 timesBeatenWithEmeralds;
|
||||
// WAD, partly set at startup time.
|
||||
|
||||
extern tic_t gametic;
|
||||
extern tic_t simtic; // current tic at simulation, if applicable (if no simulation happened, this=gametic)
|
||||
extern tic_t targetsimtic; // the target sim tic, if applicable
|
||||
extern tic_t smoothedTic; // current game tic when smoothing is enabled (\todo: could cause problems if the game objects care about gametic)
|
||||
#define localgametic leveltime
|
||||
|
||||
// Player spawn spots.
|
||||
|
||||
@@ -1177,6 +1177,9 @@ void F_WaitingPlayersTicker(void)
|
||||
|
||||
void F_WaitingPlayersDrawer(void)
|
||||
{
|
||||
if (!waitcolormap)
|
||||
F_StartWaitingPlayers();
|
||||
|
||||
UINT32 frame = (finalecount % 8) / 4; // The game only tics every other frame while waitingplayers
|
||||
INT32 flags = V_FLIP;
|
||||
const char *waittext1 = "You will join";
|
||||
|
||||
+13
-11
@@ -116,6 +116,9 @@ INT32 consoleplayer; // player taking events and displaying
|
||||
INT32 displayplayers[MAXSPLITSCREENPLAYERS]; // view being displayed
|
||||
|
||||
tic_t gametic;
|
||||
tic_t simtic; // simulated tic
|
||||
tic_t targetsimtic; // target simulated tic
|
||||
tic_t smoothedTic;
|
||||
tic_t levelstarttic; // gametic at level start
|
||||
UINT32 totalrings; // for intermission
|
||||
INT16 lastmap; // last level you were at (returning from special stages)
|
||||
@@ -3096,9 +3099,9 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
|
||||
I_Assert((oldmo != NULL) && (newmo != NULL));
|
||||
|
||||
// scan all thinkers
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -5542,16 +5545,15 @@ void G_ConsGhostTic(INT32 playernum)
|
||||
demo_p += sizeof(angle_t); // angle, unnecessary for cons.
|
||||
|
||||
mobj = NULL;
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
mobj = (mobj_t *)th;
|
||||
if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z)
|
||||
break;
|
||||
mobj = NULL; // wasn't this one, keep searching.
|
||||
}
|
||||
if (mobj && mobj->health != health) // Wasn't damaged?! This is desync! Fix it!
|
||||
if (th != &thlist[THINK_MOBJ] && mobj->health != health) // Wasn't damaged?! This is desync! Fix it!
|
||||
{
|
||||
if (demosynced)
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
|
||||
@@ -7313,7 +7315,7 @@ void G_DoPlayDemo(char *defdemoname)
|
||||
}
|
||||
|
||||
// net var data
|
||||
CV_LoadNetVars(&demo_p);
|
||||
CV_LoadNetVars(&demo_p, false);
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (*demo_p == DEMOMARKER)
|
||||
@@ -7356,7 +7358,7 @@ void G_DoPlayDemo(char *defdemoname)
|
||||
#endif
|
||||
|
||||
// net var data
|
||||
CV_LoadNetVars(&demo_p);
|
||||
CV_LoadNetVars(&demo_p, false);
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (*demo_p == DEMOMARKER)
|
||||
@@ -7973,16 +7975,16 @@ void G_DoPlayMetal(void)
|
||||
metalbuffer = metal_p = W_CacheLumpNum(l, PU_STATIC);
|
||||
|
||||
// find metal sonic
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)th;
|
||||
if (mo->type == MT_METALSONIC_RACE)
|
||||
break;
|
||||
}
|
||||
if (!mo)
|
||||
if (th == &thlist[THINK_MOBJ])
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Failed to find bot entity.\n"));
|
||||
Z_Free(metalbuffer);
|
||||
|
||||
+62
-35
@@ -755,6 +755,14 @@ void HWR_WallLighting(FOutVector *wlVerts)
|
||||
FSurfaceInfo Surf;
|
||||
float dist_p2d, d[4], s;
|
||||
|
||||
if (!dynlights->mo[j])
|
||||
continue;
|
||||
if (P_MobjWasRemoved(dynlights->mo[j]))
|
||||
{
|
||||
P_SetTarget(&dynlights->mo[j], NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check bounding box first
|
||||
if (SphereTouchBBox3D(&wlVerts[2], &wlVerts[0], &LIGHT_POS(j), DL_RADIUS(j))==false)
|
||||
continue;
|
||||
@@ -805,8 +813,6 @@ void HWR_WallLighting(FOutVector *wlVerts)
|
||||
#ifdef DL_HIGH_QUALITY
|
||||
Surf.FlatColor.s.alpha = (UINT8)((1-dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha);
|
||||
#endif
|
||||
if (!dynlights->mo[j]->state)
|
||||
return;
|
||||
// next state is null so fade out with alpha
|
||||
if (dynlights->mo[j]->state->nextstate == S_NULL)
|
||||
Surf.FlatColor.s.alpha = (UINT8)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha);
|
||||
@@ -837,6 +843,14 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts)
|
||||
FSurfaceInfo Surf;
|
||||
float dist_p2d, s;
|
||||
|
||||
if (!dynlights->mo[j])
|
||||
continue;
|
||||
if (P_MobjWasRemoved(dynlights->mo[j]))
|
||||
{
|
||||
P_SetTarget(&dynlights->mo[j], NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
// BP: The kickass Optimization: check if light touch bounding box
|
||||
if (SphereTouchBBox3D(&p1, &p2, &dynlights->position[j], DL_RADIUS(j))==false)
|
||||
continue;
|
||||
@@ -868,8 +882,6 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts)
|
||||
#ifdef DL_HIGH_QUALITY
|
||||
Surf.FlatColor.s.alpha = (unsigned char)((1 - dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha);
|
||||
#endif
|
||||
if (!dynlights->mo[j]->state)
|
||||
return;
|
||||
// next state is null so fade out with alpha
|
||||
if ((dynlights->mo[j]->state->nextstate == S_NULL))
|
||||
Surf.FlatColor.s.alpha = (unsigned char)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha);
|
||||
@@ -1000,6 +1012,14 @@ void HWR_DrawCoronas(void)
|
||||
if (!(p_lspr->type & CORONA_SPR))
|
||||
continue;
|
||||
|
||||
if (!dynlights->mo[j])
|
||||
continue;
|
||||
if (P_MobjWasRemoved(dynlights->mo[j]))
|
||||
{
|
||||
P_SetTarget(&dynlights->mo[j], NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
transform(&cx,&cy,&cz);
|
||||
|
||||
// more realistique corona !
|
||||
@@ -1061,7 +1081,8 @@ void HWR_DrawCoronas(void)
|
||||
// --------------------------------------------------------------------------
|
||||
void HWR_ResetLights(void)
|
||||
{
|
||||
dynlights->nb = 0;
|
||||
while (dynlights->nb)
|
||||
P_SetTarget(&dynlights->mo[--dynlights->nb], NULL);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -1092,24 +1113,25 @@ void HWR_DL_AddLight(gr_vissprite_t *spr, GLPatch_t *patch)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (dynlights->nb >= DL_MAX_LIGHT)
|
||||
return;
|
||||
|
||||
// check if sprite contain dynamic light
|
||||
p_lspr = t_lspr[spr->mobj->sprite];
|
||||
if ((p_lspr->type&DYNLIGHT_SPR)
|
||||
&& ((p_lspr->type != LIGHT_SPR) || cv_grstaticlighting.value)
|
||||
&& (dynlights->nb < DL_MAX_LIGHT)
|
||||
if (!(p_lspr->type & DYNLIGHT_SPR))
|
||||
return;
|
||||
if ((p_lspr->type != LIGHT_SPR) || cv_grstaticlighting.value)
|
||||
return;
|
||||
|
||||
&& spr->mobj->state)
|
||||
{
|
||||
LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(spr->mobj->x);
|
||||
LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(spr->mobj->z)+FIXED_TO_FLOAT(spr->mobj->height>>1)+p_lspr->light_yoffset;
|
||||
LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(spr->mobj->y);
|
||||
LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(spr->mobj->x);
|
||||
LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(spr->mobj->z)+FIXED_TO_FLOAT(spr->mobj->height>>1)+p_lspr->light_yoffset;
|
||||
LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(spr->mobj->y);
|
||||
|
||||
P_SetTarget(&dynlights->mo[dynlights->nb], spr->mobj);
|
||||
P_SetTarget(&dynlights->mo[dynlights->nb], spr->mobj);
|
||||
|
||||
dynlights->p_lspr[dynlights->nb] = p_lspr;
|
||||
dynlights->p_lspr[dynlights->nb] = p_lspr;
|
||||
|
||||
dynlights->nb++;
|
||||
}
|
||||
dynlights->nb++;
|
||||
}
|
||||
|
||||
static GLPatch_t lightmappatch;
|
||||
@@ -1263,6 +1285,14 @@ static void HWR_CheckSubsector(size_t num, fixed_t *bbox)
|
||||
// if (CircleTouchBBox(&p1, &p2, &LIGHT_POS(lightnum), DL_RADIUS(lightnum))==false)
|
||||
// continue;
|
||||
|
||||
if (!dynlights->mo[lightnum])
|
||||
continue;
|
||||
if (P_MobjWasRemoved(dynlights->mo[lightnum]))
|
||||
{
|
||||
P_SetTarget(&dynlights->mo[lightnum], NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
count = sub->numlines; // how many linedefs
|
||||
line = &segs[sub->firstline]; // first line seg
|
||||
while (count--)
|
||||
@@ -1280,18 +1310,20 @@ static void HWR_CheckSubsector(size_t num, fixed_t *bbox)
|
||||
// --------------------------------------------------------------------------
|
||||
static void HWR_AddMobjLights(mobj_t *thing)
|
||||
{
|
||||
if (t_lspr[thing->sprite]->type & CORONA_SPR)
|
||||
{
|
||||
LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(thing->x);
|
||||
LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(thing->z) + t_lspr[thing->sprite]->light_yoffset;
|
||||
LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(thing->y);
|
||||
if (dynlights->nb >= DL_MAX_LIGHT)
|
||||
return;
|
||||
if (!(t_lspr[thing->sprite]->type & CORONA_SPR))
|
||||
return;
|
||||
|
||||
dynlights->p_lspr[dynlights->nb] = t_lspr[thing->sprite];
|
||||
LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(thing->x);
|
||||
LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(thing->z) + t_lspr[thing->sprite]->light_yoffset;
|
||||
LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(thing->y);
|
||||
|
||||
dynlights->nb++;
|
||||
if (dynlights->nb > DL_MAX_LIGHT)
|
||||
dynlights->nb = DL_MAX_LIGHT;
|
||||
}
|
||||
P_SetTarget(&dynlights->mo[dynlights->nb], thing);
|
||||
|
||||
dynlights->p_lspr[dynlights->nb] = t_lspr[thing->sprite];
|
||||
|
||||
dynlights->nb++;
|
||||
}
|
||||
|
||||
//Hurdler: The goal of this function is to walk through all the bsp starting
|
||||
@@ -1317,12 +1349,9 @@ static void HWR_SearchLightsInMobjs(void)
|
||||
//mobj_t * mobj;
|
||||
|
||||
// search in the list of thinkers
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
{
|
||||
// a mobj ?
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
|
||||
HWR_AddMobjLights((mobj_t *)th);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1334,7 +1363,7 @@ void HWR_CreateStaticLightmaps(int bspnum)
|
||||
#ifdef STATICLIGHT
|
||||
CONS_Debug(DBG_RENDER, "HWR_CreateStaticLightmaps\n");
|
||||
|
||||
dynlights->nb = 0;
|
||||
HWR_ResetLights();
|
||||
|
||||
// First: Searching for lights
|
||||
// BP: if i was you, I will make it in create mobj since mobj can be create
|
||||
@@ -1345,8 +1374,6 @@ void HWR_CreateStaticLightmaps(int bspnum)
|
||||
// Second: Build all lightmap for walls covered by lights
|
||||
validcount++; // to be sure
|
||||
HWR_ComputeLightMapsInBSPNode(bspnum, NULL);
|
||||
|
||||
dynlights->nb = 0;
|
||||
#else
|
||||
(void)bspnum;
|
||||
#endif
|
||||
|
||||
@@ -46,6 +46,10 @@ UINT32 I_GetFreeMem(UINT32 *total);
|
||||
*/
|
||||
tic_t I_GetTime(void);
|
||||
|
||||
/** \brief Gets the current time in microseconds
|
||||
*/
|
||||
UINT64 I_GetTimeUs(void);
|
||||
|
||||
/** \brief The I_Sleep function
|
||||
|
||||
\return void
|
||||
|
||||
+63
-1
@@ -713,6 +713,35 @@ static boolean SOCK_CanGet(void)
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
typedef struct {
|
||||
boolean inUse;
|
||||
|
||||
UINT8* data;
|
||||
int dataLength;
|
||||
|
||||
int time;
|
||||
SOCKET_TYPE socket;
|
||||
mysockaddr_t sockaddr;
|
||||
int sockaddr_size;
|
||||
} DelayBuffer;
|
||||
|
||||
#define NUMDELAYPACKETS 200
|
||||
DelayBuffer delayPackets[NUMDELAYPACKETS];
|
||||
tic_t nextSpikeTime = 0;
|
||||
tic_t nextSpikeDuration = 0;
|
||||
|
||||
void SOCK_FlushDelayBuffers(boolean flushImmediate)
|
||||
{
|
||||
int time = I_GetTime();
|
||||
|
||||
for (int i = 0; i < NUMDELAYPACKETS; i++) {
|
||||
if (delayPackets[i].inUse && ((time - delayPackets[i].time) * 1000 / TICRATE >= cv_netdelay.value || flushImmediate)) {
|
||||
sendto(delayPackets[i].socket, (char *)delayPackets[i].data, delayPackets[i].dataLength, 0, &delayPackets[i].sockaddr.any, delayPackets[i].sockaddr_size);
|
||||
delayPackets[i].inUse = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr)
|
||||
{
|
||||
socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in);
|
||||
@@ -720,6 +749,7 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
|
||||
socklen_t d6 = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
socklen_t d, da = (socklen_t)sizeof(mysockaddr_t);
|
||||
tic_t time = I_GetTime();
|
||||
|
||||
switch (sockaddr->any.sa_family)
|
||||
{
|
||||
@@ -730,7 +760,39 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
|
||||
default: d = da; break;
|
||||
}
|
||||
|
||||
return sendto(socket, (char *)&doomcom->data, doomcom->datalength, 0, &sockaddr->any, d);
|
||||
if (cv_netspikes.value && time >= nextSpikeTime + nextSpikeDuration)
|
||||
{
|
||||
nextSpikeTime = time + (rand() % 35) + 1 * TICRATE;
|
||||
nextSpikeDuration = (rand() % 10) + 1;
|
||||
}
|
||||
|
||||
if (cv_netdelay.value > 0 || cv_netjitter.value > 0 || (cv_netspikes.value && time >= nextSpikeTime)) {
|
||||
// add a nasty packet delay for testing!
|
||||
boolean writtenPacket = false;
|
||||
int addSpike = (cv_netspikes.value && time >= nextSpikeTime) ? nextSpikeDuration : 0;
|
||||
|
||||
for (int i = 0; i < NUMDELAYPACKETS; i++) {
|
||||
if (!delayPackets[i].inUse) {
|
||||
delayPackets[i].data = malloc(doomcom->datalength);
|
||||
delayPackets[i].dataLength = doomcom->datalength;
|
||||
delayPackets[i].socket = socket;
|
||||
delayPackets[i].sockaddr = *sockaddr;
|
||||
delayPackets[i].time = time + (rand() % (cv_netjitter.value + 1)) + addSpike;
|
||||
delayPackets[i].sockaddr_size = d;
|
||||
delayPackets[i].inUse = true;
|
||||
memcpy(delayPackets[i].data, doomcom->data, doomcom->datalength);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return doomcom->datalength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// send it now like a normal human netcode
|
||||
return sendto(socket, (char *)&doomcom->data, doomcom->datalength, 0, &sockaddr->any, d);
|
||||
}
|
||||
}
|
||||
|
||||
static void SOCK_Send(void)
|
||||
|
||||
@@ -28,4 +28,7 @@ boolean I_InitTcpNetwork(void);
|
||||
boolean I_InitTcpDriver(void);
|
||||
void I_ShutdownTcpDriver(void);
|
||||
|
||||
// for debug delayed networking
|
||||
void SOCK_FlushDelayBuffers(boolean);
|
||||
|
||||
#endif
|
||||
@@ -54,10 +54,12 @@ static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
blockfuncerror = true;
|
||||
P_SetTarget(&bnext, NULL);
|
||||
return 0; // *shrugs*
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, continue
|
||||
P_SetTarget(&bnext, NULL);
|
||||
if (lua_toboolean(gL, -1))
|
||||
return 2; // stop whole search
|
||||
else
|
||||
|
||||
@@ -217,8 +217,6 @@ enum slope_e {
|
||||
slope_normal,
|
||||
slope_zangle,
|
||||
slope_xydirection,
|
||||
slope_sourceline,
|
||||
slope_refpos,
|
||||
slope_flags
|
||||
};
|
||||
|
||||
@@ -230,8 +228,6 @@ static const char *const slope_opt[] = {
|
||||
"normal",
|
||||
"zangle",
|
||||
"xydirection",
|
||||
"sourceline",
|
||||
"refpos",
|
||||
"flags",
|
||||
NULL};
|
||||
|
||||
@@ -1285,12 +1281,6 @@ static int slope_get(lua_State *L)
|
||||
case slope_xydirection: // xydirection
|
||||
lua_pushangle(L, slope->xydirection);
|
||||
return 1;
|
||||
case slope_sourceline: // source linedef
|
||||
LUA_PushUserdata(L, slope->sourceline, META_LINE);
|
||||
return 1;
|
||||
case slope_refpos: // refpos
|
||||
lua_pushinteger(L, slope->refpos);
|
||||
return 1;
|
||||
case slope_flags: // flags
|
||||
lua_pushinteger(L, slope->flags);
|
||||
return 1;
|
||||
@@ -1314,11 +1304,9 @@ static int slope_set(lua_State *L)
|
||||
switch(field) // todo: reorganize this shit
|
||||
{
|
||||
case slope_valid: // valid
|
||||
case slope_sourceline: // sourceline
|
||||
case slope_d: // d
|
||||
case slope_flags: // flags
|
||||
case slope_normal: // normal
|
||||
case slope_refpos: // refpos
|
||||
default:
|
||||
return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
|
||||
case slope_o: { // o
|
||||
|
||||
+10
-1
@@ -260,10 +260,19 @@ static int mobj_get(lua_State *L)
|
||||
// bprev -- same deal as sprev above, but for the blockmap.
|
||||
return UNIMPLEMENTED;
|
||||
case mobj_hnext:
|
||||
if (mo->hnext && P_MobjWasRemoved(mo->hnext))
|
||||
{ // don't put invalid mobj back into Lua.
|
||||
P_SetTarget(&mo->hnext, NULL);
|
||||
return 0;
|
||||
}
|
||||
LUA_PushUserdata(L, mo->hnext, META_MOBJ);
|
||||
break;
|
||||
case mobj_hprev:
|
||||
// implimented differently from sprev and bprev because SSNTails.
|
||||
if (mo->hprev && P_MobjWasRemoved(mo->hprev))
|
||||
{ // don't put invalid mobj back into Lua.
|
||||
P_SetTarget(&mo->hprev, NULL);
|
||||
return 0;
|
||||
}
|
||||
LUA_PushUserdata(L, mo->hprev, META_MOBJ);
|
||||
break;
|
||||
case mobj_type:
|
||||
|
||||
+12
-2
@@ -476,9 +476,19 @@ static int player_set(lua_State *L)
|
||||
else if (fastcmp(field,"old_angle_pos"))
|
||||
plr->old_angle_pos = luaL_checkangle(L, 3);
|
||||
else if (fastcmp(field,"axis1"))
|
||||
P_SetTarget(&plr->axis1, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
|
||||
{
|
||||
mobj_t *mo = NULL;
|
||||
if (!lua_isnil(L, 3))
|
||||
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
P_SetTarget(&plr->axis1, mo);
|
||||
}
|
||||
else if (fastcmp(field,"axis2"))
|
||||
P_SetTarget(&plr->axis2, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
|
||||
{
|
||||
mobj_t *mo = NULL;
|
||||
if (!lua_isnil(L, 3))
|
||||
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
P_SetTarget(&plr->axis2, mo);
|
||||
}
|
||||
else if (fastcmp(field,"bumpertime"))
|
||||
plr->bumpertime = (tic_t)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"flyangle"))
|
||||
|
||||
+20
-15
@@ -413,9 +413,9 @@ void LUA_InvalidateLevel(void)
|
||||
size_t i;
|
||||
if (!gL)
|
||||
return;
|
||||
|
||||
for (th = thinkercap.next; th && th != &thinkercap; th = th->next)
|
||||
LUA_InvalidateUserdata(th);
|
||||
for (i = 0; i < NUM_THINKERLISTS; i++)
|
||||
for (th = thlist[i].next; th && th != &thlist[i]; th = th->next)
|
||||
LUA_InvalidateUserdata(th);
|
||||
|
||||
LUA_InvalidateMapthings();
|
||||
|
||||
@@ -1026,16 +1026,17 @@ void LUA_Archive(void)
|
||||
ArchiveExtVars(&players[i], "player");
|
||||
}
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
//if (gamestate == GS_LEVEL)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
{
|
||||
// archive function will determine when to skip mobjs,
|
||||
// and write mobjnum in otherwise.
|
||||
ArchiveExtVars(th, "mobj");
|
||||
}
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
// archive function will determine when to skip mobjs,
|
||||
// and write mobjnum in otherwise.
|
||||
ArchiveExtVars(th, "mobj");
|
||||
}
|
||||
|
||||
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
|
||||
|
||||
LUAh_NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode
|
||||
@@ -1063,10 +1064,14 @@ void LUA_UnArchive(void)
|
||||
|
||||
do {
|
||||
mobjnum = READUINT32(save_p); // read a mobjnum
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker
|
||||
&& ((mobj_t *)th)->mobjnum == mobjnum) // find matching mobj
|
||||
UnArchiveExtVars(th); // apply variables
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
|
||||
continue;
|
||||
UnArchiveExtVars(th); // apply variables
|
||||
}
|
||||
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
|
||||
|
||||
LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#define META_ITERATIONSTATE "iteration state"
|
||||
|
||||
static const char *const iter_opt[] = {
|
||||
/*static const char *const iter_opt[] = {
|
||||
"all",
|
||||
"mobj",
|
||||
NULL};
|
||||
@@ -26,7 +26,7 @@ static const char *const iter_opt[] = {
|
||||
static const actionf_p1 iter_funcs[] = {
|
||||
NULL,
|
||||
(actionf_p1)P_MobjThinker
|
||||
};
|
||||
};*/
|
||||
|
||||
struct iterationState {
|
||||
actionf_p1 filter;
|
||||
@@ -58,7 +58,7 @@ static int lib_iterateThinkers(lua_State *L)
|
||||
lua_settop(L, 2);
|
||||
|
||||
if (lua_isnil(L, 2))
|
||||
th = &thinkercap;
|
||||
th = &thlist[THINK_MOBJ];
|
||||
else if (lua_isuserdata(L, 2))
|
||||
{
|
||||
if (lua_islightuserdata(L, 2))
|
||||
@@ -88,11 +88,11 @@ static int lib_iterateThinkers(lua_State *L)
|
||||
if (!next)
|
||||
return luaL_error(L, "next thinker invalidated during iteration");
|
||||
|
||||
for (; next != &thinkercap; next = next->next)
|
||||
for (; next != &thlist[THINK_MOBJ]; next = next->next)
|
||||
if (!it->filter || next->function.acp1 == it->filter)
|
||||
{
|
||||
push_thinker(next);
|
||||
if (next->next != &thinkercap)
|
||||
if (next->next != &thlist[THINK_MOBJ])
|
||||
{
|
||||
push_thinker(next->next);
|
||||
it->next = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
@@ -111,7 +111,7 @@ static int lib_startIterate(lua_State *L)
|
||||
luaL_getmetatable(L, META_ITERATIONSTATE);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
it->filter = iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
|
||||
it->filter = (actionf_p1)P_MobjThinker; //iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
|
||||
it->next = LUA_REFNIL;
|
||||
return 2;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ int LUA_ThinkerLib(lua_State *L)
|
||||
lua_pushcfunction(L, lib_iterateThinkers);
|
||||
lua_pushcclosure(L, lib_startIterate, 1);
|
||||
lua_setfield(L, -2, "iterate");
|
||||
lua_setglobal(L, "thinkers");
|
||||
lua_setglobal(L, "mobjs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -912,15 +912,16 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
|
||||
thinker_t *th;
|
||||
mobj_t *mo;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)th;
|
||||
// get offset from mt, which points to old mapthings, then add new location
|
||||
if (mo->spawnpoint)
|
||||
mo->spawnpoint = (mo->spawnpoint - mt) + mapthings;
|
||||
if (!mo->spawnpoint)
|
||||
continue;
|
||||
mo->spawnpoint = (mo->spawnpoint - mt) + mapthings;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -409,7 +409,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type)
|
||||
// new door thinker
|
||||
rtn = 1;
|
||||
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&ceiling->thinker);
|
||||
P_AddThinker(THINK_MAIN, &ceiling->thinker);
|
||||
sec->ceilingdata = ceiling;
|
||||
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
|
||||
ceiling->sector = sec;
|
||||
@@ -629,7 +629,7 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type)
|
||||
// new door thinker
|
||||
rtn = 1;
|
||||
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&ceiling->thinker);
|
||||
P_AddThinker(THINK_MAIN, &ceiling->thinker);
|
||||
sec->ceilingdata = ceiling;
|
||||
ceiling->thinker.function.acp1 = (actionf_p1)T_CrushCeiling;
|
||||
ceiling->sector = sec;
|
||||
|
||||
+57
-40
@@ -2149,7 +2149,7 @@ void A_Boss1Laser(mobj_t *actor)
|
||||
if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1)
|
||||
{
|
||||
point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE);
|
||||
point->target = actor;
|
||||
P_SetTarget(&point->target, actor);
|
||||
point->destscale = 3*FRACUNIT;
|
||||
point->scalespeed = FRACUNIT>>2;
|
||||
point->fuse = TICRATE;
|
||||
@@ -2530,10 +2530,11 @@ void A_1upThinker(mobj_t *actor)
|
||||
|
||||
if (closestplayer == -1 || skins[players[closestplayer].skin].spritedef.numframes <= states[S_PLAY_BOX1].frame)
|
||||
{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
|
||||
actor->frame = 0;
|
||||
if (actor->tracer) {
|
||||
P_RemoveMobj(actor->tracer);
|
||||
actor->tracer = NULL;
|
||||
if (actor->tracer)
|
||||
{
|
||||
mobj_t *tracer = actor->tracer;
|
||||
P_SetTarget(&actor->tracer, NULL);
|
||||
P_RemoveMobj(tracer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -2745,9 +2746,9 @@ void A_BossDeath(mobj_t *mo)
|
||||
|
||||
// scan the remaining thinkers to see
|
||||
// if all bosses are dead
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -2802,12 +2803,12 @@ bossjustdie:
|
||||
|
||||
P_SetTarget(&mo->target, NULL);
|
||||
|
||||
// Flee! Flee! Find a point to escape to! If none, just shoot upward!
|
||||
// scan the thinkers to find the runaway point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue;
|
||||
// Flee! Flee! Find a point to escape to! If none, just shoot upward!
|
||||
// scan the thinkers to find the runaway point
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
@@ -3768,6 +3769,14 @@ void A_ThrownRing(mobj_t *actor)
|
||||
INT32 stop;
|
||||
player_t *player;
|
||||
fixed_t dist;
|
||||
|
||||
if (cv_netslingdelay.value && issimulation && (tic_t)cv_netsteadyplayers.value >= targetsimtic - simtic && actor->target == players[consoleplayer].mo)
|
||||
{
|
||||
// don't move ring weapons during simulation if netslingdelay is positive
|
||||
actor->momx = actor->momy = actor->momz = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_ThrownRing", actor))
|
||||
return;
|
||||
@@ -5437,9 +5446,9 @@ void A_RingExplode(mobj_t *actor)
|
||||
|
||||
S_StartSound(actor, sfx_prloop);
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -6538,7 +6547,7 @@ void A_Boss2PogoTarget(mobj_t *actor)
|
||||
if (actor->info->missilestate) // spawn the pogo stick collision box
|
||||
{
|
||||
mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate);
|
||||
pogo->target = actor;
|
||||
P_SetTarget(&pogo->target, actor);
|
||||
}
|
||||
|
||||
actor->reactiontime = 1;
|
||||
@@ -7073,14 +7082,24 @@ void A_Boss3Path(mobj_t *actor)
|
||||
// scan the thinkers
|
||||
// to find a point that matches
|
||||
// the number
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
if (mo2->type != MT_BOSS3WAYPOINT)
|
||||
continue;
|
||||
if (!mo2->spawnpoint)
|
||||
continue;
|
||||
if (mo2->spawnpoint->angle != actor->threshold)
|
||||
continue;
|
||||
if (mo2->spawnpoint->extrainfo != actor->cusval)
|
||||
continue;
|
||||
|
||||
P_SetTarget(&actor->target, mo2);
|
||||
break;
|
||||
}
|
||||
@@ -7463,9 +7482,9 @@ void A_FindTarget(mobj_t *actor)
|
||||
CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
|
||||
|
||||
// scan the thinkers
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -7528,9 +7547,9 @@ void A_FindTracer(mobj_t *actor)
|
||||
CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
|
||||
|
||||
// scan the thinkers
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -8091,9 +8110,9 @@ void A_RemoteAction(mobj_t *actor)
|
||||
fixed_t dist1 = 0, dist2 = 0;
|
||||
|
||||
// scan the thinkers
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -8879,9 +8898,9 @@ void A_MementosTPParticles(mobj_t *actor)
|
||||
// Doesn't seem like much given the small amount of mobjs this map has but heh.
|
||||
if (!actor->target)
|
||||
{
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -8981,9 +9000,9 @@ void A_ReaperThinker(mobj_t *actor)
|
||||
}
|
||||
|
||||
// We have no target and oughta find one, so let's scan through thinkers for a waypoint of angle 0, or something.
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -9047,9 +9066,9 @@ void A_ReaperThinker(mobj_t *actor)
|
||||
P_SetTarget(&actor->target, NULL); // remove target so we can default back to first waypoint if things go ham.
|
||||
|
||||
// If we reach close to a waypoint, then we should go to the NEXT one.
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -9098,8 +9117,6 @@ void A_FlameParticle(mobj_t *actor)
|
||||
par->momz = actor->scale<<1;
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
// Function: A_OrbitNights
|
||||
//
|
||||
// Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.)
|
||||
@@ -9228,10 +9245,10 @@ void A_SetObjectTypeState(mobj_t *actor)
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue;
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
@@ -9866,9 +9883,9 @@ void A_CheckThingCount(mobj_t *actor)
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
+22
-17
@@ -1974,20 +1974,25 @@ void T_ThwompSector(levelspecthink_t *thwomp)
|
||||
// scan the thinkers to find players!
|
||||
if (!rover || (rover->flags & FF_EXISTS))
|
||||
{
|
||||
// scan the thinkers to find players!
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
UINT8 i;
|
||||
// scan the players to find victims!
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
if (!players[i].mo)
|
||||
continue;
|
||||
if (!players[i].mo->health)
|
||||
continue;
|
||||
if (players[i].mo->z > thwomp->sector->ceilingheight)
|
||||
continue;
|
||||
if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96 * FRACUNIT)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)th;
|
||||
if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator
|
||||
&& mo->z <= thwomp->sector->ceilingheight
|
||||
&& P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT)
|
||||
{
|
||||
thwomp->direction = -1;
|
||||
break;
|
||||
}
|
||||
thwomp->direction = -1;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
@@ -2675,7 +2680,7 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype)
|
||||
// new floor thinker
|
||||
rtn = 1;
|
||||
dofloor = Z_Calloc(sizeof (*dofloor), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&dofloor->thinker);
|
||||
P_AddThinker(THINK_MAIN, &dofloor->thinker);
|
||||
|
||||
// make sure another floor thinker won't get started over this one
|
||||
sec->floordata = dofloor;
|
||||
@@ -2896,7 +2901,7 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed)
|
||||
// create and initialize new elevator thinker
|
||||
rtn = 1;
|
||||
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&elevator->thinker);
|
||||
P_AddThinker(THINK_MAIN, &elevator->thinker);
|
||||
sec->floordata = elevator;
|
||||
sec->ceilingdata = elevator;
|
||||
elevator->thinker.function.acp1 = (actionf_p1)T_MoveElevator;
|
||||
@@ -3078,7 +3083,7 @@ INT32 EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline)
|
||||
return 0;
|
||||
|
||||
bouncer = Z_Calloc(sizeof (*bouncer), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&bouncer->thinker);
|
||||
P_AddThinker(THINK_MAIN, &bouncer->thinker);
|
||||
sec->ceilingdata = bouncer;
|
||||
bouncer->thinker.function.acp1 = (actionf_p1)T_BounceCheese;
|
||||
|
||||
@@ -3112,7 +3117,7 @@ INT32 EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, bool
|
||||
|
||||
// create and initialize new thinker
|
||||
faller = Z_Calloc(sizeof (*faller), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&faller->thinker);
|
||||
P_AddThinker(THINK_MAIN, &faller->thinker);
|
||||
faller->thinker.function.acp1 = (actionf_p1)T_ContinuousFalling;
|
||||
|
||||
// set up the fields
|
||||
@@ -3161,7 +3166,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
|
||||
|
||||
// create and initialize new elevator thinker
|
||||
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&elevator->thinker);
|
||||
P_AddThinker(THINK_MAIN, &elevator->thinker);
|
||||
elevator->thinker.function.acp1 = (actionf_p1)T_StartCrumble;
|
||||
|
||||
// Does this crumbler return?
|
||||
@@ -3235,7 +3240,7 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
|
||||
// create and initialize new elevator thinker
|
||||
|
||||
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&block->thinker);
|
||||
P_AddThinker(THINK_MAIN, &block->thinker);
|
||||
sec->floordata = block;
|
||||
sec->ceilingdata = block;
|
||||
block->thinker.function.acp1 = (actionf_p1)T_MarioBlock;
|
||||
|
||||
+63
-8
@@ -27,6 +27,7 @@
|
||||
#include "m_misc.h"
|
||||
#include "v_video.h" // video flags for CEchos
|
||||
#include "k_kart.h" // SRB2kart
|
||||
#include "p_local.h"
|
||||
|
||||
// CTF player names
|
||||
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
||||
@@ -923,7 +924,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
||||
if (player->powers[pw_super])
|
||||
return;
|
||||
|
||||
player->gotflag |= flagflag;
|
||||
player->gotflag |= flagflag; // >:(
|
||||
CONS_Printf(M_GetText("%s picked up the %c%s%c!\n"), plname, flagcolor, flagtext, 0x80);
|
||||
(*flagmobj) = NULL;
|
||||
// code for dealing with abilities is handled elsewhere now
|
||||
@@ -948,6 +949,60 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
||||
if (toucher->tracer && toucher->tracer->target
|
||||
&& toucher->tracer->target->type == MT_GOTEMERALD)
|
||||
{
|
||||
mobj_t *orbittarget = special->target ? special->target : special;
|
||||
mobj_t *hnext = orbittarget->hnext, *anchorpoint = NULL, *anchorpoint2 = NULL;
|
||||
mobj_t *mo2;
|
||||
thinker_t *th;
|
||||
|
||||
// The player might have two Ideyas: toucher->tracer and toucher->tracer->hnext
|
||||
// so handle their anchorpoints accordingly.
|
||||
// scan the thinkers to find the corresponding anchorpoint
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type != MT_IDEYAANCHOR)
|
||||
continue;
|
||||
|
||||
if (mo2->health == toucher->tracer->health) // do ideya numberes match?
|
||||
anchorpoint = mo2;
|
||||
else if (toucher->tracer->hnext && mo2->health == toucher->tracer->hnext->health)
|
||||
anchorpoint2 = mo2;
|
||||
|
||||
if ((!toucher->tracer->hnext && anchorpoint)
|
||||
|| (toucher->tracer->hnext && anchorpoint && anchorpoint2))
|
||||
break;
|
||||
}
|
||||
|
||||
if (anchorpoint)
|
||||
{
|
||||
toucher->tracer->flags |= MF_GRENADEBOUNCE; // custom radius factors
|
||||
toucher->tracer->threshold = 8 << 20; // X factor 0, Y factor 0, Z factor 8
|
||||
}
|
||||
|
||||
if (anchorpoint2)
|
||||
{
|
||||
toucher->tracer->hnext->flags |= MF_GRENADEBOUNCE; // custom radius factors
|
||||
toucher->tracer->hnext->threshold = 8 << 20; // X factor 0, Y factor 0, Z factor 8
|
||||
}
|
||||
|
||||
P_SetTarget(&orbittarget->hnext, toucher->tracer);
|
||||
if (!orbittarget->hnext->hnext)
|
||||
P_SetTarget(&orbittarget->hnext->hnext, hnext); // Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo.
|
||||
else
|
||||
P_SetTarget(&orbittarget->hnext->hnext->target, anchorpoint2 ? anchorpoint2 : orbittarget);
|
||||
P_SetTarget(&orbittarget->hnext->target, anchorpoint ? anchorpoint : orbittarget);
|
||||
P_SetTarget(&toucher->tracer, NULL);
|
||||
|
||||
if (hnext)
|
||||
{
|
||||
orbittarget->hnext->extravalue1 = (angle_t)(hnext->extravalue1 - 72*ANG1);
|
||||
if (orbittarget->hnext->extravalue1 > hnext->extravalue1)
|
||||
orbittarget->hnext->extravalue1 -= (72*ANG1)/orbittarget->hnext->extravalue1;
|
||||
}
|
||||
}
|
||||
else // Make sure that SOMEONE has the emerald, at least!
|
||||
{
|
||||
@@ -995,9 +1050,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
||||
count = 1;
|
||||
|
||||
// scan the remaining thinkers
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -1045,9 +1100,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
||||
|
||||
// Now we RE-scan all the thinkers to find close objects to pull
|
||||
// in from the paraloop. Isn't this just so efficient?
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -1414,9 +1469,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
||||
EV_DoElevator(&junk, bridgeFall, false);
|
||||
|
||||
// scan the remaining thinkers to find koopa
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -2545,7 +2600,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
||||
|
||||
// scan the thinkers to make sure all the old pinch dummies are gone on death
|
||||
// this can happen if the boss was hurt earlier than expected
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue;
|
||||
|
||||
+5
-5
@@ -76,7 +76,7 @@ fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxse
|
||||
P_RemoveLighting(maxsector); // out with the old, in with the new
|
||||
flick = Z_Calloc(sizeof (*flick), PU_LEVSPEC, NULL);
|
||||
|
||||
P_AddThinker(&flick->thinker);
|
||||
P_AddThinker(THINK_MAIN, &flick->thinker);
|
||||
|
||||
flick->thinker.function.acp1 = (actionf_p1)T_FireFlicker;
|
||||
flick->sector = maxsector;
|
||||
@@ -155,7 +155,7 @@ void P_SpawnLightningFlash(sector_t *sector)
|
||||
|
||||
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
|
||||
|
||||
P_AddThinker(&flash->thinker);
|
||||
P_AddThinker(THINK_MAIN, &flash->thinker);
|
||||
|
||||
flash->thinker.function.acp1 = (actionf_p1)T_LightningFlash;
|
||||
flash->sector = sector;
|
||||
@@ -214,7 +214,7 @@ strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector,
|
||||
P_RemoveLighting(maxsector); // out with the old, in with the new
|
||||
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
|
||||
|
||||
P_AddThinker(&flash->thinker);
|
||||
P_AddThinker(THINK_MAIN, &flash->thinker);
|
||||
|
||||
flash->sector = maxsector;
|
||||
flash->darktime = darktime;
|
||||
@@ -289,7 +289,7 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector,
|
||||
P_RemoveLighting(maxsector); // out with the old, in with the new
|
||||
g = Z_Calloc(sizeof (*g), PU_LEVSPEC, NULL);
|
||||
|
||||
P_AddThinker(&g->thinker);
|
||||
P_AddThinker(THINK_MAIN, &g->thinker);
|
||||
|
||||
g->sector = maxsector;
|
||||
g->minlight = minsector->lightlevel;
|
||||
@@ -350,7 +350,7 @@ void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed)
|
||||
ll->thinker.function.acp1 = (actionf_p1)T_LightFade;
|
||||
sector->lightingdata = ll; // set it to the lightlevel_t
|
||||
|
||||
P_AddThinker(&ll->thinker); // add thinker
|
||||
P_AddThinker(THINK_MAIN, &ll->thinker); // add thinker
|
||||
|
||||
ll->sector = sector;
|
||||
ll->destlevel = destvalue;
|
||||
|
||||
+15
-8
@@ -60,15 +60,21 @@
|
||||
#define mariomode (maptol & TOL_MARIO)
|
||||
#define twodlevel (maptol & TOL_2D)
|
||||
|
||||
//
|
||||
// P_TICK
|
||||
//
|
||||
|
||||
// both the head and tail of the thinker list
|
||||
extern thinker_t thinkercap;
|
||||
typedef enum
|
||||
{
|
||||
THINK_POLYOBJ,
|
||||
THINK_MAIN,
|
||||
THINK_MOBJ,
|
||||
#ifdef ESLOPE
|
||||
THINK_DYNSLOPE,
|
||||
#endif
|
||||
THINK_PRECIP,
|
||||
NUM_THINKERLISTS
|
||||
} thinklistnum_t; /**< Thinker lists. */
|
||||
extern thinker_t thlist[];
|
||||
|
||||
void P_InitThinkers(void);
|
||||
void P_AddThinker(thinker_t *thinker);
|
||||
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker);
|
||||
void P_RemoveThinker(thinker_t *thinker);
|
||||
|
||||
//
|
||||
@@ -222,7 +228,7 @@ void P_PrecipitationEffects(void);
|
||||
|
||||
void P_RemoveMobj(mobj_t *th);
|
||||
boolean P_MobjWasRemoved(mobj_t *th);
|
||||
void P_RemoveSavegameMobj(mobj_t *th);
|
||||
void P_RemoveSavegameMobj(mobj_t *th, boolean preserveLevel);
|
||||
boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state);
|
||||
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
|
||||
//void P_RunShields(void);
|
||||
@@ -267,6 +273,7 @@ void P_ColorTeamMissile(mobj_t *missile, player_t *source);
|
||||
SINT8 P_MobjFlip(mobj_t *mobj);
|
||||
fixed_t P_GetMobjGravity(mobj_t *mo);
|
||||
FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
|
||||
FUNCMATH boolean P_IsProjectile(mobjtype_t type);
|
||||
|
||||
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
|
||||
|
||||
|
||||
+1
-1
@@ -3994,7 +3994,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
|
||||
thinker_t *think;
|
||||
elevator_t *crumbler;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)T_StartCrumble)
|
||||
continue;
|
||||
|
||||
@@ -1093,7 +1093,10 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *))
|
||||
{
|
||||
P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
|
||||
if (!func(mobj))
|
||||
{
|
||||
P_SetTarget(&bnext, NULL);
|
||||
return false;
|
||||
}
|
||||
if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue.
|
||||
|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
|
||||
{
|
||||
|
||||
+101
-76
@@ -50,6 +50,8 @@ static mobj_t *overlaycap = NULL;
|
||||
static mobj_t *shadowcap = NULL;
|
||||
mobj_t *waypointcap = NULL;
|
||||
|
||||
UINT32 globalmobjnum = 0; // this should never overflow, but 4 billion would be an impressive number to reach. \todo ensure this never happens
|
||||
|
||||
void P_InitCachedActions(void)
|
||||
{
|
||||
actioncachehead.prev = actioncachehead.next = &actioncachehead;
|
||||
@@ -395,6 +397,12 @@ boolean P_WeaponOrPanel(mobjtype_t type)
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean P_IsProjectile(mobjtype_t type)
|
||||
{
|
||||
return type == MT_THROWNBOUNCE || type == MT_THROWNINFINITY || type == MT_THROWNAUTOMATIC || type == MT_THROWNSCATTER
|
||||
|| type == MT_THROWNEXPLOSION || type == MT_THROWNGRENADE || type == MT_REDRING;
|
||||
}
|
||||
|
||||
//
|
||||
// P_EmeraldManager
|
||||
//
|
||||
@@ -421,10 +429,10 @@ boolean P_WeaponOrPanel(mobjtype_t type)
|
||||
spawnpoints[i] = NULL;
|
||||
}
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
|
||||
@@ -3498,10 +3506,10 @@ void P_DestroyRobots(void)
|
||||
mobj_t *mo;
|
||||
thinker_t *think;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
if (mo->health <= 0 || !(mo->flags & MF_ENEMY || mo->flags & MF_BOSS))
|
||||
@@ -4305,9 +4313,9 @@ static void P_Boss3Thinker(mobj_t *mobj)
|
||||
|
||||
// scan the thinkers to make sure all the old pinch dummies are gone before making new ones
|
||||
// this can happen if the boss was hurt earlier than expected
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4396,15 +4404,25 @@ static void P_Boss3Thinker(mobj_t *mobj)
|
||||
// scan the thinkers
|
||||
// to find a point that matches
|
||||
// the number
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == mobj->threshold)
|
||||
{
|
||||
P_SetTarget(&mobj->target, mo2);
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
if (mo2->type != MT_BOSS3WAYPOINT)
|
||||
continue;
|
||||
if (!mo2->spawnpoint)
|
||||
continue;
|
||||
if (mo2->spawnpoint->angle != mobj->threshold)
|
||||
continue;
|
||||
if (mo2->spawnpoint->extrainfo != mobj->cusval)
|
||||
continue;
|
||||
|
||||
P_SetTarget(&mobj->tracer, mo2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4643,8 +4661,8 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
||||
P_SetTarget(&seg->target, mobj);
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
seg->hnext = P_SpawnMobj(mobj->x, mobj->y, z, MT_EGGMOBILE4_MACE);
|
||||
seg->hnext->hprev = seg;
|
||||
P_SetTarget(&seg->hnext, P_SpawnMobj(mobj->x, mobj->y, z, MT_EGGMOBILE4_MACE));
|
||||
P_SetTarget(&seg->hnext->hprev, seg);
|
||||
seg = seg->hnext;
|
||||
}
|
||||
}
|
||||
@@ -5017,9 +5035,9 @@ static void P_Boss7Thinker(mobj_t *mobj)
|
||||
closestdist = 16384*FRACUNIT; // Just in case...
|
||||
|
||||
// Find waypoint he is closest to
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -5072,9 +5090,9 @@ static void P_Boss7Thinker(mobj_t *mobj)
|
||||
|
||||
// scan the thinkers to find
|
||||
// the waypoint to use
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -5195,19 +5213,19 @@ static void P_Boss9Thinker(mobj_t *mobj)
|
||||
|
||||
// Run through the thinkers ONCE and find all of the MT_BOSS9GATHERPOINT in the map.
|
||||
// Build a hoop linked list of 'em!
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
if (mo2->type == MT_BOSS9GATHERPOINT)
|
||||
{
|
||||
if (last)
|
||||
last->hnext = mo2;
|
||||
P_SetTarget(&last->hnext, mo2);
|
||||
else
|
||||
mobj->hnext = mo2;
|
||||
mo2->hprev = last;
|
||||
P_SetTarget(&mobj->hnext, mo2);
|
||||
P_SetTarget(&mo2->hprev, last);
|
||||
last = mo2;
|
||||
}
|
||||
}
|
||||
@@ -5629,9 +5647,9 @@ mobj_t *P_GetClosestAxis(mobj_t *source)
|
||||
fixed_t dist1, dist2 = 0;
|
||||
|
||||
// scan the thinkers to find the closest axis point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -6159,12 +6177,14 @@ static void P_RemoveOverlay(mobj_t *thing)
|
||||
{
|
||||
mobj_t *mo;
|
||||
for (mo = overlaycap; mo; mo = mo->hnext)
|
||||
if (mo->hnext == thing)
|
||||
{
|
||||
P_SetTarget(&mo->hnext, thing->hnext);
|
||||
P_SetTarget(&thing->hnext, NULL);
|
||||
return;
|
||||
}
|
||||
{
|
||||
if (mo->hnext != thing)
|
||||
continue;
|
||||
|
||||
P_SetTarget(&mo->hnext, thing->hnext);
|
||||
P_SetTarget(&thing->hnext, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void P_RunShadows(void)
|
||||
@@ -6346,6 +6366,9 @@ void P_MobjThinker(mobj_t *mobj)
|
||||
if (mobj->flags & MF_NOTHINK)
|
||||
return;
|
||||
|
||||
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint)
|
||||
return;
|
||||
|
||||
// Remove dead target/tracer.
|
||||
if (mobj->target && P_MobjWasRemoved(mobj->target))
|
||||
P_SetTarget(&mobj->target, NULL);
|
||||
@@ -9613,6 +9636,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
|
||||
mobj->type = type;
|
||||
mobj->info = info;
|
||||
mobj->localmobjnum = globalmobjnum++;
|
||||
|
||||
mobj->x = x;
|
||||
mobj->y = y;
|
||||
@@ -10013,7 +10037,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||
}
|
||||
|
||||
if (!(mobj->flags & MF_NOTHINK))
|
||||
P_AddThinker(&mobj->thinker);
|
||||
P_AddThinker(THINK_MOBJ, &mobj->thinker);
|
||||
|
||||
// Call action functions when the state is set
|
||||
if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC))
|
||||
@@ -10124,7 +10148,7 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster)
|
||||
mobj->eflags |= MFE_ONGROUND;
|
||||
|
||||
if (!(mobj->flags & MF_NOTHINK))
|
||||
P_AddThinker(&mobj->thinker);
|
||||
P_AddThinker(THINK_MOBJ, &mobj->thinker);
|
||||
|
||||
// Call action functions when the state is set
|
||||
if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC))
|
||||
@@ -10198,7 +10222,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
|
||||
mobj->momz = mobjinfo[type].speed;
|
||||
|
||||
mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker;
|
||||
P_AddThinker(&mobj->thinker);
|
||||
P_AddThinker(THINK_PRECIP, &mobj->thinker);
|
||||
|
||||
CalculatePrecipFloor(mobj);
|
||||
|
||||
@@ -10329,37 +10353,28 @@ void P_RemoveMobj(mobj_t *mobj)
|
||||
}
|
||||
}
|
||||
|
||||
// free block
|
||||
// DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
|
||||
if (mobj->flags & MF_NOTHINK && !mobj->thinker.next)
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
// Invalidate mobj_t data to cause crashes if accessed!
|
||||
memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
|
||||
#endif
|
||||
|
||||
// free block
|
||||
if (!mobj->thinker.next)
|
||||
{ // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through!
|
||||
INT32 prevreferences;
|
||||
if (!mobj->thinker.references)
|
||||
{
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
// Invalidate mobj_t data to cause crashes if accessed!
|
||||
memset(mobj, 0xff, sizeof(mobj_t));
|
||||
#endif
|
||||
Z_Free(mobj); // No refrences? Can be removed immediately! :D
|
||||
}
|
||||
else
|
||||
{ // Add thinker just to delay removing it until refrences are gone.
|
||||
mobj->flags &= ~MF_NOTHINK;
|
||||
P_AddThinker((thinker_t *)mobj);
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
// Invalidate mobj_t data to cause crashes if accessed!
|
||||
memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
|
||||
#endif
|
||||
P_RemoveThinker((thinker_t *)mobj);
|
||||
Z_Free(mobj); // No refrrences? Can be removed immediately! :D
|
||||
return;
|
||||
}
|
||||
|
||||
prevreferences = mobj->thinker.references;
|
||||
P_AddThinker(THINK_MOBJ, (thinker_t *)mobj);
|
||||
mobj->thinker.references = prevreferences;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
// Invalidate mobj_t data to cause crashes if accessed!
|
||||
memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
|
||||
#endif
|
||||
P_RemoveThinker((thinker_t *)mobj);
|
||||
}
|
||||
|
||||
P_RemoveThinker((thinker_t *)mobj);
|
||||
}
|
||||
|
||||
// This does not need to be added to Lua.
|
||||
@@ -10387,7 +10402,7 @@ void P_RemovePrecipMobj(precipmobj_t *mobj)
|
||||
}
|
||||
|
||||
// Clearing out stuff for savegames
|
||||
void P_RemoveSavegameMobj(mobj_t *mobj)
|
||||
void P_RemoveSavegameMobj(mobj_t *mobj, boolean preserveLevel)
|
||||
{
|
||||
// unlink from sector and block lists
|
||||
P_UnsetThingPosition(mobj);
|
||||
@@ -10400,7 +10415,15 @@ void P_RemoveSavegameMobj(mobj_t *mobj)
|
||||
}
|
||||
|
||||
// stop any playing sound
|
||||
S_StopSound(mobj);
|
||||
if (!preserveLevel)
|
||||
{
|
||||
S_StopSound(mobj);
|
||||
}
|
||||
else
|
||||
{
|
||||
// detach any playing sounds from this mobj, but don't destroy them as they might still be there
|
||||
S_DetachChannelsFromOrigin(mobj);
|
||||
}
|
||||
|
||||
// free block
|
||||
P_RemoveThinker((thinker_t *)mobj);
|
||||
@@ -10617,7 +10640,7 @@ void P_RespawnSpecials(void)
|
||||
{
|
||||
thinker_t *th;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
mobj_t *box;
|
||||
mobj_t *newmobj;
|
||||
@@ -11767,9 +11790,9 @@ ML_NOCLIMB : Direction not controllable
|
||||
mobj->health = (mthing->angle / 360) + 1;
|
||||
|
||||
// See if other starposts exist in this level that have the same value.
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -12047,7 +12070,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
|
||||
//mobj->hprev->hnext = mobj;
|
||||
}
|
||||
else
|
||||
mobj->hprev = mobj->hnext = NULL;
|
||||
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
|
||||
|
||||
nextmobj = mobj;
|
||||
}
|
||||
@@ -12073,11 +12096,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
|
||||
mobj->z -= mobj->height/2;
|
||||
|
||||
// Link all the collision sprites together.
|
||||
mobj->hnext = NULL;
|
||||
P_SetTarget(&mobj->hnext, NULL);
|
||||
P_SetTarget(&mobj->hprev, nextmobj);
|
||||
P_SetTarget(&mobj->hprev->hnext, mobj);
|
||||
//mobj->hprev = nextmobj;
|
||||
//mobj->hprev->hnext = mobj;
|
||||
|
||||
nextmobj = mobj;
|
||||
}
|
||||
@@ -12102,11 +12123,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
|
||||
mobj->z -= mobj->height/2;
|
||||
|
||||
// Link all the collision sprites together.
|
||||
mobj->hnext = NULL;
|
||||
P_SetTarget(&mobj->hnext, NULL);
|
||||
P_SetTarget(&mobj->hprev, nextmobj);
|
||||
P_SetTarget(&mobj->hprev->hnext, mobj);
|
||||
//mobj->hprev = nextmobj;
|
||||
//mobj->hprev->hnext = mobj;
|
||||
|
||||
nextmobj = mobj;
|
||||
}
|
||||
@@ -12195,7 +12214,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
|
||||
//mobj->hprev->hnext = mobj;
|
||||
}
|
||||
else
|
||||
mobj->hprev = mobj->hnext = NULL;
|
||||
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
|
||||
|
||||
nextmobj = mobj;
|
||||
}
|
||||
@@ -12232,11 +12251,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
|
||||
mobj->z -= mobj->height/2;
|
||||
|
||||
// Link all the collision sprites together.
|
||||
mobj->hnext = NULL;
|
||||
P_SetTarget(&mobj->hnext, NULL);
|
||||
P_SetTarget(&mobj->hprev, nextmobj);
|
||||
P_SetTarget(&mobj->hprev->hnext, mobj);
|
||||
//mobj->hprev = nextmobj;
|
||||
//mobj->hprev->hnext = mobj;
|
||||
|
||||
nextmobj = mobj;
|
||||
}
|
||||
@@ -12867,6 +12884,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
|
||||
angle_t an;
|
||||
fixed_t x, y, z, slope = 0;
|
||||
|
||||
|
||||
// angle at which you fire, is player angle
|
||||
an = angle;
|
||||
|
||||
@@ -12883,6 +12901,13 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
|
||||
|
||||
th = P_SpawnMobj(x, y, z, type);
|
||||
|
||||
if (cv_netslingdelay.value && issimulation && (tic_t)cv_netsteadyplayers.value >= targetsimtic - simtic && source == players[consoleplayer].mo)
|
||||
{
|
||||
z = 0x80000000; // don't make rings appear when using netslingdelay
|
||||
th->flags |= MF_NOTHINK;
|
||||
th->sprite = SPR_NULL;
|
||||
}
|
||||
|
||||
if (source->eflags & MFE_VERTICALFLIP)
|
||||
th->flags2 |= MF2_OBJECTFLIP;
|
||||
|
||||
|
||||
@@ -354,6 +354,7 @@ typedef struct mobj_s
|
||||
fixed_t waterbottom; // bottom of the water FOF the mobj is in
|
||||
|
||||
UINT32 mobjnum; // A unique number for this mobj. Used for restoring pointers on save games.
|
||||
UINT32 localmobjnum; // A unique number for this mobj stored locally for association when restoring savestates
|
||||
|
||||
fixed_t scale;
|
||||
fixed_t destscale;
|
||||
@@ -374,6 +375,8 @@ typedef struct mobj_s
|
||||
|
||||
boolean colorized; // Whether the mobj uses the rainbow colormap
|
||||
|
||||
boolean isculled; // Whether the mobj is being culled during simulations
|
||||
|
||||
// WARNING: New fields must be added separately to savegame and Lua.
|
||||
} mobj_t;
|
||||
|
||||
@@ -464,6 +467,10 @@ void P_SetScale(mobj_t *mobj, fixed_t newscale);
|
||||
void P_XYMovement(mobj_t *mo);
|
||||
void P_EmeraldManager(void);
|
||||
|
||||
extern INT32 modulothing;
|
||||
|
||||
extern UINT32 globalmobjnum;
|
||||
|
||||
#define MAXHUNTEMERALDS 64
|
||||
extern mapthing_t *huntemeralds[MAXHUNTEMERALDS];
|
||||
extern INT32 numhuntemeralds;
|
||||
|
||||
+162
-167
@@ -142,16 +142,6 @@ FUNCINLINE static ATTRINLINE void Polyobj_vecSub2(vertex_t *dst, vertex_t *v1, v
|
||||
dst->y = v1->y - v2->y;
|
||||
}
|
||||
|
||||
// Add the polyobject's thinker to the thinker list
|
||||
// Unlike P_AddThinker, this adds it to the front of the list instead of the back, so that carrying physics can work right. -Red
|
||||
FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th)
|
||||
{
|
||||
thinkercap.next->prev = th;
|
||||
th->next = thinkercap.next;
|
||||
th->prev = &thinkercap;
|
||||
thinkercap.next = th;
|
||||
}
|
||||
|
||||
//
|
||||
// P_PointInsidePolyobj
|
||||
//
|
||||
@@ -1504,31 +1494,31 @@ void Polyobj_InitLevel(void)
|
||||
|
||||
// run down the thinker list, count the number of spawn points, and save
|
||||
// the mobj_t pointers on a queue for use below.
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mobj_t *mo = (mobj_t *)th;
|
||||
|
||||
if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM ||
|
||||
mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM)
|
||||
{
|
||||
mobj_t *mo = (mobj_t *)th;
|
||||
++numPolyObjects;
|
||||
|
||||
if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM ||
|
||||
mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM)
|
||||
{
|
||||
++numPolyObjects;
|
||||
qitem = malloc(sizeof(mobjqitem_t));
|
||||
memset(qitem, 0, sizeof(mobjqitem_t));
|
||||
qitem->mo = mo;
|
||||
M_QueueInsert(&(qitem->mqitem), &spawnqueue);
|
||||
}
|
||||
else if (mo->info->doomednum == POLYOBJ_ANCHOR_DOOMEDNUM)
|
||||
{
|
||||
++numAnchors;
|
||||
|
||||
qitem = malloc(sizeof(mobjqitem_t));
|
||||
memset(qitem, 0, sizeof(mobjqitem_t));
|
||||
qitem->mo = mo;
|
||||
M_QueueInsert(&(qitem->mqitem), &spawnqueue);
|
||||
}
|
||||
else if (mo->info->doomednum == POLYOBJ_ANCHOR_DOOMEDNUM)
|
||||
{
|
||||
++numAnchors;
|
||||
|
||||
qitem = malloc(sizeof(mobjqitem_t));
|
||||
memset(qitem, 0, sizeof(mobjqitem_t));
|
||||
qitem->mo = mo;
|
||||
M_QueueInsert(&(qitem->mqitem), &anchorqueue);
|
||||
}
|
||||
qitem = malloc(sizeof(mobjqitem_t));
|
||||
memset(qitem, 0, sizeof(mobjqitem_t));
|
||||
qitem->mo = mo;
|
||||
M_QueueInsert(&(qitem->mqitem), &anchorqueue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1548,6 +1538,11 @@ void Polyobj_InitLevel(void)
|
||||
qitem = (mobjqitem_t *)M_QueueIterator(&spawnqueue);
|
||||
|
||||
Polyobj_spawnPolyObj(i, qitem->mo, qitem->mo->spawnpoint->angle);
|
||||
|
||||
PolyObjects[i].origx = qitem->mo->x;
|
||||
PolyObjects[i].origy = qitem->mo->y;
|
||||
PolyObjects[i].origz = qitem->mo->z;
|
||||
PolyObjects[i].origangle = qitem->mo->spawnpoint->angle;
|
||||
}
|
||||
|
||||
// move polyobjects to spawn points
|
||||
@@ -1639,7 +1634,7 @@ void T_PolyObjRotate(polyrotate_t *th)
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyObjRotate: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1724,7 +1719,7 @@ void T_PolyObjMove(polymove_t *th)
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyObjMove: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1797,7 +1792,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyObjWaypoint: thinker with invalid id %d removed.", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1808,9 +1803,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
|
||||
|
||||
// Find out target first.
|
||||
// We redo this each tic to make savegame compatibility easier.
|
||||
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
|
||||
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
@@ -1889,9 +1884,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
|
||||
CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n");
|
||||
|
||||
// Find next waypoint
|
||||
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
|
||||
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
@@ -1899,8 +1894,85 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == th->sequence)
|
||||
if (mo2->threshold != th->sequence)
|
||||
continue;
|
||||
|
||||
if (th->direction == -1)
|
||||
{
|
||||
if (mo2->health == target->health - 1)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo2->health == target->health + 1)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!waypoint && th->wrap) // If specified, wrap waypoints
|
||||
{
|
||||
if (!th->continuous)
|
||||
{
|
||||
th->wrap = 0;
|
||||
th->stophere = true;
|
||||
}
|
||||
|
||||
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold != th->sequence)
|
||||
continue;
|
||||
|
||||
if (th->direction == -1)
|
||||
{
|
||||
if (waypoint == NULL)
|
||||
waypoint = mo2;
|
||||
else if (mo2->health > waypoint->health)
|
||||
waypoint = mo2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo2->health == 0)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!waypoint && th->comeback) // Come back to the start
|
||||
{
|
||||
th->direction = -th->direction;
|
||||
|
||||
if (!th->continuous)
|
||||
th->comeback = false;
|
||||
|
||||
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold != th->sequence)
|
||||
continue;
|
||||
|
||||
if (th->direction == -1)
|
||||
{
|
||||
if (mo2->health == target->health - 1)
|
||||
@@ -1919,83 +1991,6 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!waypoint && th->wrap) // If specified, wrap waypoints
|
||||
{
|
||||
if (!th->continuous)
|
||||
{
|
||||
th->wrap = 0;
|
||||
th->stophere = true;
|
||||
}
|
||||
|
||||
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == th->sequence)
|
||||
{
|
||||
if (th->direction == -1)
|
||||
{
|
||||
if (waypoint == NULL)
|
||||
waypoint = mo2;
|
||||
else if (mo2->health > waypoint->health)
|
||||
waypoint = mo2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo2->health == 0)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!waypoint && th->comeback) // Come back to the start
|
||||
{
|
||||
th->direction = -th->direction;
|
||||
|
||||
if (!th->continuous)
|
||||
th->comeback = false;
|
||||
|
||||
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == th->sequence)
|
||||
{
|
||||
if (th->direction == -1)
|
||||
{
|
||||
if (mo2->health == target->health - 1)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo2->health == target->health + 1)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (waypoint)
|
||||
@@ -2071,7 +2066,7 @@ void T_PolyDoorSlide(polyslidedoor_t *th)
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSlide: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -2176,7 +2171,7 @@ void T_PolyDoorSwing(polyswingdoor_t *th)
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSwing: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -2274,8 +2269,8 @@ void T_PolyObjDisplace(polydisplace_t *th)
|
||||
I_Error("T_PolyDoorSwing: thinker has invalid id %d\n", th->polyObjNum);
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSwing: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyObjDisplace: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -2333,7 +2328,7 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata)
|
||||
// create a new thinker
|
||||
th = Z_Malloc(sizeof(polyrotate_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotate;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
po->thinker = &th->thinker;
|
||||
|
||||
// set fields
|
||||
@@ -2398,7 +2393,7 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata)
|
||||
// create a new thinker
|
||||
th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyObjMove;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
po->thinker = &th->thinker;
|
||||
|
||||
// set fields
|
||||
@@ -2459,7 +2454,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
|
||||
// create a new thinker
|
||||
th = Z_Malloc(sizeof(polywaypoint_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyObjWaypoint;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
po->thinker = &th->thinker;
|
||||
|
||||
// set fields
|
||||
@@ -2477,9 +2472,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
|
||||
th->stophere = false;
|
||||
|
||||
// Find the first waypoint we need to use
|
||||
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
|
||||
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
@@ -2487,31 +2482,31 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == th->sequence)
|
||||
if (mo2->threshold != th->sequence)
|
||||
continue;
|
||||
|
||||
if (th->direction == -1) // highest waypoint #
|
||||
{
|
||||
if (th->direction == -1) // highest waypoint #
|
||||
if (mo2->health == 0)
|
||||
last = mo2;
|
||||
else
|
||||
{
|
||||
if (mo2->health == 0)
|
||||
last = mo2;
|
||||
else
|
||||
{
|
||||
if (first == NULL)
|
||||
first = mo2;
|
||||
else if (mo2->health > first->health)
|
||||
first = mo2;
|
||||
}
|
||||
}
|
||||
else // waypoint 0
|
||||
{
|
||||
if (mo2->health == 0)
|
||||
if (first == NULL)
|
||||
first = mo2;
|
||||
else
|
||||
{
|
||||
if (last == NULL)
|
||||
last = mo2;
|
||||
else if (mo2->health > last->health)
|
||||
last = mo2;
|
||||
}
|
||||
else if (mo2->health > first->health)
|
||||
first = mo2;
|
||||
}
|
||||
}
|
||||
else // waypoint 0
|
||||
{
|
||||
if (mo2->health == 0)
|
||||
first = mo2;
|
||||
else
|
||||
{
|
||||
if (last == NULL)
|
||||
last = mo2;
|
||||
else if (mo2->health > last->health)
|
||||
last = mo2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2548,9 +2543,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
|
||||
|
||||
// Find the actual target movement waypoint
|
||||
target = first;
|
||||
/*for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
|
||||
/*for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
|
||||
{
|
||||
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)wp;
|
||||
@@ -2558,23 +2553,23 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == th->sequence)
|
||||
if (mo2->threshold != th->sequence)
|
||||
continue;
|
||||
|
||||
if (th->direction == -1) // highest waypoint #
|
||||
{
|
||||
if (th->direction == -1) // highest waypoint #
|
||||
if (mo2->health == first->health - 1)
|
||||
{
|
||||
if (mo2->health == first->health - 1)
|
||||
{
|
||||
target = mo2;
|
||||
break;
|
||||
}
|
||||
target = mo2;
|
||||
break;
|
||||
}
|
||||
else // waypoint 0
|
||||
}
|
||||
else // waypoint 0
|
||||
{
|
||||
if (mo2->health == first->health + 1)
|
||||
{
|
||||
if (mo2->health == first->health + 1)
|
||||
{
|
||||
target = mo2;
|
||||
break;
|
||||
}
|
||||
target = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
@@ -2605,7 +2600,7 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata)
|
||||
// allocate and add a new slide door thinker
|
||||
th = Z_Malloc(sizeof(polyslidedoor_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSlide;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
|
||||
// point the polyobject to this thinker
|
||||
po->thinker = &th->thinker;
|
||||
@@ -2653,7 +2648,7 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata)
|
||||
// allocate and add a new swing door thinker
|
||||
th = Z_Malloc(sizeof(polyswingdoor_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSwing;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
|
||||
// point the polyobject to this thinker
|
||||
po->thinker = &th->thinker;
|
||||
@@ -2735,7 +2730,7 @@ INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata)
|
||||
// create a new thinker
|
||||
th = Z_Malloc(sizeof(polydisplace_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyObjDisplace;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
po->thinker = &th->thinker;
|
||||
|
||||
// set fields
|
||||
@@ -2772,7 +2767,7 @@ void T_PolyObjFlag(polymove_t *th)
|
||||
#else
|
||||
{
|
||||
CONS_Debug(DBG_POLYOBJ, "T_PolyObjFlag: thinker with invalid id %d removed.\n", th->polyObjNum);
|
||||
P_RemoveThinkerDelayed(&th->thinker);
|
||||
P_RemoveThinker(&th->thinker);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -2836,7 +2831,7 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata)
|
||||
// create a new thinker
|
||||
th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
|
||||
th->thinker.function.acp1 = (actionf_p1)T_PolyObjFlag;
|
||||
PolyObj_AddThinker(&th->thinker);
|
||||
P_AddThinker(THINK_POLYOBJ, &th->thinker);
|
||||
po->thinker = &th->thinker;
|
||||
|
||||
// set fields
|
||||
|
||||
@@ -104,6 +104,10 @@ typedef struct polyobj_s
|
||||
|
||||
// these are saved for netgames, so do not let Lua touch these!
|
||||
INT32 spawnflags; // Flags the polyobject originally spawned with
|
||||
INT32 spawntrans; // Translucency the polyobject originally spawned with
|
||||
|
||||
fixed_t origx, origy, origz;
|
||||
INT16 origangle;
|
||||
} polyobj_t;
|
||||
|
||||
//
|
||||
|
||||
+1709
-395
File diff suppressed because it is too large.
Load diff
+17
-10
@@ -18,16 +18,6 @@
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
// Persistent storage/archiving.
|
||||
// These are the load / save game routines.
|
||||
|
||||
void P_SaveGame(void);
|
||||
void P_SaveNetGame(void);
|
||||
boolean P_LoadGame(INT16 mapoverride);
|
||||
boolean P_LoadNetGame(void);
|
||||
|
||||
mobj_t *P_FindNewPosition(UINT32 oldposition);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 skincolor;
|
||||
@@ -40,6 +30,23 @@ typedef struct
|
||||
UINT16 emeralds;
|
||||
} savedata_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 buffer[16 * 1024 * 1024]; // 16 megs per frame should do
|
||||
} savestate_t;
|
||||
|
||||
// Persistent storage/archiving.
|
||||
// These are the load / save game routines.
|
||||
|
||||
void P_SaveGame(void);
|
||||
void P_SaveNetGame(void);
|
||||
void P_SaveGameState(savestate_t* savestate);
|
||||
boolean P_LoadGame(INT16 mapoverride);
|
||||
boolean P_LoadNetGame(boolean preserveLevel);
|
||||
boolean P_LoadGameState(const savestate_t* savestate);
|
||||
|
||||
mobj_t *P_FindNewPosition(UINT32 oldposition);
|
||||
|
||||
extern savedata_t savedata;
|
||||
extern UINT8 *save_p;
|
||||
|
||||
|
||||
+19
-12
@@ -832,10 +832,10 @@ void P_ReloadRings(void)
|
||||
mapthing_t *hoopsToRespawn[4096];
|
||||
mapthing_t *mt = mapthings;
|
||||
|
||||
// scan the thinkers to find rings/wings/hoops to unset
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
// scan the thinkers to find rings/spheres/hoops to unset
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)th;
|
||||
@@ -2411,18 +2411,13 @@ static void P_LevelInitStuff(void)
|
||||
void P_LoadThingsOnly(void)
|
||||
{
|
||||
// Search through all the thinkers.
|
||||
mobj_t *mo;
|
||||
thinker_t *think;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
|
||||
if (mo)
|
||||
P_RemoveMobj(mo);
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
P_RemoveMobj((mobj_t *)think);
|
||||
}
|
||||
|
||||
P_LevelInitStuff();
|
||||
@@ -2775,6 +2770,11 @@ static boolean P_CanSave(void)
|
||||
*/
|
||||
boolean P_SetupLevel(boolean skipprecip)
|
||||
{
|
||||
if (issimulation)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// use gamemap to get map number.
|
||||
// 99% of the things already did, so.
|
||||
// Map header should always be in place at this point
|
||||
@@ -2793,6 +2793,13 @@ boolean P_SetupLevel(boolean skipprecip)
|
||||
CON_Drawer(); // let the user know what we are going to do
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
|
||||
// Reset the palette
|
||||
if (rendermode != render_none)
|
||||
V_SetPaletteLump("PLAYPAL");
|
||||
|
||||
// Invalidate simulation save states
|
||||
InvalidateSavestates();
|
||||
|
||||
// Initialize sector node list.
|
||||
P_Initsecnode();
|
||||
|
||||
|
||||
+76
-79
@@ -1594,7 +1594,7 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj, sector_t *sector)
|
||||
e->sector = sector;
|
||||
e->timer = (line->backsector->ceilingheight>>FRACBITS)+(line->backsector->floorheight>>FRACBITS);
|
||||
P_SetTarget(&e->caller, mobj); // Use P_SetTarget to make sure the mobj doesn't get freed while we're delaying.
|
||||
P_AddThinker(&e->thinker);
|
||||
P_AddThinker(THINK_MAIN, &e->thinker);
|
||||
}
|
||||
|
||||
/** Used by P_LinedefExecute to check a trigger linedef's conditions
|
||||
@@ -2058,7 +2058,7 @@ void P_SwitchWeather(INT32 weathernum)
|
||||
thinker_t *think;
|
||||
precipmobj_t *precipmobj;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
|
||||
continue; // not a precipmobj thinker
|
||||
@@ -2074,7 +2074,7 @@ void P_SwitchWeather(INT32 weathernum)
|
||||
precipmobj_t *precipmobj;
|
||||
state_t *st;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
|
||||
continue; // not a precipmobj thinker
|
||||
@@ -2934,7 +2934,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
||||
scroll_t *scroller;
|
||||
thinker_t *th;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)T_Scroll)
|
||||
continue;
|
||||
@@ -3273,10 +3273,10 @@ void P_SetupSignExit(player_t *player)
|
||||
|
||||
// didn't find any signposts in the exit sector.
|
||||
// spin all signposts in the level then.
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
thing = (mobj_t *)think;
|
||||
if (thing->type != MT_SIGN)
|
||||
@@ -3320,23 +3320,18 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
|
||||
{
|
||||
thinker_t *think;
|
||||
mobj_t *mo;
|
||||
INT32 specialnum = 0;
|
||||
INT32 specialnum = (flag == MT_REDFLAG) ? 3 : 4;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
|
||||
if (mo->type != flag)
|
||||
continue;
|
||||
|
||||
if (mo->type == MT_REDFLAG)
|
||||
specialnum = 3;
|
||||
else if (mo->type == MT_BLUEFLAG)
|
||||
specialnum = 4;
|
||||
|
||||
if (GETSECSPECIAL(mo->subsector->sector->special, 4) == specialnum)
|
||||
return true;
|
||||
else if (mo->subsector->sector->ffloors) // Check the 3D floors
|
||||
@@ -3351,9 +3346,11 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
|
||||
if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum)
|
||||
continue;
|
||||
|
||||
if (mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
|
||||
&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
|
||||
return true;
|
||||
if (!(mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
|
||||
&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3763,14 +3760,14 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
||||
|
||||
// Find the center of the Eggtrap and release all the pretty animals!
|
||||
// The chimps are my friends.. heeheeheheehehee..... - LouisJM
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
if (mo2->type == MT_EGGTRAP)
|
||||
P_KillMobj(mo2, NULL, player->mo);
|
||||
if (mo2->type != MT_EGGTRAP)
|
||||
continue;
|
||||
P_KillMobj(mo2, NULL, player->mo);
|
||||
}
|
||||
|
||||
// clear the special so you can't push the button twice.
|
||||
@@ -4100,19 +4097,22 @@ DoneSection2:
|
||||
|
||||
// scan the thinkers
|
||||
// to find the first waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence
|
||||
&& mo2->health == 0)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
if (mo2->health != 0)
|
||||
continue;
|
||||
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!waypoint)
|
||||
@@ -4176,20 +4176,22 @@ DoneSection2:
|
||||
|
||||
// scan the thinkers
|
||||
// to find the last waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence)
|
||||
{
|
||||
if (!waypoint)
|
||||
waypoint = mo2;
|
||||
else if (mo2->health > waypoint->health)
|
||||
waypoint = mo2;
|
||||
}
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if (!waypoint)
|
||||
waypoint = mo2;
|
||||
else if (mo2->health > waypoint->health)
|
||||
waypoint = mo2;
|
||||
}
|
||||
|
||||
if (!waypoint)
|
||||
@@ -4391,9 +4393,9 @@ DoneSection2:
|
||||
|
||||
// scan the thinkers
|
||||
// to find the first waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4429,9 +4431,9 @@ DoneSection2:
|
||||
}
|
||||
|
||||
// Find waypoint before this one (waypointlow)
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4456,9 +4458,9 @@ DoneSection2:
|
||||
}
|
||||
|
||||
// Find waypoint after this one (waypointhigh)
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4978,11 +4980,6 @@ void P_UpdateSpecials(void)
|
||||
// POINT LIMIT
|
||||
P_CheckPointLimit();
|
||||
|
||||
#ifdef ESLOPE
|
||||
// Dynamic slopeness
|
||||
P_RunDynamicSlopes();
|
||||
#endif
|
||||
|
||||
// ANIMATE TEXTURES
|
||||
for (anim = anims; anim < lastanim; anim++)
|
||||
{
|
||||
@@ -5151,7 +5148,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
|
||||
|
||||
// Just initialise both of these to placate the compiler.
|
||||
i = 0;
|
||||
th = thinkercap.next;
|
||||
th = thlist[THINK_MAIN].next;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@@ -5161,7 +5158,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
|
||||
th = secthinkers[sec2num].thinkers[i];
|
||||
else break;
|
||||
}
|
||||
else if (th == &thinkercap)
|
||||
else if (th == &thlist[THINK_MAIN])
|
||||
break;
|
||||
|
||||
// Should this FOF have spikeness?
|
||||
@@ -5250,7 +5247,7 @@ static void P_AddSpikeThinker(sector_t *sec, INT32 referrer)
|
||||
|
||||
// create and initialize new thinker
|
||||
spikes = Z_Calloc(sizeof (*spikes), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&spikes->thinker);
|
||||
P_AddThinker(THINK_MAIN, &spikes->thinker);
|
||||
|
||||
spikes->thinker.function.acp1 = (actionf_p1)T_SpikeSector;
|
||||
|
||||
@@ -5272,7 +5269,7 @@ static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline)
|
||||
|
||||
// create and initialize new thinker
|
||||
floater = Z_Calloc(sizeof (*floater), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&floater->thinker);
|
||||
P_AddThinker(THINK_MAIN, &floater->thinker);
|
||||
|
||||
floater->thinker.function.acp1 = (actionf_p1)T_FloatSector;
|
||||
|
||||
@@ -5296,7 +5293,7 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
|
||||
|
||||
// create an initialize new thinker
|
||||
bridge = Z_Calloc(sizeof (*bridge), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&bridge->thinker);
|
||||
P_AddThinker(THINK_MAIN, &bridge->thinker);
|
||||
|
||||
bridge->thinker.function.acp1 = (actionf_p1)T_BridgeThinker;
|
||||
|
||||
@@ -5330,7 +5327,7 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline)
|
||||
|
||||
// create and initialize new elevator thinker
|
||||
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&block->thinker);
|
||||
P_AddThinker(THINK_MAIN, &block->thinker);
|
||||
|
||||
block->thinker.function.acp1 = (actionf_p1)T_MarioBlockChecker;
|
||||
block->sourceline = sourceline;
|
||||
@@ -5359,7 +5356,7 @@ static void P_AddRaiseThinker(sector_t *sec, line_t *sourceline)
|
||||
levelspecthink_t *raise;
|
||||
|
||||
raise = Z_Calloc(sizeof (*raise), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&raise->thinker);
|
||||
P_AddThinker(THINK_MAIN, &raise->thinker);
|
||||
|
||||
raise->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
|
||||
|
||||
@@ -5398,7 +5395,7 @@ static void P_AddOldAirbob(sector_t *sec, line_t *sourceline, boolean noadjust)
|
||||
levelspecthink_t *airbob;
|
||||
|
||||
airbob = Z_Calloc(sizeof (*airbob), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&airbob->thinker);
|
||||
P_AddThinker(THINK_MAIN, &airbob->thinker);
|
||||
|
||||
airbob->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
|
||||
|
||||
@@ -5459,7 +5456,7 @@ static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, lin
|
||||
|
||||
// create and initialize new elevator thinker
|
||||
thwomp = Z_Calloc(sizeof (*thwomp), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&thwomp->thinker);
|
||||
P_AddThinker(THINK_MAIN, &thwomp->thinker);
|
||||
|
||||
thwomp->thinker.function.acp1 = (actionf_p1)T_ThwompSector;
|
||||
|
||||
@@ -5495,7 +5492,7 @@ static inline void P_AddNoEnemiesThinker(sector_t *sec, line_t *sourceline)
|
||||
|
||||
// create and initialize new thinker
|
||||
nobaddies = Z_Calloc(sizeof (*nobaddies), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&nobaddies->thinker);
|
||||
P_AddThinker(THINK_MAIN, &nobaddies->thinker);
|
||||
|
||||
nobaddies->thinker.function.acp1 = (actionf_p1)T_NoEnemiesSector;
|
||||
|
||||
@@ -5517,7 +5514,7 @@ static inline void P_AddEachTimeThinker(sector_t *sec, line_t *sourceline)
|
||||
|
||||
// create and initialize new thinker
|
||||
eachtime = Z_Calloc(sizeof (*eachtime), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&eachtime->thinker);
|
||||
P_AddThinker(THINK_MAIN, &eachtime->thinker);
|
||||
|
||||
eachtime->thinker.function.acp1 = (actionf_p1)T_EachTimeThinker;
|
||||
|
||||
@@ -5539,7 +5536,7 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
|
||||
|
||||
// create and initialize new elevator thinker
|
||||
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
|
||||
P_AddThinker(&elevator->thinker);
|
||||
P_AddThinker(THINK_MAIN, &elevator->thinker);
|
||||
|
||||
elevator->thinker.function.acp1 = (actionf_p1)T_CameraScanner;
|
||||
elevator->type = elevateBounce;
|
||||
@@ -5633,7 +5630,7 @@ static inline void EV_AddLaserThinker(sector_t *sec, sector_t *sec2, line_t *lin
|
||||
|
||||
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
|
||||
|
||||
P_AddThinker(&flash->thinker);
|
||||
P_AddThinker(THINK_MAIN, &flash->thinker);
|
||||
|
||||
flash->thinker.function.acp1 = (actionf_p1)T_LaserFlash;
|
||||
flash->ffloor = ffloor;
|
||||
@@ -5762,7 +5759,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
||||
secthinkers = Z_Calloc(numsectors * sizeof(thinkerlist_t), PU_STATIC, NULL);
|
||||
|
||||
// Firstly, find out how many there are in each sector
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 == (actionf_p1)T_SpikeSector)
|
||||
secthinkers[((levelspecthink_t *)th)->sector - sectors].count++;
|
||||
@@ -5782,7 +5779,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
||||
}
|
||||
|
||||
// Finally, populate the lists.
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
|
||||
{
|
||||
size_t secnum = (size_t)-1;
|
||||
|
||||
@@ -6677,14 +6674,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
|
||||
sectors[s].midmap = lines[i].frontsector->midmap;
|
||||
break;
|
||||
|
||||
#ifdef ESLOPE // Slope copy specials. Handled here for sanity.
|
||||
case 720:
|
||||
case 721:
|
||||
case 722:
|
||||
P_CopySectorSlope(&lines[i]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ESLOPE // Slope copy specials. Handled here for sanity.
|
||||
case 720:
|
||||
case 721:
|
||||
case 722:
|
||||
P_CopySectorSlope(&lines[i]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -7040,7 +7037,7 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3
|
||||
if ((s->control = control) != -1)
|
||||
s->last_height = sectors[control].floorheight + sectors[control].ceilingheight;
|
||||
s->affectee = affectee;
|
||||
P_AddThinker(&s->thinker);
|
||||
P_AddThinker(THINK_MAIN, &s->thinker);
|
||||
}
|
||||
|
||||
/** Adds a wall scroller.
|
||||
@@ -7199,7 +7196,7 @@ static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t o
|
||||
d->exists = true;
|
||||
d->timer = 1;
|
||||
|
||||
P_AddThinker(&d->thinker);
|
||||
P_AddThinker(THINK_MAIN, &d->thinker);
|
||||
}
|
||||
|
||||
/** Makes a FOF appear/disappear
|
||||
@@ -7293,7 +7290,7 @@ static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32
|
||||
else
|
||||
f->roverfriction = false;
|
||||
|
||||
P_AddThinker(&f->thinker);
|
||||
P_AddThinker(THINK_MAIN, &f->thinker);
|
||||
}
|
||||
|
||||
/** Applies friction to all things in a sector.
|
||||
@@ -7481,7 +7478,7 @@ static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *
|
||||
p->z = p->source->z;
|
||||
}
|
||||
p->affectee = affectee;
|
||||
P_AddThinker(&p->thinker);
|
||||
P_AddThinker(THINK_MAIN, &p->thinker);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+71
-36
@@ -37,8 +37,8 @@ tic_t leveltime;
|
||||
// but the first element must be thinker_t.
|
||||
//
|
||||
|
||||
// Both the head and tail of the thinker list.
|
||||
thinker_t thinkercap;
|
||||
// The entries will behave like both the head and tail of the lists.
|
||||
thinker_t thlist[NUM_THINKERLISTS];
|
||||
|
||||
void Command_Numthinkers_f(void)
|
||||
{
|
||||
@@ -46,6 +46,9 @@ void Command_Numthinkers_f(void)
|
||||
INT32 count = 0;
|
||||
actionf_p1 action;
|
||||
thinker_t *think;
|
||||
thinklistnum_t start = 0;
|
||||
thinklistnum_t end = NUM_THINKERLISTS - 1;
|
||||
thinklistnum_t i;
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
{
|
||||
@@ -72,6 +75,7 @@ void Command_Numthinkers_f(void)
|
||||
switch (num)
|
||||
{
|
||||
case 1:
|
||||
start = end = THINK_MOBJ;
|
||||
action = (actionf_p1)P_MobjThinker;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
|
||||
break;
|
||||
@@ -84,14 +88,17 @@ void Command_Numthinkers_f(void)
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
|
||||
break;*/
|
||||
case 2:
|
||||
start = end = THINK_PRECIP;
|
||||
action = (actionf_p1)P_NullPrecipThinker;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");
|
||||
break;
|
||||
case 3:
|
||||
start = end = THINK_MAIN;
|
||||
action = (actionf_p1)T_Friction;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "T_Friction");
|
||||
break;
|
||||
case 4:
|
||||
start = end = THINK_MAIN;
|
||||
action = (actionf_p1)T_Pusher;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "T_Pusher");
|
||||
break;
|
||||
@@ -104,12 +111,15 @@ void Command_Numthinkers_f(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
if (think->function.acp1 != action)
|
||||
continue;
|
||||
for (think = thlist[i].next; think != &thlist[i]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != action)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
CONS_Printf("%d\n", count);
|
||||
@@ -141,9 +151,9 @@ void Command_CountMobjs_f(void)
|
||||
|
||||
count = 0;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
if (((mobj_t *)th)->type == i)
|
||||
@@ -161,9 +171,9 @@ void Command_CountMobjs_f(void)
|
||||
{
|
||||
count = 0;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
if (((mobj_t *)th)->type == i)
|
||||
@@ -180,20 +190,24 @@ void Command_CountMobjs_f(void)
|
||||
//
|
||||
void P_InitThinkers(void)
|
||||
{
|
||||
thinkercap.prev = thinkercap.next = &thinkercap;
|
||||
waypointcap = NULL;
|
||||
UINT8 i;
|
||||
for (i = 0; i < NUM_THINKERLISTS; i++)
|
||||
thlist[i].prev = thlist[i].next = &thlist[i];
|
||||
|
||||
waypointcap = NULL; //Hack transplant
|
||||
}
|
||||
|
||||
//
|
||||
// P_AddThinker
|
||||
// Adds a new thinker at the end of the list.
|
||||
//
|
||||
void P_AddThinker(thinker_t *thinker)
|
||||
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
|
||||
{
|
||||
thinkercap.prev->next = thinker;
|
||||
thinker->next = &thinkercap;
|
||||
thinker->prev = thinkercap.prev;
|
||||
thinkercap.prev = thinker;
|
||||
#ifdef PARANOIA
|
||||
I_Assert(n >= 0 && n < NUM_THINKERLISTS);
|
||||
#endif
|
||||
|
||||
thlist[n].prev->next = thinker;
|
||||
thinker->next = &thlist[n];
|
||||
thinker->prev = thlist[n].prev;
|
||||
thlist[n].prev = thinker;
|
||||
|
||||
thinker->references = 0; // killough 11/98: init reference counter to 0
|
||||
}
|
||||
@@ -216,22 +230,33 @@ static thinker_t *currentthinker;
|
||||
// remove it, and set currentthinker to one node preceeding it, so
|
||||
// that the next step in P_RunThinkers() will get its successor.
|
||||
//
|
||||
void P_RemoveThinkerDelayed(void *pthinker)
|
||||
void P_RemoveThinkerDelayed(thinker_t *thinker)
|
||||
{
|
||||
thinker_t *thinker = pthinker;
|
||||
if (!thinker->references)
|
||||
thinker_t *next;
|
||||
#ifdef PARANOIA
|
||||
#define BEENAROUNDBIT (0x40000000) // has to be sufficiently high that it's unlikely to happen in regular gameplay. If you change this, pay attention to the bit pattern of INT32_MIN.
|
||||
if (thinker->references & ~BEENAROUNDBIT)
|
||||
{
|
||||
{
|
||||
/* Remove from main thinker list */
|
||||
thinker_t *next = thinker->next;
|
||||
/* Note that currentthinker is guaranteed to point to us,
|
||||
* and since we're freeing our memory, we had better change that. So
|
||||
* point it to thinker->prev, so the iterator will correctly move on to
|
||||
* thinker->prev->next = thinker->next */
|
||||
(next->prev = currentthinker = thinker->prev)->next = next;
|
||||
}
|
||||
Z_Free(thinker);
|
||||
if (thinker->references & BEENAROUNDBIT) // Usually gets cleared up in one frame; what's going on here, then?
|
||||
CONS_Printf("Number of potentially faulty references: %d\n", (thinker->references & ~BEENAROUNDBIT));
|
||||
thinker->references |= BEENAROUNDBIT;
|
||||
return;
|
||||
}
|
||||
#undef BEENAROUNDBIT
|
||||
#else
|
||||
if (thinker->references)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Remove from main thinker list */
|
||||
next = thinker->next;
|
||||
/* Note that currentthinker is guaranteed to point to us,
|
||||
* and since we're freeing our memory, we had better change that. So
|
||||
* point it to thinker->prev, so the iterator will correctly move on to
|
||||
* thinker->prev->next = thinker->next */
|
||||
(next->prev = currentthinker = thinker->prev)->next = next;
|
||||
|
||||
Z_Free(thinker);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -251,7 +276,7 @@ void P_RemoveThinker(thinker_t *thinker)
|
||||
#ifdef HAVE_BLUA
|
||||
LUA_InvalidateUserdata(thinker);
|
||||
#endif
|
||||
thinker->function.acp1 = P_RemoveThinkerDelayed;
|
||||
thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -299,11 +324,21 @@ if ((*mop = targ) != NULL) // Set new target and if non-NULL, increase its count
|
||||
//
|
||||
static inline void P_RunThinkers(void)
|
||||
{
|
||||
for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = currentthinker->next)
|
||||
size_t i;
|
||||
for (i = 0; i < NUM_THINKERLISTS; i++)
|
||||
{
|
||||
if (currentthinker->function.acp1)
|
||||
for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next)
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
I_Assert(currentthinker->function.acp1 != NULL);
|
||||
#endif
|
||||
if (currentthinker->function.acp1 == P_MobjThinker && issimulation && ((mobj_t*)currentthinker)->isculled)
|
||||
continue; // apply distance culling
|
||||
|
||||
currentthinker->function.acp1(currentthinker);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ void Command_CountMobjs_f(void);
|
||||
void P_Ticker(boolean run);
|
||||
void P_PreTicker(INT32 frames);
|
||||
void P_DoTeamscrambling(void);
|
||||
void P_RemoveThinkerDelayed(void *pthinker); //killed
|
||||
void P_RemoveThinkerDelayed(thinker_t *thinker); //killed
|
||||
mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98
|
||||
|
||||
#endif
|
||||
+395
-201
@@ -356,14 +356,18 @@ void P_ResetScore(player_t *player)
|
||||
|
||||
// scan the thinkers
|
||||
// to find the egg capsule with the lowest mare
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_EGGCAPSULE && mo2->health > 0)
|
||||
if (mo2->type != MT_EGGCAPSULE)
|
||||
continue;
|
||||
if (mo2->health <= 0)
|
||||
continue;
|
||||
|
||||
{
|
||||
const UINT8 threshold = (UINT8)mo2->threshold;
|
||||
if (mare == 255)
|
||||
@@ -457,34 +461,34 @@ UINT8 P_FindHighestLap(void)
|
||||
|
||||
// scan the thinkers
|
||||
// to find the closest axis point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_AXIS)
|
||||
{
|
||||
if (mo2->threshold == mare)
|
||||
{
|
||||
if (closestaxis == NULL)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
lowestaxisnum = mo2->health;
|
||||
dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
|
||||
}
|
||||
else if (mo2->health < lowestaxisnum)
|
||||
{
|
||||
dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
|
||||
if (mo2->type != MT_AXIS)
|
||||
continue;
|
||||
|
||||
if (dist1 < dist2)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
lowestaxisnum = mo2->health;
|
||||
dist2 = dist1;
|
||||
}
|
||||
}
|
||||
if (mo2->threshold != mare)
|
||||
continue;
|
||||
|
||||
if (closestaxis == NULL)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
lowestaxisnum = mo2->health;
|
||||
dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
|
||||
}
|
||||
else if (mo2->health < lowestaxisnum)
|
||||
{
|
||||
dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
|
||||
|
||||
if (dist1 < dist2)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
lowestaxisnum = mo2->health;
|
||||
dist2 = dist1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -508,9 +512,9 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
|
||||
|
||||
// scan the thinkers
|
||||
// to find the closest axis point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -519,11 +523,13 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
|
||||
if (!(mo2->flags2 & MF2_AXIS))
|
||||
return NULL;
|
||||
|
||||
if (mo2->type == MT_AXIS)
|
||||
{
|
||||
if (mo2->health == axisnum && mo2->threshold == mare)
|
||||
return mo2;
|
||||
}
|
||||
if (mo2->type != MT_AXIS)
|
||||
continue;
|
||||
if (mo2->health != axisnum)
|
||||
continue;
|
||||
if (mo2->threshold != mare)
|
||||
continue;
|
||||
return mo2;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -541,9 +547,9 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
|
||||
|
||||
// scan the thinkers
|
||||
// to find the closest axis point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -552,11 +558,13 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
|
||||
if (!(mo2->flags2 & MF2_AXIS))
|
||||
return NULL;
|
||||
|
||||
if (mo2->type == type)
|
||||
{
|
||||
if (mo2->health == axisnum && mo2->threshold == mare)
|
||||
return mo2;
|
||||
}
|
||||
if (mo2->type != type)
|
||||
continue;
|
||||
if (mo2->health != axisnum)
|
||||
continue;
|
||||
if (mo2->threshold != mare)
|
||||
continue;
|
||||
return mo2;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -580,32 +588,33 @@ void P_TransferToAxis(player_t *player, INT32 axisnum)
|
||||
|
||||
// scan the thinkers
|
||||
// to find the closest axis point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_AXIS)
|
||||
{
|
||||
if (mo2->health == axisnum && mo2->threshold == mare)
|
||||
{
|
||||
if (closestaxis == NULL)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
|
||||
if (mo2->type != MT_AXIS)
|
||||
continue;
|
||||
if (mo2->health != axisnum)
|
||||
continue;
|
||||
if (mo2->threshold != mare)
|
||||
continue;
|
||||
|
||||
if (dist1 < dist2)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = dist1;
|
||||
}
|
||||
}
|
||||
if (closestaxis == NULL)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
|
||||
|
||||
if (dist1 < dist2)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = dist1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -679,9 +688,9 @@ static void P_DeNightserizePlayer(player_t *player)
|
||||
}
|
||||
|
||||
// Check to see if the player should be killed.
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -1593,9 +1602,9 @@ void P_SpawnShieldOrb(player_t *player)
|
||||
}
|
||||
|
||||
// blaze through the thinkers to see if an orb already exists!
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
shieldobj = (mobj_t *)th;
|
||||
@@ -2813,7 +2822,7 @@ static void P_DoClimbing(player_t *player) // SRB2kart - unused
|
||||
angle_t sideangle;
|
||||
fixed_t dx, dy;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)T_Scroll)
|
||||
continue;
|
||||
@@ -3293,7 +3302,8 @@ static void P_DoTeeter(player_t *player) // SRB2kart - unused.
|
||||
if (teeter) // only bother with objects as a last resort if you were already teetering
|
||||
{
|
||||
mobj_t *oldtmthing = tmthing;
|
||||
tmthing = teeterer = player->mo;
|
||||
teeterer = player->mo;
|
||||
P_SetTarget(&tmthing, teeterer);
|
||||
teeterxl = teeterxh = player->mo->x;
|
||||
teeteryl = teeteryh = player->mo->y;
|
||||
couldteeter = false;
|
||||
@@ -3307,7 +3317,7 @@ static void P_DoTeeter(player_t *player) // SRB2kart - unused.
|
||||
}
|
||||
teeterdone:
|
||||
teeter = solidteeter;
|
||||
tmthing = oldtmthing; // restore old tmthing, goodness knows what the game does with this before mobj thinkers
|
||||
P_SetTarget(&tmthing, oldtmthing); // restore old tmthing, goodness knows what the game does with this before mobj thinkers
|
||||
}
|
||||
}
|
||||
if (teeter)
|
||||
@@ -3366,10 +3376,16 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // SRB2kart - unused.
|
||||
mobj_t *mo = NULL;
|
||||
player->pflags |= PF_ATTACKDOWN;
|
||||
|
||||
//if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring.
|
||||
// goto firenormal; //code repetition sucks.
|
||||
// Bounce ring
|
||||
if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering])
|
||||
if (mo)
|
||||
{
|
||||
if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING)
|
||||
{
|
||||
if (cv_netslingdelay.value && issimulation && (tic_t)cv_netsteadyplayers.value >= targetsimtic - simtic && mo->target == players[consoleplayer].mo)
|
||||
// don't fire it yet
|
||||
return;
|
||||
|
||||
const boolean nblockmap = !(mo->flags & MF_NOBLOCKMAP);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (player->health <= 1)
|
||||
return;
|
||||
@@ -3620,11 +3636,177 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // SRB2kart - unused.
|
||||
#endif
|
||||
) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
|
||||
{
|
||||
player->pflags |= PF_SPINNING;
|
||||
//P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
|
||||
if (!player->spectator)
|
||||
S_StartSound(player->mo, sfx_spin);
|
||||
player->pflags |= PF_USEDOWN;
|
||||
case CA2_SPINDASH: // Spinning and Spindashing
|
||||
// Start revving
|
||||
if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<<FRACBITS, player->mo->scale)
|
||||
&& !player->mo->momz && onground && !(player->pflags & (PF_USEDOWN|PF_SPINNING))
|
||||
&& canstand)
|
||||
{
|
||||
player->mo->momx = player->cmomx;
|
||||
player->mo->momy = player->cmomy;
|
||||
player->pflags |= (PF_USEDOWN|PF_STARTDASH|PF_SPINNING);
|
||||
player->dashspeed = player->mindash;
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_SPINDASH);
|
||||
if (!player->spectator)
|
||||
S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh.
|
||||
}
|
||||
// Revving
|
||||
else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH))
|
||||
{
|
||||
if (player->dashspeed < player->maxdash)
|
||||
{
|
||||
#define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash)
|
||||
fixed_t soundcalculation = chargecalculation;
|
||||
player->dashspeed += FRACUNIT;
|
||||
if (!player->spectator && soundcalculation != chargecalculation)
|
||||
S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh.
|
||||
#undef chargecalculation
|
||||
}
|
||||
if (player->revitem && !(leveltime % 5)) // Now spawn the color thok circle.
|
||||
{
|
||||
P_SpawnSpinMobj(player, player->revitem);
|
||||
if (demorecording)
|
||||
G_GhostAddRev();
|
||||
}
|
||||
}
|
||||
|
||||
// If not moving up or down, and travelling faster than a speed of five while not holding
|
||||
// down the spin button and not spinning.
|
||||
// AKA Just go into a spin on the ground, you idiot. ;)
|
||||
else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
|
||||
&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
|
||||
|| !canstand) && !(player->pflags & (PF_USEDOWN|PF_SPINNING)))
|
||||
{
|
||||
player->pflags |= (PF_USEDOWN|PF_SPINNING);
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
|
||||
if (!player->spectator)
|
||||
S_StartSound(player->mo, sfx_spin);
|
||||
}
|
||||
else
|
||||
// Catapult the player from a spindash rev!
|
||||
if (onground && !(player->pflags & PF_USEDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
|
||||
{
|
||||
player->pflags &= ~PF_STARTDASH;
|
||||
if (player->powers[pw_carry] == CR_BRAKGOOP)
|
||||
player->dashspeed = 0;
|
||||
|
||||
if (!((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE))
|
||||
{
|
||||
if (player->dashspeed)
|
||||
{
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
|
||||
P_InstaThrust(player->mo, player->mo->angle, (player->speed = FixedMul(player->dashspeed, player->mo->scale))); // catapult forward ho!!
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
|
||||
player->pflags &= ~PF_SPINNING;
|
||||
}
|
||||
|
||||
if (!player->spectator)
|
||||
S_StartSound(player->mo, sfx_zoom);
|
||||
}
|
||||
|
||||
player->dashspeed = 0;
|
||||
}
|
||||
break;
|
||||
case CA2_GUNSLINGER:
|
||||
if (!player->mo->momz && onground && !player->weapondelay && canstand)
|
||||
{
|
||||
if (player->speed > FixedMul(10<<FRACBITS, player->mo->scale))
|
||||
{}
|
||||
else
|
||||
{
|
||||
mobj_t *lockon = P_LookForEnemies(player, false, true);
|
||||
if (lockon)
|
||||
{
|
||||
if (P_IsLocalPlayer(player)) // Only display it on your own view.
|
||||
{
|
||||
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
|
||||
P_SetTarget(&visual->target, lockon);
|
||||
}
|
||||
}
|
||||
if ((cmd->buttons & BT_USE) && !(player->pflags & PF_USEDOWN))
|
||||
{
|
||||
mobj_t *bullet;
|
||||
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_FIRE);
|
||||
|
||||
#define zpos(posmo) (posmo->z + (posmo->height - mobjinfo[player->revitem].height)/2)
|
||||
if (lockon)
|
||||
{
|
||||
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y);
|
||||
bullet = P_SpawnPointMissile(player->mo, lockon->x, lockon->y, zpos(lockon), player->revitem, player->mo->x, player->mo->y, zpos(player->mo));
|
||||
if (!demoplayback || P_AnalogMove(player))
|
||||
{
|
||||
if (player == &players[consoleplayer])
|
||||
localangle = player->mo->angle;
|
||||
else if (player == &players[secondarydisplayplayer])
|
||||
localangle2 = player->mo->angle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bullet = P_SpawnPointMissile(player->mo, player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, FRACUNIT), player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, FRACUNIT), zpos(player->mo), player->revitem, player->mo->x, player->mo->y, zpos(player->mo));
|
||||
if (bullet)
|
||||
{
|
||||
bullet->flags &= ~MF_NOGRAVITY;
|
||||
bullet->momx >>= 1;
|
||||
bullet->momy >>= 1;
|
||||
}
|
||||
}
|
||||
player->drawangle = player->mo->angle;
|
||||
#undef zpos
|
||||
|
||||
P_SetTarget(&player->mo->tracer, NULL);
|
||||
player->mo->momx >>= 1;
|
||||
player->mo->momy >>= 1;
|
||||
player->pflags |= PF_USEDOWN;
|
||||
P_SetWeaponDelay(player, TICRATE/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CA2_MELEE: // Melee attack
|
||||
if (player->panim != PA_ABILITY2 && (cmd->buttons & BT_USE)
|
||||
&& !player->mo->momz && onground && !(player->pflags & PF_USEDOWN)
|
||||
&& canstand)
|
||||
{
|
||||
P_ResetPlayer(player);
|
||||
player->pflags |= PF_THOKKED;
|
||||
#if 0
|
||||
if ((player->charability == CA_TWINSPIN) && (player->speed > FixedMul(player->runspeed, player->mo->scale)))
|
||||
{
|
||||
P_DoJump(player, false);
|
||||
player->pflags &= ~PF_STARTJUMP;
|
||||
player->mo->momz = FixedMul(player->mo->momz, 3*FRACUNIT/2); // NOT 1.5 times the jump height, but 2.25 times.
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN);
|
||||
S_StartSound(player->mo, sfx_s3k8b);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
player->mo->z += P_MobjFlip(player->mo);
|
||||
P_SetObjectMomZ(player->mo, player->mindash, false);
|
||||
if (player->mo->eflags & MFE_UNDERWATER)
|
||||
player->mo->momz >>= 1;
|
||||
#if 0
|
||||
if (FixedMul(player->speed, FINECOSINE(((player->mo->angle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT) & FINEMASK)) < FixedMul(player->maxdash, player->mo->scale))
|
||||
#else
|
||||
if (player->speed < FixedMul(player->maxdash, player->mo->scale))
|
||||
#endif
|
||||
{
|
||||
player->drawangle = player->mo->angle;
|
||||
P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
|
||||
}
|
||||
player->mo->momx += player->cmomx;
|
||||
player->mo->momy += player->cmomy;
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE);
|
||||
S_StartSound(player->mo, sfx_s3k42);
|
||||
}
|
||||
player->pflags |= PF_USEDOWN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3706,9 +3888,9 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range)
|
||||
if (player->powers[pw_super]) // increase range when super
|
||||
range *= 2;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4388,9 +4570,9 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
|
||||
fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags2 & MF2_AMBUSH ? -1 : 1);
|
||||
|
||||
// Find next waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4398,24 +4580,24 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
|
||||
// Axis things are only at beginning of list.
|
||||
if (!(mo2->flags2 & MF2_AXIS))
|
||||
break;
|
||||
if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
|
||||
continue;
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if ((mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE)
|
||||
&& mo2->threshold == sequence)
|
||||
if (player->pflags & PF_TRANSFERTOCLOSEST)
|
||||
{
|
||||
if (player->pflags & PF_TRANSFERTOCLOSEST)
|
||||
{
|
||||
if (mo2->health == player->axis1->health)
|
||||
transfer1 = mo2;
|
||||
else if (mo2->health == player->axis2->health)
|
||||
transfer2 = mo2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo2->health == player->mo->target->health)
|
||||
transfer1 = mo2;
|
||||
else if (mo2->health == player->mo->target->health + 1)
|
||||
transfer2 = mo2;
|
||||
}
|
||||
if (mo2->health == player->axis1->health)
|
||||
transfer1 = mo2;
|
||||
else if (mo2->health == player->axis2->health)
|
||||
transfer2 = mo2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo2->health == player->mo->target->health)
|
||||
transfer1 = mo2;
|
||||
else if (mo2->health == player->mo->target->health + 1)
|
||||
transfer2 = mo2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4424,9 +4606,9 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
|
||||
// Look for a wrapper point.
|
||||
if (!transfer1)
|
||||
{
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4434,27 +4616,28 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
|
||||
// Axis things are only at beginning of list.
|
||||
if (!(mo2->flags2 & MF2_AXIS))
|
||||
break;
|
||||
if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
|
||||
continue;
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == sequence && (mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
|
||||
if (!transfer1)
|
||||
{
|
||||
if (!transfer1)
|
||||
{
|
||||
transfer1 = mo2;
|
||||
transfer1last = true;
|
||||
}
|
||||
else if (mo2->health > transfer1->health)
|
||||
{
|
||||
transfer1 = mo2;
|
||||
transfer1last = true;
|
||||
}
|
||||
transfer1 = mo2;
|
||||
transfer1last = true;
|
||||
}
|
||||
else if (mo2->health > transfer1->health)
|
||||
{
|
||||
transfer1 = mo2;
|
||||
transfer1last = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!transfer2)
|
||||
{
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -4462,19 +4645,20 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
|
||||
// Axis things are only at beginning of list.
|
||||
if (!(mo2->flags2 & MF2_AXIS))
|
||||
break;
|
||||
if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
|
||||
continue;
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == sequence && (mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
|
||||
if (!transfer2)
|
||||
{
|
||||
if (!transfer2)
|
||||
{
|
||||
transfer2 = mo2;
|
||||
transfer2last = true;
|
||||
}
|
||||
else if (mo2->health > transfer2->health)
|
||||
{
|
||||
transfer2 = mo2;
|
||||
transfer2last = true;
|
||||
}
|
||||
transfer2 = mo2;
|
||||
transfer2last = true;
|
||||
}
|
||||
else if (mo2->health > transfer2->health)
|
||||
{
|
||||
transfer2 = mo2;
|
||||
transfer2last = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4999,36 +5183,34 @@ static void P_NiGHTSMovement(player_t *player)
|
||||
|
||||
// scan the thinkers
|
||||
// to find the closest axis point
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_AXIS)
|
||||
{
|
||||
if (mo2->threshold == player->mare)
|
||||
{
|
||||
if (closestaxis == NULL)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = R_PointToDist2(newx, newy, mo2->x, mo2->y)-mo2->radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist1 = R_PointToDist2(newx, newy, mo2->x, mo2->y)-mo2->radius;
|
||||
if (mo2->type != MT_AXIS)
|
||||
continue;
|
||||
if (mo2->threshold != player->mare)
|
||||
continue;
|
||||
|
||||
if (dist1 < dist2)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = dist1;
|
||||
}
|
||||
}
|
||||
if (closestaxis == NULL)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = R_PointToDist2(newx, newy, mo2->x, mo2->y) - mo2->radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist1 = R_PointToDist2(newx, newy, mo2->x, mo2->y) - mo2->radius;
|
||||
|
||||
if (dist1 < dist2)
|
||||
{
|
||||
closestaxis = mo2;
|
||||
dist2 = dist1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
P_SetTarget(&player->mo->target, closestaxis);
|
||||
}
|
||||
|
||||
@@ -5718,9 +5900,9 @@ static void P_MovePlayer(player_t *player)
|
||||
thinker_t *th;
|
||||
mobj_t *mo2;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -6279,7 +6461,20 @@ static void P_MovePlayer(player_t *player)
|
||||
/* // SRB2kart - what's a shield? Never heard of it. Never happened. Nope.
|
||||
if (cmd->buttons & BT_BRAKE) // Spin button effects
|
||||
{
|
||||
if (player->pflags & PF_JUMPED) // If the player is jumping
|
||||
mobj_t *lockon = NULL;
|
||||
if (!player->powers[pw_super] && player->powers[pw_shield] == SH_ATTRACT && !(player->pflags & PF_THOKKED))
|
||||
{
|
||||
if ((lockon = P_LookForEnemies(player, false, false)))
|
||||
{
|
||||
if (P_IsLocalPlayer(player)) // Only display it on your own view.
|
||||
{
|
||||
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
|
||||
P_SetTarget(&visual->target, lockon);
|
||||
P_SetMobjStateNF(visual, visual->info->spawnstate+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cmd->buttons & BT_USE) // Spin button effects
|
||||
{
|
||||
if (!(player->pflags & PF_USEDOWN)) // If the player is not holding down BT_BRAKE
|
||||
{
|
||||
@@ -6535,9 +6730,9 @@ static void P_DoZoomTube(player_t *player)
|
||||
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
|
||||
|
||||
// Find next waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -6545,15 +6740,17 @@ static void P_DoZoomTube(player_t *player)
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == sequence)
|
||||
{
|
||||
if ((reverse && mo2->health == player->mo->tracer->health - 1)
|
||||
|| (!reverse && mo2->health == player->mo->tracer->health + 1))
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if (reverse && mo2->health != player->mo->tracer->health - 1)
|
||||
continue;
|
||||
|
||||
if (!reverse && mo2->health != player->mo->tracer->health + 1)
|
||||
continue;
|
||||
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (waypoint)
|
||||
@@ -6677,9 +6874,9 @@ static void P_DoRopeHang(player_t *player) // SRB2kart - unused.
|
||||
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
|
||||
|
||||
// Find next waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -6687,14 +6884,14 @@ static void P_DoRopeHang(player_t *player) // SRB2kart - unused.
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == sequence)
|
||||
{
|
||||
if (mo2->health == player->mo->tracer->health + 1)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if (mo2->health != player->mo->tracer->health + 1)
|
||||
continue;
|
||||
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(player->mo->tracer->flags & MF_SLIDEME) && !waypoint)
|
||||
@@ -6702,9 +6899,9 @@ static void P_DoRopeHang(player_t *player) // SRB2kart - unused.
|
||||
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, wrapping to start...\n");
|
||||
|
||||
// Wrap around back to first waypoint
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -6712,14 +6909,14 @@ static void P_DoRopeHang(player_t *player) // SRB2kart - unused.
|
||||
if (mo2->type != MT_TUBEWAYPOINT)
|
||||
continue;
|
||||
|
||||
if (mo2->threshold == sequence)
|
||||
{
|
||||
if (mo2->health == 0)
|
||||
{
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mo2->threshold != sequence)
|
||||
continue;
|
||||
|
||||
if (mo2->health != 0)
|
||||
continue;
|
||||
|
||||
waypoint = mo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6770,25 +6967,22 @@ static void P_DoRopeHang(player_t *player) // SRB2kart - unused.
|
||||
static void P_NukeAllPlayers(player_t *player)
|
||||
{
|
||||
mobj_t *mo;
|
||||
thinker_t *think;
|
||||
UINT8 i;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
|
||||
if (!mo->player)
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
if (!players[i].mo)
|
||||
continue;
|
||||
if (players[i].mo == player->mo)
|
||||
continue;
|
||||
if (players[i].mo->health <= 0)
|
||||
continue;
|
||||
|
||||
if (mo->health <= 0) // dead
|
||||
continue;
|
||||
|
||||
if (mo == player->mo)
|
||||
continue;
|
||||
|
||||
P_DamageMobj(mo, player->mo, player->mo, 1);
|
||||
P_DamageMobj(players[i].mo, player->mo, player->mo, 1, 0);
|
||||
}
|
||||
|
||||
CONS_Printf(M_GetText("%s caused a world of pain.\n"), player_names[player-players]);
|
||||
@@ -6822,10 +7016,10 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
|
||||
}
|
||||
}
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
|
||||
@@ -6902,10 +7096,10 @@ boolean P_LookForEnemies(player_t *player)
|
||||
mobj_t *closestmo = NULL;
|
||||
angle_t an;
|
||||
|
||||
for (think = thinkercap.next; think != &thinkercap; think = think->next)
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
continue; // not a mobj thinker
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo = (mobj_t *)think;
|
||||
if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)))
|
||||
@@ -7027,9 +7221,9 @@ void P_FindEmerald(void)
|
||||
|
||||
// scan the remaining thinkers
|
||||
// to find all emeralds
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
@@ -8355,9 +8549,9 @@ void P_PlayerThink(player_t *player)
|
||||
fixed_t y = player->mo->y;
|
||||
fixed_t z = player->mo->z;
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
+2
-2
@@ -1653,8 +1653,8 @@ void R_PrecacheLevel(void)
|
||||
spritepresent = calloc(numsprites, sizeof (*spritepresent));
|
||||
if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel");
|
||||
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
|
||||
spritepresent[((mobj_t *)th)->sprite] = 1;
|
||||
|
||||
spritememory = 0;
|
||||
|
||||
+69
-29
@@ -46,7 +46,7 @@ extern INT32 msg_id;
|
||||
// 3D Sound Interface
|
||||
#include "hardware/hw3sound.h"
|
||||
#else
|
||||
static INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch, sfxinfo_t *sfxinfo);
|
||||
static INT32 S_AdjustSoundParams(const mobj_t *listener, fixed_t x, fixed_t y, fixed_t z, INT32 *vol, INT32 *sep, INT32 *pitch, sfxinfo_t *sfxinfo);
|
||||
#endif
|
||||
|
||||
CV_PossibleValue_t soundvolume_cons_t[] = {{0, "MIN"}, {31, "MAX"}, {0, NULL}};
|
||||
@@ -154,19 +154,6 @@ consvar_t cv_playsoundifunfocused = {"playsoundsifunfocused", "No", CV_SAVE|CV_C
|
||||
// percent attenuation from front to back
|
||||
#define S_IFRACVOL 30
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// sound information (if null, channel avail.)
|
||||
sfxinfo_t *sfxinfo;
|
||||
|
||||
// origin of sound
|
||||
const void *origin;
|
||||
|
||||
// handle of the sound being played
|
||||
INT32 handle;
|
||||
|
||||
} channel_t;
|
||||
|
||||
// the set of channels available
|
||||
static channel_t *channels = NULL;
|
||||
static INT32 numofchannels = 0;
|
||||
@@ -248,6 +235,7 @@ static INT32 S_getChannel(const void *origin, sfxinfo_t *sfxinfo)
|
||||
// channel is decided to be cnum.
|
||||
c->sfxinfo = sfxinfo;
|
||||
c->origin = origin;
|
||||
c->isdetached = false;
|
||||
|
||||
return cnum;
|
||||
}
|
||||
@@ -450,6 +438,9 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
|
||||
if (sound_disabled || !sound_started)
|
||||
return;
|
||||
|
||||
if (((simtic != targetsimtic - 1 && origin == listenmobj) || (origin != listenmobj && issimulation))) // local player sounds play immediately during simulations
|
||||
return;
|
||||
|
||||
// Don't want a sound? Okay then...
|
||||
if (sfx_id == sfx_None)
|
||||
return;
|
||||
@@ -583,7 +574,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
|
||||
if (origin && origin != listenmobj2)
|
||||
{
|
||||
INT32 rc;
|
||||
rc = S_AdjustSoundParams(listenmobj2, origin, &volume, &sep, &pitch, sfx);
|
||||
rc = S_AdjustSoundParams(listenmobj2, origin->x, origin->y, origin->z, &volume, &sep, &pitch, sfx);
|
||||
|
||||
if (!rc)
|
||||
goto dontplay; // Maybe the other player can hear it...
|
||||
@@ -639,7 +630,7 @@ dontplay:
|
||||
if (origin && origin != listenmobj3)
|
||||
{
|
||||
INT32 rc;
|
||||
rc = S_AdjustSoundParams(listenmobj3, origin, &volume, &sep, &pitch, sfx);
|
||||
rc = S_AdjustSoundParams(listenmobj3, origin->x, origin->y, origin->z , &volume, &sep, &pitch, sfx);
|
||||
|
||||
if (!rc)
|
||||
goto dontplay3; // Maybe the other player can hear it...
|
||||
@@ -695,7 +686,7 @@ dontplay3:
|
||||
if (origin && origin != listenmobj4)
|
||||
{
|
||||
INT32 rc;
|
||||
rc = S_AdjustSoundParams(listenmobj4, origin, &volume, &sep, &pitch, sfx);
|
||||
rc = S_AdjustSoundParams(listenmobj4, origin->x, origin->y, origin->z, &volume, &sep, &pitch, sfx);
|
||||
|
||||
if (!rc)
|
||||
goto dontplay4; // Maybe the other player can hear it...
|
||||
@@ -749,7 +740,7 @@ dontplay4:
|
||||
if (origin && origin != listenmobj)
|
||||
{
|
||||
INT32 rc;
|
||||
rc = S_AdjustSoundParams(listenmobj, origin, &volume, &sep, &pitch, sfx);
|
||||
rc = S_AdjustSoundParams(listenmobj, origin->x, origin->y, origin->z, &volume, &sep, &pitch, sfx);
|
||||
|
||||
if (!rc)
|
||||
return;
|
||||
@@ -1053,6 +1044,8 @@ void S_UpdateSounds(void)
|
||||
{
|
||||
if (I_SoundIsPlaying(c->handle))
|
||||
{
|
||||
boolean isspatial = c->origin || c->isdetached;
|
||||
|
||||
// initialize parameters
|
||||
volume = 255; // 8 bits internal volume precision
|
||||
pitch = NORM_PITCH;
|
||||
@@ -1063,11 +1056,28 @@ void S_UpdateSounds(void)
|
||||
|
||||
// check non-local sounds for distance clipping
|
||||
// or modify their params
|
||||
if (c->origin && ((c->origin != players[consoleplayer].mo)
|
||||
if (isspatial &&
|
||||
(c->origin && ((c->origin != players[consoleplayer].mo)
|
||||
|| (splitscreen && c->origin != players[displayplayers[1]].mo)
|
||||
|| (splitscreen > 1 && c->origin != players[displayplayers[2]].mo)
|
||||
|| (splitscreen > 2 && c->origin != players[displayplayers[3]].mo)))
|
||||
|| (splitscreen > 2 && c->origin != players[displayplayers[3]].mo))))
|
||||
{
|
||||
fixed_t x, y, z;
|
||||
const mobj_t *soundmobj = c->origin;
|
||||
|
||||
if (c->isdetached)
|
||||
{
|
||||
x = c->detachedx;
|
||||
y = c->detachedy;
|
||||
z = c->detachedz;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = soundmobj->x;
|
||||
y = soundmobj->y;
|
||||
z = soundmobj->z;
|
||||
}
|
||||
|
||||
// Whomever is closer gets the sound, but only in splitscreen.
|
||||
if (splitscreen)
|
||||
{
|
||||
@@ -1102,25 +1112,25 @@ void S_UpdateSounds(void)
|
||||
if (p == 1)
|
||||
{
|
||||
// Player 2 gets the sound
|
||||
audible = S_AdjustSoundParams(listenmobj2, c->origin, &volume, &sep, &pitch,
|
||||
audible = S_AdjustSoundParams(listenmobj2, x, y, z, &volume, &sep, &pitch,
|
||||
c->sfxinfo);
|
||||
}
|
||||
else if (p == 2)
|
||||
{
|
||||
// Player 3 gets the sound
|
||||
audible = S_AdjustSoundParams(listenmobj3, c->origin, &volume, &sep, &pitch,
|
||||
audible = S_AdjustSoundParams(listenmobj3, x, y, z, &volume, &sep, &pitch,
|
||||
c->sfxinfo);
|
||||
}
|
||||
else if (p == 3)
|
||||
{
|
||||
// Player 4 gets the sound
|
||||
audible = S_AdjustSoundParams(listenmobj4, c->origin, &volume, &sep, &pitch,
|
||||
audible = S_AdjustSoundParams(listenmobj4, x, y, z, &volume, &sep, &pitch,
|
||||
c->sfxinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player 1 gets the sound
|
||||
audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch,
|
||||
audible = S_AdjustSoundParams(listenmobj, x, y, z, &volume, &sep, &pitch,
|
||||
c->sfxinfo);
|
||||
}
|
||||
|
||||
@@ -1133,7 +1143,7 @@ void S_UpdateSounds(void)
|
||||
else if (listenmobj && !splitscreen)
|
||||
{
|
||||
// In the case of a single player, he or she always should get updated sound.
|
||||
audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch,
|
||||
audible = S_AdjustSoundParams(listenmobj, x, y, z, &volume, &sep, &pitch,
|
||||
c->sfxinfo);
|
||||
|
||||
if (audible)
|
||||
@@ -1203,6 +1213,37 @@ static void S_StopChannel(INT32 cnum)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// S_DetachChannelFromSource
|
||||
//
|
||||
// Detaches a sound channel from the object it came from, leaving it loose
|
||||
//
|
||||
void S_DetachChannelsFromOrigin(void* origin)
|
||||
{
|
||||
int i;
|
||||
mobj_t* originmobj = (mobj_t*)origin;
|
||||
for (i = 0; i < numofchannels; i++)
|
||||
{
|
||||
if (channels[i].origin == origin)
|
||||
{
|
||||
// small hack: player-made sounds should stay hearable
|
||||
if (originmobj->player != &players[displayplayers[0]] &&
|
||||
originmobj->player != &players[displayplayers[1]] &&
|
||||
originmobj->player != &players[displayplayers[2]] &&
|
||||
originmobj->player != &players[displayplayers[3]]
|
||||
)
|
||||
{
|
||||
channels[i].isdetached = true;
|
||||
channels[i].detachedx = originmobj->x;
|
||||
channels[i].detachedy = originmobj->y;
|
||||
channels[i].detachedz = originmobj->z;
|
||||
}
|
||||
|
||||
channels[i].origin = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// S_CalculateSoundDistance
|
||||
//
|
||||
@@ -1237,7 +1278,7 @@ fixed_t S_CalculateSoundDistance(fixed_t sx1, fixed_t sy1, fixed_t sz1, fixed_t
|
||||
// If the sound is not audible, returns a 0.
|
||||
// Otherwise, modifies parameters and returns 1.
|
||||
//
|
||||
INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch,
|
||||
INT32 S_AdjustSoundParams(const mobj_t *listener, fixed_t x, fixed_t y, fixed_t z, INT32 *vol, INT32 *sep, INT32 *pitch,
|
||||
sfxinfo_t *sfxinfo)
|
||||
{
|
||||
fixed_t approx_dist;
|
||||
@@ -1318,8 +1359,7 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v
|
||||
}
|
||||
else
|
||||
{
|
||||
approx_dist = S_CalculateSoundDistance(listensource.x, listensource.y, listensource.z,
|
||||
source->x, source->y, source->z);
|
||||
approx_dist = S_CalculateSoundDistance(listensource.x, listensource.y, listensource.z, x, y, z);
|
||||
}
|
||||
|
||||
// Ring loss, deaths, etc, should all be heard louder.
|
||||
@@ -1337,7 +1377,7 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v
|
||||
return 0;
|
||||
|
||||
// angle of source to listener
|
||||
angle = R_PointToAngle2(listensource.x, listensource.y, source->x, source->y);
|
||||
angle = R_PointToAngle2(listensource.x, listensource.y, x, y);
|
||||
|
||||
if (angle > listensource.angle)
|
||||
angle = angle - listensource.angle;
|
||||
|
||||
@@ -74,6 +74,40 @@ typedef struct {
|
||||
angle_t angle;
|
||||
} listener_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// sound information (if null, channel avail.)
|
||||
sfxinfo_t *sfxinfo;
|
||||
|
||||
// origin of sound
|
||||
const void *origin;
|
||||
|
||||
// handle of the sound being played
|
||||
INT32 handle;
|
||||
|
||||
// whether the sound is detached from its source (sound panning should not be changed)
|
||||
boolean isdetached;
|
||||
|
||||
// positioning for detached sounds
|
||||
fixed_t detachedx, detachedy, detachedz;
|
||||
|
||||
} channel_t;
|
||||
|
||||
typedef struct {
|
||||
channel_t *c;
|
||||
sfxinfo_t *s;
|
||||
UINT16 t;
|
||||
UINT8 b;
|
||||
} caption_t;
|
||||
|
||||
#define NUMCAPTIONS 8
|
||||
#define MAXCAPTIONTICS (2*TICRATE)
|
||||
#define CAPTIONFADETICS 20
|
||||
|
||||
extern caption_t closedcaptions[NUMCAPTIONS];
|
||||
void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan);
|
||||
void S_ResetCaptions(void);
|
||||
|
||||
// register sound vars and commands at game startup
|
||||
void S_RegisterSoundStuff(void);
|
||||
|
||||
@@ -107,6 +141,10 @@ void S_StartSoundAtVolume(const void *origin, sfxenum_t sound_id, INT32 volume);
|
||||
// Stop sound for thing at <origin>
|
||||
void S_StopSound(void *origin);
|
||||
|
||||
// Detaches a sound from an object, leaving it in the air at the object's original position
|
||||
void S_DetachChannelsFromOrigin(void* origin);
|
||||
|
||||
|
||||
//
|
||||
// Music Status
|
||||
//
|
||||
|
||||
+1
-1
@@ -409,7 +409,7 @@ void SCR_DisplayTicRate(void)
|
||||
tic_t totaltics = 0;
|
||||
const UINT8 *ticcntcolor = NULL;
|
||||
|
||||
for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i)
|
||||
for (i = lasttic + 1; i < TICRATE + lasttic && i < ontic; ++i)
|
||||
fpsgraph[i % TICRATE] = false;
|
||||
|
||||
fpsgraph[ontic % TICRATE] = true;
|
||||
|
||||
+117
-39
@@ -5,7 +5,7 @@
|
||||
//
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 2014-2018 by Sonic Team Junior.
|
||||
// Copyright (C) 2014-2019 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@@ -205,13 +205,12 @@ static void JoyReset(SDLJoyInfo_t *JoySet)
|
||||
|
||||
/** \brief First joystick up and running
|
||||
*/
|
||||
static INT32 joystick_started = 0;
|
||||
static INT32 joystick_started = 0;
|
||||
|
||||
/** \brief SDL info about joystick 1
|
||||
*/
|
||||
SDLJoyInfo_t JoyInfo;
|
||||
|
||||
|
||||
/** \brief Second joystick up and running
|
||||
*/
|
||||
static INT32 joystick2_started = 0;
|
||||
@@ -547,7 +546,7 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
|
||||
break;
|
||||
case VK_RETURN:
|
||||
entering_con_command = false;
|
||||
// Fall through.
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
|
||||
}
|
||||
@@ -693,7 +692,7 @@ void I_StartupKeyboard (void)
|
||||
void I_OutputMsg(const char *fmt, ...)
|
||||
{
|
||||
size_t len;
|
||||
XBOXSTATIC char txt[8192];
|
||||
char txt[8192];
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr,fmt);
|
||||
@@ -872,7 +871,6 @@ INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Misleading function: updates device indices for all players BUT the one specified.
|
||||
// Necessary for SDL_JOYDEVICEADDED events
|
||||
void I_UpdateJoystickDeviceIndices(INT32 player)
|
||||
@@ -2162,7 +2160,6 @@ void I_InitJoystick(void)
|
||||
SDL_Joystick *newjoy = NULL;
|
||||
|
||||
//I_ShutdownJoystick();
|
||||
//SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
|
||||
if (M_CheckParm("-nojoy"))
|
||||
return;
|
||||
|
||||
@@ -2186,7 +2183,7 @@ void I_InitJoystick(void)
|
||||
if (cv_usejoystick.value)
|
||||
newjoy = SDL_JoystickOpen(cv_usejoystick.value-1);
|
||||
|
||||
if (newjoy && (JoyInfo2.dev == newjoy || JoyInfo3.dev == newjoy || JoyInfo4.dev == newjoy)) // don't override an active device
|
||||
if (newjoy && (JoyInfo2.dev == newjoy || JoyInfo3.dev == newjoy || JoyInfo4.dev == newjoy)) // don't override an active device
|
||||
cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
|
||||
else if (newjoy && joy_open(cv_usejoystick.value) != -1)
|
||||
{
|
||||
@@ -2212,13 +2209,13 @@ void I_InitJoystick2(void)
|
||||
SDL_Joystick *newjoy = NULL;
|
||||
|
||||
//I_ShutdownJoystick2();
|
||||
//SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
|
||||
if (M_CheckParm("-nojoy"))
|
||||
return;
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
|
||||
{
|
||||
CONS_Printf("I_InitJoystick2()...\n");
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
|
||||
{
|
||||
CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError());
|
||||
@@ -2362,7 +2359,7 @@ INT32 I_NumJoys(void)
|
||||
return numjoy;
|
||||
}
|
||||
|
||||
static char joyname[255]; // MAX_PATH; joystick name is straight from the driver
|
||||
static char joyname[255]; // joystick name is straight from the driver
|
||||
|
||||
const char *I_GetJoyName(INT32 joyindex)
|
||||
{
|
||||
@@ -2903,11 +2900,15 @@ ticcmd_t *I_BaseTiccmd4(void)
|
||||
{
|
||||
return &emptycmd4;
|
||||
}
|
||||
static int lastTimeFudge = -1;
|
||||
extern consvar_t cv_timefudge;
|
||||
|
||||
#if defined (_WIN32)
|
||||
static HMODULE winmm = NULL;
|
||||
static DWORD starttickcount = 0; // hack for win2k time bug
|
||||
static p_timeGetTime pfntimeGetTime = NULL;
|
||||
static LARGE_INTEGER basetime = { {0, 0} };
|
||||
static LARGE_INTEGER frequency; // use this if High Resolution timer is found
|
||||
|
||||
// ---------
|
||||
// I_GetTime
|
||||
@@ -2916,6 +2917,7 @@ static p_timeGetTime pfntimeGetTime = NULL;
|
||||
// but lower precision on Windows NT
|
||||
// ---------
|
||||
|
||||
|
||||
tic_t I_GetTime(void)
|
||||
{
|
||||
tic_t newtics = 0;
|
||||
@@ -2923,10 +2925,77 @@ tic_t I_GetTime(void)
|
||||
if (!starttickcount) // high precision timer
|
||||
{
|
||||
LARGE_INTEGER currtime; // use only LowPart if high resolution counter is not available
|
||||
static LARGE_INTEGER basetime = {{0, 0}};
|
||||
|
||||
// use this if High Resolution timer is found
|
||||
static LARGE_INTEGER frequency;
|
||||
if (!basetime.QuadPart)
|
||||
{
|
||||
if (!QueryPerformanceFrequency(&frequency))
|
||||
frequency.QuadPart = 0;
|
||||
else
|
||||
QueryPerformanceCounter(&basetime);
|
||||
}
|
||||
|
||||
if (frequency.LowPart && QueryPerformanceCounter(&currtime))
|
||||
{
|
||||
newtics = (INT32)((currtime.QuadPart - basetime.QuadPart) * NEWTICRATE / frequency.QuadPart);
|
||||
}
|
||||
else if (pfntimeGetTime)
|
||||
{
|
||||
currtime.LowPart = pfntimeGetTime();
|
||||
if (!basetime.LowPart)
|
||||
basetime.LowPart = currtime.LowPart;
|
||||
newtics = (UINT32)((UINT64)(currtime.LowPart - basetime.LowPart)*NEWTICRATE/1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
newtics = (UINT32)((UINT64)(GetTickCount() - starttickcount)*NEWTICRATE/1000);
|
||||
// ADVICE TO OFFICIAL SRB2 DEV TEAM: in the official branch, some of the above lines of code divide by (1000/NEWTICRATE) when it could multiply by 1000 first and preserve precision.
|
||||
// I recommend changing this because the QueryPerformanceCounter version in fact already does that, making an inconsistent result between timer types.
|
||||
// If the server and client are using different timer types, this will cause jutter.
|
||||
// It also messes with SRB2netplus's timer fudge, meaning that for a truly accurate timerfudge it needs to know which timer the server is using...
|
||||
|
||||
// Fudge the timer to sync better with online games. Uses multiply-first approach (more accurate)
|
||||
if (cv_timefudge.value != lastTimeFudge)
|
||||
{
|
||||
if (frequency.QuadPart)
|
||||
{
|
||||
unsigned long long frame = basetime.QuadPart * NEWTICRATE / frequency.QuadPart;
|
||||
|
||||
if (cv_timefudge.value > lastTimeFudge)
|
||||
{
|
||||
frame--; // do not allow the same tic to play twice
|
||||
}
|
||||
|
||||
basetime.QuadPart = frame * frequency.QuadPart / NEWTICRATE + frequency.QuadPart * cv_timefudge.value / TICRATE / 100;
|
||||
}
|
||||
if (starttickcount)
|
||||
{
|
||||
unsigned long long frame = starttickcount * NEWTICRATE / 1000;
|
||||
|
||||
if (cv_timefudge.value > lastTimeFudge)
|
||||
{
|
||||
frame--; // do not allow the same tic to play twice
|
||||
}
|
||||
|
||||
starttickcount = (DWORD)(frame * 1000 / NEWTICRATE + 1000 * cv_timefudge.value / TICRATE / 100);
|
||||
}
|
||||
|
||||
lastTimeFudge = cv_timefudge.value;
|
||||
}
|
||||
|
||||
return newtics;
|
||||
}
|
||||
|
||||
|
||||
// I_GetTime
|
||||
// Wow I remember Windows NT
|
||||
// Anyway this returns the time passed in microseconds if applicable. Useful for benchmarking
|
||||
UINT64 I_GetTimeUs(void)
|
||||
{
|
||||
UINT64 timeUs;
|
||||
|
||||
if (!starttickcount) // high precision timer
|
||||
{
|
||||
LARGE_INTEGER currtime; // use only LowPart if high resolution counter is not available
|
||||
|
||||
if (!basetime.LowPart)
|
||||
{
|
||||
@@ -2938,21 +3007,20 @@ tic_t I_GetTime(void)
|
||||
|
||||
if (frequency.LowPart && QueryPerformanceCounter(&currtime))
|
||||
{
|
||||
newtics = (INT32)((currtime.QuadPart - basetime.QuadPart) * NEWTICRATE
|
||||
/ frequency.QuadPart);
|
||||
timeUs = (INT32)((currtime.QuadPart - basetime.QuadPart) * 1000000 / frequency.QuadPart);
|
||||
}
|
||||
else if (pfntimeGetTime)
|
||||
{
|
||||
currtime.LowPart = pfntimeGetTime();
|
||||
if (!basetime.LowPart)
|
||||
basetime.LowPart = currtime.LowPart;
|
||||
newtics = ((currtime.LowPart - basetime.LowPart)/(1000/NEWTICRATE));
|
||||
timeUs = (currtime.LowPart - basetime.LowPart) * 1000;
|
||||
}
|
||||
}
|
||||
else
|
||||
newtics = (GetTickCount() - starttickcount)/(1000/NEWTICRATE);
|
||||
timeUs = (GetTickCount() - starttickcount) * 1000;
|
||||
|
||||
return newtics;
|
||||
return timeUs;
|
||||
}
|
||||
|
||||
static void I_ShutdownTimer(void)
|
||||
@@ -2960,7 +3028,7 @@ static void I_ShutdownTimer(void)
|
||||
pfntimeGetTime = NULL;
|
||||
if (winmm)
|
||||
{
|
||||
p_timeEndPeriod pfntimeEndPeriod = (p_timeEndPeriod)GetProcAddress(winmm, "timeEndPeriod");
|
||||
p_timeEndPeriod pfntimeEndPeriod = (p_timeEndPeriod)(LPVOID)GetProcAddress(winmm, "timeEndPeriod");
|
||||
if (pfntimeEndPeriod)
|
||||
pfntimeEndPeriod(1);
|
||||
FreeLibrary(winmm);
|
||||
@@ -2972,14 +3040,29 @@ static void I_ShutdownTimer(void)
|
||||
// I_GetTime
|
||||
// returns time in 1/TICRATE second tics
|
||||
//
|
||||
static Uint64 basetime = 0;
|
||||
|
||||
tic_t I_GetTime (void)
|
||||
{
|
||||
static Uint64 basetime = 0;
|
||||
Uint64 ticks = SDL_GetTicks();
|
||||
Uint64 ticks = SDL_GetTicks();
|
||||
|
||||
if (!basetime)
|
||||
basetime = ticks;
|
||||
|
||||
// fudge the timer for better netgame sync
|
||||
if (cv_timefudge.value != lastTimeFudge)
|
||||
{
|
||||
Uint64 frame = basetime * NEWTICRATE / 1000;
|
||||
|
||||
if (cv_timefudge.value > lastTimeFudge)
|
||||
{
|
||||
frame--; // do not allow the same tic to play twice
|
||||
}
|
||||
|
||||
basetime = (Uint64)(frame * 1000 / NEWTICRATE + 1000 * cv_timefudge.value / NEWTICRATE / 100);
|
||||
lastTimeFudge = cv_timefudge.value;
|
||||
}
|
||||
|
||||
ticks -= basetime;
|
||||
|
||||
ticks = (ticks*TICRATE);
|
||||
@@ -2988,6 +3071,11 @@ tic_t I_GetTime (void)
|
||||
|
||||
return (tic_t)ticks;
|
||||
}
|
||||
|
||||
UINT64 I_GetTimeUs(void)
|
||||
{
|
||||
return (SDL_GetTicks() - basetime) * 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
@@ -3005,10 +3093,10 @@ void I_StartupTimer(void)
|
||||
winmm = LoadLibraryA("winmm.dll");
|
||||
if (winmm)
|
||||
{
|
||||
p_timeEndPeriod pfntimeBeginPeriod = (p_timeEndPeriod)GetProcAddress(winmm, "timeBeginPeriod");
|
||||
p_timeEndPeriod pfntimeBeginPeriod = (p_timeEndPeriod)(LPVOID)GetProcAddress(winmm, "timeBeginPeriod");
|
||||
if (pfntimeBeginPeriod)
|
||||
pfntimeBeginPeriod(1);
|
||||
pfntimeGetTime = (p_timeGetTime)GetProcAddress(winmm, "timeGetTime");
|
||||
pfntimeGetTime = (p_timeGetTime)(LPVOID)GetProcAddress(winmm, "timeGetTime");
|
||||
}
|
||||
I_AddExitFunc(I_ShutdownTimer);
|
||||
#endif
|
||||
@@ -3018,7 +3106,7 @@ void I_StartupTimer(void)
|
||||
|
||||
void I_Sleep(void)
|
||||
{
|
||||
if (cv_sleep.value > 0)
|
||||
if (cv_sleep.value != -1)
|
||||
SDL_Delay(cv_sleep.value);
|
||||
}
|
||||
|
||||
@@ -3153,7 +3241,7 @@ void I_Error(const char *error, ...)
|
||||
// which should fail gracefully if it can't put a message box up
|
||||
// on the target system
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
|
||||
"SRB2Kart "VERSIONSTRING" Recursive Error",
|
||||
"SRB2 "VERSIONSTRING" Recursive Error",
|
||||
buffer, NULL);
|
||||
|
||||
W_Shutdown();
|
||||
@@ -3307,7 +3395,7 @@ void I_GetDiskFreeSpace(INT64 *freespace)
|
||||
|
||||
if (!testwin95)
|
||||
{
|
||||
pfnGetDiskFreeSpaceEx = (p_GetDiskFreeSpaceExA)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDiskFreeSpaceExA");
|
||||
pfnGetDiskFreeSpaceEx = (p_GetDiskFreeSpaceExA)(LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDiskFreeSpaceExA");
|
||||
testwin95 = true;
|
||||
}
|
||||
if (pfnGetDiskFreeSpaceEx)
|
||||
@@ -3368,7 +3456,7 @@ char *I_GetUserName(void)
|
||||
INT32 I_mkdir(const char *dirname, INT32 unixright)
|
||||
{
|
||||
//[segabor]
|
||||
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) || defined (__CYGWIN__) || defined (__OS2__)
|
||||
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) || defined (__CYGWIN__)
|
||||
return mkdir(dirname, unixright);
|
||||
#elif defined (_WIN32)
|
||||
UNREFERENCED_PARAMETER(unixright); /// \todo should implement ntright under nt...
|
||||
@@ -3507,7 +3595,7 @@ static const char *searchWad(const char *searchDir)
|
||||
pathonly(tempsw);
|
||||
return tempsw;
|
||||
}
|
||||
|
||||
|
||||
strcpy(tempsw, WADKEYWORD2);
|
||||
fstemp = filesearch(tempsw, searchDir, NULL, true, 20);
|
||||
if (fstemp == FS_FOUND)
|
||||
@@ -3740,16 +3828,6 @@ UINT32 I_GetFreeMem(UINT32 *total)
|
||||
if (total)
|
||||
*total = (UINT32)info.dwTotalPhys;
|
||||
return (UINT32)info.dwAvailPhys;
|
||||
#elif defined (__OS2__)
|
||||
UINT32 pr_arena;
|
||||
|
||||
if (total)
|
||||
DosQuerySysInfo( QSV_TOTPHYSMEM, QSV_TOTPHYSMEM,
|
||||
(PVOID) total, sizeof (UINT32));
|
||||
DosQuerySysInfo( QSV_MAXPRMEM, QSV_MAXPRMEM,
|
||||
(PVOID) &pr_arena, sizeof (UINT32));
|
||||
|
||||
return pr_arena;
|
||||
#elif defined (__linux__)
|
||||
/* Linux */
|
||||
char buf[1024];
|
||||
@@ -3827,7 +3905,7 @@ const CPUInfoFlags *I_CPUInfo(void)
|
||||
#if defined (_WIN32)
|
||||
static CPUInfoFlags WIN_CPUInfo;
|
||||
SYSTEM_INFO SI;
|
||||
p_IsProcessorFeaturePresent pfnCPUID = (p_IsProcessorFeaturePresent)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsProcessorFeaturePresent");
|
||||
p_IsProcessorFeaturePresent pfnCPUID = (p_IsProcessorFeaturePresent)(LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsProcessorFeaturePresent");
|
||||
|
||||
ZeroMemory(&WIN_CPUInfo,sizeof (WIN_CPUInfo));
|
||||
if (pfnCPUID)
|
||||
|
||||
@@ -194,17 +194,37 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
|
||||
}
|
||||
else // windowed mode
|
||||
{
|
||||
int xoffset = 0, yoffset = 0, arg;
|
||||
|
||||
if (wasfullscreen)
|
||||
{
|
||||
wasfullscreen = SDL_FALSE;
|
||||
SDL_SetWindowFullscreen(window, 0);
|
||||
}
|
||||
|
||||
// Reposition window only in windowed mode
|
||||
SDL_SetWindowSize(window, width, height);
|
||||
SDL_SetWindowPosition(window,
|
||||
SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(window)),
|
||||
SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(window))
|
||||
);
|
||||
|
||||
// Offset the window w/ command line parameters, useful for multiplayer testing via batch files
|
||||
if (arg = M_CheckParm("-winxoff"))
|
||||
{
|
||||
xoffset = atoi(arg + 1 < myargc ? myargv[arg + 1] : "0");
|
||||
}
|
||||
if (arg = M_CheckParm("-winyoff"))
|
||||
{
|
||||
yoffset = atoi(arg + 1 < myargc ? myargv[arg + 1] : "0");
|
||||
}
|
||||
|
||||
if (xoffset || yoffset)
|
||||
{
|
||||
int x, y;
|
||||
SDL_GetWindowPosition(window, &x, &y);
|
||||
SDL_SetWindowPosition(window, x + xoffset, y + yoffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1294,8 +1314,14 @@ void I_StartupMouse(void)
|
||||
//
|
||||
// I_OsPolling
|
||||
//
|
||||
void SOCK_FlushDelayBuffers(boolean flush);
|
||||
|
||||
void I_OsPolling(void)
|
||||
{
|
||||
SDL_Keymod mod;
|
||||
|
||||
SOCK_FlushDelayBuffers(false);
|
||||
|
||||
if (consolevent)
|
||||
I_GetConsoleEvents();
|
||||
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
|
||||
|
||||
+17
-15
@@ -1762,31 +1762,33 @@ static void ST_doItemFinderIconsAndSound(void) // SRB2kart - unused.
|
||||
return;
|
||||
|
||||
// Scan thinkers to find emblem mobj with these ids
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
||||
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
mo2 = (mobj_t *)th;
|
||||
|
||||
if (mo2->type == MT_EMBLEM)
|
||||
if (mo2->type != MT_EMBLEM)
|
||||
continue;
|
||||
|
||||
if (!(mo2->flags & MF_SPECIAL))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < stemblems; ++i)
|
||||
{
|
||||
if (!(mo2->flags & MF_SPECIAL))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < stemblems; ++i)
|
||||
if (mo2->health == emblems[i] + 1)
|
||||
{
|
||||
if (mo2->health == emblems[i]+1)
|
||||
{
|
||||
soffset = (i * 20) - ((stemblems-1) * 10);
|
||||
soffset = (i * 20) - ((stemblems - 1) * 10);
|
||||
|
||||
newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset);
|
||||
if (newinterval && (!interval || newinterval < interval))
|
||||
interval = newinterval;
|
||||
newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset);
|
||||
if (newinterval && (!interval || newinterval < interval))
|
||||
interval = newinterval;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
|
||||
|
||||
Reference in new issue
Block a user