mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-04-14 22:21:20 +00:00
Merge branch 'next' into awayview-fix
This commit is contained in:
commit
ebdc36f56b
59 changed files with 4130 additions and 7270 deletions
|
@ -15,7 +15,7 @@ common
|
|||
ignoredextensions = "wad pk3 pk7 bak backup1 backup2 backup3 zip rar 7z";
|
||||
|
||||
// Default testing parameters
|
||||
testparameters = "-file \"%AP\" \"%F\" -warp %L";
|
||||
testparameters = "-folder \"%AF\" -file \"%AA\" \"%F\" -warp %L";
|
||||
testshortpaths = true;
|
||||
|
||||
// Action special help
|
||||
|
@ -26,7 +26,7 @@ common
|
|||
generalizedsectors = true;
|
||||
|
||||
// Maximum safe map size check (0 means skip check)
|
||||
safeboundary = 1;
|
||||
safeboundary = 0;
|
||||
|
||||
// Map boundaries. Map objects can only be placed within these boundaries
|
||||
leftboundary = -32768;
|
||||
|
@ -40,6 +40,8 @@ common
|
|||
defaultflatscale = 1.0f;
|
||||
scaledtextureoffsets = true;
|
||||
|
||||
maxcolormapalpha = 25;
|
||||
|
||||
// Thing number for start position in 3D Mode
|
||||
start3dmode = 3328;
|
||||
|
||||
|
@ -68,137 +70,6 @@ common
|
|||
}
|
||||
}
|
||||
|
||||
mapformat_doom
|
||||
{
|
||||
// The format interface handles the map data format
|
||||
formatinterface = "DoomMapSetIO";
|
||||
|
||||
// Default nodebuilder configurations
|
||||
defaultsavecompiler = "zennode_normal";
|
||||
defaulttestcompiler = "zennode_fast";
|
||||
|
||||
/*
|
||||
GAME DETECT PATTERN
|
||||
Used to guess the game for which a WAD file is made.
|
||||
|
||||
1 = One of these lumps must exist
|
||||
2 = None of these lumps must exist
|
||||
3 = All of these lumps must exist
|
||||
*/
|
||||
|
||||
gamedetect
|
||||
{
|
||||
EXTENDED = 2;
|
||||
|
||||
|
||||
BEHAVIOR = 2;
|
||||
|
||||
E#M# = 2;
|
||||
|
||||
MAP?? = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
MAP LUMP NAMES
|
||||
Map lumps are loaded with the map as long as they are right after each other. When the editor
|
||||
meets a lump which is not defined in this list it will ignore the map if not satisfied.
|
||||
The order of items defines the order in which lumps will be written to WAD file on save.
|
||||
To indicate the map header lump, use ~MAP
|
||||
|
||||
Legenda:
|
||||
required = Lump is required to exist.
|
||||
blindcopy = Lump will be copied along with the map blindly. (usefull for lumps Doom Builder doesn't use)
|
||||
nodebuild = The nodebuilder generates this lump.
|
||||
allowempty = The nodebuilder is allowed to leave this lump empty.
|
||||
script = This lump is a text-based script. Specify the filename of the script configuration to use.
|
||||
*/
|
||||
|
||||
maplumpnames
|
||||
{
|
||||
include("SRB222_misc.cfg", "doommaplumpnames");
|
||||
}
|
||||
|
||||
// When this is set to true, sectors with the same tag will light up when a line is highlighted
|
||||
linetagindicatesectors = true;
|
||||
|
||||
// Special linedefs
|
||||
include("SRB222_misc.cfg", "speciallinedefs");
|
||||
|
||||
// Default flags for first new thing
|
||||
defaultthingflags
|
||||
{
|
||||
}
|
||||
|
||||
// DEFAULT SECTOR BRIGHTNESS LEVELS
|
||||
sectorbrightness
|
||||
{
|
||||
include("SRB222_misc.cfg", "sectorbrightness");
|
||||
}
|
||||
|
||||
// SECTOR TYPES
|
||||
sectortypes
|
||||
{
|
||||
include("SRB222_sectors.cfg", "sectortypes");
|
||||
}
|
||||
|
||||
// GENERALISED SECTOR TYPES
|
||||
gen_sectortypes
|
||||
{
|
||||
include("SRB222_sectors.cfg", "gen_sectortypes");
|
||||
}
|
||||
|
||||
// LINEDEF FLAGS
|
||||
linedefflags
|
||||
{
|
||||
include("SRB222_misc.cfg", "linedefflags");
|
||||
}
|
||||
|
||||
// Linedef flags UDMF translation table
|
||||
// This is needed for copy/paste and prefabs to work properly
|
||||
// When the UDMF field name is prefixed with ! it is inverted
|
||||
linedefflagstranslation
|
||||
{
|
||||
include("SRB222_misc.cfg", "linedefflagstranslation");
|
||||
}
|
||||
|
||||
// LINEDEF ACTIVATIONS
|
||||
linedefactivations
|
||||
{
|
||||
}
|
||||
|
||||
// LINEDEF TYPES
|
||||
linedeftypes
|
||||
{
|
||||
include("SRB222_linedefs.cfg", "doom");
|
||||
}
|
||||
|
||||
// THING FLAGS
|
||||
thingflags
|
||||
{
|
||||
include("SRB222_misc.cfg", "thingflags");
|
||||
}
|
||||
|
||||
// Thing flags UDMF translation table
|
||||
// This is needed for copy/paste and prefabs to work properly
|
||||
// When the UDMF field name is prefixed with ! it is inverted
|
||||
thingflagstranslation
|
||||
{
|
||||
include("SRB222_misc.cfg", "thingflagstranslation");
|
||||
}
|
||||
|
||||
// THING FLAGS ERROR MASK
|
||||
// Mask for the thing flags which indicates the options
|
||||
// that make the same thing appear in the same modes
|
||||
thingflagsmask1 = 7; // 1 + 2 + 4
|
||||
thingflagsmask2 = 0;
|
||||
|
||||
// THING TYPES
|
||||
thingtypes
|
||||
{
|
||||
include("SRB222_things.cfg", "doom");
|
||||
}
|
||||
}
|
||||
|
||||
mapformat_udmf
|
||||
{
|
||||
// The format interface handles the map data format
|
||||
|
@ -222,9 +93,17 @@ mapformat_udmf
|
|||
{
|
||||
include("SRB222_misc.cfg", "universalfields");
|
||||
}
|
||||
|
||||
// Disable Doom-related modes that don't make sense for SRB2
|
||||
soundsupport = false;
|
||||
automapsupport = false;
|
||||
|
||||
// When this is set to true, sectors with the same tag will light up when a line is highlighted
|
||||
linetagindicatesectors = false;
|
||||
localsidedeftextureoffsets = true;
|
||||
distinctfloorandceilingbrightness = true;
|
||||
|
||||
planeequationsupport = true;
|
||||
|
||||
// Special linedefs
|
||||
include("SRB222_misc.cfg", "speciallinedefs_udmf");
|
||||
|
@ -240,6 +119,11 @@ mapformat_udmf
|
|||
include("SRB222_misc.cfg", "sectorflags");
|
||||
}
|
||||
|
||||
sectorflagscategories
|
||||
{
|
||||
include("SRB222_misc.cfg", "sectorflagscategories");
|
||||
}
|
||||
|
||||
// DEFAULT SECTOR BRIGHTNESS LEVELS
|
||||
sectorbrightness
|
||||
{
|
||||
|
@ -247,6 +131,7 @@ mapformat_udmf
|
|||
}
|
||||
|
||||
damagetypes = "Generic Water Fire Lava Electric Spike DeathPitTilt DeathPitNoTilt Instakill SpecialStage";
|
||||
triggerertypes = "Player AllPlayers Mobj";
|
||||
|
||||
// LINEDEF FLAGS
|
||||
linedefflags
|
||||
|
@ -282,7 +167,6 @@ mapformat_udmf
|
|||
// How to compare thing flags (for the stuck things error checker)
|
||||
thingflagscompare
|
||||
{
|
||||
include("UDMF_misc.cfg", "thingflagscompare");
|
||||
}
|
||||
|
||||
// THING TYPES
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,24 +1,3 @@
|
|||
linedefflags
|
||||
{
|
||||
1 = "[0] Impassable";
|
||||
2 = "[1] Block Enemies";
|
||||
4 = "[2] Double-Sided";
|
||||
8 = "[3] Upper Unpegged";
|
||||
16 = "[4] Lower Unpegged";
|
||||
32 = "[5] Slope Skew (E1)";
|
||||
64 = "[6] Not Climbable";
|
||||
128 = "[7] No Midtexture Skew (E2)";
|
||||
256 = "[8] Peg Midtexture (E3)";
|
||||
512 = "[9] Solid Midtexture (E4)";
|
||||
1024 = "[10] Repeat Midtexture (E5)";
|
||||
2048 = "[11] Netgame Only";
|
||||
4096 = "[12] No Netgame";
|
||||
8192 = "[13] Effect 6";
|
||||
16384 = "[14] Bouncy Wall";
|
||||
32768 = "[15] Transfer Line";
|
||||
}
|
||||
|
||||
|
||||
// Linedef flags UDMF translation table
|
||||
// This is needed for copy/paste and prefabs to work properly
|
||||
// When the UDMF field name is prefixed with ! it is inverted
|
||||
|
@ -42,7 +21,6 @@ linedefflagstranslation
|
|||
32768 = "transfer";
|
||||
}
|
||||
|
||||
|
||||
linedefflags_udmf
|
||||
{
|
||||
blocking = "Impassable";
|
||||
|
@ -74,19 +52,13 @@ linedefrenderstyles
|
|||
|
||||
sectorflags
|
||||
{
|
||||
colormapfog = "Fog Planes in Colormap";
|
||||
colormapfadesprites = "Fade Fullbright in Colormap";
|
||||
colormapprotected = "Protected Colormap";
|
||||
flipspecial_nofloor = "No Trigger on Floor Touch";
|
||||
flipspecial_ceiling = "Trigger on Ceiling Touch";
|
||||
triggerspecial_touch = "Trigger on Edge Touch";
|
||||
triggerspecial_headbump = "Trigger on Headbump";
|
||||
triggerline_plane = "Linedef Trigger Requires Plane Touch";
|
||||
triggerline_mobj = "Non-Pushables Can Trigger Linedef";
|
||||
invertprecip = "Invert Precipitation";
|
||||
gravityflip = "Flip Objects in Reverse Gravity";
|
||||
heatwave = "Heat Wave";
|
||||
noclipcamera = "Intangible to the Camera";
|
||||
colormapfog = "Fog Planes";
|
||||
colormapfadesprites = "Fade Fullbright";
|
||||
colormapprotected = "Protected from Tagging";
|
||||
outerspace = "Space Countdown";
|
||||
doublestepup = "Ramp Sector (double step-up/down)";
|
||||
nostepdown = "Non-Ramp Sector (No step-down)";
|
||||
|
@ -104,23 +76,59 @@ sectorflags
|
|||
zoomtubeend = "Zoom Tube End";
|
||||
finishline = "Circuit Finish Line";
|
||||
ropehang = "Rope Hang";
|
||||
jumpflip = "Flip Gravity on Jump";
|
||||
gravityoverride = "Make Reverse Gravity Temporary";
|
||||
flipspecial_nofloor = "No Trigger on Floor Touch";
|
||||
flipspecial_ceiling = "Trigger on Ceiling Touch";
|
||||
triggerspecial_touch = "Trigger on Edge Touch";
|
||||
triggerspecial_headbump = "Trigger on Headbump";
|
||||
triggerline_plane = "Linedef Trigger Requires Plane Touch";
|
||||
triggerline_mobj = "Non-Pushables Can Trigger Linedef";
|
||||
}
|
||||
|
||||
thingflags
|
||||
sectorflagscategories
|
||||
{
|
||||
1 = "[1] Extra";
|
||||
2 = "[2] Flip";
|
||||
4 = "[4] Special";
|
||||
8 = "[8] Ambush";
|
||||
invertprecip = "regular";
|
||||
gravityflip = "regular";
|
||||
heatwave = "regular";
|
||||
noclipcamera = "regular";
|
||||
colormapfog = "colormap";
|
||||
colormapfadesprites = "colormap";
|
||||
colormapprotected = "colormap";
|
||||
outerspace = "special";
|
||||
doublestepup = "special";
|
||||
nostepdown = "special";
|
||||
speedpad = "special";
|
||||
starpostactivator = "special";
|
||||
exit = "special";
|
||||
specialstagepit = "special";
|
||||
returnflag = "special";
|
||||
redteambase = "special";
|
||||
blueteambase = "special";
|
||||
fan = "special";
|
||||
supertransform = "special";
|
||||
forcespin = "special";
|
||||
zoomtubestart = "special";
|
||||
zoomtubeend = "special";
|
||||
finishline = "special";
|
||||
ropehang = "special";
|
||||
jumpflip = "special";
|
||||
gravityoverride = "special";
|
||||
flipspecial_nofloor = "trigger";
|
||||
flipspecial_ceiling = "trigger";
|
||||
triggerspecial_touch = "trigger";
|
||||
triggerspecial_headbump = "trigger";
|
||||
triggerline_plane = "trigger";
|
||||
triggerline_mobj = "trigger";
|
||||
}
|
||||
|
||||
// THING FLAGS
|
||||
thingflags_udmf
|
||||
{
|
||||
flip = "Flip";
|
||||
absolutez = "Absolute Z height";
|
||||
}
|
||||
|
||||
|
||||
// Thing flags UDMF translation table
|
||||
// This is needed for copy/paste and prefabs to work properly
|
||||
// When the UDMF field name is prefixed with ! it is inverted
|
||||
|
@ -130,9 +138,9 @@ thingflagstranslation
|
|||
2 = "flip";
|
||||
4 = "special";
|
||||
8 = "ambush";
|
||||
16 = "absolutez";
|
||||
}
|
||||
|
||||
|
||||
// DEFAULT SECTOR BRIGHTNESS LEVELS
|
||||
sectorbrightness
|
||||
{
|
||||
|
@ -171,6 +179,8 @@ sectorbrightness
|
|||
0;
|
||||
}
|
||||
|
||||
numbrightnesslevels = 32;
|
||||
|
||||
/*
|
||||
TEXTURES AND FLAT SOURCES
|
||||
This tells Doom Builder where to find the information for textures
|
||||
|
@ -221,145 +231,18 @@ universalfields
|
|||
{
|
||||
sector
|
||||
{
|
||||
lightalpha
|
||||
{
|
||||
type = 0;
|
||||
default = 25;
|
||||
}
|
||||
|
||||
fadealpha
|
||||
{
|
||||
type = 0;
|
||||
default = 25;
|
||||
}
|
||||
|
||||
fadestart
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
|
||||
fadeend
|
||||
{
|
||||
type = 0;
|
||||
default = 33;
|
||||
}
|
||||
|
||||
foglighting
|
||||
{
|
||||
type = 3;
|
||||
default = false;
|
||||
}
|
||||
|
||||
friction
|
||||
{
|
||||
type = 1;
|
||||
default = 0.90625;
|
||||
}
|
||||
|
||||
triggertag
|
||||
{
|
||||
type = 15;
|
||||
default = 0;
|
||||
}
|
||||
|
||||
triggerer
|
||||
{
|
||||
type = 2;
|
||||
default = "Player";
|
||||
}
|
||||
}
|
||||
|
||||
linedef
|
||||
{
|
||||
arg5
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg6
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg7
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg8
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg9
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
stringarg0
|
||||
{
|
||||
type = 2;
|
||||
default = "";
|
||||
}
|
||||
stringarg1
|
||||
{
|
||||
type = 2;
|
||||
default = "";
|
||||
}
|
||||
executordelay
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sidedef
|
||||
{
|
||||
repeatcnt
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
}
|
||||
|
||||
thing
|
||||
{
|
||||
arg5
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg6
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg7
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg8
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
arg9
|
||||
{
|
||||
type = 0;
|
||||
default = 0;
|
||||
}
|
||||
stringarg0
|
||||
{
|
||||
type = 2;
|
||||
default = "";
|
||||
}
|
||||
stringarg1
|
||||
{
|
||||
type = 2;
|
||||
default = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,87 +261,6 @@ allowempty = The nodebuilder is allowed to leave this lump empty.
|
|||
scriptbuild = This lump is a text-based script, which should be compiled using current script compiler;
|
||||
script = This lump is a text-based script. Specify the filename of the script configuration to use.
|
||||
*/
|
||||
|
||||
doommaplumpnames
|
||||
{
|
||||
~MAP
|
||||
{
|
||||
required = true;
|
||||
blindcopy = true;
|
||||
nodebuild = false;
|
||||
}
|
||||
|
||||
THINGS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = true;
|
||||
}
|
||||
|
||||
LINEDEFS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SIDEDEFS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
VERTEXES
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SEGS
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SSECTORS
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
NODES
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SECTORS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
REJECT
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
BLOCKMAP
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = true;
|
||||
}
|
||||
}
|
||||
|
||||
udmfmaplumpnames
|
||||
{
|
||||
ZNODES
|
||||
|
@ -682,48 +484,32 @@ thingsfilters
|
|||
|
||||
}
|
||||
|
||||
//filter3
|
||||
//{
|
||||
// name = "Normal Gravity";
|
||||
// category = "";
|
||||
// type = -1;
|
||||
//
|
||||
// fields
|
||||
// {
|
||||
// 2 = false;
|
||||
// }
|
||||
//}
|
||||
|
||||
filter3
|
||||
{
|
||||
name = "Normal Gravity";
|
||||
category = "";
|
||||
type = -1;
|
||||
|
||||
fields
|
||||
{
|
||||
2 = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
filter4
|
||||
{
|
||||
name = "Reverse Gravity";
|
||||
category = "";
|
||||
type = -1;
|
||||
|
||||
fields
|
||||
{
|
||||
2 = true;
|
||||
}
|
||||
|
||||
}
|
||||
//filter4
|
||||
//{
|
||||
// name = "Reverse Gravity";
|
||||
// category = "";
|
||||
// type = -1;
|
||||
//
|
||||
// fields
|
||||
// {
|
||||
// 2 = true;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
// Special linedefs
|
||||
speciallinedefs
|
||||
{
|
||||
soundlinedefflag = 64; // See linedefflags
|
||||
singlesidedflag = 1; // See linedefflags
|
||||
doublesidedflag = 4; // See linedefflags
|
||||
impassableflag = 1;
|
||||
upperunpeggedflag = 8;
|
||||
lowerunpeggedflag = 16;
|
||||
repeatmidtextureflag = 1024;
|
||||
pegmidtextureflag = 256;
|
||||
}
|
||||
|
||||
speciallinedefs_udmf
|
||||
{
|
||||
soundlinedefflag = "noclimb";
|
||||
|
@ -734,6 +520,8 @@ speciallinedefs_udmf
|
|||
lowerunpeggedflag = "dontpegbottom";
|
||||
repeatmidtextureflag = "wrapmidtex";
|
||||
pegmidtextureflag = "midpeg";
|
||||
slopeskewflag = "skewtd";
|
||||
nomidtextureskewflag = "noskew";
|
||||
}
|
||||
|
||||
scriptlumpnames
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
sectortypes
|
||||
{
|
||||
0 = "Normal";
|
||||
1 = "Damage";
|
||||
2 = "Damage (Water)";
|
||||
3 = "Damage (Fire)";
|
||||
4 = "Damage (Electrical)";
|
||||
5 = "Spikes";
|
||||
6 = "Death Pit (Camera Tilt)";
|
||||
7 = "Death Pit (No Camera Tilt)";
|
||||
8 = "Instant Kill";
|
||||
9 = "Ring Drainer (Floor Touch)";
|
||||
10 = "Ring Drainer (Anywhere in Sector)";
|
||||
11 = "Special Stage Damage";
|
||||
12 = "Space Countdown";
|
||||
13 = "Ramp Sector (double step-up/down)";
|
||||
14 = "Non-Ramp Sector (no step-down)";
|
||||
15 = "Bouncy FOF <deprecated>";
|
||||
16 = "Trigger Line Ex. (Pushable Objects)";
|
||||
32 = "Trigger Line Ex. (Anywhere, All Players)";
|
||||
48 = "Trigger Line Ex. (Floor Touch, All Players)";
|
||||
64 = "Trigger Line Ex. (Anywhere in Sector)";
|
||||
80 = "Trigger Line Ex. (Floor Touch)";
|
||||
96 = "Trigger Line Ex. (Emerald Check) <deprecated>";
|
||||
112 = "Trigger Line Ex. (NiGHTS Mare) <deprecated>";
|
||||
128 = "Check for Linedef Executor on FOFs";
|
||||
144 = "Egg Capsule";
|
||||
160 = "Special Stage Time/Spheres Parameters <deprecated>";
|
||||
176 = "Custom Global Gravity <deprecated>";
|
||||
1280 = "Speed Pad";
|
||||
1536 = "Flip Gravity on Jump";
|
||||
4096 = "Star Post Activator";
|
||||
8192 = "Exit/Special Stage Pit/Return Flag";
|
||||
12288 = "CTF Red Team Base";
|
||||
16384 = "CTF Blue Team Base";
|
||||
20480 = "Fan Sector";
|
||||
24576 = "Super Sonic Transform";
|
||||
28672 = "Force Spin";
|
||||
32768 = "Zoom Tube Start";
|
||||
36864 = "Zoom Tube End";
|
||||
40960 = "Circuit Finish Line";
|
||||
45056 = "Rope Hang";
|
||||
49152 = "Intangible to the Camera";
|
||||
}
|
||||
|
||||
gen_sectortypes
|
||||
{
|
||||
first
|
||||
{
|
||||
0 = "Normal";
|
||||
1 = "Damage";
|
||||
2 = "Damage (Water)";
|
||||
3 = "Damage (Fire)";
|
||||
4 = "Damage (Electrical)";
|
||||
5 = "Spikes";
|
||||
6 = "Death Pit (Camera Tilt)";
|
||||
7 = "Death Pit (No Camera Tilt)";
|
||||
8 = "Instant Kill";
|
||||
9 = "Ring Drainer (Floor Touch)";
|
||||
10 = "Ring Drainer (Anywhere in Sector)";
|
||||
11 = "Special Stage Damage";
|
||||
12 = "Space Countdown";
|
||||
13 = "Ramp Sector (double step-up/down)";
|
||||
14 = "Non-Ramp Sector (no step-down)";
|
||||
15 = "Bouncy FOF <deprecated>";
|
||||
}
|
||||
|
||||
second
|
||||
{
|
||||
0 = "Normal";
|
||||
16 = "Trigger Line Ex. (Pushable Objects)";
|
||||
32 = "Trigger Line Ex. (Anywhere, All Players)";
|
||||
48 = "Trigger Line Ex. (Floor Touch, All Players)";
|
||||
64 = "Trigger Line Ex. (Anywhere in Sector)";
|
||||
80 = "Trigger Line Ex. (Floor Touch)";
|
||||
96 = "Trigger Line Ex. (Emerald Check) <deprecated>";
|
||||
112 = "Trigger Line Ex. (NiGHTS Mare) <deprecated>";
|
||||
128 = "Check for Linedef Executor on FOFs";
|
||||
144 = "Egg Capsule";
|
||||
160 = "Special Stage Time/Spheres Parameters <deprecated>";
|
||||
176 = "Custom Global Gravity <deprecated>";
|
||||
}
|
||||
|
||||
third
|
||||
{
|
||||
0 = "Normal";
|
||||
1280 = "Speed Pad";
|
||||
1536 = "Flip Gravity on Jump";
|
||||
}
|
||||
|
||||
fourth
|
||||
{
|
||||
0 = "Normal";
|
||||
4096 = "Star Post Activator";
|
||||
8192 = "Exit/Special Stage Pit/Return Flag";
|
||||
12288 = "CTF Red Team Base";
|
||||
16384 = "CTF Blue Team Base";
|
||||
20480 = "Fan Sector";
|
||||
24576 = "Super Sonic Transform";
|
||||
28672 = "Force Spin";
|
||||
32768 = "Zoom Tube Start";
|
||||
36864 = "Zoom Tube End";
|
||||
40960 = "Circuit Finish Line";
|
||||
45056 = "Rope Hang";
|
||||
49152 = "Intangible to the Camera";
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,32 +0,0 @@
|
|||
/************************************************************************\
|
||||
Ultimate Doom Builder Game Configuration for Sonic Robo Blast 2 Version 2.2
|
||||
\************************************************************************/
|
||||
|
||||
// This is required to prevent accidental use of a different configuration
|
||||
type = "Doom Builder 2 Game Configuration";
|
||||
|
||||
// This is the title to show for this game
|
||||
game = "Sonic Robo Blast 2 - 2.2 (Doom format)";
|
||||
|
||||
// This is the simplified game engine/sourceport name
|
||||
engine = "zdoom";
|
||||
|
||||
// Settings common to all games and all map formats
|
||||
include("Includes\\SRB222_common.cfg", "common");
|
||||
|
||||
// Settings common to Doom map format
|
||||
include("Includes\\SRB222_common.cfg", "mapformat_doom");
|
||||
|
||||
include("Includes\\Game_SRB222.cfg");
|
||||
|
||||
// Script lumps detection
|
||||
scriptlumpnames
|
||||
{
|
||||
include("Includes\\SRB222_misc.cfg", "scriptlumpnames");
|
||||
}
|
||||
|
||||
//Default things filters
|
||||
thingsfilters
|
||||
{
|
||||
include("Includes\\SRB222_misc.cfg", "thingsfilters");
|
||||
}
|
|
@ -395,16 +395,16 @@ static void CON_SetupColormaps(void)
|
|||
|
||||
// 0x1 0x3 0x9 0xF
|
||||
colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185);
|
||||
colset(yellowmap, 82, 82, 73, 73, 73, 64, 64, 64, 66, 66, 66, 66, 67, 67, 67, 68);
|
||||
colset(lgreenmap, 96, 96, 98, 98, 98, 101, 101, 101, 104, 104, 104, 104, 106, 106, 106, 107);
|
||||
colset(bluemap, 146, 146, 147, 147, 147, 149, 149, 149, 152, 152, 152, 152, 155, 155, 155, 157);
|
||||
colset(redmap, 32, 32, 33, 33, 33, 35, 35, 35, 39, 39, 39, 39, 42, 42, 42, 44);
|
||||
colset(yellowmap, 82, 82, 73, 73, 73, 74, 74, 74, 66, 66, 66, 66, 67, 67, 67, 68);
|
||||
colset(lgreenmap, 96, 96, 98, 98, 98, 100, 100, 100, 103, 103, 103, 103, 105, 105, 105, 107);
|
||||
colset(bluemap, 146, 146, 147, 147, 147, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 151);
|
||||
colset(redmap, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 37, 37, 37, 39);
|
||||
colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23);
|
||||
colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60);
|
||||
colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136);
|
||||
colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165);
|
||||
colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125);
|
||||
colset(peridotmap, 72, 72, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94);
|
||||
colset(peridotmap, 73, 73, 188, 188, 188, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94);
|
||||
colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172);
|
||||
colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229);
|
||||
colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205);
|
||||
|
|
|
@ -1318,9 +1318,9 @@ static boolean CL_SendJoin(void)
|
|||
|
||||
static INT32 FindRejoinerNum(SINT8 node)
|
||||
{
|
||||
char strippednodeaddress[64];
|
||||
char addressbuffer[64];
|
||||
const char *nodeaddress;
|
||||
char *port;
|
||||
const char *strippednodeaddress;
|
||||
INT32 i;
|
||||
|
||||
// Make sure there is no dead dress before proceeding to the stripping
|
||||
|
@ -1331,10 +1331,8 @@ static INT32 FindRejoinerNum(SINT8 node)
|
|||
return -1;
|
||||
|
||||
// Strip the address of its port
|
||||
strcpy(strippednodeaddress, nodeaddress);
|
||||
port = strchr(strippednodeaddress, ':');
|
||||
if (port)
|
||||
*port = '\0';
|
||||
strcpy(addressbuffer, nodeaddress);
|
||||
strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL);
|
||||
|
||||
// Check if any player matches the stripped address
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
|
@ -2487,7 +2485,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
|||
{
|
||||
if (!snake)
|
||||
{
|
||||
F_MenuPresTicker(true); // title sky
|
||||
F_MenuPresTicker(); // title sky
|
||||
F_TitleScreenTicker(true);
|
||||
F_TitleScreenDrawer();
|
||||
}
|
||||
|
@ -3645,6 +3643,9 @@ void SV_ResetServer(void)
|
|||
|
||||
CV_RevertNetVars();
|
||||
|
||||
// Ensure synched when creating a new server
|
||||
M_CopyGameData(serverGamedata, clientGamedata);
|
||||
|
||||
DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n");
|
||||
}
|
||||
|
||||
|
@ -3768,14 +3769,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
|
|||
|
||||
if (server && I_GetNodeAddress)
|
||||
{
|
||||
char addressbuffer[64];
|
||||
const char *address = I_GetNodeAddress(node);
|
||||
char *port = NULL;
|
||||
if (address) // MI: fix msvcrt.dll!_mbscat crash?
|
||||
{
|
||||
strcpy(playeraddress[newplayernum], address);
|
||||
port = strchr(playeraddress[newplayernum], ':');
|
||||
if (port)
|
||||
*port = '\0';
|
||||
strcpy(addressbuffer, address);
|
||||
strcpy(playeraddress[newplayernum],
|
||||
I_NetSplitAddress(addressbuffer, NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1350,6 +1350,9 @@ void D_SRB2Main(void)
|
|||
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
|
||||
Z_Init();
|
||||
|
||||
clientGamedata = M_NewGameDataStruct();
|
||||
serverGamedata = M_NewGameDataStruct();
|
||||
|
||||
// Do this up here so that WADs loaded through the command line can use ExecCfg
|
||||
COM_Init();
|
||||
|
||||
|
@ -1479,7 +1482,9 @@ void D_SRB2Main(void)
|
|||
// confusion issues when loading mods.
|
||||
strlcpy(gamedatafilename, M_GetNextParm(), sizeof gamedatafilename);
|
||||
}
|
||||
G_LoadGameData();
|
||||
|
||||
G_LoadGameData(clientGamedata);
|
||||
M_CopyGameData(serverGamedata, clientGamedata);
|
||||
|
||||
#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)
|
||||
VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen
|
||||
|
@ -1710,7 +1715,7 @@ void D_SRB2Main(void)
|
|||
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
|
||||
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
|
||||
// lives hell.
|
||||
else if (!dedicated && M_MapLocked(pstartmap))
|
||||
else if (!dedicated && M_MapLocked(pstartmap, serverGamedata))
|
||||
I_Error("You need to unlock this level before you can warp to it!\n");
|
||||
else
|
||||
{
|
||||
|
|
26
src/d_net.c
26
src/d_net.c
|
@ -1207,26 +1207,32 @@ static void Internal_FreeNodenum(INT32 nodenum)
|
|||
(void)nodenum;
|
||||
}
|
||||
|
||||
char *I_NetSplitAddress(char *host, char **port)
|
||||
{
|
||||
boolean v4 = (strchr(host, '.') != NULL);
|
||||
|
||||
host = strtok(host, v4 ? ":" : "[]");
|
||||
|
||||
if (port)
|
||||
*port = strtok(NULL, ":");
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
SINT8 I_NetMakeNode(const char *hostname)
|
||||
{
|
||||
SINT8 newnode = -1;
|
||||
if (I_NetMakeNodewPort)
|
||||
{
|
||||
char *localhostname = strdup(hostname);
|
||||
char *t = localhostname;
|
||||
const char *port;
|
||||
char *port;
|
||||
if (!localhostname)
|
||||
return newnode;
|
||||
|
||||
// retrieve portnum from address!
|
||||
strtok(localhostname, ":");
|
||||
port = strtok(NULL, ":");
|
||||
hostname = I_NetSplitAddress(localhostname, &port);
|
||||
|
||||
// remove the port in the hostname as we've it already
|
||||
while ((*t != ':') && (*t != '\0'))
|
||||
t++;
|
||||
*t = '\0';
|
||||
|
||||
newnode = I_NetMakeNodewPort(localhostname, port);
|
||||
newnode = I_NetMakeNodewPort(hostname, port);
|
||||
free(localhostname);
|
||||
}
|
||||
return newnode;
|
||||
|
|
|
@ -2036,7 +2036,7 @@ static void Command_Map_f(void)
|
|||
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
|
||||
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
|
||||
// lives hell.
|
||||
if (!dedicated && M_MapLocked(newmapnum))
|
||||
if (!dedicated && M_MapLocked(newmapnum, serverGamedata))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
|
||||
Z_Free(realmapname);
|
||||
|
@ -3945,18 +3945,12 @@ void ItemFinder_OnChange(void)
|
|||
if (!cv_itemfinder.value)
|
||||
return; // it's fine.
|
||||
|
||||
if (!M_SecretUnlocked(SECRET_ITEMFINDER))
|
||||
if (!M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata))
|
||||
{
|
||||
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
|
||||
CV_StealthSetValue(&cv_itemfinder, 0);
|
||||
return;
|
||||
}
|
||||
else if (netgame || multiplayer)
|
||||
{
|
||||
CONS_Printf(M_GetText("This only works in single player.\n"));
|
||||
CV_StealthSetValue(&cv_itemfinder, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Deals with a pointlimit change by printing the change to the console.
|
||||
|
@ -4305,7 +4299,7 @@ void D_GameTypeChanged(INT32 lastgametype)
|
|||
|
||||
static void Ringslinger_OnChange(void)
|
||||
{
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && cv_ringslinger.value && !cv_debug)
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && cv_ringslinger.value && !cv_debug)
|
||||
{
|
||||
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
|
||||
CV_StealthSetValue(&cv_ringslinger, 0);
|
||||
|
@ -4318,7 +4312,7 @@ static void Ringslinger_OnChange(void)
|
|||
|
||||
static void Gravity_OnChange(void)
|
||||
{
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && !cv_debug
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && !cv_debug
|
||||
&& strcmp(cv_gravity.string, cv_gravity.defaultvalue))
|
||||
{
|
||||
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
|
||||
|
|
171
src/deh_lua.c
171
src/deh_lua.c
|
@ -10,20 +10,7 @@
|
|||
/// \file deh_lua.c
|
||||
/// \brief Lua SOC library
|
||||
|
||||
#include "g_game.h"
|
||||
#include "s_sound.h"
|
||||
#include "z_zone.h"
|
||||
#include "m_menu.h"
|
||||
#include "m_misc.h"
|
||||
#include "p_local.h"
|
||||
#include "st_stuff.h"
|
||||
#include "fastcmp.h"
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
|
||||
#include "dehacked.h"
|
||||
#include "deh_lua.h"
|
||||
#include "deh_tables.h"
|
||||
|
||||
// freeslot takes a name (string only!)
|
||||
// and allocates it to the appropriate free slot.
|
||||
|
@ -89,6 +76,8 @@ static inline int lib_freeslot(lua_State *L)
|
|||
strncpy(sprnames[j],word,4);
|
||||
//sprnames[j][4] = 0;
|
||||
used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
|
||||
// Lua needs to update the value in _G if it exists
|
||||
LUA_UpdateSprName(word, j);
|
||||
lua_pushinteger(L, j);
|
||||
r++;
|
||||
break;
|
||||
|
@ -219,18 +208,27 @@ static int lib_dummysuper(lua_State *L)
|
|||
return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;;
|
||||
}
|
||||
|
||||
static inline int lib_getenum(lua_State *L)
|
||||
static void CacheAndPushConstant(lua_State *L, const char *name, lua_Integer value)
|
||||
{
|
||||
const char *word, *p;
|
||||
// "cache" into _G
|
||||
lua_pushstring(L, name);
|
||||
lua_pushinteger(L, value);
|
||||
lua_rawset(L, LUA_GLOBALSINDEX);
|
||||
// push
|
||||
lua_pushinteger(L, value);
|
||||
}
|
||||
|
||||
// Search for a matching constant variable.
|
||||
// Result is stored into _G for faster subsequent use. (Except for SPR_ in the SOC parser)
|
||||
static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
|
||||
{
|
||||
const char *p;
|
||||
fixed_t i;
|
||||
boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
|
||||
if (lua_type(L,2) != LUA_TSTRING)
|
||||
return 0;
|
||||
word = lua_tostring(L,2);
|
||||
|
||||
if (strlen(word) == 1) { // Assume sprite frame if length 1.
|
||||
if (*word >= 'A' && *word <= '~')
|
||||
{
|
||||
lua_pushinteger(L, *word-'A');
|
||||
CacheAndPushConstant(L, word, *word-'A');
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
|
||||
|
@ -240,7 +238,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+3;
|
||||
for (i = 0; MOBJFLAG_LIST[i]; i++)
|
||||
if (fastcmp(p, MOBJFLAG_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word);
|
||||
|
@ -250,7 +248,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; MOBJFLAG2_LIST[i]; i++)
|
||||
if (fastcmp(p, MOBJFLAG2_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word);
|
||||
|
@ -260,12 +258,12 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; MOBJEFLAG_LIST[i]; i++)
|
||||
if (fastcmp(p, MOBJEFLAG_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
if (fastcmp(p, "REVERSESUPER"))
|
||||
{
|
||||
lua_pushinteger(L, (lua_Integer)MFE_REVERSESUPER);
|
||||
CacheAndPushConstant(L, word, (lua_Integer)MFE_REVERSESUPER);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word);
|
||||
|
@ -275,7 +273,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; i < 4; i++)
|
||||
if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word);
|
||||
|
@ -285,17 +283,17 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+3;
|
||||
for (i = 0; PLAYERFLAG_LIST[i]; i++)
|
||||
if (fastcmp(p, PLAYERFLAG_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
if (fastcmp(p, "FULLSTASIS"))
|
||||
{
|
||||
lua_pushinteger(L, (lua_Integer)PF_FULLSTASIS);
|
||||
CacheAndPushConstant(L, word, (lua_Integer)PF_FULLSTASIS);
|
||||
return 1;
|
||||
}
|
||||
else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release...
|
||||
{
|
||||
lua_pushinteger(L, (lua_Integer)PF_SPINDOWN);
|
||||
CacheAndPushConstant(L, word, (lua_Integer)PF_SPINDOWN);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
|
||||
|
@ -305,7 +303,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word;
|
||||
for (i = 0; Gametype_ConstantNames[i]; i++)
|
||||
if (fastcmp(p, Gametype_ConstantNames[i])) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
|
||||
|
@ -315,7 +313,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; GAMETYPERULE_LIST[i]; i++)
|
||||
if (fastcmp(p, GAMETYPERULE_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word);
|
||||
|
@ -325,7 +323,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; TYPEOFLEVEL[i].name; i++)
|
||||
if (fastcmp(p, TYPEOFLEVEL[i].name)) {
|
||||
lua_pushinteger(L, TYPEOFLEVEL[i].flag);
|
||||
CacheAndPushConstant(L, word, TYPEOFLEVEL[i].flag);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word);
|
||||
|
@ -333,9 +331,10 @@ static inline int lib_getenum(lua_State *L)
|
|||
}
|
||||
else if (fastncmp("ML_", word, 3)) {
|
||||
p = word+3;
|
||||
|
||||
for (i = 0; ML_LIST[i]; i++)
|
||||
if (fastcmp(p, ML_LIST[i])) {
|
||||
lua_pushinteger(L, ((lua_Integer)1<<i));
|
||||
CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
|
||||
return 1;
|
||||
}
|
||||
// Aliases
|
||||
|
@ -418,13 +417,13 @@ static inline int lib_getenum(lua_State *L)
|
|||
if (!FREE_STATES[i])
|
||||
break;
|
||||
if (fastcmp(p, FREE_STATES[i])) {
|
||||
lua_pushinteger(L, S_FIRSTFREESLOT+i);
|
||||
CacheAndPushConstant(L, word, S_FIRSTFREESLOT+i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < S_FIRSTFREESLOT; i++)
|
||||
if (fastcmp(p, STATE_LIST[i]+2)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "state '%s' does not exist.\n", word);
|
||||
|
@ -435,13 +434,13 @@ static inline int lib_getenum(lua_State *L)
|
|||
if (!FREE_MOBJS[i])
|
||||
break;
|
||||
if (fastcmp(p, FREE_MOBJS[i])) {
|
||||
lua_pushinteger(L, MT_FIRSTFREESLOT+i);
|
||||
CacheAndPushConstant(L, word, MT_FIRSTFREESLOT+i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MT_FIRSTFREESLOT; i++)
|
||||
if (fastcmp(p, MOBJTYPE_LIST[i]+3)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "mobjtype '%s' does not exist.\n", word);
|
||||
|
@ -450,7 +449,12 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; i < NUMSPRITES; i++)
|
||||
if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
|
||||
lua_pushinteger(L, i);
|
||||
// updating overridden sprnames is not implemented for soc parser,
|
||||
// so don't use cache
|
||||
if (mathlib)
|
||||
lua_pushinteger(L, i);
|
||||
else
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word);
|
||||
|
@ -465,12 +469,12 @@ static inline int lib_getenum(lua_State *L)
|
|||
// the spr2names entry will have "_" on the end, as in "RUN_"
|
||||
if (spr2names[i][3] == '_' && !p[3]) {
|
||||
if (fastncmp(p,spr2names[i],3)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (fastncmp(p,spr2names[i],4)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -481,7 +485,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; i < NUMSFX; i++)
|
||||
if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -490,7 +494,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; i < NUMSFX; i++)
|
||||
if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "sfx '%s' could not be found.\n", word);
|
||||
|
@ -499,7 +503,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+2;
|
||||
for (i = 0; i < NUMSFX; i++)
|
||||
if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word);
|
||||
|
@ -509,7 +513,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+3;
|
||||
for (i = 0; i < NUMPOWERS; i++)
|
||||
if (fasticmp(p, POWERS_LIST[i])) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -518,7 +522,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+3;
|
||||
for (i = 0; i < NUMPOWERS; i++)
|
||||
if (fastcmp(p, POWERS_LIST[i])) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "power '%s' could not be found.\n", word);
|
||||
|
@ -527,7 +531,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+4;
|
||||
for (i = 0; i < NUMHUDITEMS; i++)
|
||||
if (fastcmp(p, HUDITEMS_LIST[i])) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "huditem '%s' could not be found.\n", word);
|
||||
|
@ -539,13 +543,13 @@ static inline int lib_getenum(lua_State *L)
|
|||
if (!FREE_SKINCOLORS[i])
|
||||
break;
|
||||
if (fastcmp(p, FREE_SKINCOLORS[i])) {
|
||||
lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i);
|
||||
CacheAndPushConstant(L, word, SKINCOLOR_FIRSTFREESLOT+i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
|
||||
if (fastcmp(p, COLOR_ENUMS[i])) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "skincolor '%s' could not be found.\n", word);
|
||||
|
@ -556,7 +560,7 @@ static inline int lib_getenum(lua_State *L)
|
|||
for (i = 0; NIGHTSGRADE_LIST[i]; i++)
|
||||
if (*p == NIGHTSGRADE_LIST[i])
|
||||
{
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
|
||||
|
@ -566,13 +570,41 @@ static inline int lib_getenum(lua_State *L)
|
|||
p = word+3;
|
||||
for (i = 0; i < NUMMENUTYPES; i++)
|
||||
if (fastcmp(p, MENUTYPES_LIST[i])) {
|
||||
lua_pushinteger(L, i);
|
||||
CacheAndPushConstant(L, word, i);
|
||||
return 1;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word);
|
||||
return 0;
|
||||
}
|
||||
else if (!mathlib && fastncmp("A_",word,2)) {
|
||||
|
||||
if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release...
|
||||
{
|
||||
CacheAndPushConstant(L, word, (lua_Integer)BT_SPIN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; INT_CONST[i].n; i++)
|
||||
if (fastcmp(word,INT_CONST[i].n)) {
|
||||
CacheAndPushConstant(L, word, INT_CONST[i].v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lib_getenum(lua_State *L)
|
||||
{
|
||||
const char *word;
|
||||
fixed_t i;
|
||||
boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
|
||||
if (lua_type(L,2) != LUA_TSTRING)
|
||||
return 0;
|
||||
word = lua_tostring(L,2);
|
||||
|
||||
// check actions, super and globals first, as they don't have _G caching implemented
|
||||
// so they benefit from being checked first
|
||||
|
||||
if (!mathlib && fastncmp("A_",word,2)) {
|
||||
char *caps;
|
||||
// Try to get a Lua action first.
|
||||
/// \todo Push a closure that sets superactions[] and superstack.
|
||||
|
@ -611,25 +643,34 @@ static inline int lib_getenum(lua_State *L)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release...
|
||||
{
|
||||
lua_pushinteger(L, (lua_Integer)BT_SPIN);
|
||||
else if ((!mathlib && LUA_PushGlobals(L, word)) || ScanConstants(L, mathlib, word))
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; INT_CONST[i].n; i++)
|
||||
if (fastcmp(word,INT_CONST[i].n)) {
|
||||
lua_pushinteger(L, INT_CONST[i].v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
|
||||
|
||||
// DYNAMIC variables too!!
|
||||
// Try not to add anything that would break netgames or timeattack replays here.
|
||||
// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
|
||||
return LUA_PushGlobals(L, word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If a sprname has been "cached" to _G, update it to a new value.
|
||||
void LUA_UpdateSprName(const char *name, lua_Integer value)
|
||||
{
|
||||
char fullname[9] = "SPR_XXXX";
|
||||
|
||||
if (!gL)
|
||||
return;
|
||||
|
||||
strncpy(&fullname[4], name, 4);
|
||||
lua_pushstring(gL, fullname);
|
||||
lua_rawget(gL, LUA_GLOBALSINDEX);
|
||||
|
||||
if (!lua_isnil(gL, -1))
|
||||
{
|
||||
lua_pushstring(gL, name);
|
||||
lua_pushinteger(gL, value);
|
||||
lua_rawset(gL, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
lua_pop(gL, 1); // pop the rawget result
|
||||
}
|
||||
|
||||
int LUA_EnumLib(lua_State *L)
|
||||
|
|
|
@ -13,6 +13,21 @@
|
|||
#ifndef __DEH_LUA_H__
|
||||
#define __DEH_LUA_H__
|
||||
|
||||
#include "g_game.h"
|
||||
#include "s_sound.h"
|
||||
#include "z_zone.h"
|
||||
#include "m_menu.h"
|
||||
#include "m_misc.h"
|
||||
#include "p_local.h"
|
||||
#include "st_stuff.h"
|
||||
#include "fastcmp.h"
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
|
||||
#include "dehacked.h"
|
||||
#include "deh_tables.h"
|
||||
|
||||
void LUA_UpdateSprName(const char *name, lua_Integer value);
|
||||
boolean LUA_SetLuaAction(void *state, const char *actiontocompare);
|
||||
const char *LUA_GetActionName(void *action);
|
||||
void LUA_SetActionByName(void *state, const char *actiontocompare);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "dehacked.h"
|
||||
#include "deh_soc.h"
|
||||
#include "deh_lua.h" // included due to some LUA_SetLuaAction hack smh
|
||||
// also used for LUA_UpdateSprName
|
||||
#include "deh_tables.h"
|
||||
|
||||
// Loops through every constant and operation in word and performs its calculations, returning the final value.
|
||||
|
@ -439,6 +440,8 @@ void readfreeslots(MYFILE *f)
|
|||
strncpy(sprnames[i],word,4);
|
||||
//sprnames[i][4] = 0;
|
||||
used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now.
|
||||
// Lua needs to update the value in _G if it exists
|
||||
LUA_UpdateSprName(word, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3839,6 +3842,10 @@ void readmaincfg(MYFILE *f)
|
|||
{
|
||||
useContinues = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y');
|
||||
}
|
||||
else if (fastcmp(word, "SHAREEMBLEMS"))
|
||||
{
|
||||
shareEmblems = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y');
|
||||
}
|
||||
|
||||
else if (fastcmp(word, "GAMEDATA"))
|
||||
{
|
||||
|
@ -3849,7 +3856,7 @@ void readmaincfg(MYFILE *f)
|
|||
if (!GoodDataFileName(word2))
|
||||
I_Error("Maincfg: bad data file name '%s'\n", word2);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
strlcpy(gamedatafilename, word2, sizeof (gamedatafilename));
|
||||
strlwr(gamedatafilename);
|
||||
savemoddata = true;
|
||||
|
|
|
@ -575,7 +575,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
|||
} // end while
|
||||
|
||||
if (gamedataadded)
|
||||
G_LoadGameData();
|
||||
G_LoadGameData(clientGamedata);
|
||||
|
||||
if (gamestate == GS_TITLESCREEN)
|
||||
{
|
||||
|
|
|
@ -132,8 +132,6 @@ extern INT32 postimgparam2;
|
|||
extern INT32 viewwindowx, viewwindowy;
|
||||
extern INT32 viewwidth, scaledviewwidth;
|
||||
|
||||
extern boolean gamedataloaded;
|
||||
|
||||
// Player taking events, and displaying.
|
||||
extern INT32 consoleplayer;
|
||||
extern INT32 displayplayer;
|
||||
|
@ -495,8 +493,6 @@ typedef struct
|
|||
extern tolinfo_t TYPEOFLEVEL[NUMTOLNAMES];
|
||||
extern UINT32 lastcustomtol;
|
||||
|
||||
extern tic_t totalplaytime;
|
||||
|
||||
extern boolean stagefailed;
|
||||
|
||||
// Emeralds stored as bits to throw savegame hackers off.
|
||||
|
@ -515,52 +511,6 @@ extern INT32 luabanks[NUM_LUABANKS];
|
|||
|
||||
extern INT32 nummaprings; //keep track of spawned rings/coins
|
||||
|
||||
/** Time attack information, currently a very small structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
tic_t time; ///< Time in which the level was finished.
|
||||
UINT32 score; ///< Score when the level was finished.
|
||||
UINT16 rings; ///< Rings when the level was finished.
|
||||
} recorddata_t;
|
||||
|
||||
/** Setup for one NiGHTS map.
|
||||
* These are dynamically allocated because I am insane
|
||||
*/
|
||||
#define GRADE_F 0
|
||||
#define GRADE_E 1
|
||||
#define GRADE_D 2
|
||||
#define GRADE_C 3
|
||||
#define GRADE_B 4
|
||||
#define GRADE_A 5
|
||||
#define GRADE_S 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// 8 mares, 1 overall (0)
|
||||
UINT8 nummares;
|
||||
UINT32 score[9];
|
||||
UINT8 grade[9];
|
||||
tic_t time[9];
|
||||
} nightsdata_t;
|
||||
|
||||
extern nightsdata_t *nightsrecords[NUMMAPS];
|
||||
extern recorddata_t *mainrecords[NUMMAPS];
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED 1
|
||||
#define MV_BEATEN 2
|
||||
#define MV_ALLEMERALDS 4
|
||||
#define MV_ULTIMATE 8
|
||||
#define MV_PERFECT 16
|
||||
#define MV_PERFECTRA 32
|
||||
#define MV_MAX 63 // used in gamedata check, update whenever MV's are added
|
||||
#define MV_MP 128
|
||||
extern UINT8 mapvisited[NUMMAPS];
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
extern nightsdata_t ntemprecords;
|
||||
|
||||
extern UINT32 token; ///< Number of tokens collected in a level
|
||||
extern UINT32 tokenlist; ///< List of tokens collected
|
||||
extern boolean gottoken; ///< Did you get a token? Used for end of act
|
||||
|
@ -593,9 +543,12 @@ extern UINT8 useBlackRock;
|
|||
|
||||
extern UINT8 use1upSound;
|
||||
extern UINT8 maxXtraLife; // Max extra lives from rings
|
||||
|
||||
extern UINT8 useContinues;
|
||||
#define continuesInSession (!multiplayer && (ultimatemode || (useContinues && !marathonmode) || (!modeattacking && !(cursaveslot > 0))))
|
||||
|
||||
extern UINT8 shareEmblems;
|
||||
|
||||
extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations
|
||||
|
||||
// For racing
|
||||
|
@ -616,10 +569,6 @@ extern INT32 cheats;
|
|||
|
||||
extern tic_t hidetime;
|
||||
|
||||
extern UINT32 timesBeaten; // # of times the game has been beaten.
|
||||
extern UINT32 timesBeatenWithEmeralds;
|
||||
extern UINT32 timesBeatenUltimate;
|
||||
|
||||
// ===========================
|
||||
// Internal parameters, fixed.
|
||||
// ===========================
|
||||
|
|
134
src/f_finale.c
134
src/f_finale.c
|
@ -63,7 +63,6 @@ static tic_t stoptimer;
|
|||
static boolean keypressed = false;
|
||||
|
||||
// (no longer) De-Demo'd Title Screen
|
||||
static INT32 menuanimtimer; // Title screen: background animation timing
|
||||
mobj_t *titlemapcameraref = NULL;
|
||||
|
||||
// menu presentation state
|
||||
|
@ -75,6 +74,8 @@ INT32 curbgyspeed;
|
|||
boolean curbghide;
|
||||
boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus
|
||||
|
||||
static fixed_t curbgx = 0;
|
||||
static fixed_t curbgy = 0;
|
||||
static UINT8 curDemo = 0;
|
||||
static UINT32 demoDelayLeft;
|
||||
static UINT32 demoIdleLeft;
|
||||
|
@ -1411,7 +1412,7 @@ boolean F_CreditResponder(event_t *event)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug)
|
||||
if (!(serverGamedata->timesBeaten) && !(netgame || multiplayer) && !cv_debug)
|
||||
return false;
|
||||
|
||||
if (event->type != ev_keydown)
|
||||
|
@ -1573,23 +1574,17 @@ void F_GameEvaluationDrawer(void)
|
|||
#if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables
|
||||
if (finalecount >= 5*TICRATE)
|
||||
{
|
||||
INT32 startcoord = 32;
|
||||
V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:");
|
||||
|
||||
if (netgame)
|
||||
V_DrawString(8, 96, V_YELLOWMAP, "Multiplayer games\ncan't unlock\nextras!");
|
||||
else
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
{
|
||||
INT32 startcoord = 32;
|
||||
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS
|
||||
&& unlockables[i].type && !unlockables[i].nocecho)
|
||||
{
|
||||
if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS
|
||||
&& unlockables[i].type && !unlockables[i].nocecho)
|
||||
{
|
||||
if (unlockables[i].unlocked)
|
||||
V_DrawString(8, startcoord, 0, unlockables[i].name);
|
||||
startcoord += 8;
|
||||
}
|
||||
if (clientGamedata->unlocked[i])
|
||||
V_DrawString(8, startcoord, 0, unlockables[i].name);
|
||||
startcoord += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1648,28 +1643,27 @@ void F_GameEvaluationTicker(void)
|
|||
|
||||
if (finalecount == 5*TICRATE)
|
||||
{
|
||||
if (netgame || multiplayer) // modify this when we finally allow unlocking stuff in 2P
|
||||
serverGamedata->timesBeaten++;
|
||||
clientGamedata->timesBeaten++;
|
||||
|
||||
if (ALL7EMERALDS(emeralds))
|
||||
{
|
||||
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8);
|
||||
HU_SetCEchoDuration(6);
|
||||
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Multiplayer games can't unlock extras!");
|
||||
serverGamedata->timesBeatenWithEmeralds++;
|
||||
clientGamedata->timesBeatenWithEmeralds++;
|
||||
}
|
||||
|
||||
if (ultimatemode)
|
||||
{
|
||||
serverGamedata->timesBeatenUltimate++;
|
||||
clientGamedata->timesBeatenUltimate++;
|
||||
}
|
||||
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
}
|
||||
else
|
||||
{
|
||||
++timesBeaten;
|
||||
|
||||
if (ALL7EMERALDS(emeralds))
|
||||
++timesBeatenWithEmeralds;
|
||||
|
||||
if (ultimatemode)
|
||||
++timesBeatenUltimate;
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
||||
G_SaveGameData();
|
||||
}
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2183,7 +2177,7 @@ void F_EndingDrawer(void)
|
|||
//colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), str);
|
||||
V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false);
|
||||
V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
|
||||
V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((serverGamedata->timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
|
||||
}
|
||||
|
||||
if (finalecount > STOPPINGPOINT-(20+(2*TICRATE)))
|
||||
|
@ -2249,7 +2243,8 @@ void F_GameEndTicker(void)
|
|||
|
||||
void F_InitMenuPresValues(void)
|
||||
{
|
||||
menuanimtimer = 0;
|
||||
curbgx = 0;
|
||||
curbgy = 0;
|
||||
prevMenuId = 0;
|
||||
activeMenuId = MainDef.menuid;
|
||||
|
||||
|
@ -2282,17 +2277,11 @@ void F_InitMenuPresValues(void)
|
|||
//
|
||||
// F_SkyScroll
|
||||
//
|
||||
void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
|
||||
void F_SkyScroll(const char *patchname)
|
||||
{
|
||||
INT32 xscrolled, x, xneg = (scrollxspeed > 0) - (scrollxspeed < 0), tilex;
|
||||
INT32 yscrolled, y, yneg = (scrollyspeed > 0) - (scrollyspeed < 0), tiley;
|
||||
boolean xispos = (scrollxspeed >= 0), yispos = (scrollyspeed >= 0);
|
||||
INT32 x, basey = 0;
|
||||
INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
|
||||
INT16 patwidth, patheight;
|
||||
INT32 pw, ph; // scaled by dupz
|
||||
patch_t *pat;
|
||||
INT32 i, j;
|
||||
fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer;
|
||||
|
||||
if (rendermode == render_none)
|
||||
return;
|
||||
|
@ -2303,43 +2292,34 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!scrollxspeed && !scrollyspeed)
|
||||
pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY);
|
||||
|
||||
if (!curbgxspeed && !curbgyspeed)
|
||||
{
|
||||
V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY));
|
||||
V_DrawPatchFill(pat);
|
||||
W_UnlockCachedPatch(pat);
|
||||
return;
|
||||
}
|
||||
|
||||
pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY);
|
||||
// Modulo the background scrolling to prevent jumps from integer overflows
|
||||
// We already load the background patch here, so we can modulo it here
|
||||
// to avoid also having to load the patch in F_MenuPresTicker
|
||||
curbgx %= pat->width * 16;
|
||||
curbgy %= pat->height * 16;
|
||||
|
||||
patwidth = pat->width;
|
||||
patheight = pat->height;
|
||||
pw = patwidth * dupz;
|
||||
ph = patheight * dupz;
|
||||
// Ooh, fancy frame interpolation
|
||||
x = ((curbgx*dupz) + FixedInt((rendertimefrac-FRACUNIT) * curbgxspeed*dupz)) / 16;
|
||||
basey = ((curbgy*dupz) + FixedInt((rendertimefrac-FRACUNIT) * curbgyspeed*dupz)) / 16;
|
||||
|
||||
tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center
|
||||
tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2;
|
||||
if (x > 0) // Make sure that we don't leave the left or top sides empty
|
||||
x -= pat->width * dupz;
|
||||
if (basey > 0)
|
||||
basey -= pat->height * dupz;
|
||||
|
||||
fracmenuanimtimer = (menuanimtimer * FRACUNIT) - (FRACUNIT - rendertimefrac);
|
||||
xscrolltimer = ((fracmenuanimtimer*scrollxspeed)/16 + patwidth*xneg*FRACUNIT) % (patwidth * FRACUNIT);
|
||||
yscrolltimer = ((fracmenuanimtimer*scrollyspeed)/16 + patheight*yneg*FRACUNIT) % (patheight * FRACUNIT);
|
||||
|
||||
// coordinate offsets
|
||||
xscrolled = FixedInt(xscrolltimer * dupz);
|
||||
yscrolled = FixedInt(yscrolltimer * dupz);
|
||||
|
||||
for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0;
|
||||
i < tilex;
|
||||
x += pw, i++)
|
||||
for (; x < vid.width; x += pat->width * dupz)
|
||||
{
|
||||
for (y = (yispos) ? -ph*(tiley-1)+ph : 0, j = 0;
|
||||
j < tiley;
|
||||
y += ph, j++)
|
||||
{
|
||||
V_DrawScaledPatch(
|
||||
(xispos) ? xscrolled - x : x + xscrolled,
|
||||
(yispos) ? yscrolled - y : y + yscrolled,
|
||||
V_NOSCALESTART, pat);
|
||||
}
|
||||
for (INT32 y = basey; y < vid.height; y += pat->height * dupz)
|
||||
V_DrawScaledPatch(x, y, V_NOSCALESTART, pat);
|
||||
}
|
||||
|
||||
W_UnlockCachedPatch(pat);
|
||||
|
@ -2662,7 +2642,7 @@ void F_TitleScreenDrawer(void)
|
|||
if (curbgcolor >= 0)
|
||||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
|
||||
else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
|
||||
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
|
||||
F_SkyScroll(curbgname);
|
||||
|
||||
// Don't draw outside of the title screen, or if the patch isn't there.
|
||||
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
|
||||
|
@ -3417,10 +3397,10 @@ luahook:
|
|||
|
||||
// separate animation timer for backgrounds, since we also count
|
||||
// during GS_TIMEATTACK
|
||||
void F_MenuPresTicker(boolean run)
|
||||
void F_MenuPresTicker(void)
|
||||
{
|
||||
if (run)
|
||||
menuanimtimer++;
|
||||
curbgx += curbgxspeed;
|
||||
curbgy += curbgyspeed;
|
||||
}
|
||||
|
||||
// (no longer) De-Demo'd Title Screen
|
||||
|
|
|
@ -40,7 +40,7 @@ void F_TextPromptTicker(void);
|
|||
void F_GameEndDrawer(void);
|
||||
void F_IntroDrawer(void);
|
||||
void F_TitleScreenDrawer(void);
|
||||
void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname);
|
||||
void F_SkyScroll(const char *patchname);
|
||||
|
||||
void F_GameEvaluationDrawer(void);
|
||||
void F_StartGameEvaluation(void);
|
||||
|
@ -131,7 +131,7 @@ extern UINT16 curtttics;
|
|||
#define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0])
|
||||
|
||||
void F_InitMenuPresValues(void);
|
||||
void F_MenuPresTicker(boolean run);
|
||||
void F_MenuPresTicker(void);
|
||||
|
||||
//
|
||||
// WIPE
|
||||
|
|
268
src/g_game.c
268
src/g_game.c
|
@ -185,18 +185,6 @@ INT32 tokenbits; // Used for setting token bits
|
|||
// Old Special Stage
|
||||
INT32 sstimer; // Time allotted in the special stage
|
||||
|
||||
tic_t totalplaytime;
|
||||
boolean gamedataloaded = false;
|
||||
|
||||
// Time attack data for levels
|
||||
// These are dynamically allocated for space reasons now
|
||||
recorddata_t *mainrecords[NUMMAPS] = {NULL};
|
||||
nightsdata_t *nightsrecords[NUMMAPS] = {NULL};
|
||||
UINT8 mapvisited[NUMMAPS];
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
nightsdata_t ntemprecords;
|
||||
|
||||
UINT32 bluescore, redscore; // CTF and Team Match team scores
|
||||
|
||||
// ring count... for PERFECT!
|
||||
|
@ -227,6 +215,7 @@ UINT8 ammoremovaltics = 2*TICRATE;
|
|||
UINT8 use1upSound = 0;
|
||||
UINT8 maxXtraLife = 2; // Max extra lives from rings
|
||||
UINT8 useContinues = 0; // Set to 1 to enable continues outside of no-save scenarioes
|
||||
UINT8 shareEmblems = 0; // Set to 1 to share all picked up emblems in multiplayer
|
||||
|
||||
UINT8 introtoplay;
|
||||
UINT8 creditscutscene;
|
||||
|
@ -252,11 +241,6 @@ INT32 cheats; //for multiplayer cheat commands
|
|||
|
||||
tic_t hidetime;
|
||||
|
||||
// Grading
|
||||
UINT32 timesBeaten;
|
||||
UINT32 timesBeatenWithEmeralds;
|
||||
UINT32 timesBeatenUltimate;
|
||||
|
||||
typedef struct joystickvector2_s
|
||||
{
|
||||
INT32 xaxis;
|
||||
|
@ -452,86 +436,86 @@ INT16 rw_maximums[NUM_WEAPONS] =
|
|||
};
|
||||
|
||||
// Allocation for time and nights data
|
||||
void G_AllocMainRecordData(INT16 i)
|
||||
void G_AllocMainRecordData(INT16 i, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[i])
|
||||
mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
|
||||
memset(mainrecords[i], 0, sizeof(recorddata_t));
|
||||
if (!data->mainrecords[i])
|
||||
data->mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
|
||||
memset(data->mainrecords[i], 0, sizeof(recorddata_t));
|
||||
}
|
||||
|
||||
void G_AllocNightsRecordData(INT16 i)
|
||||
void G_AllocNightsRecordData(INT16 i, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[i])
|
||||
nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL);
|
||||
memset(nightsrecords[i], 0, sizeof(nightsdata_t));
|
||||
if (!data->nightsrecords[i])
|
||||
data->nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL);
|
||||
memset(data->nightsrecords[i], 0, sizeof(nightsdata_t));
|
||||
}
|
||||
|
||||
// MAKE SURE YOU SAVE DATA BEFORE CALLING THIS
|
||||
void G_ClearRecords(void)
|
||||
void G_ClearRecords(gamedata_t *data)
|
||||
{
|
||||
INT16 i;
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if (mainrecords[i])
|
||||
if (data->mainrecords[i])
|
||||
{
|
||||
Z_Free(mainrecords[i]);
|
||||
mainrecords[i] = NULL;
|
||||
Z_Free(data->mainrecords[i]);
|
||||
data->mainrecords[i] = NULL;
|
||||
}
|
||||
if (nightsrecords[i])
|
||||
if (data->nightsrecords[i])
|
||||
{
|
||||
Z_Free(nightsrecords[i]);
|
||||
nightsrecords[i] = NULL;
|
||||
Z_Free(data->nightsrecords[i]);
|
||||
data->nightsrecords[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For easy retrieval of records
|
||||
UINT32 G_GetBestScore(INT16 map)
|
||||
UINT32 G_GetBestScore(INT16 map, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[map-1])
|
||||
if (!data->mainrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return mainrecords[map-1]->score;
|
||||
return data->mainrecords[map-1]->score;
|
||||
}
|
||||
|
||||
tic_t G_GetBestTime(INT16 map)
|
||||
tic_t G_GetBestTime(INT16 map, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[map-1] || mainrecords[map-1]->time <= 0)
|
||||
if (!data->mainrecords[map-1] || data->mainrecords[map-1]->time <= 0)
|
||||
return (tic_t)UINT32_MAX;
|
||||
|
||||
return mainrecords[map-1]->time;
|
||||
return data->mainrecords[map-1]->time;
|
||||
}
|
||||
|
||||
UINT16 G_GetBestRings(INT16 map)
|
||||
UINT16 G_GetBestRings(INT16 map, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[map-1])
|
||||
if (!data->mainrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return mainrecords[map-1]->rings;
|
||||
return data->mainrecords[map-1]->rings;
|
||||
}
|
||||
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare)
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[map-1])
|
||||
if (!data->nightsrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return nightsrecords[map-1]->score[mare];
|
||||
return data->nightsrecords[map-1]->score[mare];
|
||||
}
|
||||
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare)
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[map-1] || nightsrecords[map-1]->time[mare] <= 0)
|
||||
if (!data->nightsrecords[map-1] || data->nightsrecords[map-1]->time[mare] <= 0)
|
||||
return (tic_t)UINT32_MAX;
|
||||
|
||||
return nightsrecords[map-1]->time[mare];
|
||||
return data->nightsrecords[map-1]->time[mare];
|
||||
}
|
||||
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare)
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[map-1])
|
||||
if (!data->nightsrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return nightsrecords[map-1]->grade[mare];
|
||||
return data->nightsrecords[map-1]->grade[mare];
|
||||
}
|
||||
|
||||
// For easy adding of NiGHTS records
|
||||
|
@ -553,7 +537,7 @@ void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare)
|
|||
// Update replay files/data, etc. for Record Attack
|
||||
// See G_SetNightsRecords for NiGHTS Attack.
|
||||
//
|
||||
static void G_UpdateRecordReplays(void)
|
||||
static void G_UpdateRecordReplays(gamedata_t *data)
|
||||
{
|
||||
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
|
||||
char *gpath;
|
||||
|
@ -561,17 +545,17 @@ static void G_UpdateRecordReplays(void)
|
|||
UINT8 earnedEmblems;
|
||||
|
||||
// Record new best time
|
||||
if (!mainrecords[gamemap-1])
|
||||
G_AllocMainRecordData(gamemap-1);
|
||||
if (!data->mainrecords[gamemap-1])
|
||||
G_AllocMainRecordData(gamemap-1, data);
|
||||
|
||||
if (players[consoleplayer].score > mainrecords[gamemap-1]->score)
|
||||
mainrecords[gamemap-1]->score = players[consoleplayer].score;
|
||||
if (players[consoleplayer].score > data->mainrecords[gamemap-1]->score)
|
||||
data->mainrecords[gamemap-1]->score = players[consoleplayer].score;
|
||||
|
||||
if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
|
||||
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
|
||||
if ((data->mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < data->mainrecords[gamemap-1]->time))
|
||||
data->mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
|
||||
|
||||
if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings)
|
||||
mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);
|
||||
if ((UINT16)(players[consoleplayer].rings) > data->mainrecords[gamemap-1]->rings)
|
||||
data->mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);
|
||||
|
||||
// Save demo!
|
||||
bestdemo[255] = '\0';
|
||||
|
@ -627,14 +611,14 @@ static void G_UpdateRecordReplays(void)
|
|||
free(gpath);
|
||||
|
||||
// Check emblems when level data is updated
|
||||
if ((earnedEmblems = M_CheckLevelEmblems()))
|
||||
if ((earnedEmblems = M_CheckLevelEmblems(data)))
|
||||
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
|
||||
|
||||
// Update timeattack menu's replay availability.
|
||||
Nextmap_OnChange();
|
||||
}
|
||||
|
||||
void G_SetNightsRecords(void)
|
||||
void G_SetNightsRecords(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
UINT32 totalscore = 0;
|
||||
|
@ -675,9 +659,9 @@ void G_SetNightsRecords(void)
|
|||
{
|
||||
nightsdata_t *maprecords;
|
||||
|
||||
if (!nightsrecords[gamemap-1])
|
||||
G_AllocNightsRecordData(gamemap-1);
|
||||
maprecords = nightsrecords[gamemap-1];
|
||||
if (!data->nightsrecords[gamemap-1])
|
||||
G_AllocNightsRecordData(gamemap-1, data);
|
||||
maprecords = data->nightsrecords[gamemap-1];
|
||||
|
||||
if (maprecords->nummares != ntemprecords.nummares)
|
||||
maprecords->nummares = ntemprecords.nummares;
|
||||
|
@ -739,7 +723,7 @@ void G_SetNightsRecords(void)
|
|||
}
|
||||
free(gpath);
|
||||
|
||||
if ((earnedEmblems = M_CheckLevelEmblems()))
|
||||
if ((earnedEmblems = M_CheckLevelEmblems(data)))
|
||||
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
|
||||
|
||||
// If the mare count changed, this will update the score display
|
||||
|
@ -2407,7 +2391,8 @@ void G_Ticker(boolean run)
|
|||
break;
|
||||
|
||||
case GS_TIMEATTACK:
|
||||
F_MenuPresTicker(run);
|
||||
if (run)
|
||||
F_MenuPresTicker();
|
||||
break;
|
||||
|
||||
case GS_INTRO:
|
||||
|
@ -2455,7 +2440,8 @@ void G_Ticker(boolean run)
|
|||
// then intentionally fall through
|
||||
/* FALLTHRU */
|
||||
case GS_WAITINGPLAYERS:
|
||||
F_MenuPresTicker(run);
|
||||
if (run)
|
||||
F_MenuPresTicker();
|
||||
F_TitleScreenTicker(run);
|
||||
break;
|
||||
|
||||
|
@ -3169,6 +3155,9 @@ void G_DoReborn(INT32 playernum)
|
|||
|
||||
if (resetlevel)
|
||||
{
|
||||
// Don't give completion emblems for reloading the level...
|
||||
stagefailed = true;
|
||||
|
||||
// reload the level from scratch
|
||||
if (countdowntimeup)
|
||||
{
|
||||
|
@ -3838,7 +3827,7 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
|
|||
for (ix = 0; ix < NUMMAPS; ix++)
|
||||
if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags
|
||||
&& ix != pprevmap // Don't pick the same map.
|
||||
&& (dedicated || !M_MapLocked(ix+1)) // Don't pick locked maps.
|
||||
&& (dedicated || !M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps.
|
||||
)
|
||||
okmaps[numokmaps++] = ix;
|
||||
|
||||
|
@ -3855,40 +3844,52 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
|
|||
//
|
||||
// G_UpdateVisited
|
||||
//
|
||||
static void G_UpdateVisited(void)
|
||||
static void G_UpdateVisited(gamedata_t *data, boolean silent)
|
||||
{
|
||||
boolean spec = G_IsSpecialStage(gamemap);
|
||||
// Update visitation flags?
|
||||
if (!multiplayer && !demoplayback && (gametype == GT_COOP) // SP/RA/NiGHTS mode
|
||||
if (!demoplayback
|
||||
&& G_CoopGametype() // Campaign mode
|
||||
&& !stagefailed) // Did not fail the stage
|
||||
{
|
||||
UINT8 earnedEmblems;
|
||||
|
||||
// Update visitation flags
|
||||
mapvisited[gamemap-1] |= MV_BEATEN;
|
||||
data->mapvisited[gamemap-1] |= MV_BEATEN;
|
||||
|
||||
// eh, what the hell
|
||||
if (ultimatemode)
|
||||
mapvisited[gamemap-1] |= MV_ULTIMATE;
|
||||
data->mapvisited[gamemap-1] |= MV_ULTIMATE;
|
||||
|
||||
// may seem incorrect but IS possible in what the main game uses as mp special stages, and nummaprings will be -1 in NiGHTS
|
||||
if (nummaprings > 0 && players[consoleplayer].rings >= nummaprings)
|
||||
{
|
||||
mapvisited[gamemap-1] |= MV_PERFECT;
|
||||
data->mapvisited[gamemap-1] |= MV_PERFECT;
|
||||
if (modeattacking)
|
||||
mapvisited[gamemap-1] |= MV_PERFECTRA;
|
||||
data->mapvisited[gamemap-1] |= MV_PERFECTRA;
|
||||
}
|
||||
|
||||
if (!spec)
|
||||
{
|
||||
// not available to special stages because they can only really be done in one order in an unmodified game, so impossible for first six and trivial for seventh
|
||||
if (ALL7EMERALDS(emeralds))
|
||||
mapvisited[gamemap-1] |= MV_ALLEMERALDS;
|
||||
data->mapvisited[gamemap-1] |= MV_ALLEMERALDS;
|
||||
}
|
||||
|
||||
if (modeattacking == ATTACKING_RECORD)
|
||||
G_UpdateRecordReplays();
|
||||
else if (modeattacking == ATTACKING_NIGHTS)
|
||||
G_SetNightsRecords();
|
||||
if (silent)
|
||||
{
|
||||
if (modeattacking)
|
||||
M_CheckLevelEmblems(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modeattacking == ATTACKING_RECORD)
|
||||
G_UpdateRecordReplays(data);
|
||||
else if (modeattacking == ATTACKING_NIGHTS)
|
||||
G_SetNightsRecords(data);
|
||||
}
|
||||
|
||||
if ((earnedEmblems = M_CompletionEmblems()))
|
||||
if ((earnedEmblems = M_CompletionEmblems(data)) && !silent)
|
||||
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
|
||||
}
|
||||
}
|
||||
|
@ -4091,7 +4092,8 @@ static void G_DoCompleted(void)
|
|||
|
||||
if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none))
|
||||
{
|
||||
G_UpdateVisited();
|
||||
G_UpdateVisited(serverGamedata, true);
|
||||
G_UpdateVisited(clientGamedata, false);
|
||||
G_HandleSaveLevel();
|
||||
G_AfterIntermission();
|
||||
}
|
||||
|
@ -4100,7 +4102,8 @@ static void G_DoCompleted(void)
|
|||
G_SetGamestate(GS_INTERMISSION);
|
||||
Y_StartIntermission();
|
||||
Y_LoadIntermissionData();
|
||||
G_UpdateVisited();
|
||||
G_UpdateVisited(serverGamedata, true);
|
||||
G_UpdateVisited(clientGamedata, false);
|
||||
G_HandleSaveLevel();
|
||||
}
|
||||
}
|
||||
|
@ -4287,7 +4290,7 @@ void G_LoadGameSettings(void)
|
|||
|
||||
// G_LoadGameData
|
||||
// Loads the main data file, which stores information such as emblems found, etc.
|
||||
void G_LoadGameData(void)
|
||||
void G_LoadGameData(gamedata_t *data)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j;
|
||||
|
@ -4304,13 +4307,13 @@ void G_LoadGameData(void)
|
|||
INT32 curmare;
|
||||
|
||||
// Stop saving, until we successfully load it again.
|
||||
gamedataloaded = false;
|
||||
data->loaded = false;
|
||||
|
||||
// Clear things so previously read gamedata doesn't transfer
|
||||
// to new gamedata
|
||||
G_ClearRecords(); // main and nights records
|
||||
M_ClearSecrets(); // emblems, unlocks, maps visited, etc
|
||||
totalplaytime = 0; // total play time (separate from all)
|
||||
G_ClearRecords(data); // main and nights records
|
||||
M_ClearSecrets(data); // emblems, unlocks, maps visited, etc
|
||||
data->totalplaytime = 0; // total play time (separate from all)
|
||||
|
||||
if (M_CheckParm("-nodata"))
|
||||
{
|
||||
|
@ -4321,7 +4324,7 @@ void G_LoadGameData(void)
|
|||
if (M_CheckParm("-resetdata"))
|
||||
{
|
||||
// Don't load, but do save. (essentially, reset)
|
||||
gamedataloaded = true;
|
||||
data->loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4329,7 +4332,7 @@ void G_LoadGameData(void)
|
|||
if (!length)
|
||||
{
|
||||
// No gamedata. We can save a new one.
|
||||
gamedataloaded = true;
|
||||
data->loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4352,7 +4355,7 @@ void G_LoadGameData(void)
|
|||
I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
|
||||
}
|
||||
|
||||
totalplaytime = READUINT32(save_p);
|
||||
data->totalplaytime = READUINT32(save_p);
|
||||
|
||||
#ifdef COMPAT_GAMEDATA_ID
|
||||
if (versionID == COMPAT_GAMEDATA_ID)
|
||||
|
@ -4386,7 +4389,7 @@ void G_LoadGameData(void)
|
|||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
if ((mapvisited[i] = READUINT8(save_p)) > MV_MAX)
|
||||
if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX)
|
||||
goto datacorrupt;
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
|
@ -4394,34 +4397,34 @@ void G_LoadGameData(void)
|
|||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
emblemlocations[j+i].collected = ((rtemp >> j) & 1);
|
||||
data->collected[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXEXTRAEMBLEMS;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
|
||||
extraemblems[j+i].collected = ((rtemp >> j) & 1);
|
||||
data->extraCollected[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXUNLOCKABLES;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
unlockables[j+i].unlocked = ((rtemp >> j) & 1);
|
||||
data->unlocked[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXCONDITIONSETS;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
conditionSets[j+i].achieved = ((rtemp >> j) & 1);
|
||||
data->achieved[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
|
||||
timesBeaten = READUINT32(save_p);
|
||||
timesBeatenWithEmeralds = READUINT32(save_p);
|
||||
timesBeatenUltimate = READUINT32(save_p);
|
||||
data->timesBeaten = READUINT32(save_p);
|
||||
data->timesBeatenWithEmeralds = READUINT32(save_p);
|
||||
data->timesBeatenUltimate = READUINT32(save_p);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
|
@ -4436,10 +4439,10 @@ void G_LoadGameData(void)
|
|||
|
||||
if (recscore || rectime || recrings)
|
||||
{
|
||||
G_AllocMainRecordData((INT16)i);
|
||||
mainrecords[i]->score = recscore;
|
||||
mainrecords[i]->time = rectime;
|
||||
mainrecords[i]->rings = recrings;
|
||||
G_AllocMainRecordData((INT16)i, data);
|
||||
data->mainrecords[i]->score = recscore;
|
||||
data->mainrecords[i]->time = rectime;
|
||||
data->mainrecords[i]->rings = recrings;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4449,19 +4452,21 @@ void G_LoadGameData(void)
|
|||
if ((recmares = READUINT8(save_p)) == 0)
|
||||
continue;
|
||||
|
||||
G_AllocNightsRecordData((INT16)i);
|
||||
G_AllocNightsRecordData((INT16)i, data);
|
||||
|
||||
for (curmare = 0; curmare < (recmares+1); ++curmare)
|
||||
{
|
||||
nightsrecords[i]->score[curmare] = READUINT32(save_p);
|
||||
nightsrecords[i]->grade[curmare] = READUINT8(save_p);
|
||||
nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
|
||||
data->nightsrecords[i]->score[curmare] = READUINT32(save_p);
|
||||
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p);
|
||||
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
|
||||
|
||||
if (nightsrecords[i]->grade[curmare] > GRADE_S)
|
||||
if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
|
||||
{
|
||||
goto datacorrupt;
|
||||
}
|
||||
}
|
||||
|
||||
nightsrecords[i]->nummares = recmares;
|
||||
data->nightsrecords[i]->nummares = recmares;
|
||||
}
|
||||
|
||||
// done
|
||||
|
@ -4472,10 +4477,11 @@ void G_LoadGameData(void)
|
|||
// It used to do this much earlier, but this would cause the gamedata to
|
||||
// save over itself when it I_Errors from the corruption landing point below,
|
||||
// which can accidentally delete players' legitimate data if the code ever has any tiny mistakes!
|
||||
gamedataloaded = true;
|
||||
data->loaded = true;
|
||||
|
||||
// Silent update unlockables in case they're out of sync with conditions
|
||||
M_SilentUpdateUnlockablesAndEmblems();
|
||||
M_SilentUpdateUnlockablesAndEmblems(data);
|
||||
M_SilentUpdateSkinAvailabilites();
|
||||
|
||||
return;
|
||||
|
||||
|
@ -4495,7 +4501,7 @@ void G_LoadGameData(void)
|
|||
|
||||
// G_SaveGameData
|
||||
// Saves the main data file, which stores information such as emblems found, etc.
|
||||
void G_SaveGameData(void)
|
||||
void G_SaveGameData(gamedata_t *data)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j;
|
||||
|
@ -4503,7 +4509,7 @@ void G_SaveGameData(void)
|
|||
|
||||
INT32 curmare;
|
||||
|
||||
if (!gamedataloaded)
|
||||
if (!data->loaded)
|
||||
return; // If never loaded (-nodata), don't save
|
||||
|
||||
save_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE);
|
||||
|
@ -4523,20 +4529,20 @@ void G_SaveGameData(void)
|
|||
// Version test
|
||||
WRITEUINT32(save_p, GAMEDATA_ID);
|
||||
|
||||
WRITEUINT32(save_p, totalplaytime);
|
||||
WRITEUINT32(save_p, data->totalplaytime);
|
||||
|
||||
WRITEUINT32(save_p, quickncasehash(timeattackfolder, sizeof timeattackfolder));
|
||||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
WRITEUINT8(save_p, (mapvisited[i] & MV_MAX));
|
||||
WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX));
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
btemp |= (emblemlocations[j+i].collected << j);
|
||||
btemp |= (data->collected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
@ -4544,7 +4550,7 @@ void G_SaveGameData(void)
|
|||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
|
||||
btemp |= (extraemblems[j+i].collected << j);
|
||||
btemp |= (data->extraCollected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
@ -4552,7 +4558,7 @@ void G_SaveGameData(void)
|
|||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
btemp |= (unlockables[j+i].unlocked << j);
|
||||
btemp |= (data->unlocked[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
@ -4560,23 +4566,23 @@ void G_SaveGameData(void)
|
|||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
btemp |= (conditionSets[j+i].achieved << j);
|
||||
btemp |= (data->achieved[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
||||
WRITEUINT32(save_p, timesBeaten);
|
||||
WRITEUINT32(save_p, timesBeatenWithEmeralds);
|
||||
WRITEUINT32(save_p, timesBeatenUltimate);
|
||||
WRITEUINT32(save_p, data->timesBeaten);
|
||||
WRITEUINT32(save_p, data->timesBeatenWithEmeralds);
|
||||
WRITEUINT32(save_p, data->timesBeatenUltimate);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (mainrecords[i])
|
||||
if (data->mainrecords[i])
|
||||
{
|
||||
WRITEUINT32(save_p, mainrecords[i]->score);
|
||||
WRITEUINT32(save_p, mainrecords[i]->time);
|
||||
WRITEUINT16(save_p, mainrecords[i]->rings);
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->score);
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->time);
|
||||
WRITEUINT16(save_p, data->mainrecords[i]->rings);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4590,19 +4596,19 @@ void G_SaveGameData(void)
|
|||
// NiGHTS records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (!nightsrecords[i] || !nightsrecords[i]->nummares)
|
||||
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
|
||||
{
|
||||
WRITEUINT8(save_p, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
WRITEUINT8(save_p, nightsrecords[i]->nummares);
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->nummares);
|
||||
|
||||
for (curmare = 0; curmare < (nightsrecords[i]->nummares + 1); ++curmare)
|
||||
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
|
||||
{
|
||||
WRITEUINT32(save_p, nightsrecords[i]->score[curmare]);
|
||||
WRITEUINT8(save_p, nightsrecords[i]->grade[curmare]);
|
||||
WRITEUINT32(save_p, nightsrecords[i]->time[curmare]);
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]);
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]);
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
25
src/g_game.h
25
src/g_game.h
|
@ -19,6 +19,7 @@
|
|||
#include "d_event.h"
|
||||
#include "g_demo.h"
|
||||
#include "m_cheat.h" // objectplacing
|
||||
#include "m_cond.h"
|
||||
|
||||
extern char gamedatafilename[64];
|
||||
extern char timeattackfolder[64];
|
||||
|
@ -183,7 +184,7 @@ boolean G_IsTitleCardAvailable(void);
|
|||
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
|
||||
void G_LoadGame(UINT32 slot, INT16 mapoverride);
|
||||
|
||||
void G_SaveGameData(void);
|
||||
void G_SaveGameData(gamedata_t *data);
|
||||
|
||||
void G_SaveGame(UINT32 slot, INT16 mapnum);
|
||||
|
||||
|
@ -239,7 +240,7 @@ void G_SetModeAttackRetryFlag(void);
|
|||
void G_ClearModeAttackRetryFlag(void);
|
||||
boolean G_GetModeAttackRetryFlag(void);
|
||||
|
||||
void G_LoadGameData(void);
|
||||
void G_LoadGameData(gamedata_t *data);
|
||||
void G_LoadGameSettings(void);
|
||||
|
||||
void G_SetGameModified(boolean silent);
|
||||
|
@ -248,19 +249,19 @@ void G_SetUsedCheats(boolean silent);
|
|||
void G_SetGamestate(gamestate_t newstate);
|
||||
|
||||
// Gamedata record shit
|
||||
void G_AllocMainRecordData(INT16 i);
|
||||
void G_AllocNightsRecordData(INT16 i);
|
||||
void G_ClearRecords(void);
|
||||
void G_AllocMainRecordData(INT16 i, gamedata_t *data);
|
||||
void G_AllocNightsRecordData(INT16 i, gamedata_t *data);
|
||||
void G_ClearRecords(gamedata_t *data);
|
||||
|
||||
UINT32 G_GetBestScore(INT16 map);
|
||||
tic_t G_GetBestTime(INT16 map);
|
||||
UINT16 G_GetBestRings(INT16 map);
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare);
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare);
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare);
|
||||
UINT32 G_GetBestScore(INT16 map, gamedata_t *data);
|
||||
tic_t G_GetBestTime(INT16 map, gamedata_t *data);
|
||||
UINT16 G_GetBestRings(INT16 map, gamedata_t *data);
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data);
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data);
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data);
|
||||
|
||||
void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare);
|
||||
void G_SetNightsRecords(void);
|
||||
void G_SetNightsRecords(gamedata_t *data);
|
||||
|
||||
FUNCMATH INT32 G_TicsToHours(tic_t tics);
|
||||
FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full);
|
||||
|
|
|
@ -1153,7 +1153,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
else
|
||||
texturevpeg = gl_backsector->ceilingheight + textureheight[gl_toptexture] - gl_frontsector->ceilingheight;
|
||||
|
||||
texturevpeg += gl_sidedef->rowoffset;
|
||||
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top;
|
||||
|
||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||
texturevpeg %= textureheight[gl_toptexture];
|
||||
|
@ -1162,8 +1162,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * grTex->scaleY;
|
||||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||||
wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_top) * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_top) * grTex->scaleX;
|
||||
|
||||
// Adjust t value for sloped walls
|
||||
if (!(gl_linedef->flags & ML_SKEWTD))
|
||||
|
@ -1213,7 +1213,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
else
|
||||
texturevpeg = gl_frontsector->floorheight - gl_backsector->floorheight;
|
||||
|
||||
texturevpeg += gl_sidedef->rowoffset;
|
||||
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bot;
|
||||
|
||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||
texturevpeg %= textureheight[gl_bottomtexture];
|
||||
|
@ -1222,8 +1222,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_backsector->floorheight - gl_frontsector->floorheight) * grTex->scaleY;
|
||||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||||
wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_bot) * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_bot) * grTex->scaleX;
|
||||
|
||||
// Adjust t value for sloped walls
|
||||
if (!(gl_linedef->flags & ML_SKEWTD))
|
||||
|
@ -1333,13 +1333,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
// Peg it to the floor
|
||||
if (gl_linedef->flags & ML_MIDPEG)
|
||||
{
|
||||
polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset;
|
||||
polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
polytop = polybottom + midtexheight;
|
||||
}
|
||||
// Peg it to the ceiling
|
||||
else
|
||||
{
|
||||
polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset;
|
||||
polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
polybottom = polytop - midtexheight;
|
||||
}
|
||||
|
||||
|
@ -1350,9 +1350,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
// Skew the texture, but peg it to the floor
|
||||
else if (gl_linedef->flags & ML_MIDPEG)
|
||||
{
|
||||
polybottom = popenbottom + gl_sidedef->rowoffset;
|
||||
polybottom = popenbottom + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
polytop = polybottom + midtexheight;
|
||||
polybottomslope = popenbottomslope + gl_sidedef->rowoffset;
|
||||
polybottomslope = popenbottomslope + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
polytopslope = polybottomslope + midtexheight;
|
||||
}
|
||||
// Skew it according to the ceiling's slope
|
||||
|
@ -1407,12 +1407,12 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
// Left side
|
||||
wallVerts[3].t = texturevpeg * grTex->scaleY;
|
||||
wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY;
|
||||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||||
wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
|
||||
// Right side
|
||||
wallVerts[2].t = texturevpegslope * grTex->scaleY;
|
||||
wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY;
|
||||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
|
||||
// set top/bottom coords
|
||||
// Take the texture peg into account, rather than changing the offsets past
|
||||
|
@ -1474,19 +1474,19 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
|
||||
// PEGGING
|
||||
if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW))
|
||||
texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset;
|
||||
texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
else if (gl_linedef->flags & ML_DONTPEGBOTTOM)
|
||||
texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset;
|
||||
texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
else
|
||||
// top of texture at top
|
||||
texturevpeg = gl_sidedef->rowoffset;
|
||||
texturevpeg = gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
|
||||
|
||||
grTex = HWR_GetTexture(gl_midtexture);
|
||||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
|
||||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||||
wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
|
||||
// Texture correction for slopes
|
||||
if (gl_linedef->flags & ML_NOSKEW) {
|
||||
|
@ -1634,13 +1634,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
// -- Monster Iestyn 26/06/18
|
||||
if (newline)
|
||||
{
|
||||
texturevpeg = sides[newline->sidenum[0]].rowoffset;
|
||||
texturevpeg = sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid;
|
||||
attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM);
|
||||
slopeskew = !!(newline->flags & ML_SKEWTD);
|
||||
}
|
||||
else
|
||||
{
|
||||
texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
|
||||
texturevpeg = sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid;
|
||||
attachtobottom = !!(gl_linedef->flags & ML_DONTPEGBOTTOM);
|
||||
slopeskew = !!(rover->master->flags & ML_SKEWTD);
|
||||
}
|
||||
|
@ -1672,8 +1672,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
}
|
||||
}
|
||||
|
||||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||||
wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
}
|
||||
if (rover->fofflags & FOF_FOG)
|
||||
{
|
||||
|
@ -1785,17 +1785,17 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
|||
|
||||
if (newline)
|
||||
{
|
||||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY;
|
||||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid) * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) + sides[newline->sidenum[0]].offsety_mid) * grTex->scaleY;
|
||||
}
|
||||
else
|
||||
{
|
||||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY;
|
||||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid) * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid)) * grTex->scaleY;
|
||||
}
|
||||
|
||||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||||
wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
|
||||
}
|
||||
|
||||
if (rover->fofflags & FOF_FOG)
|
||||
|
@ -3606,6 +3606,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
|
|||
|
||||
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
|
||||
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
|
||||
if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs
|
||||
scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale));
|
||||
|
||||
fscale = FIXED_TO_FLOAT(scalemul);
|
||||
fx = FIXED_TO_FLOAT(interp.x);
|
||||
|
|
|
@ -1660,7 +1660,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
|
|||
#endif
|
||||
|
||||
// SRB2CBTODO: MD2 scaling support
|
||||
finalscale *= FIXED_TO_FLOAT(spr->mobj->scale);
|
||||
finalscale *= FIXED_TO_FLOAT(interp.scale);
|
||||
|
||||
p.flip = atransform.flip;
|
||||
#ifdef USE_FTRANSFORM_MIRROR
|
||||
|
|
|
@ -216,7 +216,11 @@ HMS_connect (const char *format, ...)
|
|||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
|
||||
#ifndef NO_IPV6
|
||||
if (M_CheckParm("-noipv6"))
|
||||
#endif
|
||||
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read);
|
||||
|
|
|
@ -2862,18 +2862,6 @@ static void HU_DrawRankings(void)
|
|||
V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value));
|
||||
}
|
||||
}
|
||||
else if (gametyperankings[gametype] == GT_COOP)
|
||||
{
|
||||
INT32 totalscore = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
totalscore += players[i].score;
|
||||
}
|
||||
|
||||
V_DrawCenteredString(256, 8, 0, "TOTAL SCORE");
|
||||
V_DrawCenteredString(256, 16, 0, va("%u", totalscore));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (circuitmap)
|
||||
|
@ -2996,7 +2984,7 @@ static void HU_DrawCoopOverlay(void)
|
|||
|
||||
if (LUA_HudEnabled(hud_tabemblems))
|
||||
{
|
||||
V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(), numemblems+numextraemblems));
|
||||
V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(clientGamedata), numemblems+numextraemblems));
|
||||
V_DrawScaledPatch(128, 144 - emblemicon->height/4, 0, emblemicon);
|
||||
}
|
||||
|
||||
|
@ -3029,6 +3017,15 @@ static void HU_DrawNetplayCoopOverlay(void)
|
|||
V_DrawSmallScaledPatch(148, 6, 0, tokenicon);
|
||||
}
|
||||
|
||||
if (G_CoopGametype() && LUA_HudEnabled(hud_tabemblems))
|
||||
{
|
||||
V_DrawCenteredString(256, 14, 0, "/");
|
||||
V_DrawString(256 + 4, 14, 0, va("%d", numemblems + numextraemblems));
|
||||
V_DrawRightAlignedString(256 - 4, 14, 0, va("%d", M_CountEmblems(clientGamedata)));
|
||||
|
||||
V_DrawSmallScaledPatch(256 - (emblemicon->width / 4), 6, 0, emblemicon);
|
||||
}
|
||||
|
||||
if (!LUA_HudEnabled(hud_coopemeralds))
|
||||
return;
|
||||
|
||||
|
|
11
src/i_net.h
11
src/i_net.h
|
@ -109,6 +109,17 @@ extern boolean (*I_NetCanSend)(void);
|
|||
*/
|
||||
extern void (*I_NetFreeNodenum)(INT32 nodenum);
|
||||
|
||||
/**
|
||||
\brief split a string into address and port
|
||||
|
||||
\param address string to split
|
||||
|
||||
\param port double pointer to hold port component (optional)
|
||||
|
||||
\return address component
|
||||
*/
|
||||
extern char *I_NetSplitAddress(char *address, char **port);
|
||||
|
||||
/** \brief open a connection with specified address
|
||||
|
||||
\param address address to connect to
|
||||
|
|
71
src/i_tcp.c
71
src/i_tcp.c
|
@ -340,8 +340,14 @@ static inline void I_UPnP_rem(const char *port, const char * servicetype)
|
|||
|
||||
static const char *SOCK_AddrToStr(mysockaddr_t *sk)
|
||||
{
|
||||
static char s[64]; // 255.255.255.255:65535 or IPv6:65535
|
||||
static char s[64]; // 255.255.255.255:65535 or
|
||||
// [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535
|
||||
#ifdef HAVE_NTOP
|
||||
#ifdef HAVE_IPV6
|
||||
int v6 = (sk->any.sa_family == AF_INET6);
|
||||
#else
|
||||
int v6 = 0;
|
||||
#endif
|
||||
void *addr;
|
||||
|
||||
if(sk->any.sa_family == AF_INET)
|
||||
|
@ -355,14 +361,21 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
|
|||
|
||||
if(addr == NULL)
|
||||
sprintf(s, "No address");
|
||||
else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL)
|
||||
else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL)
|
||||
sprintf(s, "Unknown family type, error #%u", errno);
|
||||
#ifdef HAVE_IPV6
|
||||
else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0)
|
||||
strcat(s, va(":%d", ntohs(sk->ip6.sin6_port)));
|
||||
else if(sk->any.sa_family == AF_INET6)
|
||||
{
|
||||
s[0] = '[';
|
||||
strcat(s, "]");
|
||||
|
||||
if (sk->ip6.sin6_port != 0)
|
||||
strcat(s, va(":%d", ntohs(sk->ip6.sin6_port)));
|
||||
}
|
||||
#endif
|
||||
else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0)
|
||||
strcat(s, va(":%d", ntohs(sk->ip4.sin_port)));
|
||||
|
||||
#else
|
||||
if (sk->any.sa_family == AF_INET)
|
||||
{
|
||||
|
@ -427,7 +440,7 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
|||
&& (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port));
|
||||
#ifdef HAVE_IPV6
|
||||
else if (b->any.sa_family == AF_INET6)
|
||||
return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr))
|
||||
return !memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr))
|
||||
&& (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port));
|
||||
#endif
|
||||
else
|
||||
|
@ -735,8 +748,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
|
|||
unsigned long trueval = true;
|
||||
#endif
|
||||
mysockaddr_t straddr;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
socklen_t len = sizeof(straddr);
|
||||
|
||||
if (s == (SOCKET_TYPE)ERRSOCKET)
|
||||
return (SOCKET_TYPE)ERRSOCKET;
|
||||
|
@ -754,14 +766,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
|
|||
}
|
||||
#endif
|
||||
|
||||
straddr.any = *addr;
|
||||
memcpy(&straddr, addr, addrlen);
|
||||
I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr));
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
mysockaddr_t tmpaddr;
|
||||
tmpaddr.any = *addr ;
|
||||
if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
|
||||
if (straddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
|
||||
{
|
||||
opt = true;
|
||||
opts = (socklen_t)sizeof(opt);
|
||||
|
@ -778,7 +788,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
|
|||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL
|
||||
if (memcmp(&straddr.ip6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL
|
||||
{
|
||||
opt = true;
|
||||
opts = (socklen_t)sizeof(opt);
|
||||
|
@ -788,7 +798,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
|
|||
// make it IPv6 ony
|
||||
opt = true;
|
||||
opts = (socklen_t)sizeof(opt);
|
||||
if (setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts))
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore
|
||||
}
|
||||
|
@ -830,10 +840,17 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
|
|||
CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10);
|
||||
}
|
||||
|
||||
if (getsockname(s, (struct sockaddr *)&sin, &len) == -1)
|
||||
if (getsockname(s, &straddr.any, &len) == -1)
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n"));
|
||||
else
|
||||
current_port = (UINT16)ntohs(sin.sin_port);
|
||||
{
|
||||
if (family == AF_INET)
|
||||
current_port = (UINT16)ntohs(straddr.ip4.sin_port);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6)
|
||||
current_port = (UINT16)ntohs(straddr.ip6.sin6_port);
|
||||
#endif
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -844,7 +861,7 @@ static boolean UDP_Socket(void)
|
|||
struct my_addrinfo *ai, *runp, hints;
|
||||
int gaie;
|
||||
#ifdef HAVE_IPV6
|
||||
const INT32 b_ipv6 = M_CheckParm("-ipv6");
|
||||
const INT32 b_ipv6 = !M_CheckParm("-noipv6");
|
||||
#endif
|
||||
const char *serv;
|
||||
|
||||
|
@ -1156,6 +1173,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
|||
SINT8 newnode = -1;
|
||||
struct my_addrinfo *ai = NULL, *runp, hints;
|
||||
int gaie;
|
||||
size_t i;
|
||||
|
||||
if (!port || !port[0])
|
||||
port = DEFAULTPORT;
|
||||
|
@ -1183,13 +1201,24 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
|||
|
||||
while (runp != NULL)
|
||||
{
|
||||
// find ip of the server
|
||||
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0)
|
||||
// test ip address of server
|
||||
for (i = 0; i < mysocketses; ++i)
|
||||
{
|
||||
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
|
||||
break;
|
||||
/* sendto tests that there is a network to this
|
||||
address */
|
||||
if (runp->ai_addr->sa_family == myfamily[i] &&
|
||||
sendto(mysockets[i], NULL, 0, 0,
|
||||
runp->ai_addr, runp->ai_addrlen) == 0)
|
||||
{
|
||||
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
runp = runp->ai_next;
|
||||
|
||||
if (i < mysocketses)
|
||||
runp = runp->ai_next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
I_freeaddrinfo(ai);
|
||||
return newnode;
|
||||
|
|
|
@ -566,27 +566,59 @@ static luaL_Reg lib[] = {
|
|||
{NULL, NULL}
|
||||
};
|
||||
|
||||
enum cvar_e
|
||||
{
|
||||
cvar_name,
|
||||
cvar_defaultvalue,
|
||||
cvar_flags,
|
||||
cvar_value,
|
||||
cvar_string,
|
||||
cvar_changed,
|
||||
};
|
||||
|
||||
static const char *const cvar_opt[] = {
|
||||
"name",
|
||||
"defaultvalue",
|
||||
"flags",
|
||||
"value",
|
||||
"string",
|
||||
"changed",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int cvar_fields_ref = LUA_NOREF;
|
||||
|
||||
static int cvar_get(lua_State *L)
|
||||
{
|
||||
consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR);
|
||||
const char *field = luaL_checkstring(L, 2);
|
||||
enum cvar_e field = Lua_optoption(L, 2, -1, cvar_fields_ref);
|
||||
|
||||
if(fastcmp(field,"name"))
|
||||
switch (field)
|
||||
{
|
||||
case cvar_name:
|
||||
lua_pushstring(L, cvar->name);
|
||||
else if(fastcmp(field,"defaultvalue"))
|
||||
break;
|
||||
case cvar_defaultvalue:
|
||||
lua_pushstring(L, cvar->defaultvalue);
|
||||
else if(fastcmp(field,"flags"))
|
||||
break;
|
||||
case cvar_flags:
|
||||
lua_pushinteger(L, cvar->flags);
|
||||
else if(fastcmp(field,"value"))
|
||||
break;
|
||||
case cvar_value:
|
||||
lua_pushinteger(L, cvar->value);
|
||||
else if(fastcmp(field,"string"))
|
||||
break;
|
||||
case cvar_string:
|
||||
lua_pushstring(L, cvar->string);
|
||||
else if(fastcmp(field,"changed"))
|
||||
break;
|
||||
case cvar_changed:
|
||||
lua_pushboolean(L, cvar->changed);
|
||||
else if (devparm)
|
||||
return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field);
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
if (devparm)
|
||||
return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -598,6 +630,8 @@ int LUA_ConsoleLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__index");
|
||||
lua_pop(L,1);
|
||||
|
||||
cvar_fields_ref = Lua_CreateFieldTable(L, cvar_opt);
|
||||
|
||||
// Set empty registry tables
|
||||
lua_newtable(L);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "COM_Command");
|
||||
|
|
|
@ -95,6 +95,8 @@ static const char *const patch_opt[] = {
|
|||
"topoffset",
|
||||
NULL};
|
||||
|
||||
static int patch_fields_ref = LUA_NOREF;
|
||||
|
||||
// alignment types for v.drawString
|
||||
enum align {
|
||||
align_left = 0,
|
||||
|
@ -196,6 +198,8 @@ static const char *const camera_opt[] = {
|
|||
"momz",
|
||||
NULL};
|
||||
|
||||
static int camera_fields_ref = LUA_NOREF;
|
||||
|
||||
static int lib_getHudInfo(lua_State *L)
|
||||
{
|
||||
UINT32 i;
|
||||
|
@ -276,7 +280,7 @@ static int colormap_get(lua_State *L)
|
|||
static int patch_get(lua_State *L)
|
||||
{
|
||||
patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH));
|
||||
enum patch field = luaL_checkoption(L, 2, NULL, patch_opt);
|
||||
enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref);
|
||||
|
||||
// patches are invalidated when switching renderers
|
||||
if (!patch) {
|
||||
|
@ -316,7 +320,7 @@ static int patch_set(lua_State *L)
|
|||
static int camera_get(lua_State *L)
|
||||
{
|
||||
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
|
||||
enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt);
|
||||
enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref);
|
||||
|
||||
// cameras should always be valid unless I'm a nutter
|
||||
I_Assert(cam != NULL);
|
||||
|
@ -372,7 +376,7 @@ static int camera_get(lua_State *L)
|
|||
static int camera_set(lua_State *L)
|
||||
{
|
||||
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
|
||||
enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt);
|
||||
enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref);
|
||||
|
||||
I_Assert(cam != NULL);
|
||||
|
||||
|
@ -1444,6 +1448,8 @@ int LUA_HudLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L,1);
|
||||
|
||||
patch_fields_ref = Lua_CreateFieldTable(L, patch_opt);
|
||||
|
||||
luaL_newmetatable(L, META_CAMERA);
|
||||
lua_pushcfunction(L, camera_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -1452,6 +1458,8 @@ int LUA_HudLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L,1);
|
||||
|
||||
camera_fields_ref = Lua_CreateFieldTable(L, camera_opt);
|
||||
|
||||
luaL_register(L, "hud", lib_hud);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1106,75 +1106,161 @@ static int lib_mobjinfolen(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
enum mobjinfo_e
|
||||
{
|
||||
mobjinfo_doomednum,
|
||||
mobjinfo_spawnstate,
|
||||
mobjinfo_spawnhealth,
|
||||
mobjinfo_seestate,
|
||||
mobjinfo_seesound,
|
||||
mobjinfo_reactiontime,
|
||||
mobjinfo_attacksound,
|
||||
mobjinfo_painstate,
|
||||
mobjinfo_painchance,
|
||||
mobjinfo_painsound,
|
||||
mobjinfo_meleestate,
|
||||
mobjinfo_missilestate,
|
||||
mobjinfo_deathstate,
|
||||
mobjinfo_xdeathstate,
|
||||
mobjinfo_deathsound,
|
||||
mobjinfo_speed,
|
||||
mobjinfo_radius,
|
||||
mobjinfo_height,
|
||||
mobjinfo_dispoffset,
|
||||
mobjinfo_mass,
|
||||
mobjinfo_damage,
|
||||
mobjinfo_activesound,
|
||||
mobjinfo_flags,
|
||||
mobjinfo_raisestate,
|
||||
};
|
||||
|
||||
const char *const mobjinfo_opt[] = {
|
||||
"doomednum",
|
||||
"spawnstate",
|
||||
"spawnhealth",
|
||||
"seestate",
|
||||
"seesound",
|
||||
"reactiontime",
|
||||
"attacksound",
|
||||
"painstate",
|
||||
"painchance",
|
||||
"painsound",
|
||||
"meleestate",
|
||||
"missilestate",
|
||||
"deathstate",
|
||||
"xdeathstate",
|
||||
"deathsound",
|
||||
"speed",
|
||||
"radius",
|
||||
"height",
|
||||
"dispoffset",
|
||||
"mass",
|
||||
"damage",
|
||||
"activesound",
|
||||
"flags",
|
||||
"raisestate",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int mobjinfo_fields_ref = LUA_NOREF;
|
||||
|
||||
// mobjinfo_t *, field -> number
|
||||
static int mobjinfo_get(lua_State *L)
|
||||
{
|
||||
mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
|
||||
const char *field = luaL_checkstring(L, 2);
|
||||
enum mobjinfo_e field = luaL_checkoption(L, 2, mobjinfo_opt[0], mobjinfo_opt);
|
||||
|
||||
I_Assert(info != NULL);
|
||||
I_Assert(info >= mobjinfo);
|
||||
|
||||
if (fastcmp(field,"doomednum"))
|
||||
switch (field)
|
||||
{
|
||||
case mobjinfo_doomednum:
|
||||
lua_pushinteger(L, info->doomednum);
|
||||
else if (fastcmp(field,"spawnstate"))
|
||||
break;
|
||||
case mobjinfo_spawnstate:
|
||||
lua_pushinteger(L, info->spawnstate);
|
||||
else if (fastcmp(field,"spawnhealth"))
|
||||
break;
|
||||
case mobjinfo_spawnhealth:
|
||||
lua_pushinteger(L, info->spawnhealth);
|
||||
else if (fastcmp(field,"seestate"))
|
||||
break;
|
||||
case mobjinfo_seestate:
|
||||
lua_pushinteger(L, info->seestate);
|
||||
else if (fastcmp(field,"seesound"))
|
||||
break;
|
||||
case mobjinfo_seesound:
|
||||
lua_pushinteger(L, info->seesound);
|
||||
else if (fastcmp(field,"reactiontime"))
|
||||
break;
|
||||
case mobjinfo_reactiontime:
|
||||
lua_pushinteger(L, info->reactiontime);
|
||||
else if (fastcmp(field,"attacksound"))
|
||||
break;
|
||||
case mobjinfo_attacksound:
|
||||
lua_pushinteger(L, info->attacksound);
|
||||
else if (fastcmp(field,"painstate"))
|
||||
break;
|
||||
case mobjinfo_painstate:
|
||||
lua_pushinteger(L, info->painstate);
|
||||
else if (fastcmp(field,"painchance"))
|
||||
break;
|
||||
case mobjinfo_painchance:
|
||||
lua_pushinteger(L, info->painchance);
|
||||
else if (fastcmp(field,"painsound"))
|
||||
break;
|
||||
case mobjinfo_painsound:
|
||||
lua_pushinteger(L, info->painsound);
|
||||
else if (fastcmp(field,"meleestate"))
|
||||
break;
|
||||
case mobjinfo_meleestate:
|
||||
lua_pushinteger(L, info->meleestate);
|
||||
else if (fastcmp(field,"missilestate"))
|
||||
break;
|
||||
case mobjinfo_missilestate:
|
||||
lua_pushinteger(L, info->missilestate);
|
||||
else if (fastcmp(field,"deathstate"))
|
||||
break;
|
||||
case mobjinfo_deathstate:
|
||||
lua_pushinteger(L, info->deathstate);
|
||||
else if (fastcmp(field,"xdeathstate"))
|
||||
break;
|
||||
case mobjinfo_xdeathstate:
|
||||
lua_pushinteger(L, info->xdeathstate);
|
||||
else if (fastcmp(field,"deathsound"))
|
||||
break;
|
||||
case mobjinfo_deathsound:
|
||||
lua_pushinteger(L, info->deathsound);
|
||||
else if (fastcmp(field,"speed"))
|
||||
break;
|
||||
case mobjinfo_speed:
|
||||
lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not...
|
||||
else if (fastcmp(field,"radius"))
|
||||
break;
|
||||
case mobjinfo_radius:
|
||||
lua_pushfixed(L, info->radius);
|
||||
else if (fastcmp(field,"height"))
|
||||
break;
|
||||
case mobjinfo_height:
|
||||
lua_pushfixed(L, info->height);
|
||||
else if (fastcmp(field,"dispoffset"))
|
||||
break;
|
||||
case mobjinfo_dispoffset:
|
||||
lua_pushinteger(L, info->dispoffset);
|
||||
else if (fastcmp(field,"mass"))
|
||||
break;
|
||||
case mobjinfo_mass:
|
||||
lua_pushinteger(L, info->mass);
|
||||
else if (fastcmp(field,"damage"))
|
||||
break;
|
||||
case mobjinfo_damage:
|
||||
lua_pushinteger(L, info->damage);
|
||||
else if (fastcmp(field,"activesound"))
|
||||
break;
|
||||
case mobjinfo_activesound:
|
||||
lua_pushinteger(L, info->activesound);
|
||||
else if (fastcmp(field,"flags"))
|
||||
break;
|
||||
case mobjinfo_flags:
|
||||
lua_pushinteger(L, info->flags);
|
||||
else if (fastcmp(field,"raisestate"))
|
||||
break;
|
||||
case mobjinfo_raisestate:
|
||||
lua_pushinteger(L, info->raisestate);
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
|
||||
I_Assert(lua_istable(L, -1));
|
||||
lua_pushlightuserdata(L, info);
|
||||
lua_rawget(L, -2);
|
||||
if (!lua_istable(L, -1)) { // no extra values table
|
||||
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field);
|
||||
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2));
|
||||
return 0;
|
||||
}
|
||||
lua_getfield(L, -1, field);
|
||||
lua_pushvalue(L, 2); // field name
|
||||
lua_gettable(L, -2);
|
||||
if (lua_isnil(L, -1)) // no value for this field
|
||||
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field);
|
||||
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2));
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -1183,7 +1269,7 @@ static int mobjinfo_get(lua_State *L)
|
|||
static int mobjinfo_set(lua_State *L)
|
||||
{
|
||||
mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
|
||||
const char *field = luaL_checkstring(L, 2);
|
||||
enum mobjinfo_e field = Lua_optoption(L, 2, -1, mobjinfo_fields_ref);
|
||||
|
||||
if (hud_running)
|
||||
return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
|
||||
|
@ -1193,55 +1279,81 @@ static int mobjinfo_set(lua_State *L)
|
|||
I_Assert(info != NULL);
|
||||
I_Assert(info >= mobjinfo);
|
||||
|
||||
if (fastcmp(field,"doomednum"))
|
||||
switch (field)
|
||||
{
|
||||
case mobjinfo_doomednum:
|
||||
info->doomednum = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"spawnstate"))
|
||||
break;
|
||||
case mobjinfo_spawnstate:
|
||||
info->spawnstate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"spawnhealth"))
|
||||
break;
|
||||
case mobjinfo_spawnhealth:
|
||||
info->spawnhealth = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"seestate"))
|
||||
break;
|
||||
case mobjinfo_seestate:
|
||||
info->seestate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"seesound"))
|
||||
break;
|
||||
case mobjinfo_seesound:
|
||||
info->seesound = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"reactiontime"))
|
||||
break;
|
||||
case mobjinfo_reactiontime:
|
||||
info->reactiontime = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"attacksound"))
|
||||
break;
|
||||
case mobjinfo_attacksound:
|
||||
info->attacksound = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"painstate"))
|
||||
break;
|
||||
case mobjinfo_painstate:
|
||||
info->painstate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"painchance"))
|
||||
break;
|
||||
case mobjinfo_painchance:
|
||||
info->painchance = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"painsound"))
|
||||
break;
|
||||
case mobjinfo_painsound:
|
||||
info->painsound = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"meleestate"))
|
||||
break;
|
||||
case mobjinfo_meleestate:
|
||||
info->meleestate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"missilestate"))
|
||||
break;
|
||||
case mobjinfo_missilestate:
|
||||
info->missilestate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"deathstate"))
|
||||
break;
|
||||
case mobjinfo_deathstate:
|
||||
info->deathstate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"xdeathstate"))
|
||||
break;
|
||||
case mobjinfo_xdeathstate:
|
||||
info->xdeathstate = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"deathsound"))
|
||||
break;
|
||||
case mobjinfo_deathsound:
|
||||
info->deathsound = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"speed"))
|
||||
break;
|
||||
case mobjinfo_speed:
|
||||
info->speed = luaL_checkfixed(L, 3);
|
||||
else if (fastcmp(field,"radius"))
|
||||
break;
|
||||
case mobjinfo_radius:
|
||||
info->radius = luaL_checkfixed(L, 3);
|
||||
else if (fastcmp(field,"height"))
|
||||
break;
|
||||
case mobjinfo_height:
|
||||
info->height = luaL_checkfixed(L, 3);
|
||||
else if (fastcmp(field,"dispoffset"))
|
||||
break;
|
||||
case mobjinfo_dispoffset:
|
||||
info->dispoffset = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"mass"))
|
||||
break;
|
||||
case mobjinfo_mass:
|
||||
info->mass = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"damage"))
|
||||
break;
|
||||
case mobjinfo_damage:
|
||||
info->damage = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"activesound"))
|
||||
break;
|
||||
case mobjinfo_activesound:
|
||||
info->activesound = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"flags"))
|
||||
break;
|
||||
case mobjinfo_flags:
|
||||
info->flags = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"raisestate"))
|
||||
break;
|
||||
case mobjinfo_raisestate:
|
||||
info->raisestate = luaL_checkinteger(L, 3);
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
|
||||
I_Assert(lua_istable(L, -1));
|
||||
lua_pushlightuserdata(L, info);
|
||||
|
@ -1249,18 +1361,17 @@ static int mobjinfo_set(lua_State *L)
|
|||
if (lua_isnil(L, -1)) {
|
||||
// This index doesn't have a table for extra values yet, let's make one.
|
||||
lua_pop(L, 1);
|
||||
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", field);
|
||||
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", lua_tostring(L, 2));
|
||||
lua_newtable(L);
|
||||
lua_pushlightuserdata(L, info);
|
||||
lua_pushvalue(L, -2); // ext value table
|
||||
lua_rawset(L, -4); // LREG_EXTVARS table
|
||||
}
|
||||
lua_pushvalue(L, 2); // key
|
||||
lua_pushvalue(L, 3); // value to store
|
||||
lua_setfield(L, -2, field);
|
||||
lua_settable(L, -3);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
//else
|
||||
//return luaL_error(L, LUA_QL("mobjinfo_t") " has no field named " LUA_QS, field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1788,6 +1899,8 @@ int LUA_InfoLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
mobjinfo_fields_ref = Lua_CreateFieldTable(L, mobjinfo_opt);
|
||||
|
||||
luaL_newmetatable(L, META_SKINCOLOR);
|
||||
lua_pushcfunction(L, skincolor_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
|
356
src/lua_maplib.c
356
src/lua_maplib.c
|
@ -88,6 +88,8 @@ static const char *const sector_opt[] = {
|
|||
"gravity",
|
||||
NULL};
|
||||
|
||||
static int sector_fields_ref = LUA_NOREF;
|
||||
|
||||
enum subsector_e {
|
||||
subsector_valid = 0,
|
||||
subsector_sector,
|
||||
|
@ -104,6 +106,8 @@ static const char *const subsector_opt[] = {
|
|||
"polyList",
|
||||
NULL};
|
||||
|
||||
static int subsector_fields_ref = LUA_NOREF;
|
||||
|
||||
enum line_e {
|
||||
line_valid = 0,
|
||||
line_v1,
|
||||
|
@ -156,10 +160,18 @@ static const char *const line_opt[] = {
|
|||
"callcount",
|
||||
NULL};
|
||||
|
||||
static int line_fields_ref = LUA_NOREF;
|
||||
|
||||
enum side_e {
|
||||
side_valid = 0,
|
||||
side_textureoffset,
|
||||
side_rowoffset,
|
||||
side_offsetx_top,
|
||||
side_offsety_top,
|
||||
side_offsetx_mid,
|
||||
side_offsety_mid,
|
||||
side_offsetx_bot,
|
||||
side_offsety_bot,
|
||||
side_toptexture,
|
||||
side_bottomtexture,
|
||||
side_midtexture,
|
||||
|
@ -174,6 +186,12 @@ static const char *const side_opt[] = {
|
|||
"valid",
|
||||
"textureoffset",
|
||||
"rowoffset",
|
||||
"offsetx_top",
|
||||
"offsety_top",
|
||||
"offsetx_mid",
|
||||
"offsety_mid",
|
||||
"offsetx_bot",
|
||||
"offsety_bot",
|
||||
"toptexture",
|
||||
"bottomtexture",
|
||||
"midtexture",
|
||||
|
@ -184,6 +202,8 @@ static const char *const side_opt[] = {
|
|||
"text",
|
||||
NULL};
|
||||
|
||||
static int side_fields_ref = LUA_NOREF;
|
||||
|
||||
enum vertex_e {
|
||||
vertex_valid = 0,
|
||||
vertex_x,
|
||||
|
@ -204,6 +224,8 @@ static const char *const vertex_opt[] = {
|
|||
"ceilingzset",
|
||||
NULL};
|
||||
|
||||
static int vertex_fields_ref = LUA_NOREF;
|
||||
|
||||
enum ffloor_e {
|
||||
ffloor_valid = 0,
|
||||
ffloor_topheight,
|
||||
|
@ -256,6 +278,8 @@ static const char *const ffloor_opt[] = {
|
|||
"bouncestrength",
|
||||
NULL};
|
||||
|
||||
static int ffloor_fields_ref = LUA_NOREF;
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
enum seg_e {
|
||||
seg_valid = 0,
|
||||
|
@ -285,6 +309,8 @@ static const char *const seg_opt[] = {
|
|||
"polyseg",
|
||||
NULL};
|
||||
|
||||
static int seg_fields_ref = LUA_NOREF;
|
||||
|
||||
enum node_e {
|
||||
node_valid = 0,
|
||||
node_x,
|
||||
|
@ -305,6 +331,8 @@ static const char *const node_opt[] = {
|
|||
"children",
|
||||
NULL};
|
||||
|
||||
static int node_fields_ref = LUA_NOREF;
|
||||
|
||||
enum nodechild_e {
|
||||
nodechild_valid = 0,
|
||||
nodechild_right,
|
||||
|
@ -356,6 +384,8 @@ static const char *const slope_opt[] = {
|
|||
"flags",
|
||||
NULL};
|
||||
|
||||
static int slope_fields_ref = LUA_NOREF;
|
||||
|
||||
// shared by both vector2_t and vector3_t
|
||||
enum vector_e {
|
||||
vector_x = 0,
|
||||
|
@ -575,7 +605,7 @@ static int sectorlines_num(lua_State *L)
|
|||
static int sector_get(lua_State *L)
|
||||
{
|
||||
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
|
||||
enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt);
|
||||
enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref);
|
||||
INT16 i;
|
||||
|
||||
if (!sector)
|
||||
|
@ -697,7 +727,7 @@ static int sector_get(lua_State *L)
|
|||
static int sector_set(lua_State *L)
|
||||
{
|
||||
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
|
||||
enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt);
|
||||
enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref);
|
||||
|
||||
if (!sector)
|
||||
return luaL_error(L, "accessed sector_t doesn't exist anymore.");
|
||||
|
@ -814,7 +844,7 @@ static int sector_num(lua_State *L)
|
|||
static int subsector_get(lua_State *L)
|
||||
{
|
||||
subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR));
|
||||
enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt);
|
||||
enum subsector_e field = Lua_optoption(L, 2, subsector_valid, subsector_fields_ref);
|
||||
|
||||
if (!subsector)
|
||||
{
|
||||
|
@ -898,7 +928,7 @@ static int linestringargs_len(lua_State *L)
|
|||
static int line_get(lua_State *L)
|
||||
{
|
||||
line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE));
|
||||
enum line_e field = luaL_checkoption(L, 2, line_opt[0], line_opt);
|
||||
enum line_e field = Lua_optoption(L, 2, line_valid, line_fields_ref);
|
||||
|
||||
if (!line)
|
||||
{
|
||||
|
@ -1057,7 +1087,7 @@ static int sidenum_get(lua_State *L)
|
|||
static int side_get(lua_State *L)
|
||||
{
|
||||
side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
|
||||
enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt);
|
||||
enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref);
|
||||
|
||||
if (!side)
|
||||
{
|
||||
|
@ -1079,6 +1109,24 @@ static int side_get(lua_State *L)
|
|||
case side_rowoffset:
|
||||
lua_pushfixed(L, side->rowoffset);
|
||||
return 1;
|
||||
case side_offsetx_top:
|
||||
lua_pushfixed(L, side->offsetx_top);
|
||||
return 1;
|
||||
case side_offsety_top:
|
||||
lua_pushfixed(L, side->offsety_top);
|
||||
return 1;
|
||||
case side_offsetx_mid:
|
||||
lua_pushfixed(L, side->offsetx_mid);
|
||||
return 1;
|
||||
case side_offsety_mid:
|
||||
lua_pushfixed(L, side->offsety_mid);
|
||||
return 1;
|
||||
case side_offsetx_bot:
|
||||
lua_pushfixed(L, side->offsetx_bot);
|
||||
return 1;
|
||||
case side_offsety_bot:
|
||||
lua_pushfixed(L, side->offsety_bot);
|
||||
return 1;
|
||||
case side_toptexture:
|
||||
lua_pushinteger(L, side->toptexture);
|
||||
return 1;
|
||||
|
@ -1110,7 +1158,7 @@ static int side_get(lua_State *L)
|
|||
static int side_set(lua_State *L)
|
||||
{
|
||||
side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
|
||||
enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt);
|
||||
enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref);
|
||||
|
||||
if (!side)
|
||||
{
|
||||
|
@ -1136,6 +1184,24 @@ static int side_set(lua_State *L)
|
|||
case side_rowoffset:
|
||||
side->rowoffset = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_offsetx_top:
|
||||
side->offsetx_top = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_offsety_top:
|
||||
side->offsety_top = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_offsetx_mid:
|
||||
side->offsetx_mid = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_offsety_mid:
|
||||
side->offsety_mid = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_offsetx_bot:
|
||||
side->offsetx_bot = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_offsety_bot:
|
||||
side->offsety_bot = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case side_toptexture:
|
||||
side->toptexture = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
|
@ -1166,7 +1232,7 @@ static int side_num(lua_State *L)
|
|||
static int vertex_get(lua_State *L)
|
||||
{
|
||||
vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX));
|
||||
enum vertex_e field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt);
|
||||
enum vertex_e field = Lua_optoption(L, 2, vertex_valid, vertex_fields_ref);
|
||||
|
||||
if (!vertex)
|
||||
{
|
||||
|
@ -1220,7 +1286,7 @@ static int vertex_num(lua_State *L)
|
|||
static int seg_get(lua_State *L)
|
||||
{
|
||||
seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
|
||||
enum seg_e field = luaL_checkoption(L, 2, seg_opt[0], seg_opt);
|
||||
enum seg_e field = Lua_optoption(L, 2, seg_valid, seg_fields_ref);
|
||||
|
||||
if (!seg)
|
||||
{
|
||||
|
@ -1284,7 +1350,7 @@ static int seg_num(lua_State *L)
|
|||
static int node_get(lua_State *L)
|
||||
{
|
||||
node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
|
||||
enum node_e field = luaL_checkoption(L, 2, node_opt[0], node_opt);
|
||||
enum node_e field = Lua_optoption(L, 2, node_valid, node_fields_ref);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
|
@ -1920,7 +1986,7 @@ static INT32 P_GetOldFOFFlags(ffloor_t *fflr)
|
|||
static int ffloor_get(lua_State *L)
|
||||
{
|
||||
ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
|
||||
enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt);
|
||||
enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref);
|
||||
INT16 i;
|
||||
|
||||
if (!ffloor)
|
||||
|
@ -2102,7 +2168,7 @@ static void P_SetOldFOFFlags(ffloor_t *fflr, oldffloortype_e oldflags)
|
|||
static int ffloor_set(lua_State *L)
|
||||
{
|
||||
ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
|
||||
enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt);
|
||||
enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref);
|
||||
|
||||
if (!ffloor)
|
||||
return luaL_error(L, "accessed ffloor_t doesn't exist anymore.");
|
||||
|
@ -2197,7 +2263,7 @@ static int ffloor_set(lua_State *L)
|
|||
static int slope_get(lua_State *L)
|
||||
{
|
||||
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
|
||||
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
|
||||
enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref);
|
||||
|
||||
if (!slope)
|
||||
{
|
||||
|
@ -2241,7 +2307,7 @@ static int slope_get(lua_State *L)
|
|||
static int slope_set(lua_State *L)
|
||||
{
|
||||
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
|
||||
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
|
||||
enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref);
|
||||
|
||||
if (!slope)
|
||||
return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
|
||||
|
@ -2405,110 +2471,258 @@ static int lib_nummapheaders(lua_State *L)
|
|||
// mapheader_t //
|
||||
/////////////////
|
||||
|
||||
enum mapheaderinfo_e
|
||||
{
|
||||
mapheaderinfo_lvlttl,
|
||||
mapheaderinfo_subttl,
|
||||
mapheaderinfo_actnum,
|
||||
mapheaderinfo_typeoflevel,
|
||||
mapheaderinfo_nextlevel,
|
||||
mapheaderinfo_marathonnext,
|
||||
mapheaderinfo_keywords,
|
||||
mapheaderinfo_musname,
|
||||
mapheaderinfo_mustrack,
|
||||
mapheaderinfo_muspos,
|
||||
mapheaderinfo_musinterfadeout,
|
||||
mapheaderinfo_musintername,
|
||||
mapheaderinfo_muspostbossname,
|
||||
mapheaderinfo_muspostbosstrack,
|
||||
mapheaderinfo_muspostbosspos,
|
||||
mapheaderinfo_muspostbossfadein,
|
||||
mapheaderinfo_musforcereset,
|
||||
mapheaderinfo_forcecharacter,
|
||||
mapheaderinfo_weather,
|
||||
mapheaderinfo_skynum,
|
||||
mapheaderinfo_skybox_scalex,
|
||||
mapheaderinfo_skybox_scaley,
|
||||
mapheaderinfo_skybox_scalez,
|
||||
mapheaderinfo_interscreen,
|
||||
mapheaderinfo_runsoc,
|
||||
mapheaderinfo_scriptname,
|
||||
mapheaderinfo_precutscenenum,
|
||||
mapheaderinfo_cutscenenum,
|
||||
mapheaderinfo_countdown,
|
||||
mapheaderinfo_palette,
|
||||
mapheaderinfo_numlaps,
|
||||
mapheaderinfo_unlockrequired,
|
||||
mapheaderinfo_levelselect,
|
||||
mapheaderinfo_bonustype,
|
||||
mapheaderinfo_ltzzpatch,
|
||||
mapheaderinfo_ltzztext,
|
||||
mapheaderinfo_ltactdiamond,
|
||||
mapheaderinfo_maxbonuslives,
|
||||
mapheaderinfo_levelflags,
|
||||
mapheaderinfo_menuflags,
|
||||
mapheaderinfo_selectheading,
|
||||
mapheaderinfo_startrings,
|
||||
mapheaderinfo_sstimer,
|
||||
mapheaderinfo_ssspheres,
|
||||
mapheaderinfo_gravity,
|
||||
};
|
||||
|
||||
static const char *const mapheaderinfo_opt[] = {
|
||||
"lvlttl",
|
||||
"subttl",
|
||||
"actnum",
|
||||
"typeoflevel",
|
||||
"nextlevel",
|
||||
"marathonnext",
|
||||
"keywords",
|
||||
"musname",
|
||||
"mustrack",
|
||||
"muspos",
|
||||
"musinterfadeout",
|
||||
"musintername",
|
||||
"muspostbossname",
|
||||
"muspostbosstrack",
|
||||
"muspostbosspos",
|
||||
"muspostbossfadein",
|
||||
"musforcereset",
|
||||
"forcecharacter",
|
||||
"weather",
|
||||
"skynum",
|
||||
"skybox_scalex",
|
||||
"skybox_scaley",
|
||||
"skybox_scalez",
|
||||
"interscreen",
|
||||
"runsoc",
|
||||
"scriptname",
|
||||
"precutscenenum",
|
||||
"cutscenenum",
|
||||
"countdown",
|
||||
"palette",
|
||||
"numlaps",
|
||||
"unlockrequired",
|
||||
"levelselect",
|
||||
"bonustype",
|
||||
"ltzzpatch",
|
||||
"ltzztext",
|
||||
"ltactdiamond",
|
||||
"maxbonuslives",
|
||||
"levelflags",
|
||||
"menuflags",
|
||||
"selectheading",
|
||||
"startrings",
|
||||
"sstimer",
|
||||
"ssspheres",
|
||||
"gravity",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int mapheaderinfo_fields_ref = LUA_NOREF;
|
||||
|
||||
static int mapheaderinfo_get(lua_State *L)
|
||||
{
|
||||
mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER));
|
||||
const char *field = luaL_checkstring(L, 2);
|
||||
enum mapheaderinfo_e field = Lua_optoption(L, 2, -1, mapheaderinfo_fields_ref);
|
||||
INT16 i;
|
||||
if (fastcmp(field,"lvlttl"))
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case mapheaderinfo_lvlttl:
|
||||
lua_pushstring(L, header->lvlttl);
|
||||
else if (fastcmp(field,"subttl"))
|
||||
break;
|
||||
case mapheaderinfo_subttl:
|
||||
lua_pushstring(L, header->subttl);
|
||||
else if (fastcmp(field,"actnum"))
|
||||
break;
|
||||
case mapheaderinfo_actnum:
|
||||
lua_pushinteger(L, header->actnum);
|
||||
else if (fastcmp(field,"typeoflevel"))
|
||||
break;
|
||||
case mapheaderinfo_typeoflevel:
|
||||
lua_pushinteger(L, header->typeoflevel);
|
||||
else if (fastcmp(field,"nextlevel"))
|
||||
break;
|
||||
case mapheaderinfo_nextlevel:
|
||||
lua_pushinteger(L, header->nextlevel);
|
||||
else if (fastcmp(field,"marathonnext"))
|
||||
break;
|
||||
case mapheaderinfo_marathonnext:
|
||||
lua_pushinteger(L, header->marathonnext);
|
||||
else if (fastcmp(field,"keywords"))
|
||||
break;
|
||||
case mapheaderinfo_keywords:
|
||||
lua_pushstring(L, header->keywords);
|
||||
else if (fastcmp(field,"musname"))
|
||||
break;
|
||||
case mapheaderinfo_musname:
|
||||
lua_pushstring(L, header->musname);
|
||||
else if (fastcmp(field,"mustrack"))
|
||||
break;
|
||||
case mapheaderinfo_mustrack:
|
||||
lua_pushinteger(L, header->mustrack);
|
||||
else if (fastcmp(field,"muspos"))
|
||||
break;
|
||||
case mapheaderinfo_muspos:
|
||||
lua_pushinteger(L, header->muspos);
|
||||
else if (fastcmp(field,"musinterfadeout"))
|
||||
break;
|
||||
case mapheaderinfo_musinterfadeout:
|
||||
lua_pushinteger(L, header->musinterfadeout);
|
||||
else if (fastcmp(field,"musintername"))
|
||||
break;
|
||||
case mapheaderinfo_musintername:
|
||||
lua_pushstring(L, header->musintername);
|
||||
else if (fastcmp(field,"muspostbossname"))
|
||||
break;
|
||||
case mapheaderinfo_muspostbossname:
|
||||
lua_pushstring(L, header->muspostbossname);
|
||||
else if (fastcmp(field,"muspostbosstrack"))
|
||||
break;
|
||||
case mapheaderinfo_muspostbosstrack:
|
||||
lua_pushinteger(L, header->muspostbosstrack);
|
||||
else if (fastcmp(field,"muspostbosspos"))
|
||||
break;
|
||||
case mapheaderinfo_muspostbosspos:
|
||||
lua_pushinteger(L, header->muspostbosspos);
|
||||
else if (fastcmp(field,"muspostbossfadein"))
|
||||
break;
|
||||
case mapheaderinfo_muspostbossfadein:
|
||||
lua_pushinteger(L, header->muspostbossfadein);
|
||||
else if (fastcmp(field,"musforcereset"))
|
||||
break;
|
||||
case mapheaderinfo_musforcereset:
|
||||
lua_pushinteger(L, header->musforcereset);
|
||||
else if (fastcmp(field,"forcecharacter"))
|
||||
break;
|
||||
case mapheaderinfo_forcecharacter:
|
||||
lua_pushstring(L, header->forcecharacter);
|
||||
else if (fastcmp(field,"weather"))
|
||||
break;
|
||||
case mapheaderinfo_weather:
|
||||
lua_pushinteger(L, header->weather);
|
||||
else if (fastcmp(field,"skynum"))
|
||||
break;
|
||||
case mapheaderinfo_skynum:
|
||||
lua_pushinteger(L, header->skynum);
|
||||
else if (fastcmp(field,"skybox_scalex"))
|
||||
break;
|
||||
case mapheaderinfo_skybox_scalex:
|
||||
lua_pushinteger(L, header->skybox_scalex);
|
||||
else if (fastcmp(field,"skybox_scaley"))
|
||||
break;
|
||||
case mapheaderinfo_skybox_scaley:
|
||||
lua_pushinteger(L, header->skybox_scaley);
|
||||
else if (fastcmp(field,"skybox_scalez"))
|
||||
break;
|
||||
case mapheaderinfo_skybox_scalez:
|
||||
lua_pushinteger(L, header->skybox_scalez);
|
||||
else if (fastcmp(field,"interscreen")) {
|
||||
break;
|
||||
case mapheaderinfo_interscreen:
|
||||
for (i = 0; i < 8; i++)
|
||||
if (!header->interscreen[i])
|
||||
break;
|
||||
lua_pushlstring(L, header->interscreen, i);
|
||||
} else if (fastcmp(field,"runsoc"))
|
||||
break;
|
||||
case mapheaderinfo_runsoc:
|
||||
lua_pushstring(L, header->runsoc);
|
||||
else if (fastcmp(field,"scriptname"))
|
||||
break;
|
||||
case mapheaderinfo_scriptname:
|
||||
lua_pushstring(L, header->scriptname);
|
||||
else if (fastcmp(field,"precutscenenum"))
|
||||
break;
|
||||
case mapheaderinfo_precutscenenum:
|
||||
lua_pushinteger(L, header->precutscenenum);
|
||||
else if (fastcmp(field,"cutscenenum"))
|
||||
break;
|
||||
case mapheaderinfo_cutscenenum:
|
||||
lua_pushinteger(L, header->cutscenenum);
|
||||
else if (fastcmp(field,"countdown"))
|
||||
break;
|
||||
case mapheaderinfo_countdown:
|
||||
lua_pushinteger(L, header->countdown);
|
||||
else if (fastcmp(field,"palette"))
|
||||
break;
|
||||
case mapheaderinfo_palette:
|
||||
lua_pushinteger(L, header->palette);
|
||||
else if (fastcmp(field,"numlaps"))
|
||||
break;
|
||||
case mapheaderinfo_numlaps:
|
||||
lua_pushinteger(L, header->numlaps);
|
||||
else if (fastcmp(field,"unlockrequired"))
|
||||
break;
|
||||
case mapheaderinfo_unlockrequired:
|
||||
lua_pushinteger(L, header->unlockrequired);
|
||||
else if (fastcmp(field,"levelselect"))
|
||||
break;
|
||||
case mapheaderinfo_levelselect:
|
||||
lua_pushinteger(L, header->levelselect);
|
||||
else if (fastcmp(field,"bonustype"))
|
||||
break;
|
||||
case mapheaderinfo_bonustype:
|
||||
lua_pushinteger(L, header->bonustype);
|
||||
else if (fastcmp(field,"ltzzpatch"))
|
||||
break;
|
||||
case mapheaderinfo_ltzzpatch:
|
||||
lua_pushstring(L, header->ltzzpatch);
|
||||
else if (fastcmp(field,"ltzztext"))
|
||||
break;
|
||||
case mapheaderinfo_ltzztext:
|
||||
lua_pushstring(L, header->ltzztext);
|
||||
else if (fastcmp(field,"ltactdiamond"))
|
||||
break;
|
||||
case mapheaderinfo_ltactdiamond:
|
||||
lua_pushstring(L, header->ltactdiamond);
|
||||
else if (fastcmp(field,"maxbonuslives"))
|
||||
break;
|
||||
case mapheaderinfo_maxbonuslives:
|
||||
lua_pushinteger(L, header->maxbonuslives);
|
||||
else if (fastcmp(field,"levelflags"))
|
||||
break;
|
||||
case mapheaderinfo_levelflags:
|
||||
lua_pushinteger(L, header->levelflags);
|
||||
else if (fastcmp(field,"menuflags"))
|
||||
break;
|
||||
case mapheaderinfo_menuflags:
|
||||
lua_pushinteger(L, header->menuflags);
|
||||
else if (fastcmp(field,"selectheading"))
|
||||
break;
|
||||
case mapheaderinfo_selectheading:
|
||||
lua_pushstring(L, header->selectheading);
|
||||
else if (fastcmp(field,"startrings"))
|
||||
break;
|
||||
case mapheaderinfo_startrings:
|
||||
lua_pushinteger(L, header->startrings);
|
||||
else if (fastcmp(field, "sstimer"))
|
||||
break;
|
||||
case mapheaderinfo_sstimer:
|
||||
lua_pushinteger(L, header->sstimer);
|
||||
else if (fastcmp(field, "ssspheres"))
|
||||
break;
|
||||
case mapheaderinfo_ssspheres:
|
||||
lua_pushinteger(L, header->ssspheres);
|
||||
else if (fastcmp(field, "gravity"))
|
||||
break;
|
||||
case mapheaderinfo_gravity:
|
||||
lua_pushfixed(L, header->gravity);
|
||||
break;
|
||||
// TODO add support for reading numGradedMares and grades
|
||||
else {
|
||||
default:
|
||||
// Read custom vars now
|
||||
// (note: don't include the "LUA." in your lua scripts!)
|
||||
UINT8 j = 0;
|
||||
for (;j < header->numCustomOptions && !fastcmp(field, header->customopts[j].option); ++j);
|
||||
for (;j < header->numCustomOptions && !fastcmp(lua_tostring(L, 2), header->customopts[j].option); ++j);
|
||||
|
||||
if(j < header->numCustomOptions)
|
||||
lua_pushstring(L, header->customopts[j].value);
|
||||
|
@ -2539,6 +2753,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
sector_fields_ref = Lua_CreateFieldTable(L, sector_opt);
|
||||
|
||||
luaL_newmetatable(L, META_SUBSECTOR);
|
||||
lua_pushcfunction(L, subsector_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2547,6 +2763,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt);
|
||||
|
||||
luaL_newmetatable(L, META_LINE);
|
||||
lua_pushcfunction(L, line_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2555,6 +2773,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
line_fields_ref = Lua_CreateFieldTable(L, line_opt);
|
||||
|
||||
luaL_newmetatable(L, META_LINEARGS);
|
||||
lua_pushcfunction(L, lineargs_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2587,6 +2807,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
side_fields_ref = Lua_CreateFieldTable(L, side_opt);
|
||||
|
||||
luaL_newmetatable(L, META_VERTEX);
|
||||
lua_pushcfunction(L, vertex_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2595,6 +2817,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
vertex_fields_ref = Lua_CreateFieldTable(L, vertex_opt);
|
||||
|
||||
luaL_newmetatable(L, META_FFLOOR);
|
||||
lua_pushcfunction(L, ffloor_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2603,6 +2827,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L, 1);
|
||||
|
||||
ffloor_fields_ref = Lua_CreateFieldTable(L, ffloor_opt);
|
||||
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
luaL_newmetatable(L, META_SEG);
|
||||
lua_pushcfunction(L, seg_get);
|
||||
|
@ -2612,6 +2838,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
seg_fields_ref = Lua_CreateFieldTable(L, seg_opt);
|
||||
|
||||
luaL_newmetatable(L, META_NODE);
|
||||
lua_pushcfunction(L, node_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2620,6 +2848,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
node_fields_ref = Lua_CreateFieldTable(L, node_opt);
|
||||
|
||||
luaL_newmetatable(L, META_NODEBBOX);
|
||||
//lua_pushcfunction(L, nodebbox_get);
|
||||
//lua_setfield(L, -2, "__index");
|
||||
|
@ -2646,6 +2876,8 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L, 1);
|
||||
|
||||
slope_fields_ref = Lua_CreateFieldTable(L, slope_opt);
|
||||
|
||||
luaL_newmetatable(L, META_VECTOR2);
|
||||
lua_pushcfunction(L, vector2_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -2664,6 +2896,8 @@ int LUA_MapLib(lua_State *L)
|
|||
//lua_setfield(L, -2, "__len");
|
||||
lua_pop(L, 1);
|
||||
|
||||
mapheaderinfo_fields_ref = Lua_CreateFieldTable(L, mapheaderinfo_opt);
|
||||
|
||||
LUA_PushTaggableObjectArray(L, "sectors",
|
||||
lib_iterateSectors,
|
||||
lib_getSector,
|
||||
|
|
|
@ -179,10 +179,12 @@ static const char *const mobj_opt[] = {
|
|||
|
||||
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
|
||||
|
||||
static int mobj_fields_ref = LUA_NOREF;
|
||||
|
||||
static int mobj_get(lua_State *L)
|
||||
{
|
||||
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
enum mobj_e field = Lua_optoption(L, 2, NULL, mobj_opt);
|
||||
enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref);
|
||||
lua_settop(L, 2);
|
||||
|
||||
if (!mo || !ISINLEVEL) {
|
||||
|
@ -467,7 +469,7 @@ static int mobj_get(lua_State *L)
|
|||
static int mobj_set(lua_State *L)
|
||||
{
|
||||
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
enum mobj_e field = Lua_optoption(L, 2, mobj_opt[0], mobj_opt);
|
||||
enum mobj_e field = Lua_optoption(L, 2, mobj_valid, mobj_fields_ref);
|
||||
lua_settop(L, 3);
|
||||
|
||||
INLEVEL
|
||||
|
@ -876,14 +878,55 @@ static int thingstringargs_len(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
enum mapthing_e {
|
||||
mapthing_valid = 0,
|
||||
mapthing_x,
|
||||
mapthing_y,
|
||||
mapthing_angle,
|
||||
mapthing_pitch,
|
||||
mapthing_roll,
|
||||
mapthing_type,
|
||||
mapthing_options,
|
||||
mapthing_scale,
|
||||
mapthing_z,
|
||||
mapthing_extrainfo,
|
||||
mapthing_tag,
|
||||
mapthing_taglist,
|
||||
mapthing_args,
|
||||
mapthing_stringargs,
|
||||
mapthing_mobj,
|
||||
};
|
||||
|
||||
const char *const mapthing_opt[] = {
|
||||
"valid",
|
||||
"x",
|
||||
"y",
|
||||
"angle",
|
||||
"pitch",
|
||||
"roll",
|
||||
"type",
|
||||
"options",
|
||||
"scale",
|
||||
"z",
|
||||
"extrainfo",
|
||||
"tag",
|
||||
"taglist",
|
||||
"args",
|
||||
"stringargs",
|
||||
"mobj",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int mapthing_fields_ref = LUA_NOREF;
|
||||
|
||||
static int mapthing_get(lua_State *L)
|
||||
{
|
||||
mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING));
|
||||
const char *field = luaL_checkstring(L, 2);
|
||||
lua_Integer number;
|
||||
enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref);
|
||||
lua_settop(L, 2);
|
||||
|
||||
if (!mt) {
|
||||
if (fastcmp(field,"valid")) {
|
||||
if (field == mapthing_valid) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
|
@ -892,62 +935,71 @@ static int mapthing_get(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (fastcmp(field,"valid")) {
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
} else if(fastcmp(field,"x"))
|
||||
number = mt->x;
|
||||
else if(fastcmp(field,"y"))
|
||||
number = mt->y;
|
||||
else if(fastcmp(field,"angle"))
|
||||
number = mt->angle;
|
||||
else if(fastcmp(field,"pitch"))
|
||||
number = mt->pitch;
|
||||
else if(fastcmp(field,"roll"))
|
||||
number = mt->roll;
|
||||
else if(fastcmp(field,"type"))
|
||||
number = mt->type;
|
||||
else if(fastcmp(field,"options"))
|
||||
number = mt->options;
|
||||
else if(fastcmp(field,"scale"))
|
||||
number = mt->scale;
|
||||
else if(fastcmp(field,"z"))
|
||||
number = mt->z;
|
||||
else if(fastcmp(field,"extrainfo"))
|
||||
number = mt->extrainfo;
|
||||
else if(fastcmp(field,"tag"))
|
||||
number = Tag_FGet(&mt->tags);
|
||||
else if(fastcmp(field,"taglist"))
|
||||
switch (field)
|
||||
{
|
||||
LUA_PushUserdata(L, &mt->tags, META_TAGLIST);
|
||||
return 1;
|
||||
case mapthing_valid:
|
||||
lua_pushboolean(L, true);
|
||||
break;
|
||||
case mapthing_x:
|
||||
lua_pushinteger(L, mt->x);
|
||||
break;
|
||||
case mapthing_y:
|
||||
lua_pushinteger(L, mt->y);
|
||||
break;
|
||||
case mapthing_angle:
|
||||
lua_pushinteger(L, mt->angle);
|
||||
break;
|
||||
case mapthing_pitch:
|
||||
lua_pushinteger(L, mt->pitch);
|
||||
break;
|
||||
case mapthing_roll:
|
||||
lua_pushinteger(L, mt->roll);
|
||||
break;
|
||||
case mapthing_type:
|
||||
lua_pushinteger(L, mt->type);
|
||||
break;
|
||||
case mapthing_options:
|
||||
lua_pushinteger(L, mt->options);
|
||||
break;
|
||||
case mapthing_scale:
|
||||
lua_pushinteger(L, mt->scale);
|
||||
break;
|
||||
case mapthing_z:
|
||||
lua_pushinteger(L, mt->z);
|
||||
break;
|
||||
case mapthing_extrainfo:
|
||||
lua_pushinteger(L, mt->extrainfo);
|
||||
break;
|
||||
case mapthing_tag:
|
||||
lua_pushinteger(L, Tag_FGet(&mt->tags));
|
||||
break;
|
||||
case mapthing_taglist:
|
||||
LUA_PushUserdata(L, &mt->tags, META_TAGLIST);
|
||||
break;
|
||||
case mapthing_args:
|
||||
LUA_PushUserdata(L, mt->args, META_THINGARGS);
|
||||
break;
|
||||
case mapthing_stringargs:
|
||||
LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS);
|
||||
break;
|
||||
case mapthing_mobj:
|
||||
LUA_PushUserdata(L, mt->mobj, META_MOBJ);
|
||||
break;
|
||||
default:
|
||||
if (devparm)
|
||||
return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if(fastcmp(field,"args"))
|
||||
{
|
||||
LUA_PushUserdata(L, mt->args, META_THINGARGS);
|
||||
return 1;
|
||||
}
|
||||
else if(fastcmp(field,"stringargs"))
|
||||
{
|
||||
LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS);
|
||||
return 1;
|
||||
}
|
||||
else if(fastcmp(field,"mobj")) {
|
||||
LUA_PushUserdata(L, mt->mobj, META_MOBJ);
|
||||
return 1;
|
||||
} else if (devparm)
|
||||
return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field);
|
||||
else
|
||||
return 0;
|
||||
|
||||
lua_pushinteger(L, number);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mapthing_set(lua_State *L)
|
||||
{
|
||||
mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING));
|
||||
const char *field = luaL_checkstring(L, 2);
|
||||
enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref);
|
||||
lua_settop(L, 3);
|
||||
|
||||
if (!mt)
|
||||
return luaL_error(L, "accessed mapthing_t doesn't exist anymore.");
|
||||
|
@ -957,39 +1009,52 @@ static int mapthing_set(lua_State *L)
|
|||
if (hook_cmd_running)
|
||||
return luaL_error(L, "Do not alter mapthing_t in CMD building code!");
|
||||
|
||||
if(fastcmp(field,"x"))
|
||||
mt->x = (INT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"y"))
|
||||
mt->y = (INT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"angle"))
|
||||
mt->angle = (INT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"pitch"))
|
||||
mt->pitch = (INT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"roll"))
|
||||
mt->roll = (INT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"type"))
|
||||
mt->type = (UINT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"options"))
|
||||
mt->options = (UINT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"scale"))
|
||||
mt->scale = luaL_checkfixed(L, 3);
|
||||
else if(fastcmp(field,"z"))
|
||||
mt->z = (INT16)luaL_checkinteger(L, 3);
|
||||
else if(fastcmp(field,"extrainfo"))
|
||||
switch (field)
|
||||
{
|
||||
INT32 extrainfo = luaL_checkinteger(L, 3);
|
||||
if (extrainfo & ~15)
|
||||
return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15);
|
||||
mt->extrainfo = (UINT8)extrainfo;
|
||||
case mapthing_x:
|
||||
mt->x = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_y:
|
||||
mt->y = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_angle:
|
||||
mt->angle = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_pitch:
|
||||
mt->pitch = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_roll:
|
||||
mt->roll = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_type:
|
||||
mt->type = (UINT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_options:
|
||||
mt->options = (UINT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_scale:
|
||||
mt->scale = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case mapthing_z:
|
||||
mt->z = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case mapthing_extrainfo:
|
||||
INT32 extrainfo = luaL_checkinteger(L, 3);
|
||||
if (extrainfo & ~15)
|
||||
return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15);
|
||||
mt->extrainfo = (UINT8)extrainfo;
|
||||
break;
|
||||
case mapthing_tag:
|
||||
Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3));
|
||||
break;
|
||||
case mapthing_taglist:
|
||||
return LUA_ErrSetDirectly(L, "mapthing_t", "taglist");
|
||||
case mapthing_mobj:
|
||||
mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field);
|
||||
}
|
||||
else if (fastcmp(field,"tag"))
|
||||
Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3));
|
||||
else if (fastcmp(field,"taglist"))
|
||||
return LUA_ErrSetDirectly(L, "mapthing_t", "taglist");
|
||||
else if(fastcmp(field,"mobj"))
|
||||
mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
else
|
||||
return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1051,6 +1116,8 @@ int LUA_MobjLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L,1);
|
||||
|
||||
mobj_fields_ref = Lua_CreateFieldTable(L, mobj_opt);
|
||||
|
||||
luaL_newmetatable(L, META_THINGARGS);
|
||||
lua_pushcfunction(L, thingargs_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
@ -1078,6 +1145,8 @@ int LUA_MobjLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L,1);
|
||||
|
||||
mapthing_fields_ref = Lua_CreateFieldTable(L, mapthing_opt);
|
||||
|
||||
LUA_PushTaggableObjectArray(L, "mapthings",
|
||||
lib_iterateMapthings,
|
||||
lib_getMapthing,
|
||||
|
|
1243
src/lua_playerlib.c
1243
src/lua_playerlib.c
File diff suppressed because it is too large
Load diff
|
@ -306,6 +306,18 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
lua_pushinteger(L, ammoremovaltics);
|
||||
return 1;
|
||||
// end timers
|
||||
} else if (fastcmp(word,"use1upSound")) {
|
||||
lua_pushinteger(L, use1upSound);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"maxXtraLife")) {
|
||||
lua_pushinteger(L, maxXtraLife);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"useContinues")) {
|
||||
lua_pushinteger(L, useContinues);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"shareEmblems")) {
|
||||
lua_pushinteger(L, shareEmblems);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"gametype")) {
|
||||
lua_pushinteger(L, gametype);
|
||||
return 1;
|
||||
|
@ -698,20 +710,23 @@ void LUA_DumpFile(const char *filename)
|
|||
|
||||
fixed_t LUA_EvalMath(const char *word)
|
||||
{
|
||||
lua_State *L = NULL;
|
||||
static lua_State *L = NULL;
|
||||
char buf[1024], *b;
|
||||
const char *p;
|
||||
fixed_t res = 0;
|
||||
|
||||
// make a new state so SOC can't interefere with scripts
|
||||
// allocate state
|
||||
L = lua_newstate(LUA_Alloc, NULL);
|
||||
lua_atpanic(L, LUA_Panic);
|
||||
if (!L)
|
||||
{
|
||||
// make a new state so SOC can't interefere with scripts
|
||||
// allocate state
|
||||
L = lua_newstate(LUA_Alloc, NULL);
|
||||
lua_atpanic(L, LUA_Panic);
|
||||
|
||||
// open only enum lib
|
||||
lua_pushcfunction(L, LUA_EnumLib);
|
||||
lua_pushboolean(L, true);
|
||||
lua_call(L, 1, 0);
|
||||
// open only enum lib
|
||||
lua_pushcfunction(L, LUA_EnumLib);
|
||||
lua_pushboolean(L, true);
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
|
||||
// change ^ into ^^ for Lua.
|
||||
strcpy(buf, "return ");
|
||||
|
@ -736,8 +751,6 @@ fixed_t LUA_EvalMath(const char *word)
|
|||
else
|
||||
res = lua_tointeger(L, -1);
|
||||
|
||||
// clean up and return.
|
||||
lua_close(L);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1716,17 +1729,39 @@ void LUA_UnArchive(void)
|
|||
}
|
||||
|
||||
// For mobj_t, player_t, etc. to take custom variables.
|
||||
int Lua_optoption(lua_State *L, int narg,
|
||||
const char *def, const char *const lst[])
|
||||
int Lua_optoption(lua_State *L, int narg, int def, int list_ref)
|
||||
{
|
||||
const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
|
||||
int i;
|
||||
for (i=0; lst[i]; i++)
|
||||
if (fastcmp(lst[i], name))
|
||||
return i;
|
||||
if (lua_isnoneornil(L, narg))
|
||||
return def;
|
||||
|
||||
I_Assert(lua_checkstack(L, 2));
|
||||
luaL_checkstring(L, narg);
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, list_ref);
|
||||
I_Assert(lua_istable(L, -1));
|
||||
lua_pushvalue(L, narg);
|
||||
lua_rawget(L, -2);
|
||||
|
||||
if (lua_isnumber(L, -1))
|
||||
return lua_tointeger(L, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Lua_CreateFieldTable(lua_State *L, const char *const lst[])
|
||||
{
|
||||
int i;
|
||||
|
||||
lua_newtable(L);
|
||||
for (i = 0; lst[i] != NULL; i++)
|
||||
{
|
||||
lua_pushstring(L, lst[i]);
|
||||
lua_pushinteger(L, i);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
return luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
void LUA_PushTaggableObjectArray
|
||||
( lua_State *L,
|
||||
const char *field,
|
||||
|
|
|
@ -57,8 +57,8 @@ int LUA_PushGlobals(lua_State *L, const char *word);
|
|||
int LUA_CheckGlobals(lua_State *L, const char *word);
|
||||
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
|
||||
void LUA_CVarChanged(void *cvar); // lua_consolelib.c
|
||||
int Lua_optoption(lua_State *L, int narg,
|
||||
const char *def, const char *const lst[]);
|
||||
int Lua_optoption(lua_State *L, int narg, int def, int list_ref);
|
||||
int Lua_CreateFieldTable(lua_State *L, const char *const lst[]);
|
||||
void LUA_HookNetArchive(lua_CFunction archFunc);
|
||||
|
||||
void LUA_PushTaggableObjectArray
|
||||
|
|
|
@ -55,6 +55,7 @@ enum skin {
|
|||
skin_soundsid,
|
||||
skin_sprites
|
||||
};
|
||||
|
||||
static const char *const skin_opt[] = {
|
||||
"valid",
|
||||
"name",
|
||||
|
@ -95,10 +96,12 @@ static const char *const skin_opt[] = {
|
|||
|
||||
#define UNIMPLEMENTED luaL_error(L, LUA_QL("skin_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", skin_opt[field])
|
||||
|
||||
static int skin_fields_ref = LUA_NOREF;
|
||||
|
||||
static int skin_get(lua_State *L)
|
||||
{
|
||||
skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN));
|
||||
enum skin field = luaL_checkoption(L, 2, NULL, skin_opt);
|
||||
enum skin field = Lua_optoption(L, 2, -1, skin_fields_ref);
|
||||
|
||||
// skins are always valid, only added, never removed
|
||||
I_Assert(skin != NULL);
|
||||
|
@ -376,6 +379,8 @@ int LUA_SkinLib(lua_State *L)
|
|||
lua_setfield(L, -2, "__len");
|
||||
lua_pop(L,1);
|
||||
|
||||
skin_fields_ref = Lua_CreateFieldTable(L, skin_opt);
|
||||
|
||||
luaL_newmetatable(L, META_SOUNDSID);
|
||||
lua_pushcfunction(L, soundsid_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
|
|
@ -79,9 +79,9 @@ static UINT8 cheatf_warp(void)
|
|||
|
||||
// Temporarily unlock stuff.
|
||||
G_SetUsedCheats(false);
|
||||
unlockables[31].unlocked = true; // credits
|
||||
unlockables[30].unlocked = true; // sound test
|
||||
unlockables[28].unlocked = true; // level select
|
||||
clientGamedata->unlocked[31] = true; // credits
|
||||
clientGamedata->unlocked[30] = true; // sound test
|
||||
clientGamedata->unlocked[28] = true; // level select
|
||||
|
||||
// Refresh secrets menu existing.
|
||||
M_ClearMenus(true);
|
||||
|
@ -102,7 +102,7 @@ static UINT8 cheatf_devmode(void)
|
|||
// Just unlock all the things and turn on -debug and console devmode.
|
||||
G_SetUsedCheats(false);
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
unlockables[i].unlocked = true;
|
||||
clientGamedata->unlocked[i] = true;
|
||||
devparm = true;
|
||||
cv_debug |= 0x8000;
|
||||
|
||||
|
@ -238,7 +238,7 @@ boolean cht_Responder(event_t *ev)
|
|||
}
|
||||
|
||||
// Console cheat commands rely on these a lot...
|
||||
#define REQUIRE_PANDORA if (!M_SecretUnlocked(SECRET_PANDORA) && !cv_debug)\
|
||||
#define REQUIRE_PANDORA if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !cv_debug)\
|
||||
{ CONS_Printf(M_GetText("You haven't earned this yet.\n")); return; }
|
||||
|
||||
#define REQUIRE_DEVMODE if (!cv_debug)\
|
||||
|
|
249
src/m_cond.c
249
src/m_cond.c
|
@ -21,6 +21,9 @@
|
|||
#include "r_skins.h" // numskins
|
||||
#include "r_draw.h" // R_GetColorByName
|
||||
|
||||
gamedata_t *clientGamedata; // Our gamedata
|
||||
gamedata_t *serverGamedata; // Server's gamedata
|
||||
|
||||
// Map triggers for linedef executors
|
||||
// 32 triggers, one bit each
|
||||
UINT32 unlocktriggers;
|
||||
|
@ -41,6 +44,70 @@ unlockable_t unlockables[MAXUNLOCKABLES];
|
|||
INT32 numemblems = 0;
|
||||
INT32 numextraemblems = 0;
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
nightsdata_t ntemprecords;
|
||||
|
||||
// Create a new gamedata_t, for start-up
|
||||
gamedata_t *M_NewGameDataStruct(void)
|
||||
{
|
||||
gamedata_t *data = Z_Calloc(sizeof (*data), PU_STATIC, NULL);
|
||||
M_ClearSecrets(data);
|
||||
G_ClearRecords(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void M_CopyGameData(gamedata_t *dest, gamedata_t *src)
|
||||
{
|
||||
INT32 i, j;
|
||||
|
||||
M_ClearSecrets(dest);
|
||||
G_ClearRecords(dest);
|
||||
|
||||
dest->loaded = src->loaded;
|
||||
dest->totalplaytime = src->totalplaytime;
|
||||
|
||||
dest->timesBeaten = src->timesBeaten;
|
||||
dest->timesBeatenWithEmeralds = src->timesBeatenWithEmeralds;
|
||||
dest->timesBeatenUltimate = src->timesBeatenUltimate;
|
||||
|
||||
memcpy(dest->achieved, src->achieved, sizeof(dest->achieved));
|
||||
memcpy(dest->collected, src->collected, sizeof(dest->collected));
|
||||
memcpy(dest->extraCollected, src->extraCollected, sizeof(dest->extraCollected));
|
||||
memcpy(dest->unlocked, src->unlocked, sizeof(dest->unlocked));
|
||||
|
||||
memcpy(dest->mapvisited, src->mapvisited, sizeof(dest->mapvisited));
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if (!src->mainrecords[i])
|
||||
continue;
|
||||
|
||||
G_AllocMainRecordData((INT16)i, dest);
|
||||
dest->mainrecords[i]->score = src->mainrecords[i]->score;
|
||||
dest->mainrecords[i]->time = src->mainrecords[i]->time;
|
||||
dest->mainrecords[i]->rings = src->mainrecords[i]->rings;
|
||||
}
|
||||
|
||||
// Nights records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if (!src->nightsrecords[i] || !src->nightsrecords[i]->nummares)
|
||||
continue;
|
||||
|
||||
G_AllocNightsRecordData((INT16)i, dest);
|
||||
|
||||
for (j = 0; j < (src->nightsrecords[i]->nummares + 1); j++)
|
||||
{
|
||||
dest->nightsrecords[i]->score[j] = src->nightsrecords[i]->score[j];
|
||||
dest->nightsrecords[i]->grade[j] = src->nightsrecords[i]->grade[j];
|
||||
dest->nightsrecords[i]->time[j] = src->nightsrecords[i]->time[j];
|
||||
}
|
||||
|
||||
dest->nightsrecords[i]->nummares = src->nightsrecords[i]->nummares;
|
||||
}
|
||||
}
|
||||
|
||||
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2)
|
||||
{
|
||||
condition_t *cond;
|
||||
|
@ -70,89 +137,90 @@ void M_ClearConditionSet(UINT8 set)
|
|||
conditionSets[set - 1].condition = NULL;
|
||||
conditionSets[set - 1].numconditions = 0;
|
||||
}
|
||||
conditionSets[set - 1].achieved = false;
|
||||
clientGamedata->achieved[set - 1] = serverGamedata->achieved[set - 1] = false;
|
||||
}
|
||||
|
||||
// Clear ALL secrets.
|
||||
void M_ClearSecrets(void)
|
||||
void M_ClearSecrets(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
memset(mapvisited, 0, sizeof(mapvisited));
|
||||
memset(data->mapvisited, 0, sizeof(data->mapvisited));
|
||||
|
||||
for (i = 0; i < MAXEMBLEMS; ++i)
|
||||
emblemlocations[i].collected = false;
|
||||
data->collected[i] = false;
|
||||
for (i = 0; i < MAXEXTRAEMBLEMS; ++i)
|
||||
extraemblems[i].collected = false;
|
||||
data->extraCollected[i] = false;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
unlockables[i].unlocked = false;
|
||||
data->unlocked[i] = false;
|
||||
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
||||
conditionSets[i].achieved = false;
|
||||
data->achieved[i] = false;
|
||||
|
||||
timesBeaten = timesBeatenWithEmeralds = timesBeatenUltimate = 0;
|
||||
data->timesBeaten = data->timesBeatenWithEmeralds = data->timesBeatenUltimate = 0;
|
||||
|
||||
// Re-unlock any always unlocked things
|
||||
M_SilentUpdateUnlockablesAndEmblems();
|
||||
M_SilentUpdateUnlockablesAndEmblems(data);
|
||||
M_SilentUpdateSkinAvailabilites();
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Condition set checking
|
||||
// ----------------------
|
||||
static UINT8 M_CheckCondition(condition_t *cn)
|
||||
static UINT8 M_CheckCondition(condition_t *cn, gamedata_t *data)
|
||||
{
|
||||
switch (cn->type)
|
||||
{
|
||||
case UC_PLAYTIME: // Requires total playing time >= x
|
||||
return (totalplaytime >= (unsigned)cn->requirement);
|
||||
return (data->totalplaytime >= (unsigned)cn->requirement);
|
||||
case UC_GAMECLEAR: // Requires game beaten >= x times
|
||||
return (timesBeaten >= (unsigned)cn->requirement);
|
||||
return (data->timesBeaten >= (unsigned)cn->requirement);
|
||||
case UC_ALLEMERALDS: // Requires game beaten with all 7 emeralds >= x times
|
||||
return (timesBeatenWithEmeralds >= (unsigned)cn->requirement);
|
||||
return (data->timesBeatenWithEmeralds >= (unsigned)cn->requirement);
|
||||
case UC_ULTIMATECLEAR: // Requires game beaten on ultimate >= x times (in other words, never)
|
||||
return (timesBeatenUltimate >= (unsigned)cn->requirement);
|
||||
return (data->timesBeatenUltimate >= (unsigned)cn->requirement);
|
||||
case UC_OVERALLSCORE: // Requires overall score >= x
|
||||
return (M_GotHighEnoughScore(cn->requirement));
|
||||
return (M_GotHighEnoughScore(cn->requirement, data));
|
||||
case UC_OVERALLTIME: // Requires overall time <= x
|
||||
return (M_GotLowEnoughTime(cn->requirement));
|
||||
return (M_GotLowEnoughTime(cn->requirement, data));
|
||||
case UC_OVERALLRINGS: // Requires overall rings >= x
|
||||
return (M_GotHighEnoughRings(cn->requirement));
|
||||
return (M_GotHighEnoughRings(cn->requirement, data));
|
||||
case UC_MAPVISITED: // Requires map x to be visited
|
||||
return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
|
||||
case UC_MAPBEATEN: // Requires map x to be beaten
|
||||
return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
|
||||
case UC_MAPALLEMERALDS: // Requires map x to be beaten with all emeralds in possession
|
||||
return ((mapvisited[cn->requirement - 1] & MV_ALLEMERALDS) == MV_ALLEMERALDS);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_ALLEMERALDS) == MV_ALLEMERALDS);
|
||||
case UC_MAPULTIMATE: // Requires map x to be beaten on ultimate
|
||||
return ((mapvisited[cn->requirement - 1] & MV_ULTIMATE) == MV_ULTIMATE);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_ULTIMATE) == MV_ULTIMATE);
|
||||
case UC_MAPPERFECT: // Requires map x to be beaten with a perfect bonus
|
||||
return ((mapvisited[cn->requirement - 1] & MV_PERFECT) == MV_PERFECT);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_PERFECT) == MV_PERFECT);
|
||||
case UC_MAPSCORE: // Requires score on map >= x
|
||||
return (G_GetBestScore(cn->extrainfo1) >= (unsigned)cn->requirement);
|
||||
return (G_GetBestScore(cn->extrainfo1, data) >= (unsigned)cn->requirement);
|
||||
case UC_MAPTIME: // Requires time on map <= x
|
||||
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
|
||||
return (G_GetBestTime(cn->extrainfo1, data) <= (unsigned)cn->requirement);
|
||||
case UC_MAPRINGS: // Requires rings on map >= x
|
||||
return (G_GetBestRings(cn->extrainfo1) >= cn->requirement);
|
||||
return (G_GetBestRings(cn->extrainfo1, data) >= cn->requirement);
|
||||
case UC_NIGHTSSCORE:
|
||||
return (G_GetBestNightsScore(cn->extrainfo1, (UINT8)cn->extrainfo2) >= (unsigned)cn->requirement);
|
||||
return (G_GetBestNightsScore(cn->extrainfo1, (UINT8)cn->extrainfo2, data) >= (unsigned)cn->requirement);
|
||||
case UC_NIGHTSTIME:
|
||||
return (G_GetBestNightsTime(cn->extrainfo1, (UINT8)cn->extrainfo2) <= (unsigned)cn->requirement);
|
||||
return (G_GetBestNightsTime(cn->extrainfo1, (UINT8)cn->extrainfo2, data) <= (unsigned)cn->requirement);
|
||||
case UC_NIGHTSGRADE:
|
||||
return (G_GetBestNightsGrade(cn->extrainfo1, (UINT8)cn->extrainfo2) >= cn->requirement);
|
||||
return (G_GetBestNightsGrade(cn->extrainfo1, (UINT8)cn->extrainfo2, data) >= cn->requirement);
|
||||
case UC_TRIGGER: // requires map trigger set
|
||||
return !!(unlocktriggers & (1 << cn->requirement));
|
||||
case UC_TOTALEMBLEMS: // Requires number of emblems >= x
|
||||
return (M_GotEnoughEmblems(cn->requirement));
|
||||
return (M_GotEnoughEmblems(cn->requirement, data));
|
||||
case UC_EMBLEM: // Requires emblem x to be obtained
|
||||
return emblemlocations[cn->requirement-1].collected;
|
||||
return data->collected[cn->requirement-1];
|
||||
case UC_EXTRAEMBLEM: // Requires extra emblem x to be obtained
|
||||
return extraemblems[cn->requirement-1].collected;
|
||||
return data->extraCollected[cn->requirement-1];
|
||||
case UC_CONDITIONSET: // requires condition set x to already be achieved
|
||||
return M_Achieved(cn->requirement-1);
|
||||
return M_Achieved(cn->requirement-1, data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static UINT8 M_CheckConditionSet(conditionset_t *c)
|
||||
static UINT8 M_CheckConditionSet(conditionset_t *c, gamedata_t *data)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 lastID = 0;
|
||||
|
@ -173,13 +241,13 @@ static UINT8 M_CheckConditionSet(conditionset_t *c)
|
|||
continue;
|
||||
|
||||
lastID = cn->id;
|
||||
achievedSoFar = M_CheckCondition(cn);
|
||||
achievedSoFar = M_CheckCondition(cn, data);
|
||||
}
|
||||
|
||||
return achievedSoFar;
|
||||
}
|
||||
|
||||
void M_CheckUnlockConditions(void)
|
||||
void M_CheckUnlockConditions(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
conditionset_t *c;
|
||||
|
@ -187,27 +255,27 @@ void M_CheckUnlockConditions(void)
|
|||
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
||||
{
|
||||
c = &conditionSets[i];
|
||||
if (!c->numconditions || c->achieved)
|
||||
if (!c->numconditions || data->achieved[i])
|
||||
continue;
|
||||
|
||||
c->achieved = (M_CheckConditionSet(c));
|
||||
data->achieved[i] = (M_CheckConditionSet(c, data));
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
char cechoText[992] = "";
|
||||
UINT8 cechoLines = 0;
|
||||
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckUnlockConditions(data);
|
||||
|
||||
// Go through extra emblems
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected || !extraemblems[i].conditionset)
|
||||
if (data->extraCollected[i] || !extraemblems[i].conditionset)
|
||||
continue;
|
||||
if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false)
|
||||
if ((data->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1, data)) != false)
|
||||
{
|
||||
strcat(cechoText, va(M_GetText("Got \"%s\" emblem!\\"), extraemblems[i].name));
|
||||
++cechoLines;
|
||||
|
@ -217,14 +285,14 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
|
|||
// Fun part: if any of those unlocked we need to go through the
|
||||
// unlock conditions AGAIN just in case an emblem reward was reached
|
||||
if (cechoLines)
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckUnlockConditions(data);
|
||||
|
||||
// Go through unlockables
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (unlockables[i].unlocked || !unlockables[i].conditionset)
|
||||
if (data->unlocked[i] || !unlockables[i].conditionset)
|
||||
continue;
|
||||
if ((unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1)) != false)
|
||||
if ((data->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1, data)) != false)
|
||||
{
|
||||
if (unlockables[i].nocecho)
|
||||
continue;
|
||||
|
@ -248,45 +316,50 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
|
|||
HU_DoCEcho(slashed);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used when loading gamedata to make sure all unlocks are synched with conditions
|
||||
void M_SilentUpdateUnlockablesAndEmblems(void)
|
||||
void M_SilentUpdateUnlockablesAndEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
boolean checkAgain = false;
|
||||
|
||||
// Just in case they aren't to sync
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckLevelEmblems();
|
||||
M_CheckUnlockConditions(data);
|
||||
M_CheckLevelEmblems(data);
|
||||
M_CompletionEmblems(data);
|
||||
|
||||
// Go through extra emblems
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected || !extraemblems[i].conditionset)
|
||||
if (data->extraCollected[i] || !extraemblems[i].conditionset)
|
||||
continue;
|
||||
if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false)
|
||||
if ((data->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1, data)) != false)
|
||||
checkAgain = true;
|
||||
}
|
||||
|
||||
// check again if extra emblems unlocked, blah blah, etc
|
||||
if (checkAgain)
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckUnlockConditions(data);
|
||||
|
||||
// Go through unlockables
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (unlockables[i].unlocked || !unlockables[i].conditionset)
|
||||
if (data->unlocked[i] || !unlockables[i].conditionset)
|
||||
continue;
|
||||
unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1);
|
||||
data->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1, data);
|
||||
}
|
||||
}
|
||||
|
||||
void M_SilentUpdateSkinAvailabilites(void)
|
||||
{
|
||||
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
|
||||
}
|
||||
|
||||
// Emblem unlocking shit
|
||||
UINT8 M_CheckLevelEmblems(void)
|
||||
UINT8 M_CheckLevelEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
INT32 valToReach;
|
||||
|
@ -297,7 +370,7 @@ UINT8 M_CheckLevelEmblems(void)
|
|||
// Update Score, Time, Rings emblems
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type <= ET_SKIN || emblemlocations[i].type == ET_MAP || emblemlocations[i].collected)
|
||||
if (emblemlocations[i].type <= ET_SKIN || emblemlocations[i].type == ET_MAP || data->collected[i])
|
||||
continue;
|
||||
|
||||
levelnum = emblemlocations[i].level;
|
||||
|
@ -306,32 +379,32 @@ UINT8 M_CheckLevelEmblems(void)
|
|||
switch (emblemlocations[i].type)
|
||||
{
|
||||
case ET_SCORE: // Requires score on map >= x
|
||||
res = (G_GetBestScore(levelnum) >= (unsigned)valToReach);
|
||||
res = (G_GetBestScore(levelnum, data) >= (unsigned)valToReach);
|
||||
break;
|
||||
case ET_TIME: // Requires time on map <= x
|
||||
res = (G_GetBestTime(levelnum) <= (unsigned)valToReach);
|
||||
res = (G_GetBestTime(levelnum, data) <= (unsigned)valToReach);
|
||||
break;
|
||||
case ET_RINGS: // Requires rings on map >= x
|
||||
res = (G_GetBestRings(levelnum) >= valToReach);
|
||||
res = (G_GetBestRings(levelnum, data) >= valToReach);
|
||||
break;
|
||||
case ET_NGRADE: // Requires NiGHTS grade on map >= x
|
||||
res = (G_GetBestNightsGrade(levelnum, 0) >= valToReach);
|
||||
res = (G_GetBestNightsGrade(levelnum, 0, data) >= valToReach);
|
||||
break;
|
||||
case ET_NTIME: // Requires NiGHTS time on map <= x
|
||||
res = (G_GetBestNightsTime(levelnum, 0) <= (unsigned)valToReach);
|
||||
res = (G_GetBestNightsTime(levelnum, 0, data) <= (unsigned)valToReach);
|
||||
break;
|
||||
default: // unreachable but shuts the compiler up.
|
||||
continue;
|
||||
}
|
||||
|
||||
emblemlocations[i].collected = res;
|
||||
data->collected[i] = res;
|
||||
if (res)
|
||||
++somethingUnlocked;
|
||||
}
|
||||
return somethingUnlocked;
|
||||
}
|
||||
|
||||
UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough.
|
||||
UINT8 M_CompletionEmblems(gamedata_t *data) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough.
|
||||
{
|
||||
INT32 i;
|
||||
INT32 embtype;
|
||||
|
@ -342,7 +415,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type != ET_MAP || emblemlocations[i].collected)
|
||||
if (emblemlocations[i].type != ET_MAP || data->collected[i])
|
||||
continue;
|
||||
|
||||
levelnum = emblemlocations[i].level;
|
||||
|
@ -358,9 +431,9 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
if (embtype & ME_PERFECT)
|
||||
flags |= MV_PERFECT;
|
||||
|
||||
res = ((mapvisited[levelnum - 1] & flags) == flags);
|
||||
res = ((data->mapvisited[levelnum - 1] & flags) == flags);
|
||||
|
||||
emblemlocations[i].collected = res;
|
||||
data->collected[i] = res;
|
||||
if (res)
|
||||
++somethingUnlocked;
|
||||
}
|
||||
|
@ -370,48 +443,54 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
// -------------------
|
||||
// Quick unlock checks
|
||||
// -------------------
|
||||
UINT8 M_AnySecretUnlocked(void)
|
||||
UINT8 M_AnySecretUnlocked(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (!unlockables[i].nocecho && unlockables[i].unlocked)
|
||||
if (!unlockables[i].nocecho && data->unlocked[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_SecretUnlocked(INT32 type)
|
||||
UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (unlockables[i].type == type && unlockables[i].unlocked)
|
||||
if (unlockables[i].type == type && data->unlocked[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_MapLocked(INT32 mapnum)
|
||||
UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
|
||||
{
|
||||
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0)
|
||||
{
|
||||
return false;
|
||||
if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked)
|
||||
}
|
||||
|
||||
if (!data->unlocked[mapheaderinfo[mapnum-1]->unlockrequired])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
INT32 M_CountEmblems(void)
|
||||
INT32 M_CountEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 found = 0, i;
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].collected)
|
||||
if (data->collected[i])
|
||||
found++;
|
||||
}
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected)
|
||||
if (data->extraCollected[i])
|
||||
found++;
|
||||
}
|
||||
return found;
|
||||
|
@ -423,23 +502,23 @@ INT32 M_CountEmblems(void)
|
|||
|
||||
// Theoretically faster than using M_CountEmblems()
|
||||
// Stops when it reaches the target number of emblems.
|
||||
UINT8 M_GotEnoughEmblems(INT32 number)
|
||||
UINT8 M_GotEnoughEmblems(INT32 number, gamedata_t *data)
|
||||
{
|
||||
INT32 i, gottenemblems = 0;
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].collected)
|
||||
if (data->collected[i])
|
||||
if (++gottenemblems >= number) return true;
|
||||
}
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected)
|
||||
if (data->extraCollected[i])
|
||||
if (++gottenemblems >= number) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore)
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data)
|
||||
{
|
||||
INT32 mscore = 0;
|
||||
INT32 i;
|
||||
|
@ -448,16 +527,16 @@ UINT8 M_GotHighEnoughScore(INT32 tscore)
|
|||
{
|
||||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
if (!mainrecords[i])
|
||||
if (!data->mainrecords[i])
|
||||
continue;
|
||||
|
||||
if ((mscore += mainrecords[i]->score) > tscore)
|
||||
if ((mscore += data->mainrecords[i]->score) > tscore)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime)
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data)
|
||||
{
|
||||
INT32 curtics = 0;
|
||||
INT32 i;
|
||||
|
@ -467,15 +546,15 @@ UINT8 M_GotLowEnoughTime(INT32 tictime)
|
|||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
|
||||
if (!mainrecords[i] || !mainrecords[i]->time)
|
||||
if (!data->mainrecords[i] || !data->mainrecords[i]->time)
|
||||
return false;
|
||||
else if ((curtics += mainrecords[i]->time) > tictime)
|
||||
else if ((curtics += data->mainrecords[i]->time) > tictime)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings)
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data)
|
||||
{
|
||||
INT32 mrings = 0;
|
||||
INT32 i;
|
||||
|
@ -484,10 +563,10 @@ UINT8 M_GotHighEnoughRings(INT32 trings)
|
|||
{
|
||||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
if (!mainrecords[i])
|
||||
if (!data->mainrecords[i])
|
||||
continue;
|
||||
|
||||
if ((mrings += mainrecords[i]->rings) > trings)
|
||||
if ((mrings += data->mainrecords[i]->rings) > trings)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
123
src/m_cond.h
123
src/m_cond.h
|
@ -10,7 +10,11 @@
|
|||
/// \file m_cond.h
|
||||
/// \brief Unlockable condition system for SRB2 version 2.1
|
||||
|
||||
#ifndef __M_COND__
|
||||
#define __M_COND__
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomdata.h"
|
||||
|
||||
// --------
|
||||
// Typedefs
|
||||
|
@ -61,8 +65,6 @@ typedef struct
|
|||
{
|
||||
UINT32 numconditions; /// <- number of conditions.
|
||||
condition_t *condition; /// <- All conditionals to be checked.
|
||||
UINT8 achieved; /// <- Whether this conditional has been achieved already or not.
|
||||
/// (Conditional checking is skipped if true -- it's assumed you can't relock an unlockable)
|
||||
} conditionset_t;
|
||||
|
||||
// Emblem information
|
||||
|
@ -94,7 +96,6 @@ typedef struct
|
|||
INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin)
|
||||
char *stringVar; ///< String version
|
||||
char hint[110]; ///< Hint for emblem hints menu
|
||||
UINT8 collected; ///< Do you have this emblem?
|
||||
} emblem_t;
|
||||
typedef struct
|
||||
{
|
||||
|
@ -104,7 +105,6 @@ typedef struct
|
|||
UINT8 showconditionset; ///< Condition set that shows this emblem.
|
||||
UINT8 sprite; ///< emblem sprite to use, 0 - 25
|
||||
UINT16 color; ///< skincolor to use
|
||||
UINT8 collected; ///< Do you have this emblem?
|
||||
} extraemblem_t;
|
||||
|
||||
// Unlockable information
|
||||
|
@ -120,7 +120,6 @@ typedef struct
|
|||
char *stringVar;
|
||||
UINT8 nocecho;
|
||||
UINT8 nochecklist;
|
||||
UINT8 unlocked;
|
||||
} unlockable_t;
|
||||
|
||||
#define SECRET_NONE -6 // Does nil. Use with levels locked by UnlockRequired
|
||||
|
@ -143,6 +142,83 @@ typedef struct
|
|||
#define MAXEXTRAEMBLEMS 16
|
||||
#define MAXUNLOCKABLES 32
|
||||
|
||||
/** Time attack information, currently a very small structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
tic_t time; ///< Time in which the level was finished.
|
||||
UINT32 score; ///< Score when the level was finished.
|
||||
UINT16 rings; ///< Rings when the level was finished.
|
||||
} recorddata_t;
|
||||
|
||||
/** Setup for one NiGHTS map.
|
||||
* These are dynamically allocated because I am insane
|
||||
*/
|
||||
#define GRADE_F 0
|
||||
#define GRADE_E 1
|
||||
#define GRADE_D 2
|
||||
#define GRADE_C 3
|
||||
#define GRADE_B 4
|
||||
#define GRADE_A 5
|
||||
#define GRADE_S 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// 8 mares, 1 overall (0)
|
||||
UINT8 nummares;
|
||||
UINT32 score[9];
|
||||
UINT8 grade[9];
|
||||
tic_t time[9];
|
||||
} nightsdata_t;
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED 1
|
||||
#define MV_BEATEN 2
|
||||
#define MV_ALLEMERALDS 4
|
||||
#define MV_ULTIMATE 8
|
||||
#define MV_PERFECT 16
|
||||
#define MV_PERFECTRA 32
|
||||
#define MV_MAX 63 // used in gamedata check, update whenever MV's are added
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
extern nightsdata_t ntemprecords;
|
||||
|
||||
// GAMEDATA STRUCTURE
|
||||
// Everything that would get saved in gamedata.dat
|
||||
typedef struct
|
||||
{
|
||||
// WHENEVER OR NOT WE'RE READY TO SAVE
|
||||
boolean loaded;
|
||||
|
||||
// CONDITION SETS ACHIEVED
|
||||
boolean achieved[MAXCONDITIONSETS];
|
||||
|
||||
// EMBLEMS COLLECTED
|
||||
boolean collected[MAXEMBLEMS];
|
||||
|
||||
// EXTRA EMBLEMS COLLECTED
|
||||
boolean extraCollected[MAXEXTRAEMBLEMS];
|
||||
|
||||
// UNLOCKABLES UNLOCKED
|
||||
boolean unlocked[MAXUNLOCKABLES];
|
||||
|
||||
// TIME ATTACK DATA
|
||||
recorddata_t *mainrecords[NUMMAPS];
|
||||
nightsdata_t *nightsrecords[NUMMAPS];
|
||||
UINT8 mapvisited[NUMMAPS];
|
||||
|
||||
// # OF TIMES THE GAME HAS BEEN BEATEN
|
||||
UINT32 timesBeaten;
|
||||
UINT32 timesBeatenWithEmeralds;
|
||||
UINT32 timesBeatenUltimate;
|
||||
|
||||
// PLAY TIME
|
||||
UINT32 totalplaytime;
|
||||
} gamedata_t;
|
||||
|
||||
extern gamedata_t *clientGamedata;
|
||||
extern gamedata_t *serverGamedata;
|
||||
|
||||
extern conditionset_t conditionSets[MAXCONDITIONSETS];
|
||||
extern emblem_t emblemlocations[MAXEMBLEMS];
|
||||
extern extraemblem_t extraemblems[MAXEXTRAEMBLEMS];
|
||||
|
@ -153,25 +229,30 @@ extern INT32 numextraemblems;
|
|||
|
||||
extern UINT32 unlocktriggers;
|
||||
|
||||
gamedata_t *M_NewGameDataStruct(void);
|
||||
void M_CopyGameData(gamedata_t *dest, gamedata_t *src);
|
||||
|
||||
// Condition set setup
|
||||
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2);
|
||||
|
||||
// Clearing secrets
|
||||
void M_ClearConditionSet(UINT8 set);
|
||||
void M_ClearSecrets(void);
|
||||
void M_ClearSecrets(gamedata_t *data);
|
||||
|
||||
// Updating conditions and unlockables
|
||||
void M_CheckUnlockConditions(void);
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(void);
|
||||
void M_SilentUpdateUnlockablesAndEmblems(void);
|
||||
UINT8 M_CheckLevelEmblems(void);
|
||||
UINT8 M_CompletionEmblems(void);
|
||||
void M_CheckUnlockConditions(gamedata_t *data);
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(gamedata_t *data);
|
||||
void M_SilentUpdateUnlockablesAndEmblems(gamedata_t *data);
|
||||
UINT8 M_CheckLevelEmblems(gamedata_t *data);
|
||||
UINT8 M_CompletionEmblems(gamedata_t *data);
|
||||
|
||||
void M_SilentUpdateSkinAvailabilites(void);
|
||||
|
||||
// Checking unlockable status
|
||||
UINT8 M_AnySecretUnlocked(void);
|
||||
UINT8 M_SecretUnlocked(INT32 type);
|
||||
UINT8 M_MapLocked(INT32 mapnum);
|
||||
INT32 M_CountEmblems(void);
|
||||
UINT8 M_AnySecretUnlocked(gamedata_t *data);
|
||||
UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data);
|
||||
UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data);
|
||||
INT32 M_CountEmblems(gamedata_t *data);
|
||||
|
||||
// Emblem shit
|
||||
emblem_t *M_GetLevelEmblems(INT32 mapnum);
|
||||
|
@ -183,12 +264,14 @@ const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big);
|
|||
// If you're looking to compare stats for unlocks or what not, use these
|
||||
// They stop checking upon reaching the target number so they
|
||||
// should be (theoretically?) slightly faster.
|
||||
UINT8 M_GotEnoughEmblems(INT32 number);
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore);
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime);
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings);
|
||||
UINT8 M_GotEnoughEmblems(INT32 number, gamedata_t *data);
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data);
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data);
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data);
|
||||
|
||||
INT32 M_UnlockableSkinNum(unlockable_t *unlock);
|
||||
INT32 M_EmblemSkinNum(emblem_t *emblem);
|
||||
|
||||
#define M_Achieved(a) ((a) >= MAXCONDITIONSETS || conditionSets[a].achieved)
|
||||
#define M_Achieved(a, data) ((a) >= MAXCONDITIONSETS || data->achieved[a])
|
||||
|
||||
#endif
|
||||
|
|
299
src/m_menu.c
299
src/m_menu.c
|
@ -241,6 +241,7 @@ static void M_EmblemHints(INT32 choice);
|
|||
static void M_HandleEmblemHints(INT32 choice);
|
||||
UINT32 hintpage = 1;
|
||||
static void M_HandleChecklist(INT32 choice);
|
||||
static void M_PauseLevelSelect(INT32 choice);
|
||||
menu_t SR_MainDef, SR_UnlockChecklistDef;
|
||||
|
||||
static UINT8 check_on;
|
||||
|
@ -554,26 +555,30 @@ static menuitem_t MPauseMenu[] =
|
|||
{
|
||||
{IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8},
|
||||
{IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16},
|
||||
{IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_MapChange, 24},
|
||||
{IT_STRING | IT_CALL, NULL, "Emblem Hints...", M_EmblemHints, 24},
|
||||
{IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_MapChange, 32},
|
||||
|
||||
{IT_STRING | IT_CALL, NULL, "Continue", M_SelectableClearMenus,40},
|
||||
{IT_STRING | IT_CALL, NULL, "Player 1 Setup", M_SetupMultiPlayer, 48}, // splitscreen
|
||||
{IT_STRING | IT_CALL, NULL, "Player 2 Setup", M_SetupMultiPlayer2, 56}, // splitscreen
|
||||
{IT_STRING | IT_CALL, NULL, "Continue", M_SelectableClearMenus,48},
|
||||
|
||||
{IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48},
|
||||
{IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48},
|
||||
{IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48},
|
||||
{IT_STRING | IT_CALL, NULL, "Player Setup", M_SetupMultiPlayer, 56}, // alone
|
||||
{IT_STRING | IT_CALL, NULL, "Options", M_Options, 64},
|
||||
{IT_STRING | IT_CALL, NULL, "Player 1 Setup", M_SetupMultiPlayer, 56}, // splitscreen
|
||||
{IT_STRING | IT_CALL, NULL, "Player 2 Setup", M_SetupMultiPlayer2, 64},
|
||||
|
||||
{IT_STRING | IT_CALL, NULL, "Return to Title", M_EndGame, 80},
|
||||
{IT_STRING | IT_CALL, NULL, "Quit Game", M_QuitSRB2, 88},
|
||||
{IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 56}, // alone
|
||||
{IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 56},
|
||||
{IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 56},
|
||||
{IT_STRING | IT_CALL, NULL, "Player Setup", M_SetupMultiPlayer, 64},
|
||||
|
||||
{IT_STRING | IT_CALL, NULL, "Options", M_Options, 72},
|
||||
|
||||
{IT_STRING | IT_CALL, NULL, "Return to Title", M_EndGame, 88},
|
||||
{IT_STRING | IT_CALL, NULL, "Quit Game", M_QuitSRB2, 96},
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
mpause_addons = 0,
|
||||
mpause_scramble,
|
||||
mpause_hints,
|
||||
mpause_switchmap,
|
||||
|
||||
mpause_continue,
|
||||
|
@ -597,7 +602,7 @@ static menuitem_t SPauseMenu[] =
|
|||
// Pandora's Box will be shifted up if both options are available
|
||||
{IT_CALL | IT_STRING, NULL, "Pandora's Box...", M_PandorasBox, 16},
|
||||
{IT_CALL | IT_STRING, NULL, "Emblem Hints...", M_EmblemHints, 24},
|
||||
{IT_CALL | IT_STRING, NULL, "Level Select...", M_LoadGameLevelSelect, 32},
|
||||
{IT_CALL | IT_STRING, NULL, "Level Select...", M_PauseLevelSelect, 32},
|
||||
|
||||
{IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48},
|
||||
{IT_CALL | IT_STRING, NULL, "Retry", M_Retry, 56},
|
||||
|
@ -970,7 +975,7 @@ static menuitem_t MP_MainMenu[] =
|
|||
{
|
||||
{IT_HEADER, NULL, "Join a game", NULL, 0},
|
||||
{IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenuModChecks, 12},
|
||||
{IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 22},
|
||||
{IT_STRING|IT_KEYHANDLER, NULL, "Specify server address:", M_HandleConnectIP, 22},
|
||||
{IT_HEADER, NULL, "Host a game", NULL, 54},
|
||||
{IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 66},
|
||||
{IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 76},
|
||||
|
@ -1824,6 +1829,10 @@ menu_t SP_LevelSelectDef = MAPPLATTERMENUSTYLE(
|
|||
MTREE4(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER, MN_SP_LEVELSELECT),
|
||||
NULL, SP_LevelSelectMenu);
|
||||
|
||||
menu_t SP_PauseLevelSelectDef = MAPPLATTERMENUSTYLE(
|
||||
MTREE4(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER, MN_SP_LEVELSELECT),
|
||||
NULL, SP_LevelSelectMenu);
|
||||
|
||||
menu_t SP_LevelStatsDef =
|
||||
{
|
||||
MTREE2(MN_SP_MAIN, MN_SP_LEVELSTATS),
|
||||
|
@ -2284,6 +2293,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt);
|
|||
// Nextmap. Used for Level select.
|
||||
void Nextmap_OnChange(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
char *leveltitle;
|
||||
char tabase[256];
|
||||
#ifdef OLDNREPLAYNAME
|
||||
|
@ -2301,7 +2311,7 @@ void Nextmap_OnChange(void)
|
|||
{
|
||||
CV_StealthSetValue(&cv_dummymares, 0);
|
||||
// Hide the record changing CVAR if only one mare is available.
|
||||
if (!nightsrecords[cv_nextmap.value-1] || nightsrecords[cv_nextmap.value-1]->nummares < 2)
|
||||
if (!data->nightsrecords[cv_nextmap.value-1] || data->nightsrecords[cv_nextmap.value-1]->nummares < 2)
|
||||
SP_NightsAttackMenu[narecords].status = IT_DISABLED;
|
||||
else
|
||||
SP_NightsAttackMenu[narecords].status = IT_STRING|IT_CVAR;
|
||||
|
@ -2432,14 +2442,15 @@ void Nextmap_OnChange(void)
|
|||
|
||||
static void Dummymares_OnChange(void)
|
||||
{
|
||||
if (!nightsrecords[cv_nextmap.value-1])
|
||||
gamedata_t *data = clientGamedata;
|
||||
if (!data->nightsrecords[cv_nextmap.value-1])
|
||||
{
|
||||
CV_StealthSetValue(&cv_dummymares, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 mares = nightsrecords[cv_nextmap.value-1]->nummares;
|
||||
UINT8 mares = data->nightsrecords[cv_nextmap.value-1]->nummares;
|
||||
|
||||
if (cv_dummymares.value < 0)
|
||||
CV_StealthSetValue(&cv_dummymares, mares);
|
||||
|
@ -3670,9 +3681,9 @@ void M_StartControlPanel(void)
|
|||
if (!Playing())
|
||||
{
|
||||
// Secret menu!
|
||||
MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked()) ? 76 : 84;
|
||||
MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked()) ? 84 : 92;
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked(clientGamedata)) ? 76 : 84;
|
||||
MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked(clientGamedata)) ? 84 : 92;
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked(clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
currentMenu = &MainDef;
|
||||
itemOn = singleplr;
|
||||
|
@ -3680,14 +3691,14 @@ void M_StartControlPanel(void)
|
|||
else if (modeattacking)
|
||||
{
|
||||
currentMenu = &MAPauseDef;
|
||||
MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
itemOn = mapause_continue;
|
||||
}
|
||||
else if (!(netgame || multiplayer)) // Single Player
|
||||
{
|
||||
if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff.
|
||||
{
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_GRAYEDOUT) : (IT_DISABLED);
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata)) ? (IT_GRAYEDOUT) : (IT_DISABLED);
|
||||
SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
|
||||
}
|
||||
else
|
||||
|
@ -3696,7 +3707,7 @@ void M_StartControlPanel(void)
|
|||
if (players[consoleplayer].playerstate != PST_LIVE)
|
||||
++numlives;
|
||||
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
// The list of things that can disable retrying is (was?) a little too complex
|
||||
// for me to want to use the short if statement syntax
|
||||
|
@ -3707,10 +3718,10 @@ void M_StartControlPanel(void)
|
|||
}
|
||||
|
||||
// We can always use level select though. :33
|
||||
SPauseMenu[spause_levelselect].status = (gamecomplete == 1) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
SPauseMenu[spause_levelselect].status = (maplistoption != 0) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
// And emblem hints.
|
||||
SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
// Shift up Pandora's Box if both pandora and levelselect are active
|
||||
/*if (SPauseMenu[spause_pandora].status != (IT_DISABLED)
|
||||
|
@ -3745,12 +3756,10 @@ void M_StartControlPanel(void)
|
|||
if (splitscreen)
|
||||
{
|
||||
MPauseMenu[mpause_psetupsplit].status = MPauseMenu[mpause_psetupsplit2].status = IT_STRING | IT_CALL;
|
||||
MPauseMenu[mpause_psetup].text = "Player 1 Setup";
|
||||
}
|
||||
else
|
||||
{
|
||||
MPauseMenu[mpause_psetup].status = IT_STRING | IT_CALL;
|
||||
MPauseMenu[mpause_psetup].text = "Player Setup";
|
||||
|
||||
if (G_GametypeHasTeams())
|
||||
MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU;
|
||||
|
@ -3760,6 +3769,8 @@ void M_StartControlPanel(void)
|
|||
MPauseMenu[mpause_spectate].status = IT_GRAYEDOUT;
|
||||
}
|
||||
|
||||
MPauseMenu[mpause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && G_CoopGametype()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
currentMenu = &MPauseDef;
|
||||
itemOn = mpause_continue;
|
||||
}
|
||||
|
@ -4259,7 +4270,7 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y, boolean norecordatt
|
|||
x -= 4;
|
||||
lasttype = curtype;
|
||||
|
||||
if (emblem->collected)
|
||||
if (clientGamedata->collected[emblem - emblemlocations])
|
||||
V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE));
|
||||
else
|
||||
|
@ -4692,7 +4703,9 @@ static void M_DrawGenericScrollMenu(void)
|
|||
|
||||
static void M_DrawPauseMenu(void)
|
||||
{
|
||||
if (!netgame && !multiplayer && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
|
||||
gamedata_t *data = clientGamedata;
|
||||
|
||||
if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)
|
||||
{
|
||||
emblem_t *emblem_detail[3] = {NULL, NULL, NULL};
|
||||
char emblem_text[3][20];
|
||||
|
@ -4720,7 +4733,7 @@ static void M_DrawPauseMenu(void)
|
|||
{
|
||||
case ET_SCORE:
|
||||
snprintf(targettext, 9, "%d", emblem->var);
|
||||
snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap, data));
|
||||
|
||||
targettext[8] = 0;
|
||||
currenttext[8] = 0;
|
||||
|
@ -4734,7 +4747,7 @@ static void M_DrawPauseMenu(void)
|
|||
G_TicsToSeconds((tic_t)emblemslot),
|
||||
G_TicsToCentiseconds((tic_t)emblemslot));
|
||||
|
||||
emblemslot = (INT32)G_GetBestTime(gamemap); // dumb hack pt ii
|
||||
emblemslot = (INT32)G_GetBestTime(gamemap, data); // dumb hack pt ii
|
||||
if ((tic_t)emblemslot == UINT32_MAX)
|
||||
snprintf(currenttext, 9, "-:--.--");
|
||||
else
|
||||
|
@ -4750,7 +4763,7 @@ static void M_DrawPauseMenu(void)
|
|||
break;
|
||||
case ET_RINGS:
|
||||
snprintf(targettext, 9, "%d", emblem->var);
|
||||
snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap, data));
|
||||
|
||||
targettext[8] = 0;
|
||||
currenttext[8] = 0;
|
||||
|
@ -4758,8 +4771,8 @@ static void M_DrawPauseMenu(void)
|
|||
emblemslot = 2;
|
||||
break;
|
||||
case ET_NGRADE:
|
||||
snprintf(targettext, 9, "%u", P_GetScoreForGradeOverall(gamemap, emblem->var));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0));
|
||||
snprintf(targettext, 9, "%u", P_GetScoreForGrade(gamemap, 0, emblem->var));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0, data));
|
||||
|
||||
targettext[8] = 0;
|
||||
currenttext[8] = 0;
|
||||
|
@ -4773,7 +4786,7 @@ static void M_DrawPauseMenu(void)
|
|||
G_TicsToSeconds((tic_t)emblemslot),
|
||||
G_TicsToCentiseconds((tic_t)emblemslot));
|
||||
|
||||
emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0); // dumb hack pt iv
|
||||
emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0, data); // dumb hack pt iv
|
||||
if ((tic_t)emblemslot == UINT32_MAX)
|
||||
snprintf(currenttext, 9, "-:--.--");
|
||||
else
|
||||
|
@ -4807,7 +4820,7 @@ static void M_DrawPauseMenu(void)
|
|||
if (!emblem)
|
||||
continue;
|
||||
|
||||
if (emblem->collected)
|
||||
if (data->collected[emblem - emblemlocations])
|
||||
V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE));
|
||||
else
|
||||
|
@ -5019,7 +5032,9 @@ static void M_PatchSkinNameTable(void)
|
|||
//
|
||||
static boolean M_LevelAvailableOnPlatter(INT32 mapnum)
|
||||
{
|
||||
if (M_MapLocked(mapnum+1))
|
||||
gamedata_t *data = serverGamedata;
|
||||
|
||||
if (M_MapLocked(mapnum+1, data))
|
||||
return false; // not unlocked
|
||||
|
||||
switch (levellistmode)
|
||||
|
@ -5032,7 +5047,7 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum)
|
|||
return true;
|
||||
|
||||
#ifndef DEVELOP
|
||||
if (mapvisited[mapnum]) // MV_MP
|
||||
if (data->mapvisited[mapnum])
|
||||
#endif
|
||||
return true;
|
||||
|
||||
|
@ -5040,7 +5055,7 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum)
|
|||
case LLM_RECORDATTACK:
|
||||
case LLM_NIGHTSATTACK:
|
||||
#ifndef DEVELOP
|
||||
if (mapvisited[mapnum] & MV_MAX)
|
||||
if (data->mapvisited[mapnum])
|
||||
return true;
|
||||
|
||||
if (mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED)
|
||||
|
@ -5071,7 +5086,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt)
|
|||
if (!mapheaderinfo[mapnum]->lvlttl[0])
|
||||
return false;
|
||||
|
||||
/*if (M_MapLocked(mapnum+1))
|
||||
/*if (M_MapLocked(mapnum+1, serverGamedata))
|
||||
return false; // not unlocked*/
|
||||
|
||||
switch (levellistmode)
|
||||
|
@ -5966,7 +5981,7 @@ static void M_DrawLevelPlatterMenu(void)
|
|||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
|
||||
else if (!curbghide || !titlemapinaction)
|
||||
{
|
||||
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
|
||||
F_SkyScroll(curbgname);
|
||||
// Draw and animate foreground
|
||||
if (!strncmp("RECATKBG", curbgname, 8))
|
||||
M_DrawRecordAttackForeground();
|
||||
|
@ -6228,7 +6243,7 @@ static void M_DrawMessageMenu(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
|
||||
F_SkyScroll(curbgname);
|
||||
if (!strncmp("RECATKBG", curbgname, 8))
|
||||
M_DrawRecordAttackForeground();
|
||||
}
|
||||
|
@ -6904,7 +6919,7 @@ static void M_HandleAddons(INT32 choice)
|
|||
closefilemenu(true);
|
||||
|
||||
// secrets disabled by addfile...
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked(clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
if (currentMenu->prevMenu)
|
||||
M_SetupNextMenu(currentMenu->prevMenu);
|
||||
|
@ -7118,6 +7133,7 @@ static void M_DestroyRobots(INT32 choice)
|
|||
static void M_LevelSelectWarp(INT32 choice)
|
||||
{
|
||||
boolean fromloadgame = (currentMenu == &SP_LevelSelectDef);
|
||||
boolean frompause = (currentMenu == &SP_PauseLevelSelectDef);
|
||||
|
||||
(void)choice;
|
||||
|
||||
|
@ -7128,7 +7144,6 @@ static void M_LevelSelectWarp(INT32 choice)
|
|||
}
|
||||
|
||||
startmap = (INT16)(cv_nextmap.value);
|
||||
|
||||
fromlevelselect = true;
|
||||
|
||||
if (fromloadgame)
|
||||
|
@ -7136,7 +7151,20 @@ static void M_LevelSelectWarp(INT32 choice)
|
|||
else
|
||||
{
|
||||
cursaveslot = 0;
|
||||
M_SetupChoosePlayer(0);
|
||||
|
||||
if (frompause)
|
||||
{
|
||||
M_ClearMenus(true);
|
||||
|
||||
G_DeferedInitNew(false, G_BuildMapName(startmap), cv_skin.value, false, fromlevelselect); // Not sure about using cv_skin here, but it seems fine in testing.
|
||||
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
|
||||
|
||||
if (levelselect.rows)
|
||||
Z_Free(levelselect.rows);
|
||||
levelselect.rows = NULL;
|
||||
}
|
||||
else
|
||||
M_SetupChoosePlayer(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7150,7 +7178,9 @@ static boolean checklist_cangodown; // uuuueeerggghhhh HACK
|
|||
|
||||
static void M_HandleChecklist(INT32 choice)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 j;
|
||||
|
||||
switch (choice)
|
||||
{
|
||||
case KEY_DOWNARROW:
|
||||
|
@ -7167,7 +7197,7 @@ static void M_HandleChecklist(INT32 choice)
|
|||
continue;
|
||||
if (unlockables[j].conditionset > MAXCONDITIONSETS)
|
||||
continue;
|
||||
if (!unlockables[j].unlocked && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset))
|
||||
if (!data->unlocked[j] && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset, data))
|
||||
continue;
|
||||
if (unlockables[j].conditionset == unlockables[check_on].conditionset)
|
||||
continue;
|
||||
|
@ -7192,7 +7222,7 @@ static void M_HandleChecklist(INT32 choice)
|
|||
continue;
|
||||
if (unlockables[j].conditionset > MAXCONDITIONSETS)
|
||||
continue;
|
||||
if (!unlockables[j].unlocked && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset))
|
||||
if (!data->unlocked[j] && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset, data))
|
||||
continue;
|
||||
if (j && unlockables[j].conditionset == unlockables[j-1].conditionset)
|
||||
continue;
|
||||
|
@ -7218,6 +7248,9 @@ static void M_HandleChecklist(INT32 choice)
|
|||
|
||||
static void M_DrawChecklist(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 emblemCount = M_CountEmblems(data);
|
||||
|
||||
INT32 i = check_on, j = 0, y = currentMenu->y, emblems = numemblems+numextraemblems;
|
||||
UINT32 condnum, previd, maxcond;
|
||||
condition_t *cond;
|
||||
|
@ -7228,7 +7261,7 @@ static void M_DrawChecklist(void)
|
|||
// draw emblem counter
|
||||
if (emblems > 0)
|
||||
{
|
||||
V_DrawString(42, 20, (emblems == M_CountEmblems()) ? V_GREENMAP : 0, va("%d/%d", M_CountEmblems(), emblems));
|
||||
V_DrawString(42, 20, (emblems == emblemCount) ? V_GREENMAP : 0, va("%d/%d", emblemCount, emblems));
|
||||
V_DrawSmallScaledPatch(28, 20, 0, W_CachePatchName("EMBLICON", PU_PATCH));
|
||||
}
|
||||
|
||||
|
@ -7239,13 +7272,13 @@ static void M_DrawChecklist(void)
|
|||
{
|
||||
if (unlockables[i].name[0] == 0 //|| unlockables[i].nochecklist
|
||||
|| !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS
|
||||
|| (!unlockables[i].unlocked && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset)))
|
||||
|| (!data->unlocked[i] && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset, data)))
|
||||
{
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name)));
|
||||
V_DrawString(currentMenu->x, y, ((data->unlocked[i]) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((data->unlocked[i] || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name)));
|
||||
|
||||
for (j = i+1; j < MAXUNLOCKABLES; j++)
|
||||
{
|
||||
|
@ -7323,7 +7356,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
if (title)
|
||||
{
|
||||
const char *level = ((M_MapLocked(cond[condnum].requirement) || !((mapheaderinfo[cond[condnum].requirement-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].requirement-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
const char *level = ((M_MapLocked(cond[condnum].requirement, data) || !((mapheaderinfo[cond[condnum].requirement-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].requirement-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
|
||||
switch (cond[condnum].type)
|
||||
{
|
||||
|
@ -7356,7 +7389,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
if (title)
|
||||
{
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1, data) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
|
||||
switch (cond[condnum].type)
|
||||
{
|
||||
|
@ -7425,7 +7458,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
if (title)
|
||||
{
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1, data) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
|
||||
switch (cond[condnum].type)
|
||||
{
|
||||
|
@ -7488,7 +7521,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
/*V_DrawString(160, 8+(24*j), V_RETURN8, V_WordWrap(160, 292, 0, unlockables[i].objective));
|
||||
|
||||
if (unlockables[i].unlocked)
|
||||
if (data->unlocked[i])
|
||||
V_DrawString(308, 8+(24*j), V_YELLOWMAP, "Y");
|
||||
else
|
||||
V_DrawString(308, 8+(24*j), V_YELLOWMAP, "N");*/
|
||||
|
@ -7517,7 +7550,7 @@ static void M_EmblemHints(INT32 choice)
|
|||
|
||||
(void)choice;
|
||||
SR_EmblemHintMenu[0].status = (local > NUMHINTS*2) ? (IT_STRING | IT_ARROWS) : (IT_DISABLED);
|
||||
SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER)) ? (IT_CVAR|IT_STRING) : (IT_SECRET);
|
||||
SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata)) ? (IT_CVAR|IT_STRING) : (IT_SECRET);
|
||||
hintpage = 1;
|
||||
SR_EmblemHintDef.prevMenu = currentMenu;
|
||||
M_SetupNextMenu(&SR_EmblemHintDef);
|
||||
|
@ -7577,7 +7610,7 @@ static void M_DrawEmblemHints(void)
|
|||
|
||||
if (totalemblems >= ((hintpage-1)*(NUMHINTS*2) + 1) && totalemblems < (hintpage*NUMHINTS*2)+1){
|
||||
|
||||
if (emblem->collected)
|
||||
if (clientGamedata->collected[i])
|
||||
{
|
||||
collected = V_GREENMAP;
|
||||
V_DrawMappedPatch(x, y+4, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
|
||||
|
@ -7647,6 +7680,26 @@ static void M_HandleEmblemHints(INT32 choice)
|
|||
|
||||
}
|
||||
|
||||
static void M_PauseLevelSelect(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
|
||||
SP_PauseLevelSelectDef.prevMenu = currentMenu;
|
||||
levellistmode = LLM_LEVELSELECT;
|
||||
|
||||
// maplistoption is NOT specified, so that this
|
||||
// transfers the level select list from the menu
|
||||
// used to enter the game to the pause menu.
|
||||
|
||||
if (!M_PrepareLevelPlatter(-1, true))
|
||||
{
|
||||
M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
|
||||
return;
|
||||
}
|
||||
|
||||
M_SetupNextMenu(&SP_PauseLevelSelectDef);
|
||||
}
|
||||
|
||||
/*static void M_DrawSkyRoom(void)
|
||||
{
|
||||
INT32 i, y = 0;
|
||||
|
@ -8117,7 +8170,7 @@ static void M_SecretsMenu(INT32 choice)
|
|||
|
||||
SR_MainMenu[i].status = IT_SECRET;
|
||||
|
||||
if (unlockables[ul].unlocked)
|
||||
if (clientGamedata->unlocked[ul])
|
||||
{
|
||||
switch (unlockables[ul].type)
|
||||
{
|
||||
|
@ -8154,6 +8207,7 @@ INT32 ultimate_selectable = false;
|
|||
static void M_NewGame(void)
|
||||
{
|
||||
fromlevelselect = false;
|
||||
maplistoption = 0;
|
||||
|
||||
startmap = spstage_start;
|
||||
CV_SetValue(&cv_newgametype, GT_COOP); // Graue 09-08-2004
|
||||
|
@ -8165,6 +8219,7 @@ static void M_CustomWarp(INT32 choice)
|
|||
{
|
||||
INT32 ul = skyRoomMenuTranslations[choice-1];
|
||||
|
||||
maplistoption = 0;
|
||||
startmap = (INT16)(unlockables[ul].variable);
|
||||
|
||||
M_SetupChoosePlayer(0);
|
||||
|
@ -8216,7 +8271,7 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
|
||||
levellistmode = LLM_RECORDATTACK;
|
||||
if (M_GametypeHasLevels(-1))
|
||||
SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK, clientGamedata)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
else // If Record Attack is nonexistent in the current add-on...
|
||||
{
|
||||
SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the Record Attack option...
|
||||
|
@ -8226,7 +8281,7 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
|
||||
levellistmode = LLM_NIGHTSATTACK;
|
||||
if (M_GametypeHasLevels(-1))
|
||||
SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE, clientGamedata)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
else // If NiGHTS Mode is nonexistent in the current add-on...
|
||||
{
|
||||
SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the NiGHTS Mode option...
|
||||
|
@ -8249,7 +8304,7 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
SP_MainMenu[spnightsmode] .alphaKey += 8;
|
||||
}
|
||||
else // Otherwise, if Marathon Run is allowed and Record Attack is unlocked, unlock Marathon Run!
|
||||
SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
|
||||
SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK, clientGamedata)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
|
||||
|
||||
|
||||
if (tutorialmap) // If there's a tutorial available in the current add-on...
|
||||
|
@ -8357,6 +8412,7 @@ static void M_StartTutorial(INT32 choice)
|
|||
M_ClearMenus(true);
|
||||
gamecomplete = 0;
|
||||
cursaveslot = 0;
|
||||
maplistoption = 0;
|
||||
G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false);
|
||||
}
|
||||
|
||||
|
@ -8719,6 +8775,10 @@ static void M_LoadSelect(INT32 choice)
|
|||
{
|
||||
(void)choice;
|
||||
|
||||
// Reset here, if we want a level select
|
||||
// M_LoadGameLevelSelect will set it for us.
|
||||
maplistoption = 0;
|
||||
|
||||
if (saveSlotSelected == NOSAVESLOT) //last slot is play without saving
|
||||
{
|
||||
M_NewGame();
|
||||
|
@ -9626,7 +9686,7 @@ static void M_Statistics(INT32 choice)
|
|||
if (!(mapheaderinfo[i]->typeoflevel & TOL_SP) || (mapheaderinfo[i]->menuflags & LF2_HIDEINSTATS))
|
||||
continue;
|
||||
|
||||
if (!(mapvisited[i] & MV_MAX))
|
||||
if (!(clientGamedata->mapvisited[i] & MV_MAX))
|
||||
continue;
|
||||
|
||||
statsMapList[j++] = i;
|
||||
|
@ -9643,6 +9703,7 @@ static void M_Statistics(INT32 choice)
|
|||
|
||||
static void M_DrawStatsMaps(int location)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 y = 80, i = -1;
|
||||
INT16 mnum;
|
||||
extraemblem_t *exemblem;
|
||||
|
@ -9710,14 +9771,14 @@ static void M_DrawStatsMaps(int location)
|
|||
{
|
||||
exemblem = &extraemblems[i];
|
||||
|
||||
if (exemblem->collected)
|
||||
if (data->extraCollected[i])
|
||||
V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE));
|
||||
else
|
||||
V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_PATCH));
|
||||
|
||||
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE,
|
||||
(!exemblem->collected && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset))
|
||||
(!data->extraCollected[i] && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset, data))
|
||||
? M_CreateSecretMenuOption(exemblem->description)
|
||||
: exemblem->description);
|
||||
}
|
||||
|
@ -9734,6 +9795,7 @@ bottomarrow:
|
|||
|
||||
static void M_DrawLevelStats(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
char beststr[40];
|
||||
|
||||
tic_t besttime = 0;
|
||||
|
@ -9748,9 +9810,9 @@ static void M_DrawLevelStats(void)
|
|||
|
||||
V_DrawString(20, 24, V_YELLOWMAP, "Total Play Time:");
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 32, 0, va("%i hours, %i minutes, %i seconds",
|
||||
G_TicsToHours(totalplaytime),
|
||||
G_TicsToMinutes(totalplaytime, false),
|
||||
G_TicsToSeconds(totalplaytime)));
|
||||
G_TicsToHours(data->totalplaytime),
|
||||
G_TicsToMinutes(data->totalplaytime, false),
|
||||
G_TicsToSeconds(data->totalplaytime)));
|
||||
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
|
@ -9759,25 +9821,25 @@ static void M_DrawLevelStats(void)
|
|||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
|
||||
if (!mainrecords[i])
|
||||
if (!data->mainrecords[i])
|
||||
{
|
||||
mapsunfinished++;
|
||||
bestunfinished[0] = bestunfinished[1] = bestunfinished[2] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mainrecords[i]->score > 0)
|
||||
bestscore += mainrecords[i]->score;
|
||||
if (data->mainrecords[i]->score > 0)
|
||||
bestscore += data->mainrecords[i]->score;
|
||||
else
|
||||
mapunfinished = bestunfinished[0] = true;
|
||||
|
||||
if (mainrecords[i]->time > 0)
|
||||
besttime += mainrecords[i]->time;
|
||||
if (data->mainrecords[i]->time > 0)
|
||||
besttime += data->mainrecords[i]->time;
|
||||
else
|
||||
mapunfinished = bestunfinished[1] = true;
|
||||
|
||||
if (mainrecords[i]->rings > 0)
|
||||
bestrings += mainrecords[i]->rings;
|
||||
if (data->mainrecords[i]->rings > 0)
|
||||
bestrings += data->mainrecords[i]->rings;
|
||||
else
|
||||
mapunfinished = bestunfinished[2] = true;
|
||||
|
||||
|
@ -9792,7 +9854,7 @@ static void M_DrawLevelStats(void)
|
|||
else
|
||||
V_DrawString(20, 56, V_GREENMAP, "(complete)");
|
||||
|
||||
V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
|
||||
V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(data), numemblems+numextraemblems));
|
||||
V_DrawSmallScaledPatch(20, 64, 0, W_CachePatchName("EMBLICON", PU_PATCH));
|
||||
|
||||
sprintf(beststr, "%u", bestscore);
|
||||
|
@ -9859,6 +9921,7 @@ static void M_HandleLevelStats(INT32 choice)
|
|||
// Drawing function for Time Attack
|
||||
void M_DrawTimeAttackMenu(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 i, x, y, empatx, empaty, cursory = 0;
|
||||
UINT16 dispstatus;
|
||||
patch_t *PictureOfUrFace; // my WHAT
|
||||
|
@ -9875,7 +9938,7 @@ void M_DrawTimeAttackMenu(void)
|
|||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
|
||||
else if (!curbghide || !titlemapinaction)
|
||||
{
|
||||
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
|
||||
F_SkyScroll(curbgname);
|
||||
// Draw and animate foreground
|
||||
if (!strncmp("RECATKBG", curbgname, 8))
|
||||
M_DrawRecordAttackForeground();
|
||||
|
@ -10017,7 +10080,7 @@ void M_DrawTimeAttackMenu(void)
|
|||
empatx = empatch->leftoffset / 2;
|
||||
empaty = empatch->topoffset / 2;
|
||||
|
||||
if (em->collected)
|
||||
if (data->collected[em - emblemlocations])
|
||||
V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch,
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE));
|
||||
else
|
||||
|
@ -10030,34 +10093,34 @@ void M_DrawTimeAttackMenu(void)
|
|||
// Draw in-level emblems.
|
||||
M_DrawMapEmblems(cv_nextmap.value, 288, 28, true);
|
||||
|
||||
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->score)
|
||||
if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->score)
|
||||
sprintf(beststr, "(none)");
|
||||
else
|
||||
sprintf(beststr, "%u", mainrecords[cv_nextmap.value-1]->score);
|
||||
sprintf(beststr, "%u", data->mainrecords[cv_nextmap.value-1]->score);
|
||||
|
||||
V_DrawString(104-72, 33+lsheadingheight/2, V_YELLOWMAP, "SCORE:");
|
||||
V_DrawRightAlignedString(104+64, 33+lsheadingheight/2, V_ALLOWLOWERCASE, beststr);
|
||||
V_DrawRightAlignedString(104+72, 43+lsheadingheight/2, V_ALLOWLOWERCASE, reqscore);
|
||||
|
||||
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time)
|
||||
if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->time)
|
||||
sprintf(beststr, "(none)");
|
||||
else
|
||||
sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->time, true),
|
||||
G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time),
|
||||
G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time));
|
||||
sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(data->mainrecords[cv_nextmap.value-1]->time, true),
|
||||
G_TicsToSeconds(data->mainrecords[cv_nextmap.value-1]->time),
|
||||
G_TicsToCentiseconds(data->mainrecords[cv_nextmap.value-1]->time));
|
||||
|
||||
V_DrawString(104-72, 53+lsheadingheight/2, V_YELLOWMAP, "TIME:");
|
||||
V_DrawRightAlignedString(104+64, 53+lsheadingheight/2, V_ALLOWLOWERCASE, beststr);
|
||||
V_DrawRightAlignedString(104+72, 63+lsheadingheight/2, V_ALLOWLOWERCASE, reqtime);
|
||||
|
||||
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->rings)
|
||||
if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->rings)
|
||||
sprintf(beststr, "(none)");
|
||||
else
|
||||
sprintf(beststr, "%hu", mainrecords[cv_nextmap.value-1]->rings);
|
||||
sprintf(beststr, "%hu", data->mainrecords[cv_nextmap.value-1]->rings);
|
||||
|
||||
V_DrawString(104-72, 73+lsheadingheight/2, V_YELLOWMAP, "RINGS:");
|
||||
|
||||
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((mapvisited[cv_nextmap.value-1] & MV_PERFECTRA) ? V_YELLOWMAP : 0), beststr);
|
||||
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((data->mapvisited[cv_nextmap.value-1] & MV_PERFECTRA) ? V_YELLOWMAP : 0), beststr);
|
||||
|
||||
V_DrawRightAlignedString(104+72, 83+lsheadingheight/2, V_ALLOWLOWERCASE, reqrings);
|
||||
}
|
||||
|
@ -10151,6 +10214,7 @@ static void M_TimeAttack(INT32 choice)
|
|||
// Drawing function for Nights Attack
|
||||
void M_DrawNightsAttackMenu(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 i, x, y, cursory = 0;
|
||||
UINT16 dispstatus;
|
||||
|
||||
|
@ -10217,10 +10281,10 @@ void M_DrawNightsAttackMenu(void)
|
|||
lumpnum_t lumpnum;
|
||||
char beststr[40];
|
||||
|
||||
//UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0);
|
||||
UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value);
|
||||
UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value);
|
||||
tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value);
|
||||
//UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0, data);
|
||||
UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value, data);
|
||||
UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value, data);
|
||||
tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value, data);
|
||||
|
||||
M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false);
|
||||
|
||||
|
@ -10301,7 +10365,7 @@ void M_DrawNightsAttackMenu(void)
|
|||
goto skipThisOne;
|
||||
}
|
||||
|
||||
if (em->collected)
|
||||
if (data->collected[em - emblemlocations])
|
||||
V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE));
|
||||
else
|
||||
|
@ -10655,6 +10719,7 @@ static void M_Marathon(INT32 choice)
|
|||
}
|
||||
|
||||
fromlevelselect = false;
|
||||
maplistoption = 0;
|
||||
|
||||
startmap = spmarathon_start;
|
||||
CV_SetValue(&cv_newgametype, GT_COOP); // Graue 09-08-2004
|
||||
|
@ -11673,35 +11738,19 @@ static void M_StartServerMenu(INT32 choice)
|
|||
|
||||
#define CONNIP_LEN 128
|
||||
static char setupm_ip[CONNIP_LEN];
|
||||
|
||||
#define DOTS "... "
|
||||
|
||||
// Draw the funky Connect IP menu. Tails 11-19-2002
|
||||
// So much work for such a little thing!
|
||||
static void M_DrawMPMainMenu(void)
|
||||
static void M_DrawConnectIP(void)
|
||||
{
|
||||
INT32 x = currentMenu->x;
|
||||
INT32 y = currentMenu->y;
|
||||
INT32 y = currentMenu->y + 22;
|
||||
|
||||
const INT32 boxwidth = /*16*8 + 6*/ (BASEVIDWIDTH - 2*(x+5));
|
||||
const INT32 maxstrwidth = boxwidth - 5;
|
||||
char *drawnstr = malloc(sizeof(setupm_ip));
|
||||
char *drawnstr_orig = drawnstr;
|
||||
boolean drawthin, shorten = false;
|
||||
|
||||
// use generic drawer for cursor, items and title
|
||||
M_DrawGenericMenu();
|
||||
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66,
|
||||
((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS));
|
||||
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76,
|
||||
((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)");
|
||||
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116,
|
||||
((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)");
|
||||
|
||||
y += 22;
|
||||
|
||||
V_DrawFill(x+5, y+4+5, boxwidth, 8+6, 159);
|
||||
|
||||
strcpy(drawnstr, setupm_ip);
|
||||
|
@ -11749,6 +11798,28 @@ static void M_DrawMPMainMenu(void)
|
|||
free(drawnstr_orig);
|
||||
}
|
||||
|
||||
// Draw the funky Connect IP menu. Tails 11-19-2002
|
||||
// So much work for such a little thing!
|
||||
static void M_DrawMPMainMenu(void)
|
||||
{
|
||||
INT32 x = currentMenu->x;
|
||||
INT32 y = currentMenu->y;
|
||||
|
||||
// use generic drawer for cursor, items and title
|
||||
M_DrawGenericMenu();
|
||||
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66,
|
||||
((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS));
|
||||
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76,
|
||||
((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)");
|
||||
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116,
|
||||
((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)");
|
||||
|
||||
M_DrawConnectIP();
|
||||
}
|
||||
|
||||
#undef DOTS
|
||||
|
||||
// Tails 11-19-2002
|
||||
|
@ -11886,7 +11957,11 @@ static void M_HandleConnectIP(INT32 choice)
|
|||
break;
|
||||
|
||||
// Rudimentary number and period enforcing - also allows letters so hostnames can be used instead
|
||||
if ((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z'))
|
||||
// and square brackets for RFC 2732 IPv6 addresses
|
||||
if ((choice >= '-' && choice <= ':') ||
|
||||
(choice == '[' || choice == ']') ||
|
||||
(choice >= 'A' && choice <= 'Z') ||
|
||||
(choice >= 'a' && choice <= 'z'))
|
||||
{
|
||||
S_StartSound(NULL,sfx_menu1); // Tails
|
||||
setupm_ip[l] = (char)choice;
|
||||
|
@ -12544,12 +12619,12 @@ static void M_EraseDataResponse(INT32 ch)
|
|||
|
||||
// Delete the data
|
||||
if (erasecontext != 1)
|
||||
G_ClearRecords();
|
||||
G_ClearRecords(clientGamedata);
|
||||
if (erasecontext != 0)
|
||||
M_ClearSecrets();
|
||||
M_ClearSecrets(clientGamedata);
|
||||
if (erasecontext == 2)
|
||||
{
|
||||
totalplaytime = 0;
|
||||
clientGamedata->totalplaytime = 0;
|
||||
F_StartIntro();
|
||||
}
|
||||
BwehHehHe();
|
||||
|
|
|
@ -14,12 +14,11 @@
|
|||
|
||||
#include "doomdef.h"
|
||||
#include "doomtype.h"
|
||||
#include "doomstat.h" // totalplaytime
|
||||
|
||||
#include "m_random.h"
|
||||
#include "m_fixed.h"
|
||||
|
||||
|
||||
#include "m_cond.h" // totalplaytime
|
||||
|
||||
// ---------------------------
|
||||
// RNG functions (not synched)
|
||||
|
@ -252,5 +251,5 @@ void P_SetRandSeedD(const char *rfile, INT32 rline, UINT32 seed)
|
|||
*/
|
||||
UINT32 M_RandomizedSeed(void)
|
||||
{
|
||||
return ((totalplaytime & 0xFFFF) << 16)|M_RandomFixed();
|
||||
return ((serverGamedata->totalplaytime & 0xFFFF) << 16) | M_RandomFixed();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef union
|
|||
typedef struct
|
||||
{
|
||||
msg_header_t header;
|
||||
char ip[16];
|
||||
char ip[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
|
||||
char port[8];
|
||||
char name[32];
|
||||
INT32 room;
|
||||
|
|
127
src/p_inter.c
127
src/p_inter.c
|
@ -164,6 +164,62 @@ boolean P_CanPickupItem(player_t *player, boolean weapon)
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean P_CanPickupEmblem(player_t *player, INT32 emblemID)
|
||||
{
|
||||
emblem_t *emblem = NULL;
|
||||
|
||||
if (emblemID < 0 || emblemID >= numemblems)
|
||||
{
|
||||
// Invalid emblem ID, can't pickup.
|
||||
return false;
|
||||
}
|
||||
|
||||
emblem = &emblemlocations[emblemID];
|
||||
|
||||
if (demoplayback)
|
||||
{
|
||||
// Never collect emblems in replays.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->bot && player->bot != BOT_MPAI)
|
||||
{
|
||||
// Your little lap-dog can't grab these for you.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (emblem->type == ET_SKIN)
|
||||
{
|
||||
INT32 skinnum = M_EmblemSkinNum(emblem);
|
||||
|
||||
if (player->skin != skinnum)
|
||||
{
|
||||
// Incorrect skin to pick up this emblem.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean P_EmblemWasCollected(INT32 emblemID)
|
||||
{
|
||||
if (emblemID < 0 || emblemID >= numemblems)
|
||||
{
|
||||
// Invalid emblem ID, can't pickup.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shareEmblems && !serverGamedata->collected[emblemID])
|
||||
{
|
||||
// It can be worth collecting again if we're sharing emblems
|
||||
// and the server doesn't have it.
|
||||
return false;
|
||||
}
|
||||
|
||||
return clientGamedata->collected[emblemID];
|
||||
}
|
||||
|
||||
//
|
||||
// P_DoNightsScore
|
||||
//
|
||||
|
@ -563,7 +619,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
special->momx = special->momy = special->momz = 0;
|
||||
P_GivePlayerSpheres(player, 1);
|
||||
|
||||
if (special->type == MT_BLUESPHERE)
|
||||
if (special->type == MT_BLUESPHERE || special->type == MT_FLINGBLUESPHERE)
|
||||
{
|
||||
special->destscale = ((player->powers[pw_carry] == CR_NIGHTSMODE) ? 4 : 2)*special->scale;
|
||||
if (states[special->info->deathstate].tics > 0)
|
||||
|
@ -738,13 +794,70 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
// Secret emblem thingy
|
||||
case MT_EMBLEM:
|
||||
{
|
||||
if (demoplayback || (player->bot && player->bot != BOT_MPAI) || special->health <= 0 || special->health > MAXEMBLEMS)
|
||||
return;
|
||||
emblemlocations[special->health-1].collected = true;
|
||||
const boolean toucherIsServer = ((player - players) == serverplayer);
|
||||
const boolean consoleIsServer = (consoleplayer == serverplayer);
|
||||
boolean prevCollected = false;
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems();
|
||||
G_SaveGameData();
|
||||
break;
|
||||
if ((special->flags2 & MF2_NIGHTSPULL)
|
||||
&& (toucher == special->tracer))
|
||||
{
|
||||
// Since collecting may not remove the object,
|
||||
// we need to manually stop it from chasing.
|
||||
P_SetTarget(&special->tracer, NULL);
|
||||
special->flags2 &= ~MF2_NIGHTSPULL;
|
||||
special->movefactor = 0;
|
||||
special->momx = special->momy = special->momz = 0;
|
||||
}
|
||||
|
||||
if (!P_CanPickupEmblem(player, special->health - 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
prevCollected = P_EmblemWasCollected(special->health - 1);
|
||||
|
||||
if (toucherIsServer || shareEmblems)
|
||||
{
|
||||
serverGamedata->collected[special->health-1] = true;
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
}
|
||||
|
||||
if (P_IsLocalPlayer(player) || (consoleIsServer && shareEmblems))
|
||||
{
|
||||
clientGamedata->collected[special->health-1] = true;
|
||||
M_UpdateUnlockablesAndExtraEmblems(clientGamedata);
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
// This always spawns the object to prevent mobjnum issues,
|
||||
// but makes the effect invisible to whoever it doesn't matter to.
|
||||
mobj_t *spark = P_SpawnMobjFromMobj(special, 0, 0, 0, MT_SPARK);
|
||||
|
||||
if (prevCollected == false && P_EmblemWasCollected(special->health - 1) == true)
|
||||
{
|
||||
// Play the sound if it was collected.
|
||||
S_StartSound((shareEmblems ? NULL : special), special->info->deathsound);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We didn't collect it, make it invisible to us.
|
||||
spark->flags2 |= MF2_DONTDRAW;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prevCollected == false && P_EmblemWasCollected(special->health - 1) == true)
|
||||
{
|
||||
// Disappear when collecting for local games.
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// CTF Flags
|
||||
|
|
|
@ -510,6 +510,8 @@ void P_ClearStarPost(INT32 postnum);
|
|||
void P_ResetStarposts(void);
|
||||
|
||||
boolean P_CanPickupItem(player_t *player, boolean weapon);
|
||||
boolean P_CanPickupEmblem(player_t *player, INT32 emblemID);
|
||||
boolean P_EmblemWasCollected(INT32 emblemID);
|
||||
void P_DoNightsScore(player_t *player);
|
||||
void P_DoMatchSuper(player_t *player);
|
||||
|
||||
|
|
436
src/p_map.c
436
src/p_map.c
|
@ -2728,8 +2728,22 @@ increment_move
|
|||
fixed_t thingtop;
|
||||
floatok = false;
|
||||
|
||||
if (radius < MAXRADIUS/2)
|
||||
radius = MAXRADIUS/2;
|
||||
// This makes sure that there are no freezes from computing extremely small movements.
|
||||
// Originally was MAXRADIUS/2, but that can cause some bad inconsistencies for small players.
|
||||
radius = max(radius, thing->scale);
|
||||
|
||||
// And we also have to prevent Big Large (tm) movements, as those can skip too far
|
||||
// across slopes and cause us to fail step up checks on them when we otherwise shouldn't.
|
||||
radius = min(radius, 16 * thing->scale);
|
||||
|
||||
// (This whole "step" system is flawed; it was OK before, but the addition of slopes has
|
||||
// exposed the problems with doing it like this. The right thing to do would be to use
|
||||
// raycasting for physics to fix colliding in weird order, double-checking collisions,
|
||||
// randomly colliding with slopes instead of going up them, etc. I don't feel like porting
|
||||
// that from RR, as its both a huge sweeping change and still incomplete at the time of
|
||||
// writing. Clamping radius to make our steps more precise will work just fine as long
|
||||
// as you keep all of your crazy intentions to poke any of the other deep-rooted movement
|
||||
// code to yourself. -- Sal 6/5/2023)
|
||||
|
||||
do {
|
||||
if (thing->flags & MF_NOCLIP) {
|
||||
|
@ -4242,13 +4256,11 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 dama
|
|||
// the way it was and call P_CheckSector (? was P_ChangeSector - Graue) again
|
||||
// to undo the changes.
|
||||
//
|
||||
static boolean crushchange;
|
||||
static boolean nofit;
|
||||
|
||||
//
|
||||
// PIT_ChangeSector
|
||||
//
|
||||
static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
|
||||
static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush, boolean crunch)
|
||||
{
|
||||
mobj_t *killer = NULL;
|
||||
//If a thing is both pushable and vulnerable, it doesn't block the crusher because it gets killed.
|
||||
|
@ -4272,11 +4284,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
|
|||
if (thing->z + thing->height > thing->ceilingz && thing->z <= thing->ceilingz)
|
||||
{
|
||||
if (immunepushable && thing->z + thing->height > thing->subsector->sector->ceilingheight)
|
||||
{
|
||||
//Thing is a pushable and blocks the moving ceiling
|
||||
nofit = true;
|
||||
return false;
|
||||
}
|
||||
return false; //Thing is a pushable and blocks the moving ceiling
|
||||
|
||||
//Check FOFs in the sector
|
||||
if (thing->subsector->sector->ffloors && (realcrush || immunepushable))
|
||||
|
@ -4288,47 +4296,54 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
|
|||
|
||||
for (rover = thing->subsector->sector->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
if (!(((rover->fofflags & FOF_BLOCKPLAYER) && thing->player)
|
||||
|| ((rover->fofflags & FOF_BLOCKOTHERS) && !thing->player)) || !(rover->fofflags & FOF_EXISTS))
|
||||
thinker_t *think;
|
||||
|
||||
if (!(rover->fofflags & FOF_EXISTS))
|
||||
continue;
|
||||
if (thing->player && !(rover->fofflags & FOF_BLOCKPLAYER))
|
||||
continue;
|
||||
if (!thing->player && !(rover->fofflags & FOF_BLOCKOTHERS))
|
||||
continue;
|
||||
|
||||
topheight = *rover->topheight;
|
||||
bottomheight = *rover->bottomheight;
|
||||
//topheight = P_GetFFloorTopZAt (rover, thing->x, thing->y);
|
||||
//bottomheight = P_GetFFloorBottomZAt(rover, thing->x, thing->y);
|
||||
|
||||
if (bottomheight > thing->ceilingz)
|
||||
continue;
|
||||
|
||||
delta1 = thing->z - (bottomheight + topheight)/2;
|
||||
delta2 = thingtop - (bottomheight + topheight)/2;
|
||||
if (bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2))
|
||||
if (abs(delta1) < abs(delta2))
|
||||
continue;
|
||||
|
||||
if (immunepushable)
|
||||
return false; //FOF is blocked by pushable
|
||||
|
||||
if (!realcrush)
|
||||
continue;
|
||||
|
||||
//If the thing was crushed by a crumbling FOF, reward the player who made it crumble!
|
||||
for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
|
||||
{
|
||||
if (immunepushable)
|
||||
{
|
||||
//FOF is blocked by pushable
|
||||
nofit = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the thing was crushed by a crumbling FOF, reward the player who made it crumble!
|
||||
thinker_t *think;
|
||||
crumble_t *crumbler;
|
||||
crumble_t *crumbler;
|
||||
|
||||
for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 != (actionf_p1)T_StartCrumble)
|
||||
continue;
|
||||
if (think->function.acp1 != (actionf_p1)T_StartCrumble)
|
||||
continue;
|
||||
|
||||
crumbler = (crumble_t *)think;
|
||||
crumbler = (crumble_t *)think;
|
||||
|
||||
if (crumbler->player && crumbler->player->mo
|
||||
&& crumbler->player->mo != thing
|
||||
&& crumbler->actionsector == thing->subsector->sector
|
||||
&& crumbler->sector == rover->master->frontsector)
|
||||
{
|
||||
killer = crumbler->player->mo;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!crumbler->player)
|
||||
continue;
|
||||
if (!crumbler->player->mo)
|
||||
continue;
|
||||
if (crumbler->player->mo == thing)
|
||||
continue;
|
||||
if (crumbler->actionsector != thing->subsector->sector)
|
||||
continue;
|
||||
if (crumbler->sector != rover->master->frontsector)
|
||||
continue;
|
||||
|
||||
killer = crumbler->player->mo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4344,24 +4359,139 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
|
|||
}
|
||||
}
|
||||
|
||||
if (realcrush && crushchange)
|
||||
if (realcrush && crunch)
|
||||
P_DamageMobj(thing, NULL, NULL, 1, 0);
|
||||
|
||||
// keep checking (crush other things)
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean P_CheckSectorPolyObjects(sector_t *sector, boolean realcrush, boolean crunch)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
// Sal: This stupid function chain is required to fix polyobjects not being able to crush.
|
||||
// Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead
|
||||
validcount++;
|
||||
|
||||
for (i = 0; i < sector->linecount; i++)
|
||||
{
|
||||
INT32 x, y;
|
||||
polyobj_t *po = sector->lines[i]->polyobj;
|
||||
|
||||
if (!po)
|
||||
continue;
|
||||
if (po->validcount == validcount)
|
||||
continue; // skip if already checked
|
||||
if (!(po->flags & POF_SOLID))
|
||||
continue;
|
||||
if (po->lines[0]->backsector != sector) // Make sure you're currently checking the control sector
|
||||
continue;
|
||||
|
||||
po->validcount = validcount;
|
||||
|
||||
for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y)
|
||||
{
|
||||
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
|
||||
{
|
||||
mobj_t *mo;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
continue;
|
||||
|
||||
mo = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
{
|
||||
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
|
||||
|
||||
if (!P_MobjInsidePolyobj(po, mo))
|
||||
continue;
|
||||
|
||||
if (!PIT_ChangeSector(mo, realcrush, crunch) && !realcrush)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean P_CheckTouchingThinglist(sector_t *sector, boolean realcrush, boolean crunch)
|
||||
{
|
||||
msecnode_t *n;
|
||||
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
|
||||
{
|
||||
if (n->visited)
|
||||
continue;
|
||||
|
||||
n->visited = true; // mark thing as processed
|
||||
|
||||
if (n->m_thing->flags & MF_NOBLOCKMAP) //jff 4/7/98 don't do these
|
||||
continue;
|
||||
|
||||
if (!PIT_ChangeSector(n->m_thing, realcrush, crunch) && !realcrush) // process it
|
||||
return false;
|
||||
|
||||
break; // exit and start over
|
||||
}
|
||||
} while (n); // repeat from scratch until all things left are marked valid
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean P_CheckSectorFFloors(sector_t *sector, boolean realcrush, boolean crunch)
|
||||
{
|
||||
sector_t *sec;
|
||||
size_t i;
|
||||
|
||||
if (!sector->numattached)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < sector->numattached; i++)
|
||||
{
|
||||
sec = §ors[sector->attached[i]];
|
||||
|
||||
sec->moved = true;
|
||||
|
||||
P_RecalcPrecipInSector(sec);
|
||||
|
||||
if (!sector->attachedsolid[i])
|
||||
continue;
|
||||
|
||||
if (!P_CheckTouchingThinglist(sec, realcrush, crunch))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean P_CheckSectorHelper(sector_t *sector, boolean realcrush, boolean crunch)
|
||||
{
|
||||
if (!P_CheckSectorPolyObjects(sector, realcrush, crunch))
|
||||
return false;
|
||||
|
||||
if (!P_CheckSectorFFloors(sector, realcrush, crunch))
|
||||
return false;
|
||||
|
||||
// Mark all things invalid
|
||||
sector->moved = true;
|
||||
|
||||
return P_CheckTouchingThinglist(sector, realcrush, crunch);
|
||||
}
|
||||
|
||||
//
|
||||
// P_CheckSector
|
||||
//
|
||||
boolean P_CheckSector(sector_t *sector, boolean crunch)
|
||||
{
|
||||
msecnode_t *n;
|
||||
size_t i;
|
||||
|
||||
nofit = false;
|
||||
crushchange = crunch;
|
||||
|
||||
// killough 4/4/98: scan list front-to-back until empty or exhausted,
|
||||
// restarting from beginning after each thing is processed. Avoids
|
||||
// crashes, and is sure to examine all things in the sector, and only
|
||||
|
@ -4370,218 +4500,14 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
//
|
||||
// killough 4/7/98: simplified to avoid using complicated counter
|
||||
|
||||
|
||||
// First, let's see if anything will keep it from crushing.
|
||||
|
||||
// Sal: This stupid function chain is required to fix polyobjects not being able to crush.
|
||||
// Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead
|
||||
validcount++;
|
||||
|
||||
for (i = 0; i < sector->linecount; i++)
|
||||
{
|
||||
if (sector->lines[i]->polyobj)
|
||||
{
|
||||
polyobj_t *po = sector->lines[i]->polyobj;
|
||||
if (po->validcount == validcount)
|
||||
continue; // skip if already checked
|
||||
if (!(po->flags & POF_SOLID))
|
||||
continue;
|
||||
if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector
|
||||
{
|
||||
INT32 x, y;
|
||||
po->validcount = validcount;
|
||||
|
||||
for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y)
|
||||
{
|
||||
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
|
||||
{
|
||||
mobj_t *mo;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
continue;
|
||||
|
||||
mo = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
{
|
||||
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
|
||||
|
||||
if (!P_MobjInsidePolyobj(po, mo))
|
||||
continue;
|
||||
|
||||
if (!PIT_ChangeSector(mo, false))
|
||||
{
|
||||
nofit = true;
|
||||
return nofit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sector->numattached)
|
||||
{
|
||||
sector_t *sec;
|
||||
for (i = 0; i < sector->numattached; i++)
|
||||
{
|
||||
sec = §ors[sector->attached[i]];
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
sec->moved = true;
|
||||
|
||||
P_RecalcPrecipInSector(sec);
|
||||
|
||||
if (!sector->attachedsolid[i])
|
||||
continue;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
if (!n->visited)
|
||||
{
|
||||
n->visited = true;
|
||||
if (!(n->m_thing->flags & MF_NOBLOCKMAP))
|
||||
{
|
||||
if (!PIT_ChangeSector(n->m_thing, false))
|
||||
{
|
||||
nofit = true;
|
||||
return nofit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (n);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark all things invalid
|
||||
sector->moved = true;
|
||||
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
|
||||
if (!n->visited) // unprocessed thing found
|
||||
{
|
||||
n->visited = true; // mark thing as processed
|
||||
if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these
|
||||
{
|
||||
if (!PIT_ChangeSector(n->m_thing, false)) // process it
|
||||
{
|
||||
nofit = true;
|
||||
return nofit;
|
||||
}
|
||||
}
|
||||
break; // exit and start over
|
||||
}
|
||||
} while (n); // repeat from scratch until all things left are marked valid
|
||||
if (!P_CheckSectorHelper(sector, false, crunch))
|
||||
return true;
|
||||
|
||||
// Nothing blocked us, so lets crush for real!
|
||||
P_CheckSectorHelper(sector, true, crunch);
|
||||
|
||||
// Sal: This stupid function chain is required to fix polyobjects not being able to crush.
|
||||
// Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead
|
||||
validcount++;
|
||||
|
||||
for (i = 0; i < sector->linecount; i++)
|
||||
{
|
||||
if (sector->lines[i]->polyobj)
|
||||
{
|
||||
polyobj_t *po = sector->lines[i]->polyobj;
|
||||
if (po->validcount == validcount)
|
||||
continue; // skip if already checked
|
||||
if (!(po->flags & POF_SOLID))
|
||||
continue;
|
||||
if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector
|
||||
{
|
||||
INT32 x, y;
|
||||
po->validcount = validcount;
|
||||
|
||||
for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y)
|
||||
{
|
||||
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
|
||||
{
|
||||
mobj_t *mo;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
continue;
|
||||
|
||||
mo = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
{
|
||||
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
|
||||
|
||||
if (!P_MobjInsidePolyobj(po, mo))
|
||||
continue;
|
||||
|
||||
PIT_ChangeSector(mo, true);
|
||||
return nofit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sector->numattached)
|
||||
{
|
||||
sector_t *sec;
|
||||
for (i = 0; i < sector->numattached; i++)
|
||||
{
|
||||
sec = §ors[sector->attached[i]];
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
sec->moved = true;
|
||||
|
||||
P_RecalcPrecipInSector(sec);
|
||||
|
||||
if (!sector->attachedsolid[i])
|
||||
continue;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
if (!n->visited)
|
||||
{
|
||||
n->visited = true;
|
||||
if (!(n->m_thing->flags & MF_NOBLOCKMAP))
|
||||
{
|
||||
PIT_ChangeSector(n->m_thing, true);
|
||||
return nofit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (n);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark all things invalid
|
||||
sector->moved = true;
|
||||
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
|
||||
if (!n->visited) // unprocessed thing found
|
||||
{
|
||||
n->visited = true; // mark thing as processed
|
||||
if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these
|
||||
{
|
||||
PIT_ChangeSector(n->m_thing, true); // process it
|
||||
return nofit;
|
||||
}
|
||||
break; // exit and start over
|
||||
}
|
||||
} while (n); // repeat from scratch until all things left are marked valid
|
||||
|
||||
return nofit;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -509,26 +509,26 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
|
|||
// on non-solid polyobjects should NEVER happen in the future
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
texbottom = back->floorheight + side->rowoffset + side->offsety_mid;
|
||||
textop = back->ceilingheight + side->rowoffset + side->offsety_mid;
|
||||
} else if (linedef->flags & ML_MIDTEX) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
texbottom = back->floorheight + side->rowoffset + side->offsety_mid;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset + side->offsety_mid;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = opentop + side->rowoffset;
|
||||
texbottom = openbottom + side->rowoffset + side->offsety_mid;
|
||||
textop = opentop + side->rowoffset + side->offsety_mid;
|
||||
} else if (linedef->flags & ML_MIDPEG) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
texbottom = openbottom + side->rowoffset + side->offsety_mid;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop + side->rowoffset;
|
||||
textop = opentop + side->rowoffset + side->offsety_mid;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
}
|
||||
|
|
51
src/p_mobj.c
51
src/p_mobj.c
|
@ -3139,7 +3139,8 @@ boolean P_SceneryZMovement(mobj_t *mo)
|
|||
|
||||
if (P_CheckDeathPitCollide(mo))
|
||||
{
|
||||
P_RemoveMobj(mo);
|
||||
if (mo->type != MT_GHOST) // ghosts play death animations instead, so don't remove them
|
||||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -9716,6 +9717,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
A_AttractChase(mobj);
|
||||
break;
|
||||
case MT_EMBLEM:
|
||||
if (P_EmblemWasCollected(mobj->health - 1) || !P_CanPickupEmblem(&players[consoleplayer], mobj->health - 1))
|
||||
mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
|
||||
else
|
||||
mobj->frame &= ~FF_TRANSMASK;
|
||||
|
||||
if (mobj->flags2 & MF2_NIGHTSPULL)
|
||||
P_NightsItemChase(mobj);
|
||||
break;
|
||||
|
@ -12005,8 +12011,8 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
|
|||
|
||||
break;
|
||||
case MT_EMBLEM:
|
||||
if (netgame || multiplayer)
|
||||
return false; // Single player (You're next on my shit list)
|
||||
if (!G_CoopGametype())
|
||||
return false; // Gametype's not right
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -12150,7 +12156,6 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
|
|||
INT32 j;
|
||||
emblem_t* emblem = M_GetLevelEmblems(gamemap);
|
||||
skincolornum_t emcolor;
|
||||
boolean validEmblem = true;
|
||||
|
||||
while (emblem)
|
||||
{
|
||||
|
@ -12175,42 +12180,19 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
|
|||
emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting
|
||||
mobj->color = (UINT16)emcolor;
|
||||
|
||||
validEmblem = !emblemlocations[j].collected;
|
||||
mobj->frame &= ~FF_TRANSMASK;
|
||||
|
||||
if (emblemlocations[j].type == ET_SKIN)
|
||||
if (emblemlocations[j].type == ET_GLOBAL)
|
||||
{
|
||||
INT32 skinnum = M_EmblemSkinNum(&emblemlocations[j]);
|
||||
|
||||
if (players[0].skin != skinnum)
|
||||
mobj->reactiontime = emblemlocations[j].var;
|
||||
if (emblemlocations[j].var & GE_NIGHTSITEM)
|
||||
{
|
||||
validEmblem = false;
|
||||
mobj->flags |= MF_NIGHTSITEM;
|
||||
mobj->flags &= ~MF_SPECIAL;
|
||||
mobj->flags2 |= MF2_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
if (validEmblem == false)
|
||||
{
|
||||
P_UnsetThingPosition(mobj);
|
||||
mobj->flags |= MF_NOCLIP;
|
||||
mobj->flags &= ~MF_SPECIAL;
|
||||
mobj->flags |= MF_NOBLOCKMAP;
|
||||
mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
|
||||
P_SetThingPosition(mobj);
|
||||
}
|
||||
else
|
||||
{
|
||||
mobj->frame &= ~FF_TRANSMASK;
|
||||
|
||||
if (emblemlocations[j].type == ET_GLOBAL)
|
||||
{
|
||||
mobj->reactiontime = emblemlocations[j].var;
|
||||
if (emblemlocations[j].var & GE_NIGHTSITEM)
|
||||
{
|
||||
mobj->flags |= MF_NIGHTSITEM;
|
||||
mobj->flags &= ~MF_SPECIAL;
|
||||
mobj->flags2 |= MF2_DONTDRAW;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13706,7 +13688,6 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime)
|
|||
UINT8 numitemtypes;
|
||||
if (!udmf)
|
||||
return;
|
||||
CONS_Printf("Itemstring: %s\n", mthing->stringargs[0]);
|
||||
P_ParseItemTypes(mthing->stringargs[0], itemtypes, &numitemtypes);
|
||||
P_SpawnItemCircle(mthing, itemtypes, numitemtypes, mthing->args[0], mthing->args[1] << FRACBITS, bonustime);
|
||||
return;
|
||||
|
|
225
src/p_saveg.c
225
src/p_saveg.c
|
@ -47,6 +47,7 @@ UINT8 *save_p;
|
|||
#define ARCHIVEBLOCK_POBJS 0x7F928546
|
||||
#define ARCHIVEBLOCK_THINKERS 0x7F37037C
|
||||
#define ARCHIVEBLOCK_SPECIALS 0x7F228378
|
||||
#define ARCHIVEBLOCK_EMBLEMS 0x7F4A5445
|
||||
|
||||
// Note: This cannot be bigger
|
||||
// than an UINT16
|
||||
|
@ -4339,6 +4340,8 @@ static void P_NetArchiveMisc(boolean resending)
|
|||
|
||||
WRITEUINT32(save_p, hidetime);
|
||||
|
||||
WRITEUINT32(save_p, unlocktriggers);
|
||||
|
||||
// Is it paused?
|
||||
if (paused)
|
||||
WRITEUINT8(save_p, 0x2f);
|
||||
|
@ -4437,6 +4440,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
|||
|
||||
hidetime = READUINT32(save_p);
|
||||
|
||||
unlocktriggers = READUINT32(save_p);
|
||||
|
||||
// Is it paused?
|
||||
if (READUINT8(save_p) == 0x2f)
|
||||
paused = true;
|
||||
|
@ -4444,6 +4449,224 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline void P_NetArchiveEmblems(void)
|
||||
{
|
||||
gamedata_t *data = serverGamedata;
|
||||
INT32 i, j;
|
||||
UINT8 btemp;
|
||||
INT32 curmare;
|
||||
|
||||
WRITEUINT32(save_p, ARCHIVEBLOCK_EMBLEMS);
|
||||
|
||||
// These should be synchronized before savegame loading by the wad files being the same anyway,
|
||||
// but just in case, for now, we'll leave them here for testing. It would be very bad if they mismatch.
|
||||
WRITEUINT8(save_p, (UINT8)savemoddata);
|
||||
WRITEINT32(save_p, numemblems);
|
||||
WRITEINT32(save_p, numextraemblems);
|
||||
|
||||
// The rest of this is lifted straight from G_SaveGameData in g_game.c
|
||||
// TODO: Optimize this to only send information about emblems, unlocks, etc. which actually exist
|
||||
// There is no need to go all the way up to MAXEMBLEMS when wads are guaranteed to be the same.
|
||||
|
||||
WRITEUINT32(save_p, data->totalplaytime);
|
||||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX));
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
btemp |= (data->collected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXEXTRAEMBLEMS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
|
||||
btemp |= (data->extraCollected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXUNLOCKABLES;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
btemp |= (data->unlocked[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXCONDITIONSETS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
btemp |= (data->achieved[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
||||
WRITEUINT32(save_p, data->timesBeaten);
|
||||
WRITEUINT32(save_p, data->timesBeatenWithEmeralds);
|
||||
WRITEUINT32(save_p, data->timesBeatenUltimate);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (data->mainrecords[i])
|
||||
{
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->score);
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->time);
|
||||
WRITEUINT16(save_p, data->mainrecords[i]->rings);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITEUINT32(save_p, 0);
|
||||
WRITEUINT32(save_p, 0);
|
||||
WRITEUINT16(save_p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// NiGHTS records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
|
||||
{
|
||||
WRITEUINT8(save_p, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->nummares);
|
||||
|
||||
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
|
||||
{
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]);
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]);
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void P_NetUnArchiveEmblems(void)
|
||||
{
|
||||
gamedata_t *data = serverGamedata;
|
||||
INT32 i, j;
|
||||
UINT8 rtemp;
|
||||
UINT32 recscore;
|
||||
tic_t rectime;
|
||||
UINT16 recrings;
|
||||
UINT8 recmares;
|
||||
INT32 curmare;
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_EMBLEMS)
|
||||
I_Error("Bad $$$.sav at archive block Emblems");
|
||||
|
||||
savemoddata = (boolean)READUINT8(save_p); // this one is actually necessary because savemoddata stays false otherwise for some reason.
|
||||
|
||||
if (numemblems != READINT32(save_p))
|
||||
I_Error("numemblems mismatch");
|
||||
if (numextraemblems != READINT32(save_p))
|
||||
I_Error("numextraemblems mismatch");
|
||||
|
||||
// This shouldn't happen, but if something really fucked up happens and you transfer
|
||||
// the SERVER player's gamedata over your own CLIENT gamedata,
|
||||
// then this prevents it from being saved over yours.
|
||||
data->loaded = false;
|
||||
|
||||
M_ClearSecrets(data);
|
||||
G_ClearRecords(data);
|
||||
|
||||
// The rest of this is lifted straight from G_LoadGameData in g_game.c
|
||||
// TODO: Optimize this to only read information about emblems, unlocks, etc. which actually exist
|
||||
// There is no need to go all the way up to MAXEMBLEMS when wads are guaranteed to be the same.
|
||||
|
||||
data->totalplaytime = READUINT32(save_p);
|
||||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX)
|
||||
I_Error("Bad $$$.sav dearchiving Emblems");
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
data->collected[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXEXTRAEMBLEMS;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
|
||||
data->extraCollected[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXUNLOCKABLES;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
data->unlocked[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXCONDITIONSETS;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
data->achieved[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
|
||||
data->timesBeaten = READUINT32(save_p);
|
||||
data->timesBeatenWithEmeralds = READUINT32(save_p);
|
||||
data->timesBeatenUltimate = READUINT32(save_p);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
recscore = READUINT32(save_p);
|
||||
rectime = (tic_t)READUINT32(save_p);
|
||||
recrings = READUINT16(save_p);
|
||||
|
||||
if (recrings > 10000 || recscore > MAXSCORE)
|
||||
I_Error("Bad $$$.sav dearchiving Emblems");
|
||||
|
||||
if (recscore || rectime || recrings)
|
||||
{
|
||||
G_AllocMainRecordData((INT16)i, data);
|
||||
data->mainrecords[i]->score = recscore;
|
||||
data->mainrecords[i]->time = rectime;
|
||||
data->mainrecords[i]->rings = recrings;
|
||||
}
|
||||
}
|
||||
|
||||
// Nights records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if ((recmares = READUINT8(save_p)) == 0)
|
||||
continue;
|
||||
|
||||
G_AllocNightsRecordData((INT16)i, data);
|
||||
|
||||
for (curmare = 0; curmare < (recmares+1); ++curmare)
|
||||
{
|
||||
data->nightsrecords[i]->score[curmare] = READUINT32(save_p);
|
||||
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p);
|
||||
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
|
||||
|
||||
if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
|
||||
{
|
||||
I_Error("Bad $$$.sav dearchiving Emblems");
|
||||
}
|
||||
}
|
||||
|
||||
data->nightsrecords[i]->nummares = recmares;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void P_ArchiveLuabanksAndConsistency(void)
|
||||
{
|
||||
UINT8 i, banksinuse = NUM_LUABANKS;
|
||||
|
@ -4507,6 +4730,7 @@ void P_SaveNetGame(boolean resending)
|
|||
|
||||
CV_SaveNetVars(&save_p);
|
||||
P_NetArchiveMisc(resending);
|
||||
P_NetArchiveEmblems();
|
||||
|
||||
// Assign the mobjnumber for pointer tracking
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
|
@ -4559,6 +4783,7 @@ boolean P_LoadNetGame(boolean reloading)
|
|||
CV_LoadNetVars(&save_p);
|
||||
if (!P_NetUnArchiveMisc(reloading))
|
||||
return false;
|
||||
P_NetUnArchiveEmblems();
|
||||
P_NetUnArchivePlayers();
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
|
|
|
@ -876,7 +876,7 @@ static void P_SpawnMapThings(boolean spawnemblems)
|
|||
size_t i;
|
||||
mapthing_t *mt;
|
||||
|
||||
// Spawn axis points first so they are at the front of the list for fast searching.
|
||||
// Spawn axis points first so they are at the front of the list for fast searching.
|
||||
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
|
||||
{
|
||||
switch (mt->type)
|
||||
|
@ -1240,6 +1240,9 @@ static void P_LoadSidedefs(UINT8 *data)
|
|||
}
|
||||
sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
|
||||
|
||||
sd->offsetx_top = sd->offsetx_mid = sd->offsetx_bot = 0;
|
||||
sd->offsety_top = sd->offsety_mid = sd->offsety_bot = 0;
|
||||
|
||||
P_SetSidedefSector(i, SHORT(msd->sector));
|
||||
|
||||
// Special info stored in texture fields!
|
||||
|
@ -1777,6 +1780,18 @@ static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char
|
|||
sides[i].textureoffset = atol(val)<<FRACBITS;
|
||||
else if (fastcmp(param, "offsety"))
|
||||
sides[i].rowoffset = atol(val)<<FRACBITS;
|
||||
else if (fastcmp(param, "offsetx_top"))
|
||||
sides[i].offsetx_top = atol(val) << FRACBITS;
|
||||
else if (fastcmp(param, "offsetx_mid"))
|
||||
sides[i].offsetx_mid = atol(val) << FRACBITS;
|
||||
else if (fastcmp(param, "offsetx_bottom"))
|
||||
sides[i].offsetx_bot = atol(val) << FRACBITS;
|
||||
else if (fastcmp(param, "offsety_top"))
|
||||
sides[i].offsety_top = atol(val) << FRACBITS;
|
||||
else if (fastcmp(param, "offsety_mid"))
|
||||
sides[i].offsety_mid = atol(val) << FRACBITS;
|
||||
else if (fastcmp(param, "offsety_bottom"))
|
||||
sides[i].offsety_bot = atol(val) << FRACBITS;
|
||||
else if (fastcmp(param, "texturetop"))
|
||||
sides[i].toptexture = R_TextureNumForName(val);
|
||||
else if (fastcmp(param, "texturebottom"))
|
||||
|
@ -2461,6 +2476,18 @@ static void P_WriteTextmap(void)
|
|||
fprintf(f, "offsetx = %d;\n", wsides[i].textureoffset >> FRACBITS);
|
||||
if (wsides[i].rowoffset != 0)
|
||||
fprintf(f, "offsety = %d;\n", wsides[i].rowoffset >> FRACBITS);
|
||||
if (wsides[i].offsetx_top != 0)
|
||||
fprintf(f, "offsetx_top = %d;\n", wsides[i].offsetx_top >> FRACBITS);
|
||||
if (wsides[i].offsety_top != 0)
|
||||
fprintf(f, "offsety_top = %d;\n", wsides[i].offsety_top >> FRACBITS);
|
||||
if (wsides[i].offsetx_mid != 0)
|
||||
fprintf(f, "offsetx_mid = %d;\n", wsides[i].offsetx_mid >> FRACBITS);
|
||||
if (wsides[i].offsety_mid != 0)
|
||||
fprintf(f, "offsety_mid = %d;\n", wsides[i].offsety_mid >> FRACBITS);
|
||||
if (wsides[i].offsetx_bot != 0)
|
||||
fprintf(f, "offsetx_bottom = %d;\n", wsides[i].offsetx_bot >> FRACBITS);
|
||||
if (wsides[i].offsety_bot != 0)
|
||||
fprintf(f, "offsety_bottom = %d;\n", wsides[i].offsety_bot >> FRACBITS);
|
||||
if (wsides[i].toptexture > 0 && wsides[i].toptexture < numtextures)
|
||||
fprintf(f, "texturetop = \"%.*s\";\n", 8, textures[wsides[i].toptexture]->name);
|
||||
if (wsides[i].bottomtexture > 0 && wsides[i].bottomtexture < numtextures)
|
||||
|
@ -2828,6 +2855,8 @@ static void P_LoadTextmap(void)
|
|||
// Defaults.
|
||||
sd->textureoffset = 0;
|
||||
sd->rowoffset = 0;
|
||||
sd->offsetx_top = sd->offsetx_mid = sd->offsetx_bot = 0;
|
||||
sd->offsety_top = sd->offsety_mid = sd->offsety_bot = 0;
|
||||
sd->toptexture = R_TextureNumForName("-");
|
||||
sd->midtexture = R_TextureNumForName("-");
|
||||
sd->bottomtexture = R_TextureNumForName("-");
|
||||
|
@ -7460,7 +7489,7 @@ static void P_WriteLetter(void)
|
|||
{
|
||||
char *buf, *b;
|
||||
|
||||
if (!unlockables[28].unlocked) // pandora's box
|
||||
if (!serverGamedata->unlocked[28]) // pandora's box
|
||||
return;
|
||||
|
||||
if (modeattacking)
|
||||
|
@ -7804,10 +7833,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
nextmapoverride = 0;
|
||||
skipstats = 0;
|
||||
|
||||
if (!(netgame || multiplayer || demoplayback))
|
||||
mapvisited[gamemap-1] |= MV_VISITED;
|
||||
else if (netgame || multiplayer)
|
||||
mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently
|
||||
if (!demoplayback)
|
||||
{
|
||||
clientGamedata->mapvisited[gamemap-1] |= MV_VISITED;
|
||||
serverGamedata->mapvisited[gamemap-1] |= MV_VISITED;
|
||||
}
|
||||
|
||||
levelloading = false;
|
||||
|
||||
|
|
17
src/p_spec.c
17
src/p_spec.c
|
@ -1795,9 +1795,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|
|||
{ // Unlockable triggers required
|
||||
INT32 trigid = triggerline->args[1];
|
||||
|
||||
if (netgame || multiplayer)
|
||||
return false;
|
||||
else if (trigid < 0 || trigid > 31) // limited by 32 bit variable
|
||||
if (trigid < 0 || trigid > 31) // limited by 32 bit variable
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", triggerline->sidenum[0], trigid);
|
||||
return false;
|
||||
|
@ -1810,14 +1808,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|
|||
{ // An unlockable itself must be unlocked!
|
||||
INT32 unlockid = triggerline->args[1];
|
||||
|
||||
if (netgame || multiplayer)
|
||||
return false;
|
||||
else if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count
|
||||
if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid);
|
||||
return false;
|
||||
}
|
||||
else if (!(unlockables[unlockid-1].unlocked))
|
||||
else if (!(serverGamedata->unlocked[unlockid-1]))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -2942,7 +2938,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
|||
break;
|
||||
|
||||
case 441: // Trigger unlockable
|
||||
if (!(netgame || multiplayer))
|
||||
{
|
||||
INT32 trigid = line->args[0];
|
||||
|
||||
|
@ -2953,10 +2948,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
|||
unlocktriggers |= 1 << trigid;
|
||||
|
||||
// Unlocked something?
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
G_SaveGameData(); // only save if unlocked something
|
||||
G_SaveGameData(clientGamedata); // only save if unlocked something
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -675,7 +675,10 @@ void P_Ticker(boolean run)
|
|||
|
||||
// Keep track of how long they've been playing!
|
||||
if (!demoplayback) // Don't increment if a demo is playing.
|
||||
totalplaytime++;
|
||||
{
|
||||
clientGamedata->totalplaytime++;
|
||||
serverGamedata->totalplaytime++;
|
||||
}
|
||||
|
||||
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))
|
||||
P_DoSpecialStageStuff();
|
||||
|
|
|
@ -559,6 +559,10 @@ typedef struct
|
|||
// add this to the calculated texture top
|
||||
fixed_t rowoffset;
|
||||
|
||||
// per-texture offsets for UDMF
|
||||
fixed_t offsetx_top, offsetx_mid, offsetx_bot;
|
||||
fixed_t offsety_top, offsety_mid, offsety_bot;
|
||||
|
||||
// Texture indices.
|
||||
// We do not maintain names here.
|
||||
INT32 toptexture, bottomtexture, midtexture;
|
||||
|
|
63
src/r_main.c
63
src/r_main.c
|
@ -1092,34 +1092,12 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
|
|||
void R_SetupFrame(player_t *player)
|
||||
{
|
||||
camera_t *thiscam;
|
||||
boolean chasecam = false;
|
||||
|
||||
if (splitscreen && player == &players[secondarydisplayplayer]
|
||||
&& player != &players[consoleplayer])
|
||||
{
|
||||
boolean chasecam = R_ViewpointHasChasecam(player);
|
||||
|
||||
if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
|
||||
thiscam = &camera2;
|
||||
chasecam = (cv_chasecam2.value != 0);
|
||||
R_SetViewContext(VIEWCONTEXT_PLAYER2);
|
||||
}
|
||||
else
|
||||
{
|
||||
thiscam = &camera;
|
||||
chasecam = (cv_chasecam.value != 0);
|
||||
R_SetViewContext(VIEWCONTEXT_PLAYER1);
|
||||
}
|
||||
|
||||
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
|
||||
chasecam = true; // force chasecam on
|
||||
else if (player->spectator) // no spectator chasecam
|
||||
chasecam = false; // force chasecam off
|
||||
|
||||
if (chasecam && !thiscam->chase)
|
||||
{
|
||||
P_ResetCamera(player, thiscam);
|
||||
thiscam->chase = true;
|
||||
}
|
||||
else if (!chasecam)
|
||||
thiscam->chase = false;
|
||||
|
||||
newview->sky = false;
|
||||
|
||||
|
@ -1348,11 +1326,37 @@ boolean R_ViewpointHasChasecam(player_t *player)
|
|||
{
|
||||
camera_t *thiscam;
|
||||
boolean chasecam = false;
|
||||
boolean isplayer2 = (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer]);
|
||||
|
||||
if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
|
||||
if (isplayer2)
|
||||
{
|
||||
thiscam = &camera2;
|
||||
chasecam = (cv_chasecam2.value != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
thiscam = &camera;
|
||||
chasecam = (cv_chasecam.value != 0);
|
||||
}
|
||||
|
||||
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
|
||||
chasecam = true; // force chasecam on
|
||||
else if (player->spectator) // no spectator chasecam
|
||||
chasecam = false; // force chasecam off
|
||||
|
||||
if (chasecam && !thiscam->chase)
|
||||
{
|
||||
P_ResetCamera(player, thiscam);
|
||||
thiscam->chase = true;
|
||||
}
|
||||
else if (!chasecam && thiscam->chase)
|
||||
{
|
||||
P_ResetCamera(player, thiscam);
|
||||
thiscam->chase = false;
|
||||
}
|
||||
|
||||
if (isplayer2)
|
||||
{
|
||||
R_SetViewContext(VIEWCONTEXT_PLAYER2);
|
||||
if (thiscam->reset)
|
||||
{
|
||||
|
@ -1362,8 +1366,6 @@ boolean R_ViewpointHasChasecam(player_t *player)
|
|||
}
|
||||
else
|
||||
{
|
||||
thiscam = &camera;
|
||||
chasecam = (cv_chasecam.value != 0);
|
||||
R_SetViewContext(VIEWCONTEXT_PLAYER1);
|
||||
if (thiscam->reset)
|
||||
{
|
||||
|
@ -1372,11 +1374,6 @@ boolean R_ViewpointHasChasecam(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
|
||||
chasecam = true; // force chasecam on
|
||||
else if (player->spectator) // no spectator chasecam
|
||||
chasecam = false; // force chasecam off
|
||||
|
||||
return chasecam;
|
||||
}
|
||||
|
||||
|
|
26
src/r_segs.c
26
src/r_segs.c
|
@ -49,6 +49,7 @@ fixed_t rw_distance;
|
|||
static INT32 rw_x, rw_stopx;
|
||||
static angle_t rw_centerangle;
|
||||
static fixed_t rw_offset;
|
||||
static fixed_t rw_offset_top, rw_offset_mid, rw_offset_bot;
|
||||
static fixed_t rw_offset2; // for splats
|
||||
static fixed_t rw_scale, rw_scalestep;
|
||||
static fixed_t rw_midtexturemid, rw_toptexturemid, rw_bottomtexturemid;
|
||||
|
@ -778,7 +779,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
|
||||
if (newline)
|
||||
{
|
||||
offsetvalue = sides[newline->sidenum[0]].rowoffset;
|
||||
offsetvalue = sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid;
|
||||
if (newline->flags & ML_DONTPEGBOTTOM)
|
||||
{
|
||||
skewslope = *pfloor->b_slope; // skew using bottom slope
|
||||
|
@ -790,7 +791,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
}
|
||||
else
|
||||
{
|
||||
offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset;
|
||||
offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset + sides[pfloor->master->sidenum[0]].offsety_mid;
|
||||
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
{
|
||||
skewslope = *pfloor->b_slope; // skew using bottom slope
|
||||
|
@ -1335,7 +1336,7 @@ static void R_RenderSegLoop (void)
|
|||
dc_yl = yl;
|
||||
dc_yh = yh;
|
||||
dc_texturemid = rw_midtexturemid;
|
||||
dc_source = R_GetColumn(midtexture,texturecolumn);
|
||||
dc_source = R_GetColumn(midtexture,texturecolumn + (rw_offset_mid>>FRACBITS));
|
||||
dc_texheight = textureheight[midtexture]>>FRACBITS;
|
||||
|
||||
//profile stuff ---------------------------------------------------------
|
||||
|
@ -1396,7 +1397,7 @@ static void R_RenderSegLoop (void)
|
|||
dc_yl = yl;
|
||||
dc_yh = mid;
|
||||
dc_texturemid = rw_toptexturemid;
|
||||
dc_source = R_GetColumn(toptexture,texturecolumn);
|
||||
dc_source = R_GetColumn(toptexture,texturecolumn + (rw_offset_top>>FRACBITS));
|
||||
dc_texheight = textureheight[toptexture]>>FRACBITS;
|
||||
colfunc();
|
||||
ceilingclip[rw_x] = (INT16)mid;
|
||||
|
@ -1433,7 +1434,7 @@ static void R_RenderSegLoop (void)
|
|||
dc_yh = yh;
|
||||
dc_texturemid = rw_bottomtexturemid;
|
||||
dc_source = R_GetColumn(bottomtexture,
|
||||
texturecolumn);
|
||||
texturecolumn + (rw_offset_bot>>FRACBITS));
|
||||
dc_texheight = textureheight[bottomtexture]>>FRACBITS;
|
||||
colfunc();
|
||||
floorclip[rw_x] = (INT16)mid;
|
||||
|
@ -1452,7 +1453,7 @@ static void R_RenderSegLoop (void)
|
|||
{
|
||||
// save texturecol
|
||||
// for backdrawing of masked mid texture
|
||||
maskedtexturecol[rw_x] = (INT16)texturecolumn;
|
||||
maskedtexturecol[rw_x] = (INT16)(texturecolumn + (rw_offset_mid>>FRACBITS));
|
||||
|
||||
if (maskedtextureheight != NULL) {
|
||||
maskedtextureheight[rw_x] = (curline->linedef->flags & ML_MIDPEG) ?
|
||||
|
@ -1783,7 +1784,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
rw_midtexturemid = worldtop;
|
||||
rw_midtextureslide = ceilingfrontslide;
|
||||
}
|
||||
rw_midtexturemid += sidedef->rowoffset;
|
||||
rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid;
|
||||
|
||||
ds_p->silhouette = SIL_BOTH;
|
||||
ds_p->sprtopclip = screenheightarray;
|
||||
|
@ -2022,8 +2023,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
}
|
||||
}
|
||||
|
||||
rw_toptexturemid += sidedef->rowoffset;
|
||||
rw_bottomtexturemid += sidedef->rowoffset;
|
||||
rw_toptexturemid += sidedef->rowoffset + sidedef->offsety_top;
|
||||
rw_bottomtexturemid += sidedef->rowoffset + sidedef->offsety_bot;
|
||||
|
||||
// allocate space for masked texture tables
|
||||
if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors))
|
||||
|
@ -2266,8 +2267,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
rw_midtexturebackslide = ceilingbackslide;
|
||||
}
|
||||
}
|
||||
rw_midtexturemid += sidedef->rowoffset;
|
||||
rw_midtextureback += sidedef->rowoffset;
|
||||
rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid;
|
||||
rw_midtextureback += sidedef->rowoffset + sidedef->offsety_mid;
|
||||
|
||||
maskedtexture = true;
|
||||
}
|
||||
|
@ -2305,6 +2306,9 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
/// don't use texture offset for splats
|
||||
rw_offset2 = rw_offset + curline->offset;
|
||||
rw_offset += sidedef->textureoffset + curline->offset;
|
||||
rw_offset_top = sidedef->offsetx_top;
|
||||
rw_offset_mid = sidedef->offsetx_mid;
|
||||
rw_offset_bot = sidedef->offsetx_bot;
|
||||
rw_centerangle = ANGLE_90 + viewangle - rw_normalangle;
|
||||
|
||||
// calculate light table
|
||||
|
|
|
@ -194,7 +194,7 @@ UINT32 R_GetSkinAvailabilities(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (unlockables[i].unlocked)
|
||||
if (clientGamedata->unlocked[i])
|
||||
{
|
||||
response |= (1 << unlockShift);
|
||||
}
|
||||
|
@ -242,11 +242,12 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
|
|||
// Force 3.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (playernum != -1 && players[playernum].bot)
|
||||
{
|
||||
//Force 4.
|
||||
return true;
|
||||
}
|
||||
{
|
||||
// Force 4.
|
||||
return true;
|
||||
}
|
||||
|
||||
// We will now check if this skin is supposed to be locked or not.
|
||||
|
||||
|
@ -284,7 +285,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
|
|||
else
|
||||
{
|
||||
// We want to check our global unlockables.
|
||||
return (unlockables[unlockID].unlocked);
|
||||
return (clientGamedata->unlocked[unlockID]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1324,6 +1324,8 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
|
|||
if (trans >= 9) return;
|
||||
|
||||
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
|
||||
if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs
|
||||
scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale));
|
||||
|
||||
patch = W_CachePatchName("DSHADOW", PU_SPRITE);
|
||||
xscale = FixedDiv(projection, tz);
|
||||
|
|
|
@ -1692,6 +1692,7 @@ UINT8 soundtestpage = 1;
|
|||
//
|
||||
boolean S_PrepareSoundTest(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
musicdef_t *def;
|
||||
INT32 pos = numsoundtestdefs = 0;
|
||||
|
||||
|
@ -1717,9 +1718,9 @@ boolean S_PrepareSoundTest(void)
|
|||
if (!(def->soundtestpage & soundtestpage))
|
||||
continue;
|
||||
soundtestdefs[pos++] = def;
|
||||
if (def->soundtestcond > 0 && !(mapvisited[def->soundtestcond-1] & MV_BEATEN))
|
||||
if (def->soundtestcond > 0 && !(data->mapvisited[def->soundtestcond-1] & MV_BEATEN))
|
||||
continue;
|
||||
if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond))
|
||||
if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond, data))
|
||||
continue;
|
||||
def->allowed = true;
|
||||
}
|
||||
|
|
|
@ -2352,7 +2352,7 @@ void I_Quit(void)
|
|||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
G_SaveGameData(clientGamedata); // Tails 12-08-2002
|
||||
//added:16-02-98: when recording a demo, should exit using 'q' key,
|
||||
// but sometimes we forget and use 'F10'.. so save here too.
|
||||
|
||||
|
@ -2436,7 +2436,7 @@ void I_Error(const char *error, ...)
|
|||
if (errorcount == 8)
|
||||
{
|
||||
M_SaveConfig(NULL);
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
if (errorcount > 20)
|
||||
{
|
||||
|
@ -2469,7 +2469,7 @@ void I_Error(const char *error, ...)
|
|||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
G_SaveGameData(clientGamedata); // Tails 12-08-2002
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
if (demorecording)
|
||||
|
|
118
src/st_stuff.c
118
src/st_stuff.c
|
@ -108,6 +108,9 @@ static patch_t *sneakers;
|
|||
static patch_t *gravboots;
|
||||
static patch_t *nonicon;
|
||||
static patch_t *nonicon2;
|
||||
static patch_t *nightopianhelper;
|
||||
static patch_t *linkfreeze;
|
||||
static patch_t *superparaloop;
|
||||
static patch_t *bluestat;
|
||||
static patch_t *byelstat;
|
||||
static patch_t *orngstat;
|
||||
|
@ -313,6 +316,10 @@ void ST_LoadGraphics(void)
|
|||
nonicon2 = W_CachePatchName("NONICON2", PU_HUDGFX);
|
||||
|
||||
// NiGHTS HUD things
|
||||
nightopianhelper = W_CachePatchName("NHLPICON", PU_HUDGFX);
|
||||
linkfreeze = W_CachePatchName("NLFZICON", PU_HUDGFX);
|
||||
superparaloop = W_CachePatchName("NSPRICON", PU_HUDGFX);
|
||||
|
||||
bluestat = W_CachePatchName("BLUESTAT", PU_HUDGFX);
|
||||
byelstat = W_CachePatchName("BYELSTAT", PU_HUDGFX);
|
||||
orngstat = W_CachePatchName("ORNGSTAT", PU_HUDGFX);
|
||||
|
@ -1448,6 +1455,21 @@ void ST_drawWipeTitleCard(void)
|
|||
}
|
||||
}
|
||||
|
||||
#define ICONSEP (16+4) // matches weapon rings HUD
|
||||
|
||||
static INT32 ST_powerupHUDoffset(UINT16 timer)
|
||||
{
|
||||
if (timer > 7)
|
||||
return ICONSEP;
|
||||
else
|
||||
{
|
||||
UINT8 a = ICONSEP, b = 7-timer;
|
||||
while (b--)
|
||||
a = 2*a/3;
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
static void ST_drawPowerupHUD(void)
|
||||
{
|
||||
patch_t *p = NULL;
|
||||
|
@ -1455,7 +1477,6 @@ static void ST_drawPowerupHUD(void)
|
|||
INT32 offs = hudinfo[HUD_POWERUPS].x;
|
||||
const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0);
|
||||
static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0}, finishoffs[2] = {0, 0};
|
||||
#define ICONSEP (16+4) // matches weapon rings HUD
|
||||
|
||||
if (F_GetPromptHideHud(hudinfo[HUD_POWERUPS].y))
|
||||
return;
|
||||
|
@ -1567,15 +1588,7 @@ static void ST_drawPowerupHUD(void)
|
|||
DRAWTIMERICON(invincibility, invulntime)
|
||||
}
|
||||
|
||||
if (invulntime > 7)
|
||||
offs -= ICONSEP;
|
||||
else
|
||||
{
|
||||
UINT8 a = ICONSEP, b = 7-invulntime;
|
||||
while (b--)
|
||||
a = 2*a/3;
|
||||
offs -= a;
|
||||
}
|
||||
offs -= ST_powerupHUDoffset(invulntime);
|
||||
|
||||
// Super Sneakers
|
||||
if (stplyr->powers[pw_sneakers] > 3*TICRATE || (stplyr->powers[pw_sneakers] && leveltime & 1))
|
||||
|
@ -1583,15 +1596,7 @@ static void ST_drawPowerupHUD(void)
|
|||
DRAWTIMERICON(sneakers, stplyr->powers[pw_sneakers])
|
||||
}
|
||||
|
||||
if (stplyr->powers[pw_sneakers] > 7)
|
||||
offs -= ICONSEP;
|
||||
else
|
||||
{
|
||||
UINT8 a = ICONSEP, b = 7-stplyr->powers[pw_sneakers];
|
||||
while (b--)
|
||||
a = 2*a/3;
|
||||
offs -= a;
|
||||
}
|
||||
offs -= ST_powerupHUDoffset(stplyr->powers[pw_sneakers]);
|
||||
|
||||
// Gravity Boots
|
||||
if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1))
|
||||
|
@ -1599,6 +1604,36 @@ static void ST_drawPowerupHUD(void)
|
|||
DRAWTIMERICON(gravboots, stplyr->powers[pw_gravityboots])
|
||||
}
|
||||
|
||||
offs -= ST_powerupHUDoffset(stplyr->powers[pw_gravityboots]);
|
||||
|
||||
// --------------------
|
||||
// NiGHTS timer-based powerups
|
||||
// --------------------
|
||||
|
||||
// Nightopian Helper
|
||||
if (stplyr->powers[pw_nights_helper] > 3*TICRATE || (stplyr->powers[pw_nights_helper] && leveltime & 1))
|
||||
{
|
||||
DRAWTIMERICON(nightopianhelper, stplyr->powers[pw_nights_helper])
|
||||
}
|
||||
|
||||
offs -= ST_powerupHUDoffset(stplyr->powers[pw_nights_helper]);
|
||||
|
||||
// Link Freeze
|
||||
if (stplyr->powers[pw_nights_linkfreeze] > 3*TICRATE || (stplyr->powers[pw_nights_linkfreeze] && leveltime & 1))
|
||||
{
|
||||
DRAWTIMERICON(linkfreeze, stplyr->powers[pw_nights_linkfreeze])
|
||||
}
|
||||
|
||||
offs -= ST_powerupHUDoffset(stplyr->powers[pw_nights_linkfreeze]);
|
||||
|
||||
// Super Paraloop
|
||||
if (stplyr->powers[pw_nights_superloop] > 3*TICRATE || (stplyr->powers[pw_nights_superloop] && leveltime & 1))
|
||||
{
|
||||
DRAWTIMERICON(superparaloop, stplyr->powers[pw_nights_superloop])
|
||||
}
|
||||
|
||||
//offs -= ST_powerupHUDoffset(stplyr->powers[pw_nights_superloop]);
|
||||
|
||||
#undef DRAWTIMERICON
|
||||
#undef ICONSEP
|
||||
}
|
||||
|
@ -1697,7 +1732,7 @@ static void ST_drawNightsRecords(void)
|
|||
ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
|
||||
|
||||
// If new record, say so!
|
||||
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore)
|
||||
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1, clientGamedata) <= stplyr->lastmarescore)
|
||||
{
|
||||
if (stplyr->texttimer & 16)
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *");
|
||||
|
@ -2545,7 +2580,7 @@ static void ST_doHuntIconsAndSound(void)
|
|||
S_StartSound(NULL, sfx_emfind);
|
||||
}
|
||||
|
||||
static void ST_doItemFinderIconsAndSound(void)
|
||||
static boolean ST_doItemFinderIconsAndSound(void)
|
||||
{
|
||||
INT32 emblems[16];
|
||||
thinker_t *th;
|
||||
|
@ -2556,6 +2591,12 @@ static void ST_doItemFinderIconsAndSound(void)
|
|||
INT32 interval = 0, newinterval = 0;
|
||||
INT32 soffset;
|
||||
|
||||
if (!(cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata)))
|
||||
{
|
||||
// Not unlocked, or not enabled. Use emerald hunt radar.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type > ET_SKIN || emblemlocations[i].level != gamemap)
|
||||
|
@ -2563,15 +2604,21 @@ static void ST_doItemFinderIconsAndSound(void)
|
|||
|
||||
emblems[stemblems++] = i;
|
||||
|
||||
if (!emblemlocations[i].collected)
|
||||
if (!P_EmblemWasCollected(i) && P_CanPickupEmblem(stplyr, i))
|
||||
{
|
||||
++stunfound;
|
||||
}
|
||||
|
||||
if (stemblems >= 16)
|
||||
break;
|
||||
}
|
||||
|
||||
// Found all/none exist? Don't waste our time
|
||||
if (!stunfound)
|
||||
return;
|
||||
{
|
||||
// Allow emerald hunt radar to function after they're all collected.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scan thinkers to find emblem mobj with these ids
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
|
@ -2591,6 +2638,9 @@ static void ST_doItemFinderIconsAndSound(void)
|
|||
{
|
||||
if (mo2->health == emblems[i] + 1)
|
||||
{
|
||||
if (P_EmblemWasCollected(emblems[i]) || !P_CanPickupEmblem(stplyr, emblems[i]))
|
||||
break;
|
||||
|
||||
soffset = (i * 20) - ((stemblems - 1) * 10);
|
||||
|
||||
newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset);
|
||||
|
@ -2605,6 +2655,8 @@ static void ST_doItemFinderIconsAndSound(void)
|
|||
|
||||
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0 && renderisnewtic)
|
||||
S_StartSound(NULL, sfx_emfind);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -2723,9 +2775,7 @@ static void ST_overlayDrawer(void)
|
|||
ST_drawRaceHUD();
|
||||
|
||||
// Emerald Hunt Indicators
|
||||
if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER))
|
||||
ST_doItemFinderIconsAndSound();
|
||||
else
|
||||
if (!ST_doItemFinderIconsAndSound())
|
||||
ST_doHuntIconsAndSound();
|
||||
|
||||
if(!P_IsLocalPlayer(stplyr))
|
||||
|
@ -2740,18 +2790,16 @@ static void ST_overlayDrawer(void)
|
|||
}
|
||||
|
||||
// This is where we draw all the fun cheese if you have the chasecam off!
|
||||
if (!(maptol & TOL_NIGHTS))
|
||||
if ((stplyr == &players[displayplayer] && !camera.chase)
|
||||
|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))
|
||||
{
|
||||
if ((stplyr == &players[displayplayer] && !camera.chase)
|
||||
|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))
|
||||
{
|
||||
ST_drawFirstPersonHUD();
|
||||
if (cv_powerupdisplay.value)
|
||||
ST_drawPowerupHUD(); // same as it ever was...
|
||||
}
|
||||
else if (cv_powerupdisplay.value == 2)
|
||||
ST_drawFirstPersonHUD();
|
||||
if (cv_powerupdisplay.value)
|
||||
ST_drawPowerupHUD(); // same as it ever was...
|
||||
}
|
||||
else if (cv_powerupdisplay.value == 2)
|
||||
ST_drawPowerupHUD(); // same as it ever was...
|
||||
|
||||
}
|
||||
else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2)
|
||||
ST_drawPowerupHUD(); // same as it ever was...
|
||||
|
|
|
@ -1092,12 +1092,14 @@ void Y_Ticker(void)
|
|||
S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching!
|
||||
|
||||
// Update when done with tally
|
||||
if (!(netgame || multiplayer) && !demoplayback)
|
||||
if (!demoplayback)
|
||||
{
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
}
|
||||
else if (!(intertic & 1))
|
||||
|
@ -1228,12 +1230,14 @@ void Y_Ticker(void)
|
|||
S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching!
|
||||
|
||||
// Update when done with tally
|
||||
if (!(netgame || multiplayer) && !demoplayback)
|
||||
if (!demoplayback)
|
||||
{
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
}
|
||||
else if (!(intertic & 1))
|
||||
|
|
Loading…
Reference in a new issue