Merge remote-tracking branch 'upstream/next' into software-dropshadows

This commit is contained in:
fickleheart 2020-01-11 17:09:57 -06:00
commit 27bd7e4a7f
96 changed files with 18203 additions and 8014 deletions

View file

@ -0,0 +1,77 @@
// Default lump name for new map
defaultlumpname = "MAP01";
//GZDB specific. Don't try to load lumps that don't exist.
basegame = 0;
//Sky textures for vanilla maps
defaultskytextures
{
SKY1 = "MAP01,MAP02,MAP03,MAP33,MAP50,MAP60,MAPF0,MAPM0";
SKY2 = "MAPM7,MAPMB";
SKY4 = "MAP04,MAP06,MAP61,MAPF6,MAPM1";
SKY6 = "MAP05,MAP51,MAPMA";
SKY7 = "MAPM2,MAPM5";
SKY8 = "MAP07,MAP08,MAP09,MAP52,MAP62,MAPF1";
SKY10 = "MAP10,MAP12,MAP53,MAP63,MAPM3";
SKY11 = "MAP11,MAPF7";
SKY13 = "MAP13,MAP64";
SKY14 = "MAP14";
SKY15 = "MAP15,MAP54";
SKY17 = "MAP70";
SKY20 = "MAP32,MAP55,MAP65,MAPF2,MAPF5";
SKY21 = "MAPM4";
SKY22 = "MAP22,MAP23,MAP25,MAP26,MAP27,MAP56,MAP66,MAPF4,MAPM6";
SKY30 = "MAP30";
SKY31 = "MAP31";
SKY35 = "MAP42";
SKY40 = "MAP41,MAP71,MAPM9";
SKY55 = "MAPF3,MAPM8";
SKY68 = "MAPF8";
SKY99 = "MAP57,MAPZ0";
SKY159 = "MAP16";
SKY172 = "MAP40";
SKY300 = "MAP72";
SKY301 = "MAP73";
}
// Skill levels
skills
{
1 = "Normal";
}
// Skins
skins
{
Sonic;
Tails;
Knuckles;
Amy;
Fang;
Metalsonic;
}
// Gametypes
gametypes
{
-1 = "Single Player";
0 = "Co-op";
1 = "Competition";
2 = "Race";
3 = "Match";
4 = "Team Match";
5 = "Tag";
6 = "Hide and Seek";
7 = "CTF";
}
// Texture loading options
defaultwalltexture = "GFZROCK";
defaultfloortexture = "GFZFLR01";
defaultceilingtexture = "F_SKY1";
// Default texture sets
// (these are not required, but useful for new users)
texturesets
{
}

View file

@ -0,0 +1,309 @@
common
{
// Some common settings
// Default testing parameters
testparameters = "-file \"%AP\" \"%F\" -warp %L";
testshortpaths = true;
// Action special help (mxd)
actionspecialhelp = "https://wiki.srb2.org/wiki/Linedef_type_%K";
// Default nodebuilder configurations
defaultsavecompiler = "zennode_normal";
defaulttestcompiler = "zennode_fast";
// Generalized actions
generalizedlinedefs = false;
generalizedsectors = true;
mixtexturesflats = true;
defaulttexturescale = 1.0f;
defaultflatscale = 1.0f;
scaledtextureoffsets = true;
// Thing number for start position in 3D Mode
start3dmode = 3328;
// Texture sources
textures
{
include("SRB222_misc.cfg", "textures");
}
// Patch sources
patches
{
include("SRB222_misc.cfg", "patches");
}
// Sprite sources
sprites
{
include("SRB222_misc.cfg", "sprites");
}
// Flat sources
flats
{
include("SRB222_misc.cfg", "flats");
}
}
mapformat_doom
{
// The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
formatinterface = "SRB2MapSetIO";
/*
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 (As far as 2.2 goes, they're empty just like in 2.1)
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;
}
mapformat_udmf
{
// The format interface handles the map data format
formatinterface = "UniversalMapSetIO";
// Enables support for long (> 8 chars) texture names
// WARNING: this should only be enabled for UDMF game configurations!
// WARNING: enabling this will make maps incompatible with Doom Builder 2 and can lead to problems in Slade 3!
longtexturenames = false;
// Default nodebuilder configurations
defaultsavecompiler = "zdbsp_udmf_normal";
defaulttestcompiler = "zdbsp_udmf_fast";
engine = "srb2"; // override that so that DB2 uses the correct namespace
maplumpnames
{
include("UDMF_misc.cfg", "udmfmaplumpnames_begin");
include("SRB222_misc.cfg", "udmfmaplumpnames");
include("UDMF_misc.cfg", "udmfmaplumpnames_end");
}
universalfields
{
// include("SRB222_misc.cfg", "universalfields");
}
// When this is set to true, sectors with the same tag will light up when a line is highlighted
linetagindicatesectors = false;
// Special linedefs
include("SRB222_misc.cfg", "speciallinedefs_udmf");
// Default flags for first new thing (As far as 2.2 goes, they're empty just like in 2.1)
defaultthingflags
{
}
// Generalized actions
generalizedlinedefs = false;
// SECTOR FLAGS
sectorflags
{
// include("SRB222_misc.cfg", "sectorflags");
}
// DEFAULT SECTOR BRIGHTNESS LEVELS
sectorbrightness
{
include("SRB222_misc.cfg", "sectorbrightness");
}
// SECTOR TYPES
sectortypes
{
include("SRB222_sectors.cfg", "sectortypes");
}
// SECTOR RENSERSTYLES
/* sectorrenderstyles
{
include("SRB222_misc.cfg", "sectorrenderstyles");
}*/
// LINEDEF FLAGS
linedefflags
{
include("SRB222_misc.cfg", "linedefflags_udmf");
}
// LINEDEF ACTIVATIONS
linedefactivations
{
include("SRB222_misc.cfg", "linedefactivations_udmf");
}
linedefflagstranslation
{
}
// LINEDEF RENSERSTYLES
linedefrenderstyles
{
include("SRB222_misc.cfg", "linedefrenderstyles");
}
//SIDEDEF FLAGS
/* sidedefflags
{
include("UDMF_misc.cfg", "sidedefflags");
}*/
// THING FLAGS
thingflags
{
include("SRB222_misc.cfg", "thingflags_udmf");
}
// 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 RENSERSTYLES
/* thingrenderstyles
{
include("SRB222_misc.cfg", "thingrenderstyles");
}*/
// How to compare thing flags (for the stuck things error checker)
/* thingflagscompare
{
include("UDMF_misc.cfg", "thingflagscompare");
}*/
//mxd. 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
{
}
// LINEDEF TYPES
linedeftypes
{
include("SRB222_linedefs.cfg", "udmf");
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,726 @@
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 ACTIVATIONS
// Make sure these are in order from lowest value to highest value
linedefactivations
{
}
// 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
{
1 = "blocking";
2 = "blockmonsters";
4 = "twosided";
8 = "dontpegtop";
16 = "dontpegbottom";
32 = "skewtd";
64 = "noclimb";
128 = "noskew";
256 = "midpeg";
512 = "midsolid";
1024 = "wrapmidtex";
2048 = "netonly";
4096 = "nonet";
8192 = "effect6";
16384 = "bouncy";
32768 = "transfer";
}
linedefflags_udmf
{
blocking = "Impassable";
blockmonsters = "Block Enemies";
twosided = "Double-Sided";
dontpegtop = "Upper Unpegged";
dontpegbottom = "Lower Unpegged";
skewtd = "Slope Skew";
noclimb = "Not Climbable";
noskew = "No Midtexture Skew";
midpeg = "Peg Midtexture";
midsolid = "Solid Midtexture";
wrapmidtex = "Repeat Midtexture";
// netonly = "Netgame-Only special";
// nonet = "No netgame special";
// effect6 = "Effect 6";
bouncy = "Bouncy Wall";
// transfer = "Transfer Line";
}
linedefactivations_udmf
{
notriggerorder = "Out of Order";
netonly = "Netgame-Only";
nonet = "No netgame";
}
sidedefflags
{
clipmidtex = "Clip middle texture";
wrapmidtex = "Wrap middle texture";
smoothlighting = "Smooth lighting";
nofakecontrast = "Even lighting";
nodecals = "No decals";
lightfog = "Use sidedef brightness on fogged walls";
}
//RENDER STYLES
thingrenderstyles
{
}
linedefrenderstyles
{
translucent = "Translucent";
fog = "Fog";
}
sectorrenderstyles
{
}
thingflags
{
1 = "[1] Extra";
2 = "[2] Flip";
4 = "[4] Special";
8 = "[8] Ambush";
}
// THING FLAGS
thingflags_udmf
{
extra = "Extra";
flip = "Flip";
special = "Special";
ambush = "Ambush";
}
// 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
{
1 = "extra";
2 = "flip";
4 = "special";
8 = "ambush";
}
// DEFAULT SECTOR BRIGHTNESS LEVELS
sectorbrightness
{
255;
248;
240;
232;
224;
216;
208;
200;
192;
184;
176;
168;
160;
152;
144;
136;
128;
120;
112;
104;
96;
88;
80;
72;
64;
56;
48;
40;
32;
24;
16;
8;
0;
}
/*
TEXTURES AND FLAT SOURCES
This tells Doom Builder where to find the information for textures
and flats in the IWAD file, Addition WAD file and Map WAD file.
Start and end lumps must be given in a structure (of which the
key name doesnt matter) and any textures or flats in between them
are loaded in either the textures category or flats category.
For textures: PNAMES, TEXTURE1 and TEXTURE2 are loaded by default.
*/
textures
{
zdoom1
{
start = "TX_START";
end = "TX_END";
}
}
/*
ADDITIONAL UNIVERSAL DOOM MAP FORMAT FIELD DEFINITIONS
Only add fields here that Doom Builder does not edit with its own user-interface!
The "default" field must match the UDMF specifications!
Field data types:
0 = integer *
1 = float
2 = string
3 = bool
4 = linedef action (integer) *
5 = sector effect (integer) *
6 = texture (string)
7 = flat (string)
8 = angle in degrees (integer)
9 = angle in radians (float)
10 = XXRRGGBB color (integer)
11 = enum option (integer) *
12 = enum bits (integer) *
13 = sector tag (integer) *
14 = thing tag (integer) *
15 = linedef tag (integer) *
16 = enum option (string)
17 = angle in degrees (float)
22 = byte angle (integer)
*/
universalfields
{
sector
{
friction
{
name = "Friction";
type = 1;
default = 1;
}
specialeffectplanes
{
type = 11;
enum = "floorceiling";
default = 0;
}
colormapbegin
{
type = 0;
default = 0;
}
colormapend
{
type = 0;
default = 33;
}
foglighting
{
type = 3;
default = false;
}
teambase
{
type = 11;
enum = "ctfteam";
default = 0;
}
triggersector
{
type = 3;
default = false;
}
triggerobject
{
type = 11;
enum = "triggerobjects";
default = 0;
}
triggersurface
{
type = 11;
enum = "triggersurfaces";
default = 0;
}
ringdrain
{
type = 1;
default = 0;
}
}
linedef
{
executordelay
{
type = 0;
default = 0;
}
midtexrepetitions
{
type = 0;
default = 0;
}
arg5
{
type = 0;
default = 0;
}
arg1str
{
type = 2;
default = "";
}
}
thing
{
}
}
/*
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. (useful for lumps Doom Builder doesn't use)
nodebuild = The nodebuilder generates this lump.
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
{
required = false;
nodebuild = true;
allowempty = false;
}
REJECT
{
required = false;
nodebuild = true;
allowempty = false;
}
BLOCKMAP
{
required = false;
nodebuild = true;
allowempty = true;
}
}
// ENUMERATIONS
// These are enumerated lists for linedef types and UDMF fields.
// Reserved names are: angledeg, anglerad, color, texture, flat
enums
{
falsetrue
{
0 = "False";
1 = "True";
}
yesno
{
0 = "Yes";
1 = "No";
}
noyes
{
0 = "No";
1 = "Yes";
}
onoff
{
0 = "On";
1 = "Off";
}
offon
{
0 = "Off";
1 = "On";
}
updown
{
0 = "Up";
1 = "Down";
}
downup
{
0 = "Down";
1 = "Up";
}
addset
{
0 = "Add";
1 = "Set";
}
floorceiling
{
0 = "Floor";
1 = "Ceiling";
2 = "Floor and ceiling";
}
triggertype
{
0 = "Continuous";
1 = "Each Time (Enter)";
2 = "Each Time (Enter and leave)";
3 = "Once";
}
frontback
{
0 = "None";
1 = "Front";
2 = "Back";
}
ctfteam
{
0 = "None";
1 = "Red";
2 = "Blue";
}
triggerobjects
{
0 = "Any player";
1 = "All players";
2 = "Pushable object";
3 = "Any object with thinker";
}
triggersurfaces
{
0 = "Floor touch";
1 = "Ceiling touch";
2 = "Floor or ceiling touch";
3 = "Anywhere in sector";
}
tangibility
{
1 = "Intangible from top";
2 = "Intangible from bottom";
4 = "Don't block players";
8 = "Don't block non-players";
}
}
//Default things filters
thingsfilters
{
filter0
{
name = "Player starts";
category = "starts";
type = -1;
}
filter1
{
name = "Enemies";
category = "enemies";
type = -1;
}
filter2
{
name = "NiGHTS Track";
category = "nightstrk";
type = -1;
}
filter3
{
name = "Normal Gravity";
category = "";
type = -1;
fields
{
2 = false;
}
}
filter4
{
name = "Reverse Gravity";
category = "";
type = -1;
fields
{
2 = true;
}
}
}
thingsfilters_udmf
{
}
// 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";
singlesidedflag = "blocking";
doublesidedflag = "twosided";
impassableflag = "blocking";
upperunpeggedflag = "dontpegtop";
lowerunpeggedflag = "dontpegbottom";
repeatmidtextureflag = "wrapmidtex";
pegmidtextureflag = "midpeg";
}
scriptlumpnames
{
MAINCFG
{
script = "SOC.cfg";
}
OBJCTCFG
{
script = "SOC.cfg";
}
SOC_
{
script = "SOC.cfg";
isprefix = true;
}
LUA_
{
script = "Lua.cfg";
isprefix = true;
}
}
// Texture sources
textures
{
zdoom1
{
start = "TX_START";
end = "TX_END";
}
}
// Patch sources
patches
{
standard1
{
start = "P_START";
end = "P_END";
}
standard2
{
start = "PP_START";
end = "PP_END";
}
}
// Sprite sources
sprites
{
standard1
{
start = "S_START";
end = "S_END";
}
standard2
{
start = "SS_START";
end = "SS_END";
}
}
// Flat sources
flats
{
standard1
{
start = "F_START";
end = "F_END";
}
standard2
{
start = "FF_START";
end = "FF_END";
}
standard3
{
start = "FF_START";
end = "F_END";
}
standard4
{
start = "F_START";
end = "FF_END";
}
}

View file

@ -0,0 +1,109 @@
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";
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)";
112 = "Trigger Line Ex. (NiGHTS Mare)";
128 = "Check for Linedef Executor on FOFs";
144 = "Egg Capsule";
160 = "Special Stage Time/Rings Parameters";
176 = "Custom Global Gravity";
512 = "Wind/Current";
1024 = "Conveyor Belt";
1280 = "Speed Pad";
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";
}
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)";
112 = "Trigger Line Ex. (NiGHTS Mare)";
128 = "Check for Linedef Executor on FOFs";
144 = "Egg Capsule";
160 = "Special Stage Time/Rings Parameters";
176 = "Custom Global Gravity";
}
third
{
0 = "Normal";
512 = "Wind/Current";
1024 = "Conveyor Belt";
1280 = "Speed Pad";
}
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

View file

@ -0,0 +1,38 @@
/************************************************************************\
Zone 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");
}
// THING TYPES
thingtypes
{
include("Includes\\SRB222_things.cfg");
}
//Default things filters
thingsfilters
{
include("Includes\\SRB222_misc.cfg", "thingsfilters");
}

View file

@ -0,0 +1,47 @@
/************************************************************************\
Zone 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 (UDMF)";
// 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_udmf");
include("Includes\\Game_SRB222.cfg");
// Script lumps detection
scriptlumpnames
{
include("Includes\\SRB222_misc.cfg", "scriptlumpnames");
}
// THING TYPES
thingtypes
{
include("Includes\\SRB222_things.cfg");
}
//Default things filters
thingsfilters
{
include("Includes\\SRB222_misc.cfg", "thingsfilters");
}
// ENUMERATIONS
// Each engine has its own additional thing types
// These are enumerated lists for linedef types and UDMF fields.
enums
{
// Basic game enums
include("Includes\\SRB222_misc.cfg", "enums");
}

View file

@ -127,13 +127,17 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
}
// Orientation
if ((bot->pflags & (PF_SPINNING|PF_STARTDASH)) || flymode == 2)
if (bot->pflags & (PF_SPINNING|PF_STARTDASH))
{
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT
}
else if (flymode == 2)
{
cmd->angleturn = sonic->player->cmd.angleturn - (tails->angle >> 16);
}
else
{
cmd->angleturn = (ang - tails->angle) >> FRACBITS;
cmd->angleturn = (ang - tails->angle) >> 16; // NOT FRACBITS DAMNIT
}
// ********
@ -222,7 +226,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
{
if (dist < followthres && dist > touchdist) // Do positioning
{
cmd->angleturn = (ang - tails->angle) >> FRACBITS;
cmd->angleturn = (ang - tails->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->forwardmove = 50;
spinmode = true;
}
@ -230,7 +234,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
{
if (!bmom && (!(bot->pflags & PF_SPINNING) || (bot->dashspeed && bot->pflags & PF_SPINNING)))
{
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT
spin = true;
}
spinmode = true;
@ -244,7 +248,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
if (bot->pflags & PF_SPINNING || !spin_last)
{
spin = true;
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->forwardmove = MAXPLMOVE;
spinmode = true;
}
@ -290,7 +294,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
else if (dist < followmin)
{
// Copy inputs
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT
bot->drawangle = ang;
cmd->forwardmove = 8 * pcmd->forwardmove / 10;
cmd->sidemove = 8 * pcmd->sidemove / 10;
@ -335,27 +339,6 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
jump_last = jump;
spin_last = spin;
// ********
// Thinkfly overlay
if (thinkfly)
{
if (!tails->hnext)
{
P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY));
if (tails->hnext)
{
P_SetTarget(&tails->hnext->target, tails);
P_SetTarget(&tails->hnext->hprev, tails);
P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR);
}
}
}
else if (tails->hnext && tails->hnext->type == MT_OVERLAY && tails->hnext->state == states+S_FLIGHTINDICATOR)
{
P_RemoveMobj(tails->hnext);
P_SetTarget(&tails->hnext, NULL);
}
// Turn the virtual keypresses into ticcmd_t.
B_KeysToTiccmd(tails, cmd, forward, backward, left, right, false, false, jump, spin);
@ -379,7 +362,7 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
}
// Bot AI isn't programmed in analog.
CV_SetValue(&cv_analog2, false);
CV_SetValue(&cv_analog[1], false);
#ifdef HAVE_BLUA
// Let Lua scripts build ticcmds
@ -565,3 +548,30 @@ void B_RespawnBot(INT32 playernum)
P_SetScale(tails, sonic->scale);
tails->destscale = sonic->destscale;
}
void B_HandleFlightIndicator(player_t *player)
{
mobj_t *tails = player->mo;
if (!tails)
return;
if (thinkfly && player->bot == 1 && tails->health)
{
if (!tails->hnext)
{
P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY));
if (tails->hnext)
{
P_SetTarget(&tails->hnext->target, tails);
P_SetTarget(&tails->hnext->hprev, tails);
P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR);
}
}
}
else if (tails->hnext && tails->hnext->type == MT_OVERLAY && tails->hnext->state == states+S_FLIGHTINDICATOR)
{
P_RemoveMobj(tails->hnext);
P_SetTarget(&tails->hnext, NULL);
}
}

View file

@ -15,3 +15,4 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
boolean B_CheckRespawn(player_t *player);
void B_MoveBlocked(player_t *player);
void B_RespawnBot(INT32 playernum);
void B_HandleFlightIndicator(player_t *player);

View file

@ -54,7 +54,7 @@ static void COM_Add_f(void);
static void CV_EnforceExecVersion(void);
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr);
static boolean CV_Command(void);
static consvar_t *CV_FindVar(const char *name);
consvar_t *CV_FindVar(const char *name);
static const char *CV_StringValue(const char *var_name);
static consvar_t *consvar_vars; // list of registered console variables
@ -1106,7 +1106,7 @@ static const char *cv_null_string = "";
* \return Pointer to the variable if found, or NULL.
* \sa CV_FindNetVar
*/
static consvar_t *CV_FindVar(const char *name)
consvar_t *CV_FindVar(const char *name)
{
consvar_t *cvar;
@ -2114,7 +2114,12 @@ void CV_SaveVariables(FILE *f)
// Silly hack for Min/Max vars
if (!strcmp(cvar->string, "MAX") || !strcmp(cvar->string, "MIN"))
{
if (cvar->flags & CV_FLOAT)
sprintf(stringtowrite, "%f", FIXED_TO_FLOAT(cvar->value));
else
sprintf(stringtowrite, "%d", cvar->value);
}
else
strcpy(stringtowrite, cvar->string);

View file

@ -20,6 +20,15 @@
// Command buffer & command execution
//===================================
/* Lua command registration flags. */
enum
{
COM_ADMIN = 1,
COM_SPLITSCREEN = 2,
COM_LOCAL = 4,
};
/* Command buffer flags. */
enum
{
COM_SAFE = 1,
@ -149,6 +158,9 @@ void CV_ToggleExecVersion(boolean enable);
// register a variable for use at the console
void CV_RegisterVar(consvar_t *variable);
// returns a console variable by name
consvar_t *CV_FindVar(const char *name);
// sets changed to 0 for every console variable
void CV_ClearChangedFlags(void);

View file

@ -611,11 +611,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->health = LONG(players[i].mo->health);
rsp->angle = (angle_t)LONG(players[i].mo->angle);
#ifdef ROTSPRITE
rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle);
#else
rsp->rollangle = 0;
#endif
rsp->x = LONG(players[i].mo->x);
rsp->y = LONG(players[i].mo->y);
rsp->z = LONG(players[i].mo->z);
@ -766,9 +762,7 @@ static void resynch_read_player(resynch_pak *rsp)
//At this point, the player should have a body, whether they were respawned or not.
P_UnsetThingPosition(players[i].mo);
players[i].mo->angle = (angle_t)LONG(rsp->angle);
#ifdef ROTSPRITE
players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle);
#endif
players[i].mo->eflags = (UINT16)SHORT(rsp->eflags);
players[i].mo->flags = LONG(rsp->flags);
players[i].mo->flags2 = LONG(rsp->flags2);
@ -1025,7 +1019,7 @@ static void SV_SendResynch(INT32 node)
netbuffer->packettype = PT_RESYNCHEND;
netbuffer->u.resynchend.randomseed = P_GetRandSeed();
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
resynch_write_ctf(&netbuffer->u.resynchend);
resynch_write_others(&netbuffer->u.resynchend);
@ -1271,8 +1265,12 @@ static boolean CL_SendJoin(void)
if (splitscreen || botingame)
localplayers++;
netbuffer->u.clientcfg.localplayers = localplayers;
netbuffer->u.clientcfg._255 = 255;
netbuffer->u.clientcfg.packetversion = PACKETVERSION;
netbuffer->u.clientcfg.version = VERSION;
netbuffer->u.clientcfg.subversion = SUBVERSION;
strncpy(netbuffer->u.clientcfg.application, SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application);
strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME);
strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME);
return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak));
@ -1283,15 +1281,20 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
UINT8 *p;
netbuffer->packettype = PT_SERVERINFO;
netbuffer->u.serverinfo._255 = 255;
netbuffer->u.serverinfo.packetversion = PACKETVERSION;
netbuffer->u.serverinfo.version = VERSION;
netbuffer->u.serverinfo.subversion = SUBVERSION;
strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION,
sizeof netbuffer->u.serverinfo.application);
// return back the time value so client can compute their ping
netbuffer->u.serverinfo.time = (tic_t)LONG(servertime);
netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers();
netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value;
netbuffer->u.serverinfo.gametype = (UINT8)gametype;
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
netbuffer->u.serverinfo.isdedicated = (UINT8)dedicated;
@ -1718,12 +1721,21 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
if (serverlistcount >= MAXSERVERLIST)
return; // list full
if (info->_255 != 255)
return;/* old packet format */
if (info->packetversion != PACKETVERSION)
return;/* old new packet format */
if (info->version != VERSION)
return; // Not same version.
if (info->subversion != SUBVERSION)
return; // Close, but no cigar.
if (strcmp(info->application, SRB2APPLICATION))
return;/* that's a different mod */
i = serverlistcount++;
}
@ -2111,12 +2123,9 @@ static void CL_ConnectToServer(boolean viams)
if (i != -1)
{
UINT8 num = serverlist[i].info.gametype;
const char *gametypestr = NULL;
char *gametypestr = serverlist[i].info.gametypename;
CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername);
if (num < NUMGAMETYPES)
gametypestr = Gametype_Names[num];
if (gametypestr)
gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0';
CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr);
CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100,
serverlist[i].info.version%100, serverlist[i].info.subversion);
@ -2430,7 +2439,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
}
}
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you!
// If in a special stage, redistribute the player's spheres across
@ -2486,6 +2495,17 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
(void)reason;
#endif
// don't look through someone's view who isn't there
if (playernum == displayplayer)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
// Reset player data
CL_ClearPlayer(playernum);
@ -2503,16 +2523,13 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
}
if (playernum == displayplayer)
displayplayer = consoleplayer; // don't look through someone's view who isn't there
#ifdef HAVE_BLUA
LUA_InvalidatePlayer(&players[playernum]);
#endif
if (G_TagGametype()) //Check if you still have a game. Location flexible. =P
P_CheckSurvivors();
else if (gametype == GT_RACE || gametype == GT_COMPETITION)
else if (gametyperules & GTR_RACE)
P_CheckRacers();
}
@ -3461,7 +3478,7 @@ void SV_StartSinglePlayerServer(void)
server = true;
netgame = false;
multiplayer = false;
gametype = GT_COOP;
G_SetGametype(GT_COOP);
// no more tic the game with this settings!
SV_StopServer();
@ -3507,6 +3524,12 @@ static void HandleConnect(SINT8 node)
if (bannednode && bannednode[node])
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server"));
else if (netbuffer->u.clientcfg._255 != 255 ||
netbuffer->u.clientcfg.packetversion != PACKETVERSION)
SV_SendRefuse(node, "Incompatible packet formats.");
else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application))
SV_SendRefuse(node, "Different SRB2 modifications\nare not compatible.");
else if (netbuffer->u.clientcfg.version != VERSION
|| netbuffer->u.clientcfg.subversion != SUBVERSION)
SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION));
@ -3629,6 +3652,10 @@ static void HandleServerInfo(SINT8 node)
const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE;
netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff);
netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0;
netbuffer->u.serverinfo.application
[sizeof netbuffer->u.serverinfo.application - 1] = '\0';
netbuffer->u.serverinfo.gametypename
[sizeof netbuffer->u.serverinfo.gametypename - 1] = '\0';
SL_InsertServer(&netbuffer->u.serverinfo, node);
}
@ -3740,7 +3767,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (client)
{
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype;
G_SetGametype(netbuffer->u.servercfg.gametype);
modifiedgame = netbuffer->u.servercfg.modifiedgame;
for (j = 0; j < MAXPLAYERS; j++)
adminplayers[j] = netbuffer->u.servercfg.adminplayers[j];
@ -4124,7 +4151,7 @@ static void HandlePacketFromPlayer(SINT8 node)
P_SetRandSeed(netbuffer->u.resynchend.randomseed);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
resynch_read_ctf(&netbuffer->u.resynchend);
resynch_read_others(&netbuffer->u.resynchend);
@ -4624,9 +4651,9 @@ static void Local_Maketic(INT32 realtics)
// and G_MapEventsToControls
if (!dedicated) rendergametic = gametic;
// translate inputs (keyboard/mouse/joystick) into game controls
G_BuildTiccmd(&localcmds, realtics);
G_BuildTiccmd(&localcmds, realtics, 1);
if (splitscreen || botingame)
G_BuildTiccmd2(&localcmds2, realtics);
G_BuildTiccmd(&localcmds2, realtics, 2);
localcmds.angleturn |= TICCMD_RECEIVED;
}

View file

@ -19,6 +19,16 @@
#include "tables.h"
#include "d_player.h"
/*
The 'packet version' may be used with packets whose
format is expected to change between versions.
This version is independent of the mod name, and standard
version and subversion. It should only account for the
basic fields of the packet, and change infrequently.
*/
#define PACKETVERSION 1
// Network play related stuff.
// There is a data struct that stores network
// communication related stuff, and another
@ -320,8 +330,13 @@ typedef struct {
#pragma warning(default : 4200)
#endif
#define MAXAPPLICATION 16
typedef struct
{
UINT8 _255;/* see serverinfo_pak */
UINT8 packetversion;
char application[MAXAPPLICATION];
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
UINT8 localplayers;
@ -334,11 +349,19 @@ typedef struct
// This packet is too large
typedef struct
{
/*
In the old packet, 'version' is the first field. Now that field is set
to 255 always, so older versions won't be confused with the new
versions or vice-versa.
*/
UINT8 _255;
UINT8 packetversion;
char application[MAXAPPLICATION];
UINT8 version;
UINT8 subversion;
UINT8 numberofplayer;
UINT8 maxplayer;
UINT8 gametype;
char gametypename[24];
UINT8 modifiedgame;
UINT8 cheatsenabled;
UINT8 isdedicated;

View file

@ -766,7 +766,7 @@ void D_StartTitle(void)
if (netgame)
{
if (gametype == GT_COOP)
if (gametyperules & GTR_CAMPAIGN)
{
G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat
@ -813,7 +813,7 @@ void D_StartTitle(void)
gameaction = ga_nothing;
displayplayer = consoleplayer = 0;
gametype = GT_COOP;
G_SetGametype(GT_COOP);
paused = false;
advancedemo = false;
F_InitMenuPresValues();
@ -832,7 +832,7 @@ void D_StartTitle(void)
CV_SetValue(&cv_usemouse, tutorialusemouse);
CV_SetValue(&cv_alwaysfreelook, tutorialfreelook);
CV_SetValue(&cv_mousemove, tutorialmousemove);
CV_SetValue(&cv_analog, tutorialanalog);
CV_SetValue(&cv_analog[0], tutorialanalog);
M_StartMessage("Do you want to \x82save the recommended \x82movement controls?\x80\n\nPress 'Y' or 'Enter' to confirm\nPress 'N' or any key to keep \nyour current controls",
M_TutorialSaveControlResponse, MM_YESNO);
}
@ -1474,14 +1474,14 @@ void D_SRB2Main(void)
if (newgametype == -1) // reached end of the list with no match
{
j = atoi(sgametype); // assume they gave us a gametype number, which is okay too
if (j >= 0 && j < NUMGAMETYPES)
if (j >= 0 && j < gametypecount)
newgametype = (INT16)j;
}
if (newgametype != -1)
{
j = gametype;
gametype = newgametype;
G_SetGametype(newgametype);
D_GameTypeChanged(j);
}
}
@ -1517,7 +1517,7 @@ void D_SRB2Main(void)
{
levelstarttic = gametic;
G_SetGamestate(GS_LEVEL);
if (!P_SetupLevel(false))
if (!P_LoadLevel(false))
I_Quit(); // fail so reset game stuff
}
}

View file

@ -327,6 +327,10 @@ consvar_t cv_numlaps = {"numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_con
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
// Point and time limits for every gametype
INT32 pointlimits[NUMGAMETYPES];
INT32 timelimits[NUMGAMETYPES];
// log elemental hazards -- not a netvar, is local to current player
consvar_t cv_hazardlog = {"hazardlog", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -381,6 +385,9 @@ char timedemo_csv_id[256];
boolean timedemo_quit;
INT16 gametype = GT_COOP;
UINT32 gametyperules = 0;
INT16 gametypecount = (GT_CTF + 1);
boolean splitscreen = false;
boolean circuitmap = false;
INT32 adminplayers[MAXPLAYERS];
@ -774,6 +781,10 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_fireaxis2);
CV_RegisterVar(&cv_firenaxis);
CV_RegisterVar(&cv_firenaxis2);
CV_RegisterVar(&cv_deadzone);
CV_RegisterVar(&cv_deadzone2);
CV_RegisterVar(&cv_digitaldeadzone);
CV_RegisterVar(&cv_digitaldeadzone2);
// filesrch.c
CV_RegisterVar(&cv_addons_option);
@ -812,20 +823,34 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_joyscale2);
// Analog Control
CV_RegisterVar(&cv_analog);
CV_RegisterVar(&cv_analog2);
CV_RegisterVar(&cv_useranalog);
CV_RegisterVar(&cv_useranalog2);
CV_RegisterVar(&cv_analog[0]);
CV_RegisterVar(&cv_analog[1]);
CV_RegisterVar(&cv_useranalog[0]);
CV_RegisterVar(&cv_useranalog[1]);
// deez New User eXperiences
CV_RegisterVar(&cv_directionchar);
CV_RegisterVar(&cv_directionchar2);
CV_RegisterVar(&cv_directionchar[0]);
CV_RegisterVar(&cv_directionchar[1]);
CV_RegisterVar(&cv_autobrake);
CV_RegisterVar(&cv_autobrake2);
// Ported from kart
CV_RegisterVar(&cv_deadzone);
CV_RegisterVar(&cv_deadzone2);
// hi here's some new controls
CV_RegisterVar(&cv_cam_shiftfacing[0]);
CV_RegisterVar(&cv_cam_shiftfacing[1]);
CV_RegisterVar(&cv_cam_turnfacing[0]);
CV_RegisterVar(&cv_cam_turnfacing[1]);
CV_RegisterVar(&cv_cam_turnfacingability[0]);
CV_RegisterVar(&cv_cam_turnfacingability[1]);
CV_RegisterVar(&cv_cam_turnfacingspindash[0]);
CV_RegisterVar(&cv_cam_turnfacingspindash[1]);
CV_RegisterVar(&cv_cam_turnfacinginput[0]);
CV_RegisterVar(&cv_cam_turnfacinginput[1]);
CV_RegisterVar(&cv_cam_centertoggle[0]);
CV_RegisterVar(&cv_cam_centertoggle[1]);
CV_RegisterVar(&cv_cam_lockedinput[0]);
CV_RegisterVar(&cv_cam_lockedinput[1]);
CV_RegisterVar(&cv_cam_lockonboss[0]);
CV_RegisterVar(&cv_cam_lockonboss[1]);
// s_sound.c
CV_RegisterVar(&cv_soundvolume);
@ -1130,7 +1155,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true;
// Can change skin during initial countdown.
if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)
if ((gametyperules & GTR_RACE) && leveltime < 4*TICRATE)
return true;
if (G_TagGametype())
@ -1494,9 +1519,9 @@ void SendWeaponPref(void)
buf[0] = 0;
if (cv_flipcam.value)
buf[0] |= 1;
if (cv_analog.value)
if (cv_analog[0].value && cv_directionchar[0].value != 2)
buf[0] |= 2;
if (cv_directionchar.value)
if (cv_directionchar[0].value == 1)
buf[0] |= 4;
if (cv_autobrake.value)
buf[0] |= 8;
@ -1510,9 +1535,9 @@ void SendWeaponPref2(void)
buf[0] = 0;
if (cv_flipcam2.value)
buf[0] |= 1;
if (cv_analog2.value)
if (cv_analog[1].value && cv_directionchar[1].value != 2)
buf[0] |= 2;
if (cv_directionchar2.value)
if (cv_directionchar[1].value == 1)
buf[0] |= 4;
if (cv_autobrake2.value)
buf[0] |= 8;
@ -1903,7 +1928,7 @@ static void Command_Map_f(void)
if (isdigit(gametypename[0]))
{
d = atoi(gametypename);
if (d >= 0 && d < NUMGAMETYPES)
if (d >= 0 && d < gametypecount)
newgametype = d;
else
{
@ -1911,7 +1936,7 @@ static void Command_Map_f(void)
"Gametype number %d is out of range. Use a number between"
" 0 and %d inclusive. ...Or just use the name. :v\n",
d,
NUMGAMETYPES-1);
gametypecount-1);
Z_Free(realmapname);
Z_Free(mapname);
return;
@ -1977,7 +2002,7 @@ static void Command_Map_f(void)
CV_SetValue(&cv_usemouse, tutorialusemouse);
CV_SetValue(&cv_alwaysfreelook, tutorialfreelook);
CV_SetValue(&cv_mousemove, tutorialmousemove);
CV_SetValue(&cv_analog, tutorialanalog);
CV_SetValue(&cv_analog[0], tutorialanalog);
}
tutorialmode = false; // warping takes us out of tutorial mode
@ -2030,8 +2055,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
lastgametype = gametype;
gametype = READUINT8(*cp);
G_SetGametype(gametype); // I fear putting that macro as an argument
if (gametype < 0 || gametype >= NUMGAMETYPES)
if (gametype < 0 || gametype >= gametypecount)
gametype = lastgametype;
else if (gametype != lastgametype)
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
@ -2376,7 +2402,7 @@ static void Command_Teamchange_f(void)
}
//additional check for hide and seek. Don't allow change of status after hidetime ends.
if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE))
if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE))
{
CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n"));
return;
@ -2473,7 +2499,7 @@ static void Command_Teamchange2_f(void)
}
//additional check for hide and seek. Don't allow change of status after hidetime ends.
if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE))
if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE))
{
CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n"));
return;
@ -2602,7 +2628,7 @@ static void Command_ServerTeamChange_f(void)
}
//additional check for hide and seek. Don't allow change of status after hidetime ends.
if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE))
if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE))
{
CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n"));
return;
@ -2691,6 +2717,16 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
return;
}
#ifdef HAVE_BLUA
// Don't switch team, just go away, please, go awaayyyy, aaauuauugghhhghgh
if (!LUAh_TeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled))
return;
#endif
//no status changes after hidetime
if ((gametyperules & GTR_HIDEFROZEN) && (leveltime >= (hidetime * TICRATE)))
error = true;
//Make sure that the right team number is sent. Keep in mind that normal clients cannot change to certain teams in certain gametypes.
switch (gametype)
{
@ -2845,7 +2881,15 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
//reset view if you are changed, or viewing someone who was changed.
if (playernum == consoleplayer || displayplayer == playernum)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
if (displayplayer != consoleplayer) // You're already viewing yourself. No big deal.
LUAh_ViewpointSwitch(&players[playernum], &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
if (G_GametypeHasTeams())
{
@ -3581,7 +3625,7 @@ static void Command_ShowGametype_f(void)
}
// get name string for current gametype
if (gametype >= 0 && gametype < NUMGAMETYPES)
if (gametype >= 0 && gametype < gametypecount)
gametypestr = Gametype_Names[gametype];
if (gametypestr)
@ -3643,7 +3687,7 @@ void ItemFinder_OnChange(void)
static void PointLimit_OnChange(void)
{
// Don't allow pointlimit in Single Player/Co-Op/Race!
if (server && Playing() && G_PlatformGametype())
if (server && Playing() && !(gametyperules & GTR_POINTLIMIT))
{
if (cv_pointlimit.value)
CV_StealthSetValue(&cv_pointlimit, 0);
@ -3682,7 +3726,7 @@ static void CoopStarposts_OnChange(void)
{
INT32 i;
if (!(netgame || multiplayer) || gametype != GT_COOP)
if (!(netgame || multiplayer) || !G_GametypeUsesCoopStarposts())
return;
switch (cv_coopstarposts.value)
@ -3737,7 +3781,7 @@ static void CoopLives_OnChange(void)
{
INT32 i;
if (!(netgame || multiplayer) || gametype != GT_COOP)
if (!(netgame || multiplayer) || !G_GametypeUsesCoopLives())
return;
switch (cv_cooplives.value)
@ -3806,7 +3850,7 @@ UINT32 timelimitintics = 0;
static void TimeLimit_OnChange(void)
{
// Don't allow timelimit in Single Player/Co-Op/Race!
if (server && Playing() && cv_timelimit.value != 0 && G_PlatformGametype())
if (server && Playing() && cv_timelimit.value != 0 && !(gametyperules & GTR_TIMELIMIT))
{
CV_SetValue(&cv_timelimit, 0);
return;
@ -3842,9 +3886,9 @@ void D_GameTypeChanged(INT32 lastgametype)
{
const char *oldgt = NULL, *newgt = NULL;
if (lastgametype >= 0 && lastgametype < NUMGAMETYPES)
if (lastgametype >= 0 && lastgametype < gametypecount)
oldgt = Gametype_Names[lastgametype];
if (gametype >= 0 && lastgametype < NUMGAMETYPES)
if (gametype >= 0 && lastgametype < gametypecount)
newgt = Gametype_Names[gametype];
if (oldgt && newgt)
@ -3898,11 +3942,20 @@ void D_GameTypeChanged(INT32 lastgametype)
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
default:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
CV_SetValue(&cv_timelimit, timelimits[gametype]);
CV_SetValue(&cv_pointlimit, pointlimits[gametype]);
}
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
}
}
else if (!multiplayer && !netgame)
{
gametype = GT_COOP;
G_SetGametype(GT_COOP);
// These shouldn't matter anymore
//CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue);
//CV_SetValue(&cv_itemrespawn, 0);
@ -3911,7 +3964,7 @@ void D_GameTypeChanged(INT32 lastgametype)
// reset timelimit and pointlimit in race/coop, prevent stupid cheats
if (server)
{
if (G_PlatformGametype())
if (!(gametyperules & GTR_POINTLIMIT))
{
if (cv_timelimit.value)
CV_SetValue(&cv_timelimit, 0);
@ -3929,6 +3982,7 @@ void D_GameTypeChanged(INT32 lastgametype)
// When swapping to a gametype that supports spectators,
// make everyone a spectator initially.
// Averted with GTR_NOSPECTATORSPAWN.
if (!splitscreen && (G_GametypeHasSpectators()))
{
INT32 i;
@ -3936,7 +3990,7 @@ void D_GameTypeChanged(INT32 lastgametype)
if (playeringame[i])
{
players[i].ctfteam = 0;
players[i].spectator = true;
players[i].spectator = (gametyperules & GTR_NOSPECTATORSPAWN) ? false : true;
}
}

View file

@ -22,6 +22,7 @@
#include "m_menu.h"
#include "m_misc.h"
#include "f_finale.h"
#include "y_inter.h"
#include "dehacked.h"
#include "st_stuff.h"
#include "i_system.h"
@ -76,6 +77,7 @@ static UINT16 get_mus(const char *word, UINT8 dehacked_mode);
static hudnum_t get_huditem(const char *word);
static menutype_t get_menutype(const char *word);
#ifndef HAVE_BLUA
static INT16 get_gametype(const char *word);
static powertype_t get_power(const char *word);
#endif
@ -590,6 +592,16 @@ static void readfreeslots(MYFILE *f)
} else
CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n");
}
else if (fastcmp(type, "TOL"))
{
if (lastcustomtol > 31)
CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n");
else
{
G_AddTOL((1<<lastcustomtol), word);
lastcustomtol++;
}
}
else
deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word);
}
@ -863,14 +875,12 @@ static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame)
strupr(word);
value = atoi(word2); // used for numerical settings
#ifdef ROTSPRITE
if (fastcmp(word, "XPIVOT"))
sprinfo->pivot[frame].x = value;
else if (fastcmp(word, "YPIVOT"))
sprinfo->pivot[frame].y = value;
else if (fastcmp(word, "ROTAXIS"))
sprinfo->pivot[frame].rotaxis = value;
#endif
else
{
f->curpos = lastline;
@ -1095,10 +1105,10 @@ static void readsprite2(MYFILE *f, INT32 num)
Z_Free(s);
}
static const struct {
const char *name;
const UINT16 flag;
} TYPEOFLEVEL[] = {
INT32 numtolinfo = NUMBASETOL;
UINT32 lastcustomtol = 13;
tolinfo_t TYPEOFLEVEL[NUMMAXTOL] = {
{"SOLO",TOL_SP},
{"SP",TOL_SP},
{"SINGLEPLAYER",TOL_SP},
@ -1114,8 +1124,6 @@ static const struct {
{"TAG",TOL_TAG},
{"CTF",TOL_CTF},
{"CUSTOM",TOL_CUSTOM},
{"2D",TOL_2D},
{"MARIO",TOL_MARIO},
{"NIGHTS",TOL_NIGHTS},
@ -1128,6 +1136,216 @@ static const struct {
{NULL, 0}
};
// copypasted from readPlayer :sleep:
static const char *const GAMETYPERULE_LIST[];
static void readgametype(MYFILE *f, char *gtname)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2, *word2lwr = NULL;
char *tmp;
INT32 i, j;
INT16 newgtidx = 0;
UINT32 newgtrules = 0;
UINT32 newgttol = 0;
INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0;
UINT8 newgtleftcolor = 0;
UINT8 newgtrightcolor = 0;
INT16 newgtrankingstype = -1;
int newgtinttype = 0;
char gtdescription[441];
char gtconst[MAXLINELEN];
// Empty strings.
gtdescription[0] = '\0';
gtconst[0] = '\0';
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
if (fastcmp(word, "DESCRIPTION"))
{
char *descr = NULL;
for (i = 0; i < MAXLINELEN-3; i++)
{
if (s[i] == '=')
{
descr = &s[i+2];
break;
}
}
if (descr)
{
strcpy(gtdescription, descr);
strcat(gtdescription, myhashfgets(descr, sizeof (gtdescription), f));
}
else
strcpy(gtdescription, "");
// For some reason, cutting the string did not work above. Most likely due to strcpy or strcat...
// It works down here, though.
{
INT32 numline = 0;
for (i = 0; i < MAXLINELEN-1; i++)
{
if (numline < 20 && gtdescription[i] == '\n')
numline++;
if (numline >= 20 || gtdescription[i] == '\0' || gtdescription[i] == '#')
break;
}
}
gtdescription[strlen(gtdescription)-1] = '\0';
gtdescription[i] = '\0';
continue;
}
word2 = strtok(NULL, " = ");
if (word2)
{
if (!word2lwr)
word2lwr = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
strcpy(word2lwr, word2);
strupr(word2);
}
else
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
// Game type rules
if (fastcmp(word, "RULES"))
{
// GTR_
newgtrules = (UINT32)get_number(word2);
}
// Identifier
else if (fastcmp(word, "IDENTIFIER"))
{
// GT_
strncpy(gtconst, word2, MAXLINELEN);
}
// Point and time limits
else if (fastcmp(word, "DEFAULTPOINTLIMIT"))
newgtpointlimit = (INT32)i;
else if (fastcmp(word, "DEFAULTTIMELIMIT"))
newgttimelimit = (INT32)i;
// Level platter
else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR"))
newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2);
else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR"))
newgtleftcolor = (UINT8)get_number(word2);
else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR"))
newgtrightcolor = (UINT8)get_number(word2);
// Rankings type
else if (fastcmp(word, "RANKINGTYPE"))
{
// Case insensitive
newgtrankingstype = (int)get_number(word2);
}
// Intermission type
else if (fastcmp(word, "INTERMISSIONTYPE"))
{
// Case sensitive
newgtinttype = (int)get_number(word2lwr);
}
// Type of level
else if (fastcmp(word, "TYPEOFLEVEL"))
{
if (i) // it's just a number
newgttol = (UINT32)i;
else
{
UINT16 tol = 0;
tmp = strtok(word2,",");
do {
for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fasticmp(tmp, TYPEOFLEVEL[i].name))
break;
if (!TYPEOFLEVEL[i].name)
deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp);
tol |= TYPEOFLEVEL[i].flag;
} while((tmp = strtok(NULL,",")) != NULL);
newgttol = tol;
}
}
// The SOC probably provided gametype rules as words,
// instead of using the RULES keyword.
// Like for example "NOSPECTATORSPAWN = TRUE".
// This is completely valid, and looks better anyway.
else
{
UINT32 wordgt = 0;
for (j = 0; GAMETYPERULE_LIST[j]; j++)
if (fastcmp(word, GAMETYPERULE_LIST[j])) {
if (!j) // GTR_CAMPAIGN
wordgt |= 1;
else
wordgt |= (1<<j);
if (i || word2[0] == 'T' || word2[0] == 'Y')
newgtrules |= wordgt;
break;
}
if (!wordgt)
deh_warning("readgametype %s: unknown word '%s'", gtname, word);
}
}
} while (!myfeof(f)); // finish when the line is empty
// Free strings.
Z_Free(s);
if (word2lwr)
Z_Free(word2lwr);
// Ran out of gametype slots
if (gametypecount == NUMGAMETYPEFREESLOTS)
{
CONS_Alert(CONS_WARNING, "Ran out of free gametype slots!\n");
return;
}
// Add the new gametype
newgtidx = G_AddGametype(newgtrules);
G_AddGametypeTOL(newgtidx, newgttol);
G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor);
// Not covered by G_AddGametype alone.
if (newgtrankingstype == -1)
newgtrankingstype = newgtidx;
gametyperankings[newgtidx] = newgtrankingstype;
intermissiontypes[newgtidx] = newgtinttype;
pointlimits[newgtidx] = newgtpointlimit;
timelimits[newgtidx] = newgttimelimit;
// Write the new gametype name.
Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname);
// Write the constant name.
if (gtconst[0] == '\0')
strncpy(gtconst, gtname, MAXLINELEN);
G_AddGametypeConstant(newgtidx, (const char *)gtconst);
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
}
static const struct {
const char *name;
const mobjtype_t type;
@ -1395,7 +1613,7 @@ static void readlevelheader(MYFILE *f, INT32 num)
else if (fastcmp(word, "TYPEOFLEVEL"))
{
if (i) // it's just a number
mapheaderinfo[num-1]->typeoflevel = (UINT16)i;
mapheaderinfo[num-1]->typeoflevel = (UINT32)i;
else
{
UINT16 tol = 0;
@ -1520,10 +1738,27 @@ static void readlevelheader(MYFILE *f, INT32 num)
deh_warning("Level header %d: invalid bonus type number %d", num, i);
}
// Title card
else if (fastcmp(word, "TITLECARDZIGZAG"))
{
deh_strlcpy(mapheaderinfo[num-1]->ltzzpatch, word2,
sizeof(mapheaderinfo[num-1]->ltzzpatch), va("Level header %d: title card zigzag patch name", num));
}
else if (fastcmp(word, "TITLECARDZIGZAGTEXT"))
{
deh_strlcpy(mapheaderinfo[num-1]->ltzztext, word2,
sizeof(mapheaderinfo[num-1]->ltzztext), va("Level header %d: title card zigzag text patch name", num));
}
else if (fastcmp(word, "TITLECARDACTDIAMOND"))
{
deh_strlcpy(mapheaderinfo[num-1]->ltactdiamond, word2,
sizeof(mapheaderinfo[num-1]->ltactdiamond), va("Level header %d: title card act diamond patch name", num));
}
else if (fastcmp(word, "MAXBONUSLIVES"))
mapheaderinfo[num-1]->maxbonuslives = (SINT8)i;
else if (fastcmp(word, "LEVELFLAGS"))
mapheaderinfo[num-1]->levelflags = (UINT8)i;
mapheaderinfo[num-1]->levelflags = (UINT16)i;
else if (fastcmp(word, "MENUFLAGS"))
mapheaderinfo[num-1]->menuflags = (UINT8)i;
@ -2673,11 +2908,9 @@ static actionpointer_t actionpointers[] =
{{A_SpawnObjectRelative}, "A_SPAWNOBJECTRELATIVE"},
{{A_ChangeAngleRelative}, "A_CHANGEANGLERELATIVE"},
{{A_ChangeAngleAbsolute}, "A_CHANGEANGLEABSOLUTE"},
#ifdef ROTSPRITE
{{A_RollAngle}, "A_ROLLANGLE"},
{{A_ChangeRollAngleRelative},"A_CHANGEROLLANGLERELATIVE"},
{{A_ChangeRollAngleAbsolute},"A_CHANGEROLLANGLEABSOLUTE"},
#endif
{{A_PlaySound}, "A_PLAYSOUND"},
{{A_FindTarget}, "A_FINDTARGET"},
{{A_FindTracer}, "A_FINDTRACER"},
@ -3197,6 +3430,8 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num));
else if (fastcmp(word, "CONDITIONSET"))
extraemblems[num-1].conditionset = (UINT8)value;
else if (fastcmp(word, "SHOWCONDITIONSET"))
extraemblems[num-1].showconditionset = (UINT8)value;
else
{
strupr(word2);
@ -3283,6 +3518,8 @@ static void readunlockable(MYFILE *f, INT32 num)
unlockables[num].height = (UINT16)i;
else if (fastcmp(word, "CONDITIONSET"))
unlockables[num].conditionset = (UINT8)i;
else if (fastcmp(word, "SHOWCONDITIONSET"))
unlockables[num].showconditionset = (UINT8)i;
else if (fastcmp(word, "NOCECHO"))
unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "NOCHECKLIST"))
@ -4155,6 +4392,7 @@ static void ignorelines(MYFILE *f)
static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char textline[MAXLINELEN];
char *word;
char *word2;
INT32 i;
@ -4175,6 +4413,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
char *traverse;
myfgets(s, MAXLINELEN, f);
memcpy(textline, s, MAXLINELEN);
if (s[0] == '\n' || s[0] == '#')
continue;
@ -4363,6 +4602,36 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
ignorelines(f);
}
}
else if (fastcmp(word, "GAMETYPE"))
{
// Get the gametype name from textline
// instead of word2, so that gametype names
// aren't allcaps
INT32 c;
for (c = 0; c < MAXLINELEN; c++)
{
if (textline[c] == '\0')
break;
if (textline[c] == ' ')
{
char *gtname = (textline+c+1);
if (gtname)
{
// remove funny characters
INT32 j;
for (j = 0; j < (MAXLINELEN - c); j++)
{
if (gtname[j] == '\0')
break;
if (gtname[j] < 32)
gtname[j] = '\0';
}
readgametype(f, gtname);
}
break;
}
}
}
else if (fastcmp(word, "CUTSCENE"))
{
if (i > 0 && i < 129)
@ -8404,6 +8673,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_NIGHTSCHIP", // NiGHTS Chip
"MT_FLINGNIGHTSCHIP", // Lost NiGHTS Chip
"MT_NIGHTSSTAR", // NiGHTS Star
"MT_FLINGNIGHTSSTAR", // Lost NiGHTS Star
"MT_NIGHTSSUPERLOOP",
"MT_NIGHTSDRILLREFILL",
"MT_NIGHTSHELPER",
@ -8561,9 +8831,11 @@ static const char *const MOBJEFLAG_LIST[] = {
"JUSTSTEPPEDDOWN", // used for ramp sectors
"VERTICALFLIP", // Vertically flip sprite/allow upside-down physics
"GOOWATER", // Goo water
"TOUCHLAVA", // The mobj is touching a lava block
"PUSHED", // Mobj was already pushed this tic
"SPRUNG", // Mobj was already sprung this tic
"APPLYPMOMZ", // Platform movement
"TRACERANGLE", // Compute and trigger on mobj angle relative to tracer
NULL
};
@ -8635,6 +8907,42 @@ static const char *const PLAYERFLAG_LIST[] = {
NULL // stop loop here.
};
static const char *const GAMETYPERULE_LIST[] = {
"CAMPAIGN",
"RINGSLINGER",
"SPECTATORS",
"LIVES",
"TEAMS",
"FIRSTPERSON",
"POWERSTONES",
"TEAMFLAGS",
"FRIENDLY",
"SPECIALSTAGES",
"EMERALDTOKENS",
"EMERALDHUNT",
"RACE",
"TAG",
"POINTLIMIT",
"TIMELIMIT",
"OVERTIME",
"HURTMESSAGES",
"FRIENDLYFIRE",
"STARTCOUNTDOWN",
"HIDEFROZEN",
"BLINDFOLDED",
"RESPAWNDELAY",
"PITYSHIELD",
"DEATHPENALTY",
"NOSPECTATORSPAWN",
"DEATHMATCHSTARTS",
"SPAWNINVUL",
"SPAWNENEMIES",
"ALLOWEXIT",
"NOTITLECARD",
"CUTSCENES",
NULL
};
#ifdef HAVE_BLUA
// Linedef flags
static const char *const ML_LIST[16] = {
@ -9050,21 +9358,6 @@ struct {
{"tr_trans90",tr_trans90},
{"NUMTRANSMAPS",NUMTRANSMAPS},
// Type of levels
{"TOL_SP",TOL_SP},
{"TOL_COOP",TOL_COOP},
{"TOL_COMPETITION",TOL_COMPETITION},
{"TOL_RACE",TOL_RACE},
{"TOL_MATCH",TOL_MATCH},
{"TOL_TAG",TOL_TAG},
{"TOL_CTF",TOL_CTF},
{"TOL_CUSTOM",TOL_CUSTOM},
{"TOL_2D",TOL_2D},
{"TOL_MARIO",TOL_MARIO},
{"TOL_NIGHTS",TOL_NIGHTS},
{"TOL_ERZ3",TOL_ERZ3},
{"TOL_XMAS",TOL_XMAS},
// Level flags
{"LF_SCRIPTISFILE",LF_SCRIPTISFILE},
{"LF_SPEEDMUSIC",LF_SPEEDMUSIC},
@ -9173,6 +9466,10 @@ struct {
{"SF_MULTIABILITY",SF_MULTIABILITY},
{"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION},
// Dashmode constants
{"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD},
{"DASHMODE_MAX",DASHMODE_MAX},
// Character abilities!
// Primary
{"CA_NONE",CA_NONE}, // now slot 0!
@ -9247,15 +9544,16 @@ struct {
{"DMG_CANHURTSELF",DMG_CANHURTSELF},
{"DMG_DEATHMASK",DMG_DEATHMASK},
// Gametypes, for use with global var "gametype"
{"GT_COOP",GT_COOP},
{"GT_COMPETITION",GT_COMPETITION},
{"GT_RACE",GT_RACE},
{"GT_MATCH",GT_MATCH},
{"GT_TEAMMATCH",GT_TEAMMATCH},
{"GT_TAG",GT_TAG},
{"GT_HIDEANDSEEK",GT_HIDEANDSEEK},
{"GT_CTF",GT_CTF},
// Intermission types
{"int_none",int_none},
{"int_coop",int_coop},
{"int_match",int_match},
{"int_teammatch",int_teammatch},
//{"int_tag",int_tag},
{"int_ctf",int_ctf},
{"int_spec",int_spec},
{"int_race",int_race},
{"int_comp",int_comp},
// Jingles (jingletype_t)
{"JT_NONE",JT_NONE},
@ -9428,12 +9726,10 @@ struct {
{"DI_SOUTHEAST",DI_SOUTHEAST},
{"NUMDIRS",NUMDIRS},
#ifdef ROTSPRITE
// Sprite rotation axis (rotaxis_t)
{"ROTAXIS_X",ROTAXIS_X},
{"ROTAXIS_Y",ROTAXIS_Y},
{"ROTAXIS_Z",ROTAXIS_Z},
#endif
// Buttons (ticcmd_t)
{"BT_WEAPONMASK",BT_WEAPONMASK}, //our first four bits.
@ -9450,6 +9746,11 @@ struct {
{"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable
{"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable
// Lua command registration flags
{"COM_ADMIN",COM_ADMIN},
{"COM_SPLITSCREEN",COM_SPLITSCREEN},
{"COM_LOCAL",COM_LOCAL},
// cvflags_t
{"CV_SAVE",CV_SAVE},
{"CV_CALL",CV_CALL},
@ -9549,7 +9850,7 @@ struct {
};
static mobjtype_t get_mobjtype(const char *word)
{ // Returns the vlaue of MT_ enumerations
{ // Returns the value of MT_ enumerations
mobjtype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
@ -9701,8 +10002,22 @@ static menutype_t get_menutype(const char *word)
}
#ifndef HAVE_BLUA
static INT16 get_gametype(const char *word)
{ // Returns the value of GT_ enumerations
INT16 i;
if (*word >= '0' && *word <= '9')
return atoi(word);
if (fastncmp("GT_",word,3))
word += 3; // take off the GT_
for (i = 0; i < NUMGAMETYPES; i++)
if (fastcmp(word, Gametype_ConstantNames[i]+3))
return i;
deh_warning("Couldn't find gametype named 'GT_%s'",word);
return GT_COOP;
}
static powertype_t get_power(const char *word)
{ // Returns the vlaue of pw_ enumerations
{ // Returns the value of pw_ enumerations
powertype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
@ -9896,11 +10211,42 @@ static fixed_t find_const(const char **rword)
free(word);
return r;
}
else if (fastncmp("MN_",word,4)) {
else if (fastncmp("MN_",word,3)) {
r = get_menutype(word);
free(word);
return r;
}
else if (fastncmp("GT_",word,4)) {
r = get_gametype(word);
free(word);
return r;
}
else if (fastncmp("GTR_", word, 4)) {
char *p = word+4;
for (i = 0; GAMETYPERULE_LIST[i]; i++)
if (fastcmp(p, GAMETYPERULE_LIST[i])) {
free(word);
return (1<<i);
}
// Not found error
const_warning("game type rule",word);
free(word);
return 0;
}
else if (fastncmp("TOL_", word, 4)) {
char *p = word+4;
for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fastcmp(p, TYPEOFLEVEL[i].name)) {
free(word);
return TYPEOFLEVEL[i].flag;
}
// Not found error
const_warning("typeoflevel",word);
free(word);
return 0;
}
else if (fastncmp("HUD_",word,4)) {
r = get_huditem(word);
free(word);
@ -10110,6 +10456,20 @@ static inline int lib_freeslot(lua_State *L)
}
r++;
}
else if (fastcmp(type, "TOL"))
{
if (lastcustomtol > 31)
CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n");
else
{
UINT32 newtol = (1<<lastcustomtol);
CONS_Printf("TypeOfLevel TOL_%s allocated.\n",word);
G_AddTOL(newtol, word);
lua_pushinteger(L, newtol);
lastcustomtol++;
r++;
}
}
Z_Free(s);
lua_remove(L, 1);
continue;
@ -10214,6 +10574,36 @@ static inline int lib_getenum(lua_State *L)
if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("GT_", word, 3)) {
p = word;
for (i = 0; Gametype_ConstantNames[i]; i++)
if (fastcmp(p, Gametype_ConstantNames[i])) {
lua_pushinteger(L, i);
return 1;
}
if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("GTR_", word, 4)) {
p = word+4;
for (i = 0; GAMETYPERULE_LIST[i]; i++)
if (fastcmp(p, GAMETYPERULE_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i));
return 1;
}
if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("TOL_", word, 4)) {
p = word+4;
for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fastcmp(p, TYPEOFLEVEL[i].name)) {
lua_pushinteger(L, TYPEOFLEVEL[i].flag);
return 1;
}
if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("ML_", word, 3)) {
p = word+3;
for (i = 0; i < 16; i++)
@ -10451,126 +10841,7 @@ static inline int lib_getenum(lua_State *L)
// DYNAMIC variables too!!
// Try not to add anything that would break netgames or timeattack replays here.
// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
if (fastcmp(word,"gamemap")) {
lua_pushinteger(L, gamemap);
return 1;
} else if (fastcmp(word,"maptol")) {
lua_pushinteger(L, maptol);
return 1;
} else if (fastcmp(word,"ultimatemode")) {
lua_pushboolean(L, ultimatemode != 0);
return 1;
} else if (fastcmp(word,"mariomode")) {
lua_pushboolean(L, mariomode != 0);
return 1;
} else if (fastcmp(word,"twodlevel")) {
lua_pushboolean(L, twodlevel != 0);
return 1;
} else if (fastcmp(word,"circuitmap")) {
lua_pushboolean(L, circuitmap);
return 1;
} else if (fastcmp(word,"netgame")) {
lua_pushboolean(L, netgame);
return 1;
} else if (fastcmp(word,"multiplayer")) {
lua_pushboolean(L, multiplayer);
return 1;
} else if (fastcmp(word,"modeattacking")) {
lua_pushboolean(L, modeattacking);
return 1;
} else if (fastcmp(word,"splitscreen")) {
lua_pushboolean(L, splitscreen);
return 1;
} else if (fastcmp(word,"gamecomplete")) {
lua_pushboolean(L, gamecomplete);
return 1;
} else if (fastcmp(word,"devparm")) {
lua_pushboolean(L, devparm);
return 1;
} else if (fastcmp(word,"modifiedgame")) {
lua_pushboolean(L, modifiedgame && !savemoddata);
return 1;
} else if (fastcmp(word,"menuactive")) {
lua_pushboolean(L, menuactive);
return 1;
} else if (fastcmp(word,"paused")) {
lua_pushboolean(L, paused);
return 1;
} else if (fastcmp(word,"titlemap")) {
lua_pushinteger(L, titlemap);
return 1;
} else if (fastcmp(word,"titlemapinaction")) {
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
return 1;
} else if (fastcmp(word,"gametype")) {
lua_pushinteger(L, gametype);
return 1;
} else if (fastcmp(word,"leveltime")) {
lua_pushinteger(L, leveltime);
return 1;
} else if (fastcmp(word,"curWeather")) {
lua_pushinteger(L, curWeather);
return 1;
} else if (fastcmp(word,"globalweather")) {
lua_pushinteger(L, globalweather);
return 1;
} else if (fastcmp(word,"levelskynum")) {
lua_pushinteger(L, levelskynum);
return 1;
} else if (fastcmp(word,"globallevelskynum")) {
lua_pushinteger(L, globallevelskynum);
return 1;
} else if (fastcmp(word,"mapmusname")) {
lua_pushstring(L, mapmusname);
return 1;
} else if (fastcmp(word,"mapmusflags")) {
lua_pushinteger(L, mapmusflags);
return 1;
} else if (fastcmp(word,"mapmusposition")) {
lua_pushinteger(L, mapmusposition);
return 1;
// local player variables, by popular request
} else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1)
if (consoleplayer < 0 || !playeringame[consoleplayer])
return 0;
LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1)
if (displayplayer < 0 || !playeringame[displayplayer])
return 0;
LUA_PushUserdata(L, &players[displayplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen
if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer])
return 0;
LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER);
return 1;
// end local player variables
} else if (fastcmp(word,"server")) {
if ((!multiplayer || !netgame) && !playeringame[serverplayer])
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array.
LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)");
if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer))
return 0;
LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);
return 1;
} else if (fastcmp(word,"gravity")) {
lua_pushinteger(L, gravity);
return 1;
} else if (fastcmp(word,"VERSIONSTRING")) {
lua_pushstring(L, VERSIONSTRING);
return 1;
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
}
return 0;
return LUA_PushGlobals(L, word);
}
int LUA_EnumLib(lua_State *L)
@ -10637,6 +10908,8 @@ static int lib_getActionName(lua_State *L)
return luaL_typerror(L, 1, "action userdata or Lua function");
}
int LUA_SOCLib(lua_State *L)
{
lua_register(L,"freeslot",lib_freeslot);

View file

@ -130,6 +130,9 @@ extern FILE *logstream;
extern char logfilename[1024];
#endif
/* A mod name to further distinguish versions. */
#define SRB2APPLICATION "SRB2"
//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
#ifdef DEVELOP
#define VERSION 0 // Game version
@ -461,6 +464,8 @@ extern void *(*M_Memcpy)(void* dest, const void* src, size_t n) FUNCNONNULL;
char *va(const char *format, ...) FUNCPRINTF;
char *M_GetToken(const char *inputString);
void M_UnGetToken(void);
UINT32 M_GetTokenPos(void);
void M_SetTokenPos(UINT32 newPos);
char *sizeu1(size_t num);
char *sizeu2(size_t num);
char *sizeu3(size_t num);
@ -629,7 +634,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Sprite rotation
#define ROTSPRITE
#define ROTANGLES 24 // Needs to be a divisor of 360 (45, 60, 90, 120...)
#define ROTANGLES 72 // Needs to be a divisor of 360 (45, 60, 90, 120...)
#define ROTANGDIFF (360 / ROTANGLES)
/// PNG support

View file

@ -39,7 +39,7 @@ extern UINT32 mapmusposition;
#define MUSIC_FORCERESET 0x4000 // -*--------------
// Use other bits if necessary.
extern INT16 maptol;
extern UINT32 maptol;
extern UINT8 globalweather;
extern INT32 curWeather;
extern INT32 cursaveslot;
@ -84,6 +84,9 @@ extern boolean addedtogame; // true after the server has added you
extern boolean multiplayer;
extern INT16 gametype;
extern UINT32 gametyperules;
extern INT16 gametypecount;
extern boolean splitscreen;
extern boolean circuitmap; // Does this level have 'circuit mode'?
extern boolean fromlevelselect;
@ -137,7 +140,7 @@ extern INT32 tutorialgcs; // which control scheme is loaded?
extern INT32 tutorialusemouse; // store cv_usemouse user value
extern INT32 tutorialfreelook; // store cv_alwaysfreelook user value
extern INT32 tutorialmousemove; // store cv_mousemove user value
extern INT32 tutorialanalog; // store cv_analog user value
extern INT32 tutorialanalog; // store cv_analog[0] user value
extern boolean looptitle;
@ -284,7 +287,7 @@ typedef struct
char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
char subttl[33]; ///< Subtitle for level
UINT8 actnum; ///< Act number or 0 for none.
UINT16 typeoflevel; ///< Combination of typeoflevel flags.
UINT32 typeoflevel; ///< Combination of typeoflevel flags.
INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end.
char musname[7]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
@ -310,12 +313,17 @@ typedef struct
SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.)
SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.)
UINT8 levelflags; ///< LF_flags: merged booleans into one UINT8 for space, see below
UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below
UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus
char selectheading[22]; ///< Level select heading. Allows for controllable grouping.
UINT16 startrings; ///< Number of rings players start with.
// Title card.
char ltzzpatch[8]; ///< Zig zag patch.
char ltzztext[8]; ///< Zig zag text.
char ltactdiamond[8]; ///< Act diamond.
// Freed animals stuff.
UINT8 numFlickies; ///< Internal. For freed flicky support.
mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
@ -361,6 +369,73 @@ typedef struct
extern mapheader_t* mapheaderinfo[NUMMAPS];
// Gametypes
#define NUMGAMETYPEFREESLOTS 128
enum GameType
{
GT_COOP = 0, // also used in single player
GT_COMPETITION, // Classic "Race"
GT_RACE,
GT_MATCH,
GT_TEAMMATCH,
GT_TAG,
GT_HIDEANDSEEK,
GT_CTF, // capture the flag
GT_FIRSTFREESLOT,
GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1,
NUMGAMETYPES
};
// If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c
// Gametype rules
enum GameTypeRules
{
GTR_CAMPAIGN = 1, // Linear Co-op map progression, don't allow random maps
GTR_RINGSLINGER = 1<<1, // Outside of Co-op, Competition, and Race (overriden by cv_ringslinger)
GTR_SPECTATORS = 1<<2, // Outside of Co-op, Competition, and Race
GTR_LIVES = 1<<3, // Co-op and Competition
GTR_TEAMS = 1<<4, // Team Match, CTF
GTR_FIRSTPERSON = 1<<5, // First person camera
GTR_POWERSTONES = 1<<6, // Power stones (Match and CTF)
GTR_TEAMFLAGS = 1<<7, // Gametype has team flags (CTF)
GTR_FRIENDLY = 1<<8, // Co-op
GTR_SPECIALSTAGES = 1<<9, // Allow special stages
GTR_EMERALDTOKENS = 1<<10, // Spawn emerald tokens
GTR_EMERALDHUNT = 1<<11, // Emerald Hunt
GTR_RACE = 1<<12, // Race and Competition
GTR_TAG = 1<<13, // Tag and Hide and Seek
GTR_POINTLIMIT = 1<<14, // Ringslinger point limit
GTR_TIMELIMIT = 1<<15, // Ringslinger time limit
GTR_OVERTIME = 1<<16, // Allow overtime
GTR_HURTMESSAGES = 1<<17, // Hit and death messages
GTR_FRIENDLYFIRE = 1<<18, // Always allow friendly fire
GTR_STARTCOUNTDOWN = 1<<19, // Hide time countdown (Tag and Hide and Seek)
GTR_HIDEFROZEN = 1<<20, // Frozen after hide time (Hide and Seek, but not Tag)
GTR_BLINDFOLDED = 1<<21, // Blindfolded view (Tag and Hide and Seek)
GTR_RESPAWNDELAY = 1<<22, // Respawn delay
GTR_PITYSHIELD = 1<<23, // Award pity shield
GTR_DEATHPENALTY = 1<<24, // Death score penalty
GTR_NOSPECTATORSPAWN = 1<<25, // Use with GTR_SPECTATORS, spawn in the map instead of with the spectators
GTR_DEATHMATCHSTARTS = 1<<26, // Use deathmatch starts
GTR_SPAWNINVUL = 1<<27, // Babysitting deterrent
GTR_SPAWNENEMIES = 1<<28, // Spawn enemies
GTR_ALLOWEXIT = 1<<29, // Allow exit sectors
GTR_NOTITLECARD = 1<<30, // Don't show the title card
GTR_CUTSCENES = 1<<31, // Play cutscenes, ending, credits, and evaluation
};
// String names for gametypes
extern const char *Gametype_Names[NUMGAMETYPES];
extern const char *Gametype_ConstantNames[NUMGAMETYPES];
// Point and time limits for every gametype
extern INT32 pointlimits[NUMGAMETYPES];
extern INT32 timelimits[NUMGAMETYPES];
enum TypeOfLevel
{
TOL_SP = 0x01, ///< Single Player
@ -376,36 +451,26 @@ enum TypeOfLevel
TOL_CTF = 0x40, ///< Capture the Flag
// CTF default = 64
TOL_CUSTOM = 0x80, ///< Custom (Lua-scripted, etc.)
// 0x80 was here
TOL_2D = 0x0100, ///< 2D
TOL_MARIO = 0x0200, ///< Mario
TOL_NIGHTS = 0x0400, ///< NiGHTS
TOL_ERZ3 = 0x0800, ///< ERZ3
TOL_XMAS = 0x1000 ///< Christmas NiGHTS
TOL_XMAS = 0x1000, ///< Christmas NiGHTS
};
// Gametypes
enum GameType
#define NUMBASETOL 18
#define NUMMAXTOL (18 + NUMGAMETYPEFREESLOTS)
typedef struct
{
GT_COOP = 0, // also used in single player
GT_COMPETITION, // Classic "Race"
GT_RACE,
GT_MATCH,
GT_TEAMMATCH,
GT_TAG,
GT_HIDEANDSEEK,
GT_CTF, // capture the flag
NUMGAMETYPES
};
// If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c
// String names for gametypes
extern const char *Gametype_Names[NUMGAMETYPES];
const char *name;
UINT32 flag;
} tolinfo_t;
extern tolinfo_t TYPEOFLEVEL[NUMMAXTOL];
extern INT32 numtolinfo;
extern UINT32 lastcustomtol;
extern tic_t totalplaytime;

View file

@ -2547,7 +2547,7 @@ void F_StartTitleScreen(void)
camera.x = startpos->x << FRACBITS;
camera.y = startpos->y << FRACBITS;
camera.subsector = R_PointInSubsector(camera.x, camera.y);
camera.z = camera.subsector->sector->floorheight + ((startpos->options >> ZSHIFT) << FRACBITS);
camera.z = camera.subsector->sector->floorheight + (startpos->z << FRACBITS);
camera.angle = (startpos->angle % 360)*ANG1;
camera.aiming = 0;
}
@ -3790,7 +3790,7 @@ void F_ContinueDrawer(void)
sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\
sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\
patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH);\
V_DrawFixedPatch((dx), (dy), FRACUNIT, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\
V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\
}
if (offsy < 0)

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2013-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2019 by Sonic Team Junior.
//
// This program is free software distributed under the

File diff suppressed because it is too large Load diff

View file

@ -68,15 +68,37 @@ extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime,
extern consvar_t cv_crosshair, cv_crosshair2;
extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_chasefreelook, cv_mousemove;
extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_chasefreelook2, cv_mousemove2;
extern consvar_t cv_useranalog, cv_useranalog2;
extern consvar_t cv_analog, cv_analog2;
extern consvar_t cv_directionchar, cv_directionchar2;
extern consvar_t cv_useranalog[2], cv_analog[2];
extern consvar_t cv_directionchar[2];
typedef enum {
CS_LEGACY,
CS_LMAOGALOG,
CS_STANDARD,
CS_SIMPLE = CS_LMAOGALOG|CS_STANDARD,
} controlstyle_e;
#define G_ControlStyle(ssplayer) (cv_directionchar[(ssplayer)-1].value == 3 ? CS_LMAOGALOG : ((cv_analog[(ssplayer)-1].value ? CS_LMAOGALOG : 0) | (cv_directionchar[(ssplayer)-1].value ? CS_STANDARD : 0)))
#define P_ControlStyle(player) ((((player)->pflags & PF_ANALOGMODE) ? CS_LMAOGALOG : 0) | (((player)->pflags & PF_DIRECTIONCHAR) ? CS_STANDARD : 0))
extern consvar_t cv_autobrake, cv_autobrake2;
extern consvar_t cv_deadzone, cv_deadzone2;
extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis;
extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2;
extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis,cv_deadzone,cv_digitaldeadzone;
extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2,cv_deadzone2,cv_digitaldeadzone2;
extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest;
// hi here's some new controls
extern consvar_t cv_cam_shiftfacing[2], cv_cam_turnfacing[2],
cv_cam_turnfacingability[2], cv_cam_turnfacingspindash[2], cv_cam_turnfacinginput[2],
cv_cam_centertoggle[2], cv_cam_lockedinput[2], cv_cam_lockonboss[2];
typedef enum
{
LOCK_BOSS = 1<<0,
LOCK_ENEMY = 1<<1,
LOCK_INTERESTS = 1<<2,
} lockassist_e;
// mouseaiming (looking up/down with the mouse or keyboard)
#define KB_LOOKSPEED (1<<25)
#define MAXPLMOVE (50)
@ -84,8 +106,10 @@ extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_g
// build an internal map name MAPxx from map number
const char *G_BuildMapName(INT32 map);
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics);
void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics);
extern boolean ticcmd_centerviewdown[2]; // For simple controls, lock the camera behind the player
extern mobj_t *ticcmd_ztargetfocus[2]; // Locking onto an object?
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer);
// copy ticcmd_t to and fro the normal way
ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n);
@ -146,6 +170,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar,
void G_DoLoadLevel(boolean resetplayer);
void G_StartTitleCard(void);
void G_PreLevelTitleCard(void);
boolean G_IsTitleCardAvailable(void);
void G_DeferedPlayDemo(const char *demo);
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
@ -205,14 +230,29 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill);
void G_StopDemo(void);
boolean G_CheckDemoStatus(void);
extern UINT32 gametypedefaultrules[NUMGAMETYPES];
extern UINT32 gametypetol[NUMGAMETYPES];
extern INT16 gametyperankings[NUMGAMETYPES];
void G_SetGametype(INT16 gametype);
INT16 G_AddGametype(UINT32 rules);
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst);
void G_UpdateGametypeSelections(void);
void G_AddTOL(UINT32 newtol, const char *tolname);
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol);
void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor);
INT32 G_GetGametypeByName(const char *gametypestr);
boolean G_IsSpecialStage(INT32 mapnum);
boolean G_GametypeUsesLives(void);
boolean G_GametypeUsesCoopLives(void);
boolean G_GametypeUsesCoopStarposts(void);
boolean G_GametypeHasTeams(void);
boolean G_GametypeHasSpectators(void);
boolean G_RingSlingerGametype(void);
boolean G_PlatformGametype(void);
boolean G_TagGametype(void);
boolean G_CompetitionGametype(void);
boolean G_EnoughPlayersFinished(void);
void G_ExitLevel(void);
void G_NextLevel(void);

View file

@ -132,6 +132,7 @@ extern INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; //
extern INT32 gamecontrolbisdefault[num_gamecontrolschemes][num_gamecontrols][2];
#define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]])
#define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]])
#define PLAYERINPUTDOWN(p, gc) ((p) == 2 ? PLAYER2INPUTDOWN(gc) : PLAYER1INPUTDOWN(gc))
#define num_gcl_tutorial_check 6
#define num_gcl_tutorial_used 8

View file

@ -449,8 +449,12 @@ static poly_t *CutOutSubsecPoly(seg_t *lseg, INT32 count, poly_t *poly)
// for each seg of the subsector
for (; count--; lseg++)
{
//x,y,dx,dy (like a divline)
line_t *line = lseg->linedef;
if (lseg->glseg)
continue;
//x,y,dx,dy (like a divline)
p1.x = FIXED_TO_FLOAT(lseg->side ? line->v2->x : line->v1->x);
p1.y = FIXED_TO_FLOAT(lseg->side ? line->v2->y : line->v1->y);
p2.x = FIXED_TO_FLOAT(lseg->side ? line->v1->x : line->v2->x);

View file

@ -122,11 +122,11 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
if (mipmap->colormap)
texel = mipmap->colormap[texel];
// transparent pixel
if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)
alpha = 0x00;
else
// If the mipmap is chromakeyed, check if the texel's color
// is equivalent to the chroma key's color index.
alpha = 0xff;
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
alpha = 0x00;
// hope compiler will get this switch out of the loops (dreams...)
// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
@ -654,7 +654,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex)
#ifndef NO_PNG_LUMPS
if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false);
realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL);
else
#endif
#ifdef WALLFLATS
@ -698,7 +698,7 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm
// lump is a png so convert it
size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum);
if ((patch != NULL) && R_IsLumpPNG((const UINT8 *)patch, len))
patch = R_PNGToPatch((const UINT8 *)patch, len, NULL, true);
patch = R_PNGToPatch((const UINT8 *)patch, len, NULL);
#endif
// don't do it twice (like a cache)
@ -1324,23 +1324,6 @@ GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum)
return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
}
#ifdef ROTSPRITE
GLPatch_t *HWR_GetCachedGLRotSprite(aatree_t *hwrcache, UINT16 rollangle, patch_t *rawpatch)
{
GLPatch_t *grpatch;
if (!(grpatch = M_AATreeGet(hwrcache, rollangle)))
{
grpatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL);
grpatch->rawpatch = rawpatch;
grpatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL);
M_AATreeSet(hwrcache, rollangle, grpatch);
}
return grpatch;
}
#endif
// Need to do this because they aren't powers of 2
static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight,
lumpnum_t fademasklumpnum, UINT16 fmwidth, UINT16 fmheight)

View file

@ -72,6 +72,7 @@
#include "../v_video.h"
#include "hw_clip.h"
#include "hw_glob.h"
#include "../r_main.h"
#include "../r_state.h"
#include "../tables.h"
#include "r_opengl/r_opengl.h"
@ -328,7 +329,7 @@ angle_t gld_FrustumAngle(void)
// NEWCLIP TODO: SRB2CBTODO: make a global render_fov for this function
float render_fov = FIXED_TO_FLOAT(cv_grfov.value);
float render_fov = FIXED_TO_FLOAT(cv_fov.value);
float render_fovratio = (float)BASEVIDWIDTH / (float)BASEVIDHEIGHT; // SRB2CBTODO: NEWCLIPTODO: Is this right?
float render_multiplier = 64.0f / render_fovratio / RMUL;

View file

@ -115,13 +115,11 @@ typedef struct
FLOAT fovxangle, fovyangle;
UINT8 splitscreen;
boolean flip; // screenflip
#ifdef ROTSPRITE
boolean roll;
SINT8 rollflip;
FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ
UINT8 rotaxis;
FLOAT centerx, centery;
#endif
#ifdef USE_FTRANSFORM_MIRROR
boolean mirror; // SRB2Kart: Encore Mode
#endif

View file

@ -113,9 +113,6 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum);
void HWR_SetPalette(RGBA_t *palette);
GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump);
GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum);
#ifdef ROTSPRITE
GLPatch_t *HWR_GetCachedGLRotSprite(aatree_t *hwrcache, UINT16 rollangle, patch_t *rawpatch);
#endif
void HWR_GetFadeMask(lumpnum_t fademasklumpnum);
// --------

View file

@ -1026,6 +1026,34 @@ static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
}
#endif
static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y)
{
INT16 finallight = lightnum;
if (cv_grfakecontrast.value != 0)
{
const UINT8 contrast = 8;
fixed_t extralight = 0;
if (v1y == v2y)
extralight = -contrast;
else if (v1x == v2x)
extralight = contrast;
if (extralight != 0)
{
finallight += extralight;
if (finallight < 0)
finallight = 0;
if (finallight > 255)
finallight = 255;
}
}
return (FUINT)finallight;
}
//
// HWR_SplitWall
//
@ -1044,19 +1072,20 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
float endpegt, endpegb, endpegmul;
float endheight = 0.0f, endbheight = 0.0f;
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
// use this as a temp var to store P_GetZAt's return value each time
fixed_t temp;
#endif
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
INT32 solid, i;
lightlist_t * list = sector->lightlist;
const UINT8 alpha = Surf->FlatColor.s.alpha;
FUINT lightnum = sector->lightlevel;
FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
extracolormap_t *colormap = NULL;
realtop = top = wallVerts[3].y;
@ -1086,12 +1115,12 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
{
if (pfloor && (pfloor->flags & FF_FOG))
{
lightnum = pfloor->master->frontsector->lightlevel;
lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y);
colormap = pfloor->master->frontsector->extra_colormap;
}
else
{
lightnum = *list[i].lightlevel;
lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y);
colormap = *list[i].extra_colormap;
}
}
@ -1395,7 +1424,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT));
}
lightnum = gr_frontsector->lightlevel;
lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
colormap = gr_frontsector->extra_colormap;
if (gr_frontsector)
@ -2150,7 +2179,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
blendmode = PF_Fog|PF_NoTexture;
lightnum = rover->master->frontsector->lightlevel;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
colormap = rover->master->frontsector->extra_colormap;
if (rover->master->frontsector->extra_colormap)
@ -2270,7 +2299,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
blendmode = PF_Fog|PF_NoTexture;
lightnum = rover->master->frontsector->lightlevel;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
colormap = rover->master->frontsector->extra_colormap;
if (rover->master->frontsector->extra_colormap)
@ -3771,10 +3800,15 @@ static void HWR_Subsector(size_t num)
while (count--)
{
if (!line->glseg
#ifdef POLYOBJECTS
if (!line->polyseg) // ignore segs that belong to polyobjects
&& !line->polyseg // ignore segs that belong to polyobjects
#endif
)
{
HWR_AddLine(line);
}
line++;
}
}
@ -5113,7 +5147,12 @@ void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boo
planeinfo[numplanes].isceiling = isceiling;
planeinfo[numplanes].fixedheight = fixedheight;
if (planecolormap && (planecolormap->fog & 1))
planeinfo[numplanes].lightlevel = lightlevel;
else
planeinfo[numplanes].lightlevel = 255;
planeinfo[numplanes].levelflat = levelflat;
planeinfo[numplanes].xsub = xsub;
planeinfo[numplanes].alpha = alpha;
@ -5145,7 +5184,12 @@ void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polyse
polyplaneinfo[numpolyplanes].isceiling = isceiling;
polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
if (planecolormap && (planecolormap->fog & 1))
polyplaneinfo[numpolyplanes].lightlevel = lightlevel;
else
polyplaneinfo[numpolyplanes].lightlevel = 255;
polyplaneinfo[numpolyplanes].levelflat = levelflat;
polyplaneinfo[numpolyplanes].polysector = polysector;
polyplaneinfo[numpolyplanes].alpha = alpha;
@ -5486,9 +5530,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
spritedef_t *sprdef;
spriteframe_t *sprframe;
spriteinfo_t *sprinfo;
md2_t *md2;
size_t lumpoff;
unsigned rot;
UINT8 flip;
UINT16 flip;
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
angle_t ang;
@ -5501,17 +5546,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
fixed_t spr_offset, spr_topoffset;
#ifdef ROTSPRITE
patch_t *rotsprite = NULL;
angle_t arollangle;
UINT32 rollangle;
INT32 rollangle = 0;
#endif
if (!thing)
return;
#ifdef ROTSPRITE
arollangle = thing->rollangle;
rollangle = AngleFixed(arollangle)>>FRACBITS;
#endif
this_scale = FIXED_TO_FLOAT(thing->scale);
// transform the origin point
@ -5522,8 +5562,21 @@ static void HWR_ProjectSprite(mobj_t *thing)
tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
// thing is behind view plane?
if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmodels.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
if (tz < ZCLIP_PLANE && !papersprite)
{
if (cv_grmodels.value) //Yellow: Only MD2's dont disappear
{
if (thing->skin && thing->sprite == SPR_PLAY)
md2 = &md2_playermodels[( (skin_t *)thing->skin - skins )];
else
md2 = &md2_models[thing->sprite];
if (md2->notfound || md2->scale < 0.0f)
return;
}
else
return;
}
// The above can stay as it works for cutting sprites that are too close
tr_x = FIXED_TO_FLOAT(thing->x);
@ -5579,12 +5632,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
flip = sprframe->flip; // Will only be 0x00 or 0xFF
if (papersprite && ang < ANGLE_180)
{
if (flip)
flip = 0;
else
flip = 255;
}
flip ^= 0xFFFF;
}
else
{
@ -5593,6 +5641,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
rot = 6; // F7 slot
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
rot = 2; // F3 slot
else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
{
rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
rot = ((rot & 1)<<3)|(rot>>1);
}
else // Normal behaviour
rot = (ang+ANGLE_202h)>>29;
@ -5601,12 +5654,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
flip = sprframe->flip & (1<<rot);
if (papersprite && ang < ANGLE_180)
{
if (flip)
flip = 0;
else
flip = 1<<rot;
}
flip ^= (1<<rot);
}
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
@ -5618,11 +5666,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lumpoff].topoffset;
#ifdef ROTSPRITE
if (rollangle > 0)
if (thing->rollangle)
{
if (!sprframe->rotsprite.cached[rot])
rollangle = R_GetRollAngle(thing->rollangle);
if (!(sprframe->rotsprite.cached & (1<<rot)))
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rollangle /= ROTANGDIFF;
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)
{
@ -5896,7 +5944,7 @@ static void HWR_DrawSkyBackground(player_t *player)
if (cv_grskydome.value)
{
FTransform dometransform;
const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
postimg_t *type;
if (splitscreen && player == &players[secondarydisplayplayer])
@ -6074,7 +6122,7 @@ void HWR_SetViewSize(void)
// ==========================================================================
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
{
const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
postimg_t *type;
if (splitscreen && player == &players[secondarydisplayplayer])
@ -6200,7 +6248,7 @@ if (0)
viewangle = localaiming2;
// Handle stuff when you are looking farther up or down.
if ((aimingangle || cv_grfov.value+player->fovadd > 90*FRACUNIT))
if ((aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT))
{
dup_viewangle += ANGLE_90;
HWR_ClearClipSegs();
@ -6278,7 +6326,7 @@ if (0)
// ==========================================================================
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
{
const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
postimg_t *type;
const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
@ -6420,7 +6468,7 @@ if (0)
viewangle = localaiming2;
// Handle stuff when you are looking farther up or down.
if ((aimingangle || cv_grfov.value+player->fovadd > 90*FRACUNIT))
if ((aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT))
{
dup_viewangle += ANGLE_90;
HWR_ClearClipSegs();
@ -6549,9 +6597,7 @@ static void CV_grmodellighting_OnChange(void);
static void CV_grfiltermode_OnChange(void);
static void CV_granisotropic_OnChange(void);
static void CV_grfogdensity_OnChange(void);
static void CV_grfov_OnChange(void);
static CV_PossibleValue_t grfov_cons_t[] = {{0, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}};
static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
{HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
@ -6560,7 +6606,7 @@ static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA
{0, NULL}};
CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grsoftwarefog = {"gr_softwarefog", "Off", CV_SAVE, grsoftwarefog_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -6578,9 +6624,9 @@ consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_O
consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfakecontrast = {"gr_fakecontrast", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfov = {"gr_fov", "90", CV_FLOAT|CV_CALL, grfov_cons_t, CV_grfov_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsigned,
CV_grfogdensity_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -6616,17 +6662,10 @@ static void CV_granisotropic_OnChange(void)
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value);
}
static void CV_grfov_OnChange(void)
{
if ((netgame || multiplayer) && !cv_debug && cv_grfov.value != 90*FRACUNIT)
CV_Set(&cv_grfov, cv_grfov.defaultvalue);
}
//added by Hurdler: console varibale that are saved
void HWR_AddCommands(void)
{
CV_RegisterVar(&cv_grfovchange);
CV_RegisterVar(&cv_grfov);
CV_RegisterVar(&cv_fovchange);
CV_RegisterVar(&cv_grfogdensity);
CV_RegisterVar(&cv_grfogcolor);
@ -6646,6 +6685,7 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_grskydome);
CV_RegisterVar(&cv_grspritebillboarding);
CV_RegisterVar(&cv_grfakecontrast);
CV_RegisterVar(&cv_grfiltermode);
CV_RegisterVar(&cv_grrounddown);

View file

@ -84,7 +84,6 @@ extern consvar_t cv_grstaticlighting;
extern consvar_t cv_grcoronas;
extern consvar_t cv_grcoronasize;
#endif
extern consvar_t cv_grfov;
extern consvar_t cv_grmodels;
extern consvar_t cv_grmodelinterpolation;
extern consvar_t cv_grmodellighting;
@ -95,10 +94,11 @@ extern consvar_t cv_grsoftwarefog;
extern consvar_t cv_grfiltermode;
extern consvar_t cv_granisotropicmode;
extern consvar_t cv_grcorrecttricks;
extern consvar_t cv_grfovchange;
extern consvar_t cv_fovchange;
extern consvar_t cv_grsolvetjoin;
extern consvar_t cv_grspritebillboarding;
extern consvar_t cv_grskydome;
extern consvar_t cv_grfakecontrast;
extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowy;

View file

@ -654,10 +654,14 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
UINT16 w = gpatch->width, h = gpatch->height;
UINT32 size = w*h;
RGBA_t *image, *blendimage, *cur, blendcolor;
UINT8 translation[16]; // First the color index
UINT8 cutoff[16]; // Brightness cutoff before using the next color
UINT8 translen = 0;
UINT8 i;
// vanilla port
UINT8 translation[16];
blendcolor = V_GetColor(0); // initialize
memset(translation, 0, sizeof(translation));
memset(cutoff, 0, sizeof(cutoff));
if (grmip->width == 0)
{
@ -681,17 +685,46 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
image = gpatch->mipmap->grInfo.data;
blendimage = blendgpatch->mipmap->grInfo.data;
blendcolor = V_GetColor(0); // initialize
// TC_METALSONIC includes an actual skincolor translation, on top of its flashing.
if (skinnum == TC_METALSONIC)
color = SKINCOLOR_COBALT;
if (color != SKINCOLOR_NONE)
memcpy(&translation, &Color_Index[color - 1], 16);
{
UINT8 numdupes = 1;
translation[translen] = Color_Index[color-1][0];
cutoff[translen] = 255;
for (i = 1; i < 16; i++)
{
if (translation[translen] == Color_Index[color-1][i])
{
numdupes++;
continue;
}
if (translen > 0)
{
cutoff[translen] = cutoff[translen-1] - (256 / (16 / numdupes));
}
numdupes = 1;
translen++;
translation[translen] = (UINT8)Color_Index[color-1][i];
}
translen++;
}
while (size--)
{
if (skinnum == TC_BOSS)
{
// Turn everything below a certain threshold white
if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue <= 82)
if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue < 127)
{
// Lactozilla: Invert the colors
cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue);
@ -705,23 +738,23 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
cur->s.alpha = image->s.alpha;
}
else if (skinnum == TC_METALSONIC)
{
// Turn everything below a certain blue threshold white
if (image->s.red == 0 && image->s.green == 0 && image->s.blue <= 82)
else if (skinnum == TC_ALLWHITE)
{
// Turn everything white
cur->s.red = cur->s.green = cur->s.blue = 255;
cur->s.alpha = image->s.alpha;
}
else
{
cur->s.red = image->s.red;
cur->s.green = image->s.green;
cur->s.blue = image->s.blue;
// Everything below requires a blend image
if (blendimage == NULL)
{
cur->rgba = image->rgba;
goto skippixel;
}
cur->s.alpha = image->s.alpha;
}
else if (skinnum == TC_DASHMODE)
// Metal Sonic dash mode
if (skinnum == TC_DASHMODE)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
@ -741,35 +774,37 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
bcolor.s.red = 255;
bcolor.s.green = (blendimage->s.red + blendimage->s.green + blendimage->s.blue) / 3;
}
if (image->s.alpha && image->s.red > image->s.green << 1) // this is pretty arbitrary, but it works well for Metal Sonic
{
icolor.s.red = image->s.blue;
icolor.s.blue = image->s.red;
}
cur->s.red = (ialpha * icolor.s.red + balpha * bcolor.s.red)/255;
cur->s.green = (ialpha * icolor.s.green + balpha * bcolor.s.green)/255;
cur->s.blue = (ialpha * icolor.s.blue + balpha * bcolor.s.blue)/255;
cur->s.alpha = image->s.alpha;
}
}
else if (skinnum == TC_ALLWHITE)
{
// Turn everything white
cur->s.red = cur->s.green = cur->s.blue = 255;
cur->s.alpha = image->s.alpha;
}
else
{
// All settings that use skincolors!
UINT16 brightness;
if (translen <= 0)
{
cur->rgba = image->rgba;
goto skippixel;
}
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
if (skinnum == TC_RAINBOW)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
goto skippixel;
}
else
{
@ -785,8 +820,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
if (blendimage->s.alpha == 0)
{
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
goto skippixel; // for metal sonic blend
}
else
{
@ -798,8 +832,8 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
// (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...)
{
RGBA_t nextcolor;
UINT8 firsti, secondi, mul;
UINT32 r, g, b;
UINT8 firsti, secondi, mul, mulmax;
INT32 r, g, b;
// Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors.
// Ensue horrible mess.
@ -808,7 +842,6 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
UINT16 brightdif = 256;
UINT8 colorbrightnesses[16];
INT32 compare, m, d;
UINT8 i;
// Ignore pure white & pitch black
if (brightness > 253 || brightness < 2)
@ -820,18 +853,21 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
firsti = 0;
mul = 0;
mulmax = 1;
for (i = 0; i < 16; i++)
for (i = 0; i < translen; i++)
{
RGBA_t tempc = V_GetColor(translation[i]);
SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
}
for (i = 0; i < 16; i++)
for (i = 0; i < translen; i++)
{
if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is)
continue;
compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness));
if (compare < brightdif)
{
brightdif = (UINT16)compare;
@ -840,7 +876,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
}
secondi = firsti+1; // next color in line
if (secondi == 16)
if (secondi >= translen)
{
m = (INT16)brightness; // - 0;
d = (INT16)colorbrightnesses[firsti]; // - 0;
@ -854,40 +890,53 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
if (m >= d)
m = d-1;
mulmax = 16;
// calculate the "gradient" multiplier based on how close this color is to the one next in line
if (m <= 0 || d <= 0)
mul = 0;
else
mul = 15 - ((m * 16) / d);
mul = (mulmax-1) - ((m * mulmax) / d);
}
else
{
// Thankfully, it's normally way more simple.
// Just convert brightness to a skincolor value, use remainder to find the gradient multipler
firsti = ((UINT8)(255-brightness) / 16);
// Just convert brightness to a skincolor value, use distance to next position to find the gradient multipler
firsti = 0;
for (i = 1; i < translen; i++)
{
if (brightness >= cutoff[i])
break;
firsti = i;
}
secondi = firsti+1;
mul = ((UINT8)(255-brightness) % 16);
mulmax = cutoff[firsti];
if (secondi < translen)
mulmax -= cutoff[secondi];
mul = cutoff[firsti] - brightness;
}
blendcolor = V_GetColor(translation[firsti]);
if (mul > 0 // If it's 0, then we only need the first color.
&& translation[firsti] != translation[secondi]) // Some colors have duplicate colors in a row, so let's just save the process
if (mul > 0) // If it's 0, then we only need the first color.
{
if (secondi == 16) // blend to black
if (secondi >= translen) // blend to black
nextcolor = V_GetColor(31);
else
nextcolor = V_GetColor(translation[secondi]);
// Find difference between points
r = (UINT32)(nextcolor.s.red - blendcolor.s.red);
g = (UINT32)(nextcolor.s.green - blendcolor.s.green);
b = (UINT32)(nextcolor.s.blue - blendcolor.s.blue);
r = (INT32)(nextcolor.s.red - blendcolor.s.red);
g = (INT32)(nextcolor.s.green - blendcolor.s.green);
b = (INT32)(nextcolor.s.blue - blendcolor.s.blue);
// Find the gradient of the two points
r = ((mul * r) / 16);
g = ((mul * g) / 16);
b = ((mul * b) / 16);
r = ((mul * r) / mulmax);
g = ((mul * g) / mulmax);
b = ((mul * b) / mulmax);
// Add gradient value to color
blendcolor.s.red += r;
@ -936,9 +985,29 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
skippixel:
// *Now* we can do Metal Sonic's flashing
if (skinnum == TC_METALSONIC)
{
// Blend dark blue into white
if (cur->s.alpha > 0 && cur->s.red == 0 && cur->s.green == 0 && cur->s.blue < 255 && cur->s.blue > 31)
{
// Sal: Invert non-blue
cur->s.red = cur->s.green = (255 - cur->s.blue);
cur->s.blue = 255;
}
cur++; image++; blendimage++;
cur->s.alpha = image->s.alpha;
}
}
}
cur++; image++;
if (blendimage != NULL)
blendimage++;
}
return;
@ -977,6 +1046,14 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT
// If here, the blended texture has not been created
// So we create it
if ((blendgpatch && blendgpatch->mipmap->grInfo.format)
&& (gpatch->width != blendgpatch->width || gpatch->height != blendgpatch->height))
{
// Blend image exists, but it's bad.
HWD.pfnSetTexture(gpatch->mipmap);
return;
}
//BP: WARNING: don't free it manually without clearing the cache of harware renderer
// (it have a liste of mipmap)
// this malloc is cleared in HWR_FreeTextureCache
@ -1108,7 +1185,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
{
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
extracolormap_t *colormap = sector->extra_colormap;
extracolormap_t *colormap = NULL;
if (sector->numlights)
{
@ -1145,13 +1222,12 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
INT32 durs = spr->mobj->state->tics;
INT32 tics = spr->mobj->tics;
//mdlframe_t *next = NULL;
const boolean papersprite = (spr->mobj->frame & FF_PAPERSPRITE);
const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP));
spritedef_t *sprdef;
spriteframe_t *sprframe;
#ifdef ROTSPRITE
spriteinfo_t *sprinfo;
angle_t ang;
#endif
INT32 mod;
float finalscale;
@ -1175,16 +1251,12 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
{
md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
md2->skin = (skin_t*)spr->mobj->skin-skins;
#ifdef ROTSPRITE
sprinfo = &((skin_t *)spr->mobj->skin)->sprinfo[spr->mobj->sprite2];
#endif
}
else
{
md2 = &md2_models[spr->mobj->sprite];
#ifdef ROTSPRITE
sprinfo = &spriteinfo[spr->mobj->sprite];
#endif
}
if (md2->error)
@ -1225,11 +1297,9 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
md2_loadBlendTexture(md2);
if (gpatch && gpatch->mipmap->grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
{
if (md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format
&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
{
INT32 skinnum = INT32_MAX;
if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized)
@ -1260,7 +1330,9 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
// Translation or skin number found
if (skinnum != INT32_MAX)
{
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
}
else
{
// Sorry nothing
@ -1268,12 +1340,6 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
}
}
else
{
// This is safe, since we know the texture has been downloaded
HWD.pfnSetTexture(gpatch->mipmap);
}
}
else
{
// Sprite
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
@ -1367,14 +1433,12 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
sprframe = &sprdef->spriteframes[spr->mobj->frame & FF_FRAMEMASK];
if (sprframe->rotate)
if (sprframe->rotate || papersprite)
{
fixed_t anglef = AngleFixed(spr->mobj->angle);
if (spr->mobj->player)
anglef = AngleFixed(spr->mobj->player->drawangle);
else
anglef = AngleFixed(spr->mobj->angle);
p.angley = FIXED_TO_FLOAT(anglef);
}
@ -1384,9 +1448,8 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
p.angley = FIXED_TO_FLOAT(anglef);
}
#ifdef ROTSPRITE
p.rollangle = 0.0f;
p.rollflip = 0;
p.rollflip = 1;
p.rotaxis = 0;
if (spr->mobj->rollangle)
{
@ -1409,7 +1472,6 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
p.rollflip = -1;
}
#endif
p.anglex = 0.0f;

View file

@ -2076,7 +2076,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f);
#ifdef ROTSPRITE
if (pos->roll)
{
float roll = (1.0f * pos->rollflip);
@ -2089,7 +2088,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
pglRotatef(pos->rollangle, roll, 0.0f, 0.0f);
pglTranslatef(-pos->centerx, -pos->centery, 0);
}
#endif
pglScalef(scalex, scaley, scalez);
@ -2224,11 +2222,11 @@ EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration,
EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
{
static boolean special_splitscreen;
float used_fov;
pglLoadIdentity();
if (stransform)
{
boolean fovx90;
used_fov = stransform->fovxangle;
#ifdef USE_FTRANSFORM_MIRROR
// mirroring from Kart
if (stransform->mirror)
@ -2244,45 +2242,57 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
pglRotatef(stransform->angley+270.0f, 0.0f, 1.0f, 0.0f);
pglTranslatef(-stransform->x, -stransform->z, -stransform->y);
pglMatrixMode(GL_PROJECTION);
pglLoadIdentity();
fovx90 = stransform->fovxangle > 0.0f && fabsf(stransform->fovxangle - 90.0f) < 0.5f;
special_splitscreen = (stransform->splitscreen && fovx90);
if (special_splitscreen)
GLPerspective(53.13f, 2*ASPECT_RATIO); // 53.13 = 2*atan(0.5)
else
GLPerspective(stransform->fovxangle, ASPECT_RATIO);
pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer)
pglMatrixMode(GL_MODELVIEW);
special_splitscreen = stransform->splitscreen;
}
else
{
used_fov = fov;
pglScalef(1.0f, 1.0f, -1.0f);
}
pglMatrixMode(GL_PROJECTION);
pglLoadIdentity();
if (special_splitscreen)
GLPerspective(53.13f, 2*ASPECT_RATIO); // 53.13 = 2*atan(0.5)
{
used_fov = atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI;
GLPerspective(used_fov, 2*ASPECT_RATIO);
}
else
//Hurdler: is "fov" correct?
GLPerspective(fov, ASPECT_RATIO);
GLPerspective(used_fov, ASPECT_RATIO);
pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer)
pglMatrixMode(GL_MODELVIEW);
}
pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
}
EXPORT INT32 HWRAPI(GetTextureUsed) (void)
{
FTextureInfo* tmp = gr_cachehead;
FTextureInfo *tmp = gr_cachehead;
INT32 res = 0;
while (tmp)
{
res += tmp->height*tmp->width*(screen_depth/8);
// Figure out the correct bytes-per-pixel for this texture
// I don't know which one the game actually _uses_ but this
// follows format2bpp in hw_cache.c
int bpp = 1;
int format = tmp->grInfo.format;
if (format == GR_RGBA)
bpp = 4;
else if (format == GR_TEXFMT_RGB_565
|| format == GR_TEXFMT_ARGB_1555
|| format == GR_TEXFMT_ARGB_4444
|| format == GR_TEXFMT_ALPHA_INTENSITY_88
|| format == GR_TEXFMT_AP_88)
bpp = 2;
// Add it up!
res += tmp->height*tmp->width*bpp;
tmp = tmp->nextmipmap;
}
return res;
}

View file

@ -2070,7 +2070,7 @@ static void HU_drawGametype(void)
{
const char *strvalue = NULL;
if (gametype < 0 || gametype >= NUMGAMETYPES)
if (gametype < 0 || gametype >= gametypecount)
return; // not a valid gametype???
strvalue = Gametype_Names[gametype];
@ -2201,10 +2201,14 @@ void HU_Drawer(void)
return;
// draw the crosshair, not when viewing demos nor with chasecam
if (!automapactive && cv_crosshair.value && !demoplayback && !camera.chase && !players[displayplayer].spectator)
if (!automapactive && cv_crosshair.value && !demoplayback &&
(!camera.chase || ticcmd_ztargetfocus[0])
&& !players[displayplayer].spectator)
HU_DrawCrosshair();
if (!automapactive && cv_crosshair2.value && !demoplayback && !camera2.chase && !players[secondarydisplayplayer].spectator)
if (!automapactive && cv_crosshair2.value && !demoplayback &&
(!camera2.chase || ticcmd_ztargetfocus[1])
&& !players[secondarydisplayplayer].spectator)
HU_DrawCrosshair2();
// draw desynch text
@ -2378,7 +2382,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
for (i = 0; i < scorelines; i++)
{
if (players[tab[i].num].spectator && gametype != GT_COOP)
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
continue; //ignore them.
greycheck = greycheckdef;
@ -2441,7 +2445,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
}
}
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives));
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
{
@ -2454,7 +2458,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -2548,7 +2552,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
| (greycheck ? 0 : V_TRANSLUCENT)
| V_ALLOWLOWERCASE, name);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
{
if (players[tab[i].num].gotflag & GF_REDFLAG) // Red
V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, rflagico, 0);
@ -2676,7 +2680,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
| (greycheck ? V_TRANSLUCENT : 0)
| V_ALLOWLOWERCASE, name);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
{
if (players[tab[i].num].gotflag & GF_REDFLAG) // Red
V_DrawSmallScaledPatch(x-28, y-4, 0, rflagico);
@ -2733,7 +2737,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
for (i = 0; i < scorelines; i++)
{
if (players[tab[i].num].spectator && gametype != GT_COOP)
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
continue; //ignore them.
greycheck = greycheckdef;
@ -2750,7 +2754,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
| (greycheck ? V_TRANSLUCENT : 0)
| V_ALLOWLOWERCASE, name);
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives));
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);
@ -2799,7 +2803,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
}
// All data drawn with thin string for space.
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -2839,7 +2843,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
for (i = 0; i < scorelines; i++)
{
if (players[tab[i].num].spectator && gametype != GT_COOP)
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
continue; //ignore them.
greycheck = greycheckdef;
@ -2909,7 +2913,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
}
// All data drawn with thin string for space.
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -3033,21 +3037,21 @@ static void HU_DrawRankings(void)
// draw the current gametype in the lower right
HU_drawGametype();
if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP)
if (gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT))
{
if (cv_timelimit.value && timelimitintics > 0)
if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0)
{
V_DrawCenteredString(64, 8, 0, "TIME");
V_DrawCenteredString(64, 16, 0, va("%i:%02i", G_TicsToMinutes(stplyr->realtime, true), G_TicsToSeconds(stplyr->realtime)));
}
if (cv_pointlimit.value > 0)
if ((gametyperules & GTR_POINTLIMIT) && cv_pointlimit.value > 0)
{
V_DrawCenteredString(256, 8, 0, "POINT LIMIT");
V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value));
}
}
else if (gametype == GT_COOP)
else if (gametyperankings[gametype] == GT_COOP)
{
INT32 totalscore = 0;
for (i = 0; i < MAXPLAYERS; i++)
@ -3081,7 +3085,7 @@ static void HU_DrawRankings(void)
tab[i].num = -1;
tab[i].name = 0;
if (gametype == GT_RACE && !circuitmap)
if (gametyperankings[gametype] == GT_RACE && !circuitmap)
tab[i].count = INT32_MAX;
}
@ -3090,7 +3094,7 @@ static void HU_DrawRankings(void)
if (!playeringame[j])
continue;
if (gametype != GT_COOP && players[j].spectator)
if (!G_PlatformGametype() && players[j].spectator)
continue;
for (i = 0; i < MAXPLAYERS; i++)
@ -3098,10 +3102,10 @@ static void HU_DrawRankings(void)
if (!playeringame[i])
continue;
if (gametype != GT_COOP && players[i].spectator)
if (!G_PlatformGametype() && players[i].spectator)
continue;
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -3124,7 +3128,7 @@ static void HU_DrawRankings(void)
}
}
}
else if (gametype == GT_COMPETITION)
else if (gametyperankings[gametype] == GT_COMPETITION)
{
// todo put something more fitting for the gametype here, such as current
// number of categories led

View file

@ -3565,7 +3565,7 @@ state_t states[NUMSTATES] =
{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS60|8, 3, {NULL}, 0, 0, S_NULL}, // S_PUMATRAIL4
// Hammer
{SPR_HAMM, FF_ANIMATE, -1, {NULL}, 4, 3, S_NULL}, // S_HAMMER
{SPR_HAMM, FF_ANIMATE, -1, {NULL}, 3, 3, S_NULL}, // S_HAMMER
// Koopa
{SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KOOPA1
@ -4492,7 +4492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
@ -6273,7 +6273,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOTHINK, // flags
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_SCENERY, // flags
S_NULL // raisestate
},
@ -11992,7 +11992,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
@ -12019,7 +12019,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
@ -19791,7 +19791,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
1000, // spawnhealth
S_NIGHTSSTARXMAS, // seestate
sfx_None, // seesound
8, // reactiontime
MT_FLINGNIGHTSSTAR, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
@ -19812,6 +19812,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FLINGNIGHTSSTAR
-1, // doomednum
S_NIGHTSSTAR, // spawnstate
1000, // spawnhealth
S_NIGHTSSTARXMAS, // seestate
sfx_None, // seesound
MT_FLINGNIGHTSSTAR, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
MT_NIGHTSSTAR, // painchance
sfx_s3k33, // painsound
S_RING, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_ncitem, // deathsound
38*FRACUNIT, // speed
16*FRACUNIT, // radius
24*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SLIDEME|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_NIGHTSSUPERLOOP
1707, // doomednum
S_NIGHTSSUPERLOOP, // spawnstate

View file

@ -155,11 +155,9 @@ void A_SpawnObjectAbsolute();
void A_SpawnObjectRelative();
void A_ChangeAngleRelative();
void A_ChangeAngleAbsolute();
#ifdef ROTSPRITE
void A_RollAngle();
void A_ChangeRollAngleRelative();
void A_ChangeRollAngleAbsolute();
#endif
void A_PlaySound();
void A_FindTarget();
void A_FindTracer();
@ -4704,6 +4702,7 @@ typedef enum mobj_type
MT_NIGHTSCHIP, // NiGHTS Chip
MT_FLINGNIGHTSCHIP, // Lost NiGHTS Chip
MT_NIGHTSSTAR, // NiGHTS Star
MT_FLINGNIGHTSSTAR, // Lost NiGHTS Star
MT_NIGHTSSUPERLOOP,
MT_NIGHTSDRILLREFILL,
MT_NIGHTSHELPER,

View file

@ -12,6 +12,7 @@
#include "doomdef.h"
#ifdef HAVE_BLUA
#include "fastcmp.h"
#include "p_local.h"
#include "p_setup.h" // So we can have P_SetupLevelSky
#ifdef ESLOPE
@ -23,6 +24,8 @@
#include "m_random.h"
#include "s_sound.h"
#include "g_game.h"
#include "m_menu.h"
#include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText
#include "console.h"
#include "d_netcmd.h" // IsPlayerAdmin
@ -144,10 +147,8 @@ static const struct {
{META_MOBJINFO, "mobjinfo_t"},
{META_SFXINFO, "sfxinfo_t"},
{META_SPRITEINFO, "spriteinfo_t"},
#ifdef ROTSPRITE
{META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"},
#endif
{META_MOBJ, "mobj_t"},
{META_MAPTHING, "mapthing_t"},
@ -2632,6 +2633,145 @@ static int lib_sStartMusicCaption(lua_State *L)
// G_GAME
////////////
// Copypasted from lib_cvRegisterVar :]
static int lib_gAddGametype(lua_State *L)
{
const char *k;
lua_Integer i;
const char *gtname = NULL;
const char *gtconst = NULL;
const char *gtdescription = NULL;
INT16 newgtidx = 0;
UINT32 newgtrules = 0;
UINT32 newgttol = 0;
INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0;
UINT8 newgtleftcolor = 0;
UINT8 newgtrightcolor = 0;
INT16 newgtrankingstype = -1;
int newgtinttype = 0;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
// Ran out of gametype slots
if (gametypecount == NUMGAMETYPEFREESLOTS)
return luaL_error(L, "Ran out of free gametype slots!");
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e);
#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
lua_pushnil(L);
while (lua_next(L, 1)) {
// stack: gametype table, key/index, value
// 1 2 3
i = 0;
k = NULL;
if (lua_isnumber(L, 2))
i = lua_tointeger(L, 2);
else if (lua_isstring(L, 2))
k = lua_tostring(L, 2);
// Sorry, no gametype rules as key names.
if (i == 1 || (k && fasticmp(k, "name"))) {
if (!lua_isstring(L, 3))
TYPEERROR("name", LUA_TSTRING)
gtname = Z_StrDup(lua_tostring(L, 3));
} else if (i == 2 || (k && fasticmp(k, "identifier"))) {
if (!lua_isstring(L, 3))
TYPEERROR("identifier", LUA_TSTRING)
gtconst = Z_StrDup(lua_tostring(L, 3));
} else if (i == 3 || (k && fasticmp(k, "rules"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("rules", LUA_TNUMBER)
newgtrules = (UINT32)lua_tointeger(L, 3);
} else if (i == 4 || (k && fasticmp(k, "typeoflevel"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("typeoflevel", LUA_TNUMBER)
newgttol = (UINT32)lua_tointeger(L, 3);
} else if (i == 5 || (k && fasticmp(k, "rankingtype"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("rankingtype", LUA_TNUMBER)
newgtrankingstype = (INT16)lua_tointeger(L, 3);
} else if (i == 6 || (k && fasticmp(k, "intermissiontype"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("intermissiontype", LUA_TNUMBER)
newgtinttype = (int)lua_tointeger(L, 3);
} else if (i == 7 || (k && fasticmp(k, "defaultpointlimit"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("defaultpointlimit", LUA_TNUMBER)
newgtpointlimit = (INT32)lua_tointeger(L, 3);
} else if (i == 8 || (k && fasticmp(k, "defaulttimelimit"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("defaulttimelimit", LUA_TNUMBER)
newgttimelimit = (INT32)lua_tointeger(L, 3);
} else if (i == 9 || (k && fasticmp(k, "description"))) {
if (!lua_isstring(L, 3))
TYPEERROR("description", LUA_TSTRING)
gtdescription = Z_StrDup(lua_tostring(L, 3));
} else if (i == 10 || (k && fasticmp(k, "headerleftcolor"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("headerleftcolor", LUA_TNUMBER)
newgtleftcolor = (UINT8)lua_tointeger(L, 3);
} else if (i == 11 || (k && fasticmp(k, "headerrightcolor"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("headerrightcolor", LUA_TNUMBER)
newgtrightcolor = (UINT8)lua_tointeger(L, 3);
// Key name specified
} else if ((!i) && (k && fasticmp(k, "headercolor"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("headercolor", LUA_TNUMBER)
newgtleftcolor = newgtrightcolor = (UINT8)lua_tointeger(L, 3);
}
lua_pop(L, 1);
}
#undef FIELDERROR
#undef TYPEERROR
// pop gametype table
lua_pop(L, 1);
// Set defaults
if (gtname == NULL)
gtname = Z_StrDup("Unnamed gametype");
if (gtdescription == NULL)
gtdescription = Z_StrDup("???");
// Add the new gametype
newgtidx = G_AddGametype(newgtrules);
G_AddGametypeTOL(newgtidx, newgttol);
G_SetGametypeDescription(newgtidx, NULL, newgtleftcolor, newgtrightcolor);
strncpy(gametypedesc[newgtidx].notes, gtdescription, 441);
// Not covered by G_AddGametype alone.
if (newgtrankingstype == -1)
newgtrankingstype = newgtidx;
gametyperankings[newgtidx] = newgtrankingstype;
intermissiontypes[newgtidx] = newgtinttype;
pointlimits[newgtidx] = newgtpointlimit;
timelimits[newgtidx] = newgttimelimit;
// Write the new gametype name.
Gametype_Names[newgtidx] = gtname;
// Write the constant name.
if (gtconst == NULL)
gtconst = gtname;
G_AddGametypeConstant(newgtidx, gtconst);
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
// done
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
return 0;
}
static int lib_gBuildMapName(lua_State *L)
{
INT32 map = luaL_optinteger(L, 1, gamemap);
@ -2664,23 +2804,17 @@ static int lib_gSetCustomExitVars(lua_State *L)
// Supported:
// G_SetCustomExitVars(); [reset to defaults]
// G_SetCustomExitVars(int) [nextmap override only]
// G_SetCustomExitVars(bool) [skipstats only]
// G_SetCustomExitVars(int, bool) [both of the above]
if (n >= 1)
{
if (lua_isnumber(L, 1) || n >= 2)
{
nextmapoverride = (INT16)luaL_checknumber(L, 1);
lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available
}
skipstats = luaL_optinteger(L, 2, 0);
}
else
{
// G_SetCustomExitVars(nil, int) [skipstats only]
// G_SetCustomExitVars(int, int) [both of the above]
nextmapoverride = 0;
skipstats = 0;
if (n >= 1)
{
nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
skipstats = (INT16)luaL_optinteger(L, 2, 0);
}
// ---
return 0;
}
@ -2720,6 +2854,22 @@ static int lib_gGametypeUsesLives(lua_State *L)
return 1;
}
static int lib_gGametypeUsesCoopLives(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_GametypeUsesCoopLives());
return 1;
}
static int lib_gGametypeUsesCoopStarposts(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_GametypeUsesCoopStarposts());
return 1;
}
static int lib_gGametypeHasTeams(lua_State *L)
{
//HUDSAFE
@ -2760,6 +2910,14 @@ static int lib_gTagGametype(lua_State *L)
return 1;
}
static int lib_gCompetitionGametype(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_CompetitionGametype());
return 1;
}
static int lib_gTicsToHours(lua_State *L)
{
tic_t rtic = luaL_checkinteger(L, 1);
@ -2997,6 +3155,7 @@ static luaL_Reg lib[] = {
{"S_StartMusicCaption", lib_sStartMusicCaption},
// g_game
{"G_AddGametype", lib_gAddGametype},
{"G_BuildMapName",lib_gBuildMapName},
{"G_DoReborn",lib_gDoReborn},
{"G_SetCustomExitVars",lib_gSetCustomExitVars},
@ -3004,11 +3163,14 @@ static luaL_Reg lib[] = {
{"G_ExitLevel",lib_gExitLevel},
{"G_IsSpecialStage",lib_gIsSpecialStage},
{"G_GametypeUsesLives",lib_gGametypeUsesLives},
{"G_GametypeUsesCoopLives",lib_gGametypeUsesCoopLives},
{"G_GametypeUsesCoopStarposts",lib_gGametypeUsesCoopStarposts},
{"G_GametypeHasTeams",lib_gGametypeHasTeams},
{"G_GametypeHasSpectators",lib_gGametypeHasSpectators},
{"G_RingSlingerGametype",lib_gRingSlingerGametype},
{"G_PlatformGametype",lib_gPlatformGametype},
{"G_TagGametype",lib_gTagGametype},
{"G_CompetitionGametype",lib_gCompetitionGametype},
{"G_TicsToHours",lib_gTicsToHours},
{"G_TicsToMinutes",lib_gTicsToMinutes},
{"G_TicsToSeconds",lib_gTicsToSeconds},

View file

@ -118,12 +118,12 @@ void COM_Lua_f(void)
lua_rawgeti(gL, -1, 2); // push flags from command info table
if (lua_isboolean(gL, -1))
flags = (lua_toboolean(gL, -1) ? 1 : 0);
flags = (lua_toboolean(gL, -1) ? COM_ADMIN : 0);
else
flags = (UINT8)lua_tointeger(gL, -1);
lua_pop(gL, 1); // pop flags
if (flags & 2) // flag 2: splitscreen player command.
if (flags & COM_SPLITSCREEN) // flag 2: splitscreen player command.
{
if (!splitscreen)
{
@ -133,12 +133,12 @@ void COM_Lua_f(void)
playernum = secondarydisplayplayer;
}
if (netgame)
if (netgame && !( flags & COM_LOCAL ))/* don't send local commands */
{ // Send the command through the network
UINT8 argc;
lua_pop(gL, 1); // pop command info table
if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command.
if (flags & COM_ADMIN && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command.
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -158,7 +158,7 @@ void COM_Lua_f(void)
WRITEUINT8(p, argc);
for (i = 0; i < argc; i++)
WRITESTRINGN(p, COM_Argv(i), 255);
if (flags & 2)
if (flags & COM_SPLITSCREEN)
SendNetXCmd2(XD_LUACMD, buf, p-buf);
else
SendNetXCmd(XD_LUACMD, buf, p-buf);
@ -192,7 +192,15 @@ static int lib_comAddCommand(lua_State *L)
if (lua_gettop(L) >= 3)
{ // For the third argument, only take a boolean or a number.
lua_settop(L, 3);
if (lua_type(L, 3) != LUA_TBOOLEAN)
if (lua_type(L, 3) == LUA_TBOOLEAN)
{
CONS_Alert(CONS_WARNING,
"Using a boolean for admin commands is "
"deprecated and will be removed.\n"
"Use \"COM_ADMIN\" instead.\n"
);
}
else
luaL_checktype(L, 3, LUA_TNUMBER);
}
else
@ -427,6 +435,26 @@ static int lib_cvRegisterVar(lua_State *L)
return 1;
}
static int lib_cvFindVar(lua_State *L)
{
consvar_t *cv;
if (( cv = CV_FindVar(luaL_checkstring(L,1)) ))
{
lua_settop(L,1);/* We only want one argument in the stack. */
lua_pushlightuserdata(L, cv);/* Now the second value on stack. */
luaL_getmetatable(L, META_CVAR);
/*
The metatable is the last value on the stack, so this
applies it to the second value, which is the cvar.
*/
lua_setmetatable(L,2);
lua_pushvalue(L,2);
return 1;
}
else
return 0;
}
// CONS_Printf for a single player
// Use 'print' in baselib for a global message.
static int lib_consPrintf(lua_State *L)
@ -466,6 +494,7 @@ static luaL_Reg lib[] = {
{"COM_BufAddText", lib_comBufAddText},
{"COM_BufInsertText", lib_comBufInsertText},
{"CV_RegisterVar", lib_cvRegisterVar},
{"CV_FindVar", lib_cvFindVar},
{"CONS_Printf", lib_consPrintf},
{NULL, NULL}
};

View file

@ -20,9 +20,12 @@ enum hook {
hook_MapChange,
hook_MapLoad,
hook_PlayerJoin,
hook_PreThinkFrame,
hook_ThinkFrame,
hook_PostThinkFrame,
hook_MobjSpawn,
hook_MobjCollide,
hook_MobjLineCollide,
hook_MobjMoveCollide,
hook_TouchSpecial,
hook_MobjFuse,
@ -51,6 +54,10 @@ enum hook {
hook_PlayerCanDamage,
hook_PlayerQuit,
hook_IntermissionThinker,
hook_TeamSwitch,
hook_ViewpointSwitch,
hook_SeenPlayer,
hook_PlayerThink,
hook_MAX // last hook
};
@ -59,12 +66,16 @@ extern const char *const hookNames[];
void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load)
void LUAh_MapLoad(void); // Hook for map load
void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer
void LUAh_PreThinkFrame(void); // Hook for frame (before mobj and player thinkers)
void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers)
void LUAh_PostThinkFrame(void); // Hook for frame (at end of tick, ie after overlays, precipitation, specials)
boolean LUAh_MobjHook(mobj_t *mo, enum hook which);
boolean LUAh_PlayerHook(player_t *plr, enum hook which);
#define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type
UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which);
#define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type
#define LUAh_MobjLineCollide(thing, line) LUAh_MobjLineCollideHook(thing, line, hook_MobjLineCollide) // Hook for PIT_CheckThing by (thing) mobj type
#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
#define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
@ -93,5 +104,11 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAft
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
void LUAh_IntermissionThinker(void); // Hook for Y_Ticker
boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh....
UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode
#ifdef SEENAMES
boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_NAMECHECK
#endif
#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink
#endif

View file

@ -31,9 +31,12 @@ const char *const hookNames[hook_MAX+1] = {
"MapChange",
"MapLoad",
"PlayerJoin",
"PreThinkFrame",
"ThinkFrame",
"PostThinkFrame",
"MobjSpawn",
"MobjCollide",
"MobjLineCollide",
"MobjMoveCollide",
"TouchSpecial",
"MobjFuse",
@ -62,6 +65,10 @@ const char *const hookNames[hook_MAX+1] = {
"PlayerCanDamage",
"PlayerQuit",
"IntermissionThinker",
"TeamSwitch",
"ViewpointSwitch",
"SeenPlayer",
"PlayerThink",
NULL
};
@ -121,6 +128,7 @@ static int lib_addHook(lua_State *L)
// Take a mobjtype enum which this hook is specifically for.
case hook_MobjSpawn:
case hook_MobjCollide:
case hook_MobjLineCollide:
case hook_MobjMoveCollide:
case hook_TouchSpecial:
case hook_MobjFuse:
@ -180,6 +188,7 @@ static int lib_addHook(lua_State *L)
lastp = &mobjthinkerhooks[hook.s.mt];
break;
case hook_MobjCollide:
case hook_MobjLineCollide:
case hook_MobjMoveCollide:
lastp = &mobjcollidehooks[hook.s.mt];
break;
@ -203,8 +212,12 @@ static int lib_addHook(lua_State *L)
case hook_PlayerSpawn:
case hook_FollowMobj:
case hook_PlayerCanDamage:
case hook_TeamSwitch:
case hook_ViewpointSwitch:
case hook_SeenPlayer:
case hook_ShieldSpawn:
case hook_ShieldSpecial:
case hook_PlayerThink:
lastp = &playerhooks;
break;
case hook_LinedefExecute:
@ -407,6 +420,29 @@ void LUAh_PlayerJoin(int playernum)
lua_settop(gL, 0);
}
// Hook for frame (before mobj and player thinkers)
void LUAh_PreThinkFrame(void)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_PreThinkFrame/8] & (1<<(hook_PreThinkFrame%8))))
return;
for (hookp = roothook; hookp; hookp = hookp->next)
{
if (hookp->type != hook_PreThinkFrame)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
if (lua_pcall(gL, 0, 0, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
}
}
}
// Hook for frame (after mobj and player thinkers)
void LUAh_ThinkFrame(void)
{
@ -430,6 +466,30 @@ void LUAh_ThinkFrame(void)
}
}
// Hook for frame (at end of tick, ie after overlays, precipitation, specials)
void LUAh_PostThinkFrame(void)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_PostThinkFrame/8] & (1<<(hook_PostThinkFrame%8))))
return;
for (hookp = roothook; hookp; hookp = hookp->next)
{
if (hookp->type != hook_PostThinkFrame)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
if (lua_pcall(gL, 0, 0, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
}
}
}
// Hook for mobj collisions
UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
{
@ -509,6 +569,84 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
return shouldCollide;
}
UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which)
{
hook_p hookp;
UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no.
if (!gL || !(hooksAvailable[which/8] & (1<<(which%8))))
return 0;
I_Assert(thing->type < NUMMOBJTYPES);
lua_settop(gL, 0);
// Look for all generic mobj collision hooks
for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, thing, META_MOBJ);
LUA_PushUserdata(gL, line, META_LINE);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{ // if nil, leave shouldCollide = 0.
if (lua_toboolean(gL, -1))
shouldCollide = 1; // Force yes
else
shouldCollide = 2; // Force no
}
lua_pop(gL, 1);
}
for (hookp = mobjcollidehooks[thing->type]; hookp; hookp = hookp->next)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, thing, META_MOBJ);
LUA_PushUserdata(gL, line, META_LINE);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{ // if nil, leave shouldCollide = 0.
if (lua_toboolean(gL, -1))
shouldCollide = 1; // Force yes
else
shouldCollide = 2; // Force no
}
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return shouldCollide;
}
// Hook for mobj thinkers
boolean LUAh_MobjThinker(mobj_t *mo)
{
@ -657,14 +795,16 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
lua_pushinteger(gL, damage);
lua_pushinteger(gL, damagetype);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
if (lua_pcall(gL, 4, 1, 0)) {
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
if (lua_pcall(gL, 5, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
@ -745,14 +885,16 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
lua_pushinteger(gL, damage);
lua_pushinteger(gL, damagetype);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
if (lua_pcall(gL, 4, 1, 0)) {
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
if (lua_pcall(gL, 5, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
@ -823,13 +965,15 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8
LUA_PushUserdata(gL, target, META_MOBJ);
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
lua_pushinteger(gL, damagetype);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
if (lua_pcall(gL, 3, 1, 0)) {
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
lua_pushvalue(gL, -5);
if (lua_pcall(gL, 4, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
@ -1346,4 +1490,146 @@ void LUAh_IntermissionThinker(void)
}
}
// Hook for team switching
// It's just an edit of LUAh_ViewpointSwitch.
boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble)
{
hook_p hookp;
boolean canSwitchTeam = true;
if (!gL || !(hooksAvailable[hook_TeamSwitch/8] & (1<<(hook_TeamSwitch%8))))
return true;
lua_settop(gL, 0);
for (hookp = playerhooks; hookp; hookp = hookp->next)
{
if (hookp->type != hook_TeamSwitch)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
lua_pushinteger(gL, newteam);
lua_pushboolean(gL, fromspectators);
lua_pushboolean(gL, tryingautobalance);
lua_pushboolean(gL, tryingscramble);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
if (lua_pcall(gL, 5, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1))
canSwitchTeam = false; // Can't switch team
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return canSwitchTeam;
}
// Hook for spy mode
UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced)
{
hook_p hookp;
UINT8 canSwitchView = 0; // 0 = default, 1 = force yes, 2 = force no.
if (!gL || !(hooksAvailable[hook_ViewpointSwitch/8] & (1<<(hook_ViewpointSwitch%8))))
return 0;
lua_settop(gL, 0);
hud_running = true; // local hook
for (hookp = playerhooks; hookp; hookp = hookp->next)
{
if (hookp->type != hook_ViewpointSwitch)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER);
lua_pushboolean(gL, forced);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
if (lua_pcall(gL, 3, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{ // if nil, leave canSwitchView = 0.
if (lua_toboolean(gL, -1))
canSwitchView = 1; // Force viewpoint switch
else
canSwitchView = 2; // Skip viewpoint switch
}
lua_pop(gL, 1);
}
lua_settop(gL, 0);
hud_running = false;
return canSwitchView;
}
// Hook for MT_NAMECHECK
#ifdef SEENAMES
boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend)
{
hook_p hookp;
boolean hasSeenPlayer = true;
if (!gL || !(hooksAvailable[hook_SeenPlayer/8] & (1<<(hook_SeenPlayer%8))))
return 0;
lua_settop(gL, 0);
hud_running = true; // local hook
for (hookp = playerhooks; hookp; hookp = hookp->next)
{
if (hookp->type != hook_SeenPlayer)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, seenfriend, META_PLAYER);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1))
hasSeenPlayer = false; // Hasn't seen player
lua_pop(gL, 1);
}
lua_settop(gL, 0);
hud_running = false;
return hasSeenPlayer;
}
#endif // SEENAMES
#endif

View file

@ -21,6 +21,7 @@ enum hud {
// Match / CTF / Tag / Ringslinger
hud_weaponrings,
hud_powerstones,
hud_teamscores,
// NiGHTS mode
hud_nightslink,
hud_nightsdrill,
@ -33,6 +34,9 @@ enum hud {
hud_coopemeralds,
hud_tokens,
hud_tabemblems,
// Intermission
hud_intermissiontally,
hud_intermissionmessages,
hud_MAX
};
@ -43,4 +47,5 @@ boolean LUA_HudEnabled(enum hud option);
void LUAh_GameHUD(player_t *stplyr);
void LUAh_ScoresHUD(void);
void LUAh_TitleHUD(void);
void LUAh_TitleCardHUD(player_t *stplyr);
void LUAh_TitleCardHUD(player_t *stplayr);
void LUAh_IntermissionHUD(void);

View file

@ -53,6 +53,7 @@ static const char *const hud_disable_options[] = {
"weaponrings",
"powerstones",
"teamscores",
"nightslink",
"nightsdrill",
@ -65,6 +66,9 @@ static const char *const hud_disable_options[] = {
"coopemeralds",
"tokens",
"tabemblems",
"intermissiontally",
"intermissionmessages",
NULL};
enum hudinfo {
@ -97,12 +101,14 @@ static const char *const patch_opt[] = {
enum hudhook {
hudhook_game = 0,
hudhook_scores,
hudhook_intermission,
hudhook_title,
hudhook_titlecard
};
static const char *const hudhook_opt[] = {
"game",
"scores",
"intermission",
"title",
"titlecard",
NULL};
@ -462,11 +468,11 @@ static int libd_getSpritePatch(lua_State *L)
// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
// in case somebody didn't know that angle 0 really just maps all 8 angles to the same patch
// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
if (angle != 0)
angle--;
if (angle >= 8) // out of range?
if (angle >= ((sprframe->rotate & SRF_3DGE) ? 16 : 8)) // out of range?
return 0;
// push both the patch and it's "flip" value
@ -557,11 +563,11 @@ static int libd_getSprite2Patch(lua_State *L)
// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
// in case somebody didn't know that angle 0 really just maps all 8 angles to the same patch
// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
if (angle != 0)
angle--;
if (angle >= 8) // out of range?
if (angle >= ((sprframe->rotate & SRF_3DGE) ? 16 : 8)) // out of range?
return 0;
// push both the patch and it's "flip" value
@ -1135,13 +1141,16 @@ int LUA_HudLib(lua_State *L)
lua_rawseti(L, -2, 2); // HUD[2] = game rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 3); // HUD[2] = scores rendering functions array
lua_rawseti(L, -2, 3); // HUD[3] = scores rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 4); // HUD[3] = title rendering functions array
lua_rawseti(L, -2, 4); // HUD[4] = intermission rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 5); // HUD[4] = title card rendering functions array
lua_rawseti(L, -2, 5); // HUD[5] = title rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 6); // HUD[6] = title card rendering functions array
lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
luaL_newmetatable(L, META_HUDINFO);
@ -1313,4 +1322,29 @@ void LUAh_TitleCardHUD(player_t *stplayr)
hud_running = false;
}
void LUAh_IntermissionHUD(void)
{
if (!gL || !(hudAvailable & (1<<hudhook_intermission)))
return;
hud_running = true;
lua_pop(gL, -1);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 4); // HUD[4] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
lua_pushnil(gL);
while (lua_next(gL, -3) != 0) {
lua_pushvalue(gL, -3); // graphics library (HUD[1])
LUA_Call(gL, 1);
}
lua_pop(gL, -1);
hud_running = false;
}
#endif

View file

@ -266,7 +266,6 @@ static int lib_getSpriteInfo(lua_State *L)
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to spriteinfo[] (%s)", e);
#define TYPEERROR(f, t1, t2) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t1), lua_typename(L, t2)))
#ifdef ROTSPRITE
static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, int idx)
{
int okcool = 0;
@ -360,7 +359,6 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
return 0;
}
#endif
static int lib_setSpriteInfo(lua_State *L)
{
@ -393,14 +391,11 @@ static int lib_setSpriteInfo(lua_State *L)
if (lua_isnumber(L, 2))
{
i = lua_tointeger(L, 2);
#ifndef ROTSPRITE
i++; // shift index in case of missing rotsprite support
#endif
}
else
str = luaL_checkstring(L, 2);
#ifdef ROTSPRITE
if (i == 1 || (str && fastcmp(str, "pivot")))
{
// pivot[] is a table
@ -409,7 +404,6 @@ static int lib_setSpriteInfo(lua_State *L)
else
FIELDERROR("pivot", va("%s expected, got %s", lua_typename(L, LUA_TTABLE), luaL_typename(L, -1)))
}
#endif
lua_pop(L, 1);
}
@ -434,7 +428,6 @@ static int spriteinfo_get(lua_State *L)
I_Assert(sprinfo != NULL);
#ifdef ROTSPRITE
// push spriteframepivot_t userdata
if (fastcmp(field, "pivot"))
{
@ -448,7 +441,6 @@ static int spriteinfo_get(lua_State *L)
return 1;
}
else
#endif
return luaL_error(L, LUA_QL("spriteinfo_t") " has no field named " LUA_QS, field);
return 0;
@ -473,6 +465,7 @@ static int spriteinfo_set(lua_State *L)
#ifdef ROTSPRITE
if (sprites != NULL)
R_FreeSingleRotSprite(&sprites[sprinfo-spriteinfo]);
#endif
if (fastcmp(field, "pivot"))
{
@ -488,7 +481,6 @@ static int spriteinfo_set(lua_State *L)
}
}
else
#endif
return luaL_error(L, va("Field %s does not exist in spriteinfo_t", field));
return 0;
@ -506,7 +498,6 @@ static int spriteinfo_num(lua_State *L)
}
// framepivot_t
#ifdef ROTSPRITE
static int pivotlist_get(lua_State *L)
{
void **userdata;
@ -616,7 +607,6 @@ static int framepivot_num(lua_State *L)
lua_pushinteger(L, 2);
return 1;
}
#endif
////////////////
// STATE INFO //
@ -1538,7 +1528,6 @@ int LUA_InfoLib(lua_State *L)
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
#ifdef ROTSPRITE
luaL_newmetatable(L, META_PIVOTLIST);
lua_pushcfunction(L, pivotlist_get);
lua_setfield(L, -2, "__index");
@ -1560,7 +1549,6 @@ int LUA_InfoLib(lua_State *L)
lua_pushcfunction(L, framepivot_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
#endif
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);

View file

@ -23,10 +23,8 @@ extern lua_State *gL;
#define META_MOBJINFO "MOBJINFO_T*"
#define META_SFXINFO "SFXINFO_T*"
#define META_SPRITEINFO "SPRITEINFO_T*"
#ifdef ROTSPRITE
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
#endif
#define META_MOBJ "MOBJ_T*"
#define META_MAPTHING "MAPTHING_T*"

View file

@ -134,6 +134,7 @@ enum side_e {
side_toptexture,
side_bottomtexture,
side_midtexture,
side_line,
side_sector,
side_special,
side_repeatcnt,
@ -157,14 +158,20 @@ enum vertex_e {
vertex_valid = 0,
vertex_x,
vertex_y,
vertex_z
vertex_floorz,
vertex_floorzset,
vertex_ceilingz,
vertex_ceilingzset
};
static const char *const vertex_opt[] = {
"valid",
"x",
"y",
"z",
"floorz",
"floorzset",
"ceilingz",
"ceilingzset",
NULL};
enum ffloor_e {
@ -445,7 +452,7 @@ static int sectorlines_get(lua_State *L)
// get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result
// we need this to determine the array's actual size, and therefore also the maximum value allowed as an index
// this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy
numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
/* OLD HACK
// check first linedef to figure which of its sectors owns this sector->lines pointer
@ -479,7 +486,7 @@ static int sectorlines_num(lua_State *L)
return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
// see comments in the _get function above
numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
lua_pushinteger(L, numoflines);
return 1;
}
@ -869,6 +876,9 @@ static int side_get(lua_State *L)
case side_midtexture:
lua_pushinteger(L, side->midtexture);
return 1;
case side_line:
LUA_PushUserdata(L, side->line, META_LINE);
return 1;
case side_sector:
LUA_PushUserdata(L, side->sector, META_SECTOR);
return 1;
@ -902,6 +912,7 @@ static int side_set(lua_State *L)
switch(field)
{
case side_valid: // valid
case side_line:
case side_sector:
case side_special:
case side_text:
@ -965,8 +976,17 @@ static int vertex_get(lua_State *L)
case vertex_y:
lua_pushfixed(L, vertex->y);
return 1;
case vertex_z:
lua_pushfixed(L, vertex->z);
case vertex_floorzset:
lua_pushboolean(L, vertex->floorzset);
return 1;
case vertex_ceilingzset:
lua_pushboolean(L, vertex->ceilingzset);
return 1;
case vertex_floorz:
lua_pushfixed(L, vertex->floorz);
return 1;
case vertex_ceilingz:
lua_pushfixed(L, vertex->ceilingz);
return 1;
}
return 0;
@ -2071,6 +2091,12 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushinteger(L, header->levelselect);
else if (fastcmp(field,"bonustype"))
lua_pushinteger(L, header->bonustype);
else if (fastcmp(field,"ltzzpatch"))
lua_pushstring(L, header->ltzzpatch);
else if (fastcmp(field,"ltzztext"))
lua_pushstring(L, header->ltzztext);
else if (fastcmp(field,"ltactdiamond"))
lua_pushstring(L, header->ltactdiamond);
else if (fastcmp(field,"maxbonuslives"))
lua_pushinteger(L, header->maxbonuslives);
else if (fastcmp(field,"levelflags"))

View file

@ -32,9 +32,7 @@ enum mobj_e {
mobj_snext,
mobj_sprev,
mobj_angle,
#ifdef ROTSPRITE
mobj_rollangle,
#endif
mobj_sprite,
mobj_frame,
mobj_sprite2,
@ -101,9 +99,7 @@ static const char *const mobj_opt[] = {
"snext",
"sprev",
"angle",
#ifdef ROTSPRITE
"rollangle",
#endif
"sprite",
"frame",
"sprite2",
@ -205,11 +201,9 @@ static int mobj_get(lua_State *L)
case mobj_angle:
lua_pushangle(L, mo->angle);
break;
#ifdef ROTSPRITE
case mobj_rollangle:
lua_pushangle(L, mo->rollangle);
break;
#endif
case mobj_sprite:
lua_pushinteger(L, mo->sprite);
break;
@ -462,11 +456,9 @@ static int mobj_set(lua_State *L)
else if (mo->player == &players[secondarydisplayplayer])
localangle2 = mo->angle;
break;
#ifdef ROTSPRITE
case mobj_rollangle:
mo->rollangle = luaL_checkangle(L, 3);
break;
#endif
case mobj_sprite:
mo->sprite = luaL_checkinteger(L, 3);
break;

View file

@ -18,7 +18,9 @@
#include "w_wad.h"
#include "p_setup.h"
#include "r_state.h"
#include "r_sky.h"
#include "g_game.h"
#include "f_finale.h"
#include "byteptr.h"
#include "p_saveg.h"
#include "p_local.h"
@ -79,8 +81,237 @@ FUNCNORETURN static int LUA_Panic(lua_State *L)
#endif
}
// Moved here from lib_getenum.
int LUA_PushGlobals(lua_State *L, const char *word)
{
if (fastcmp(word,"gamemap")) {
lua_pushinteger(L, gamemap);
return 1;
} else if (fastcmp(word,"maptol")) {
lua_pushinteger(L, maptol);
return 1;
} else if (fastcmp(word,"ultimatemode")) {
lua_pushboolean(L, ultimatemode != 0);
return 1;
} else if (fastcmp(word,"mariomode")) {
lua_pushboolean(L, mariomode != 0);
return 1;
} else if (fastcmp(word,"twodlevel")) {
lua_pushboolean(L, twodlevel != 0);
return 1;
} else if (fastcmp(word,"circuitmap")) {
lua_pushboolean(L, circuitmap);
return 1;
} else if (fastcmp(word,"netgame")) {
lua_pushboolean(L, netgame);
return 1;
} else if (fastcmp(word,"multiplayer")) {
lua_pushboolean(L, multiplayer);
return 1;
} else if (fastcmp(word,"modeattacking")) {
lua_pushboolean(L, modeattacking);
return 1;
} else if (fastcmp(word,"splitscreen")) {
lua_pushboolean(L, splitscreen);
return 1;
} else if (fastcmp(word,"gamecomplete")) {
lua_pushboolean(L, gamecomplete);
return 1;
} else if (fastcmp(word,"devparm")) {
lua_pushboolean(L, devparm);
return 1;
} else if (fastcmp(word,"modifiedgame")) {
lua_pushboolean(L, modifiedgame && !savemoddata);
return 1;
} else if (fastcmp(word,"menuactive")) {
lua_pushboolean(L, menuactive);
return 1;
} else if (fastcmp(word,"paused")) {
lua_pushboolean(L, paused);
return 1;
} else if (fastcmp(word,"bluescore")) {
lua_pushinteger(L, bluescore);
return 1;
} else if (fastcmp(word,"redscore")) {
lua_pushinteger(L, redscore);
return 1;
} else if (fastcmp(word,"timelimit")) {
lua_pushinteger(L, cv_timelimit.value);
return 1;
} else if (fastcmp(word,"pointlimit")) {
lua_pushinteger(L, cv_pointlimit.value);
return 1;
// begin map vars
} else if (fastcmp(word,"spstage_start")) {
lua_pushinteger(L, spstage_start);
return 1;
} else if (fastcmp(word,"sstage_start")) {
lua_pushinteger(L, sstage_start);
return 1;
} else if (fastcmp(word,"sstage_end")) {
lua_pushinteger(L, sstage_end);
return 1;
} else if (fastcmp(word,"smpstage_start")) {
lua_pushinteger(L, smpstage_start);
return 1;
} else if (fastcmp(word,"smpstage_end")) {
lua_pushinteger(L, smpstage_end);
return 1;
} else if (fastcmp(word,"titlemap")) {
lua_pushinteger(L, titlemap);
return 1;
} else if (fastcmp(word,"titlemapinaction")) {
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
return 1;
} else if (fastcmp(word,"bootmap")) {
lua_pushinteger(L, bootmap);
return 1;
} else if (fastcmp(word,"tutorialmap")) {
lua_pushinteger(L, tutorialmap);
return 1;
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
lua_pushinteger(L, skincolor_redteam);
return 1;
} else if (fastcmp(word,"skincolor_blueteam")) {
lua_pushinteger(L, skincolor_blueteam);
return 1;
} else if (fastcmp(word,"skincolor_redring")) {
lua_pushinteger(L, skincolor_redring);
return 1;
} else if (fastcmp(word,"skincolor_bluering")) {
lua_pushinteger(L, skincolor_bluering);
return 1;
// end CTF colors
// begin timers
} else if (fastcmp(word,"invulntics")) {
lua_pushinteger(L, invulntics);
return 1;
} else if (fastcmp(word,"sneakertics")) {
lua_pushinteger(L, sneakertics);
return 1;
} else if (fastcmp(word,"flashingtics")) {
lua_pushinteger(L, flashingtics);
return 1;
} else if (fastcmp(word,"tailsflytics")) {
lua_pushinteger(L, tailsflytics);
return 1;
} else if (fastcmp(word,"underwatertics")) {
lua_pushinteger(L, underwatertics);
return 1;
} else if (fastcmp(word,"spacetimetics")) {
lua_pushinteger(L, spacetimetics);
return 1;
} else if (fastcmp(word,"extralifetics")) {
lua_pushinteger(L, extralifetics);
return 1;
} else if (fastcmp(word,"nightslinktics")) {
lua_pushinteger(L, nightslinktics);
return 1;
} else if (fastcmp(word,"gameovertics")) {
lua_pushinteger(L, gameovertics);
return 1;
} else if (fastcmp(word,"ammoremovaltics")) {
lua_pushinteger(L, ammoremovaltics);
return 1;
// end timers
} else if (fastcmp(word,"gametype")) {
lua_pushinteger(L, gametype);
return 1;
} else if (fastcmp(word,"gametyperules")) {
lua_pushinteger(L, gametyperules);
return 1;
} else if (fastcmp(word,"leveltime")) {
lua_pushinteger(L, leveltime);
return 1;
} else if (fastcmp(word,"sstimer")) {
lua_pushinteger(L, sstimer);
return 1;
} else if (fastcmp(word,"curWeather")) {
lua_pushinteger(L, curWeather);
return 1;
} else if (fastcmp(word,"globalweather")) {
lua_pushinteger(L, globalweather);
return 1;
} else if (fastcmp(word,"levelskynum")) {
lua_pushinteger(L, levelskynum);
return 1;
} else if (fastcmp(word,"globallevelskynum")) {
lua_pushinteger(L, globallevelskynum);
return 1;
} else if (fastcmp(word,"mapmusname")) {
lua_pushstring(L, mapmusname);
return 1;
} else if (fastcmp(word,"mapmusflags")) {
lua_pushinteger(L, mapmusflags);
return 1;
} else if (fastcmp(word,"mapmusposition")) {
lua_pushinteger(L, mapmusposition);
return 1;
// local player variables, by popular request
} else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1)
if (consoleplayer < 0 || !playeringame[consoleplayer])
return 0;
LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1)
if (displayplayer < 0 || !playeringame[displayplayer])
return 0;
LUA_PushUserdata(L, &players[displayplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen
if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer])
return 0;
LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER);
return 1;
// end local player variables
} else if (fastcmp(word,"server")) {
if ((!multiplayer || !netgame) && !playeringame[serverplayer])
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array.
LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)");
if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer))
return 0;
LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);
return 1;
} else if (fastcmp(word,"gravity")) {
lua_pushinteger(L, gravity);
return 1;
} else if (fastcmp(word,"VERSIONSTRING")) {
lua_pushstring(L, VERSIONSTRING);
return 1;
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
}
return 0;
}
// See the above.
int LUA_CheckGlobals(lua_State *L, const char *word)
{
if (fastcmp(word, "redscore"))
redscore = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "bluescore"))
bluescore = (UINT32)luaL_checkinteger(L, 2);
else
return 0;
// Global variable set, so return and don't error.
return 1;
}
// This function decides which global variables you are allowed to set.
static int noglobals(lua_State *L)
static int setglobals(lua_State *L)
{
const char *csname;
char *name;
@ -106,6 +337,9 @@ static int noglobals(lua_State *L)
return 0;
}
if (LUA_CheckGlobals(L, csname))
return 0;
Z_Free(name);
return luaL_error(L, "Implicit global " LUA_QS " prevented. Create a local variable instead.", csname);
}
@ -144,7 +378,7 @@ static void LUA_ClearState(void)
// lock the global namespace
lua_getmetatable(L, LUA_GLOBALSINDEX);
lua_pushcfunction(L, noglobals);
lua_pushcfunction(L, setglobals);
lua_setfield(L, -2, "__newindex");
lua_newtable(L);
lua_setfield(L, -2, "__metatable");

View file

@ -54,6 +54,8 @@ void LUA_InvalidatePlayer(player_t *player);
void LUA_Step(void);
void LUA_Archive(void);
void LUA_UnArchive(void);
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(const char *name); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg,

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2013-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2013 by "Ninji".
// Copyright (C) 2013-2019 by Sonic Team Junior.
//

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2013-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2013-2019 by Sonic Team Junior.
//
// This program is free software distributed under the

View file

@ -517,6 +517,7 @@ void Command_Teleport_f(void)
if (!starpostnum) // spawnpoints...
{
mapthing_t *mt;
fixed_t offset;
if (starpostpath >= numcoopstarts)
{
@ -527,6 +528,7 @@ void Command_Teleport_f(void)
mt = playerstarts[starpostpath]; // Given above check, should never be NULL.
intx = mt->x<<FRACBITS;
inty = mt->y<<FRACBITS;
offset = mt->z<<FRACBITS;
ss = R_IsPointInSubsector(intx, inty);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
@ -538,17 +540,9 @@ void Command_Teleport_f(void)
// Flagging a player's ambush will make them start on the ceiling
// Objectflip inverts
if (!!(mt->options & MTF_AMBUSH) ^ !!(mt->options & MTF_OBJECTFLIP))
{
intz = ss->sector->ceilingheight - p->mo->height;
if (mt->options >> ZSHIFT)
intz -= ((mt->options >> ZSHIFT) << FRACBITS);
}
intz = ss->sector->ceilingheight - p->mo->height - offset;
else
{
intz = ss->sector->floorheight;
if (mt->options >> ZSHIFT)
intz += ((mt->options >> ZSHIFT) << FRACBITS);
}
intz = ss->sector->floorheight + offset;
if (mt->options & MTF_OBJECTFLIP) // flip the player!
{
@ -778,7 +772,7 @@ void Command_CauseCfail_f(void)
P_SetThingPosition(players[consoleplayer].mo);
// CTF consistency test
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
{
if (blueflag) {
P_RemoveMobj(blueflag);
@ -1106,7 +1100,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
#else
fixed_t cheight = sec->ceilingheight;
#endif
mt->options = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
mt->z = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
}
else
{
@ -1115,12 +1109,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
#else
fixed_t fheight = sec->floorheight;
#endif
mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS);
mt->z = (UINT16)((player->mo->z - fheight)>>FRACBITS);
}
mt->options <<= ZSHIFT;
mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle)));
mt->options |= (UINT16)cv_opflags.value;
mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value;
return mt;
}
@ -1187,21 +1180,21 @@ void OP_NightsObjectplace(player_t *player)
mt->options = (mt->options & ~(UINT16)cv_opflags.value) | (UINT16)cv_ophoopflags.value;
mt->angle = (INT16)(mt->angle+(INT16)((FixedInt(FixedDiv(temp*FRACUNIT, 360*(FRACUNIT/256))))<<8));
P_SpawnHoopsAndRings(mt, false);
P_SpawnHoop(mt);
}
// This places a bumper!
if (cmd->buttons & BT_TOSSFLAG)
{
UINT16 vertangle = (UINT16)(player->anotherflyangle % 360);
UINT16 newflags, newz;
UINT16 newflags;
player->pflags |= PF_ATTACKDOWN;
if (!OP_HeightOkay(player, false))
return;
mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_NIGHTSBUMPER].doomednum, false);
newz = min((mt->options >> ZSHIFT) - (mobjinfo[MT_NIGHTSBUMPER].height/4), 0);
mt->z = min(mt->z - (mobjinfo[MT_NIGHTSBUMPER].height/4), 0);
// height offset: from P_TouchSpecialThing case MT_NIGHTSBUMPER
// clockwise
@ -1232,7 +1225,7 @@ void OP_NightsObjectplace(player_t *player)
else // forward
newflags = 0;
mt->options = (newz << ZSHIFT) | newflags;
mt->options = (mt->z << ZSHIFT) | newflags;
// if NiGHTS is facing backwards, orient the Thing angle forwards so that the sprite angle
// displays correctly. Backwards movement via the Thing flags is unaffected.
@ -1250,7 +1243,7 @@ void OP_NightsObjectplace(player_t *player)
return;
mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_BLUESPHERE].doomednum, false);
P_SpawnHoopsAndRings(mt, false);
P_SpawnMapThing(mt);
}
// This places a ring!
@ -1261,7 +1254,7 @@ void OP_NightsObjectplace(player_t *player)
return;
mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_RING].doomednum, false);
P_SpawnHoopsAndRings(mt, false);
P_SpawnMapThing(mt);
}
// This places a custom object as defined in the console cv_mapthingnum.
@ -1293,15 +1286,10 @@ void OP_NightsObjectplace(player_t *player)
mt = OP_CreateNewMapThing(player, (UINT16)cv_mapthingnum.value, false);
mt->angle = angle;
if (mt->type == 300 // Ring
|| mt->type == 308 || mt->type == 309 // Team Rings
|| mt->type == 1706 // Sphere
|| (mt->type >= 600 && mt->type <= 609) // Placement patterns
|| mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops
|| mt->type == 1800) // Mario Coin
{
P_SpawnHoopsAndRings(mt, false);
}
if (mt->type >= 600 && mt->type <= 609) // Placement patterns
P_SpawnItemPattern(mt, false);
else if (mt->type == 1705 || mt->type == 1713) // NiGHTS Hoops
P_SpawnHoop(mt);
else
P_SpawnMapThing(mt);
}
@ -1316,7 +1304,7 @@ void OP_ObjectplaceMovement(player_t *player)
{
ticcmd_t *cmd = &player->cmd;
if (!player->climbing && (netgame || !cv_analog.value || (player->pflags & PF_SPINNING)))
if (!player->climbing && (netgame || !cv_analog[0].value || (player->pflags & PF_SPINNING)))
player->drawangle = player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
ticruned++;
@ -1438,19 +1426,14 @@ void OP_ObjectplaceMovement(player_t *player)
return;
mt = OP_CreateNewMapThing(player, (UINT16)spawnthing, ceiling);
if (mt->type == 300 // Ring
|| mt->type == 308 || mt->type == 309 // Team Rings
|| mt->type == 1706 // Nights Wing
|| (mt->type >= 600 && mt->type <= 609) // Placement patterns
|| mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops
|| mt->type == 1800) // Mario Coin
{
P_SpawnHoopsAndRings(mt, false);
}
if (mt->type >= 600 && mt->type <= 609) // Placement patterns
P_SpawnItemPattern(mt, false);
else if (mt->type == 1705 || mt->type == 1713) // NiGHTS Hoops
P_SpawnHoop(mt);
else
P_SpawnMapThing(mt);
CONS_Printf(M_GetText("Placed object type %d at %d, %d, %d, %d\n"), mt->type, mt->x, mt->y, mt->options>>ZSHIFT, mt->angle);
CONS_Printf(M_GetText("Placed object type %d at %d, %d, %d, %d\n"), mt->type, mt->x, mt->y, mt->z, mt->angle);
}
}

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2019 by Sonic Team Junior.
//
// This program is free software distributed under the

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2019 by Sonic Team Junior.
//
// This program is free software distributed under the
@ -98,8 +98,9 @@ typedef struct
typedef struct
{
char name[20]; ///< Name of the goal (used in the "emblem awarded" cecho)
char description[40];///< Description of goal (used in statistics)
char description[40]; ///< Description of goal (used in statistics)
UINT8 conditionset; ///< Condition set that awards this emblem.
UINT8 showconditionset; ///< Condition set that shows this emblem.
UINT8 sprite; ///< emblem sprite to use, 0 - 25
UINT8 color; ///< skincolor to use
UINT8 collected; ///< Do you have this emblem?
@ -112,6 +113,7 @@ typedef struct
char objective[64];
UINT16 height; // menu height
UINT8 conditionset;
UINT8 showconditionset;
INT16 type;
INT16 variable;
UINT8 nocecho;

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2019 by Sonic Team Junior.
//
// This program is free software distributed under the
@ -298,11 +298,14 @@ menu_t OP_MPControlsDef, OP_MiscControlsDef;
menu_t OP_P1ControlsDef, OP_P2ControlsDef, OP_MouseOptionsDef;
menu_t OP_Mouse2OptionsDef, OP_Joystick1Def, OP_Joystick2Def;
menu_t OP_CameraOptionsDef, OP_Camera2OptionsDef;
menu_t OP_PlaystyleDef;
static void M_VideoModeMenu(INT32 choice);
static void M_Setup1PControlsMenu(INT32 choice);
static void M_Setup2PControlsMenu(INT32 choice);
static void M_Setup1PJoystickMenu(INT32 choice);
static void M_Setup2PJoystickMenu(INT32 choice);
static void M_Setup1PPlaystyleMenu(INT32 choice);
static void M_Setup2PPlaystyleMenu(INT32 choice);
static void M_AssignJoystick(INT32 choice);
static void M_ChangeControl(INT32 choice);
@ -348,6 +351,9 @@ static void M_DrawLevelStats(void);
static void M_DrawTimeAttackMenu(void);
static void M_DrawNightsAttackMenu(void);
static void M_DrawSetupChoosePlayerMenu(void);
static void M_DrawControlsDefMenu(void);
static void M_DrawCameraOptionsMenu(void);
static void M_DrawPlaystyleMenu(void);
static void M_DrawControl(void);
static void M_DrawMainVideoMenu(void);
static void M_DrawVideoMode(void);
@ -375,6 +381,7 @@ static void M_HandleSoundTest(INT32 choice);
static void M_HandleImageDef(INT32 choice);
static void M_HandleLoadSave(INT32 choice);
static void M_HandleLevelStats(INT32 choice);
static void M_HandlePlaystyleMenu(INT32 choice);
#ifndef NONET
static boolean M_CancelConnect(void);
static void M_HandleConnectIP(INT32 choice);
@ -614,7 +621,7 @@ static menuitem_t MISC_ChangeTeamMenu[] =
{IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90},
};
static const gtdesc_t gametypedesc[] =
gtdesc_t gametypedesc[NUMGAMETYPES] =
{
{{ 54, 54}, "Play through the single-player campaign with your friends, teaming up to beat Dr Eggman's nefarious challenges!"},
{{103, 103}, "Speed your way through the main acts, competing in several different categories to see who's the best."},
@ -1040,9 +1047,8 @@ static menuitem_t OP_P1ControlsMenu[] =
{IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_CameraOptionsDef, 50},
//{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog, 100},
{IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar, 70},
{IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake, 80},
{IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake, 70},
{IT_CALL | IT_STRING, NULL, "Play Style...", M_Setup1PPlaystyleMenu, 80},
};
static menuitem_t OP_P2ControlsMenu[] =
@ -1053,9 +1059,8 @@ static menuitem_t OP_P2ControlsMenu[] =
{IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_Camera2OptionsDef, 50},
//{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog2, 100},
{IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar2, 70},
{IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake2, 80},
{IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake2, 70},
{IT_CALL | IT_STRING, NULL, "Play Style...", M_Setup2PPlaystyleMenu, 80},
};
static menuitem_t OP_ChangeControlsMenu[] =
@ -1127,8 +1132,8 @@ static menuitem_t OP_Joystick1Menu[] =
{IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 120},
{IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 130},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER,
NULL, "Deadzone", &cv_deadzone, 140 },
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone, 140},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone, 150},
};
static menuitem_t OP_Joystick2Menu[] =
@ -1145,8 +1150,8 @@ static menuitem_t OP_Joystick2Menu[] =
{IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,120},
{IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER,
NULL, "Deadzone", &cv_deadzone2, 140 },
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone2,140},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone2,150},
};
static menuitem_t OP_JoystickSetMenu[1+MAX_JOYSTICKS];
@ -1183,32 +1188,98 @@ static menuitem_t OP_Mouse2OptionsMenu[] =
static menuitem_t OP_CameraOptionsMenu[] =
{
{IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam , 10},
{IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 20},
{IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam_orbit , 30},
{IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam_adjust, 40},
{IT_HEADER, NULL, "General Toggles", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam , 6},
{IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 11},
{IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam_orbit , 16},
{IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam_adjust, 21},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam_dist, 60},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam_height, 70},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Spacial Speed", &cv_cam_speed, 80},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Turning Speed", &cv_cam_turnmultiplier, 90},
{IT_HEADER, NULL, "Camera Positioning", NULL, 30},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam_savedist[0][0], 36},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam_saveheight[0][0], 41},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Spacial Speed", &cv_cam_speed, 46},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Rotation Speed", &cv_cam_turnmultiplier, 51},
{IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 100},
{IT_HEADER, NULL, "Display Options", NULL, 60},
{IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 66},
};
static menuitem_t OP_Camera2OptionsMenu[] =
{
{IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam2 , 10},
{IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 20},
{IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam2_orbit , 30},
{IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam2_adjust, 40},
{IT_HEADER, NULL, "General Toggles", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam2 , 6},
{IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 11},
{IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam2_orbit , 16},
{IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam2_adjust, 21},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam2_dist, 60},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam2_height, 70},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Spacial Speed", &cv_cam2_speed, 80},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Turning Speed", &cv_cam2_turnmultiplier, 90},
{IT_HEADER, NULL, "Camera Positioning", NULL, 30},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam_savedist[0][1], 36},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam_saveheight[0][1], 41},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Spacial Speed", &cv_cam2_speed, 46},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Rotation Speed", &cv_cam2_turnmultiplier, 51},
{IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 100},
{IT_HEADER, NULL, "Display Options", NULL, 60},
{IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 66},
};
static menuitem_t OP_CameraExtendedOptionsMenu[] =
{
{IT_HEADER, NULL, "General Toggles", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam , 6},
{IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 11},
{IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam_orbit , 16},
{IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam_adjust, 21},
{IT_HEADER, NULL, "Camera Positioning", NULL, 30},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam_savedist[1][0], 36},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam_saveheight[1][0], 41},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Spacial Speed", &cv_cam_speed, 46},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Rotation Speed", &cv_cam_turnmultiplier, 51},
{IT_HEADER, NULL, "Automatic Camera Options", NULL, 60},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Shift to player angle", &cv_cam_shiftfacing[0], 66},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to player angle", &cv_cam_turnfacing[0], 71},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to ability", &cv_cam_turnfacingability[0], 76},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to spindash", &cv_cam_turnfacingspindash[0], 81},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to input", &cv_cam_turnfacinginput[0], 86},
{IT_HEADER, NULL, "Locked Camera Options", NULL, 95},
{IT_STRING | IT_CVAR, NULL, "Lock button behavior", &cv_cam_centertoggle[0], 101},
{IT_STRING | IT_CVAR, NULL, "Sideways movement", &cv_cam_lockedinput[0], 106},
{IT_STRING | IT_CVAR, NULL, "Targeting assist", &cv_cam_lockonboss[0], 111},
{IT_HEADER, NULL, "Display Options", NULL, 120},
{IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 126},
};
static menuitem_t OP_Camera2ExtendedOptionsMenu[] =
{
{IT_HEADER, NULL, "General Toggles", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam2 , 6},
{IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 11},
{IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam2_orbit , 16},
{IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam2_adjust, 21},
{IT_HEADER, NULL, "Camera Positioning", NULL, 30},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam_savedist[1][1], 36},
{IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam_saveheight[1][1], 41},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Spacial Speed", &cv_cam2_speed, 46},
{IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Rotation Speed", &cv_cam2_turnmultiplier, 51},
{IT_HEADER, NULL, "Automatic Camera Options", NULL, 60},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Shift to player angle", &cv_cam_shiftfacing[1], 66},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to player angle", &cv_cam_turnfacing[1], 71},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to ability", &cv_cam_turnfacingability[1], 76},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to spindash", &cv_cam_turnfacingspindash[1], 81},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Turn to input", &cv_cam_turnfacinginput[1], 86},
{IT_HEADER, NULL, "Locked Camera Options", NULL, 95},
{IT_STRING | IT_CVAR, NULL, "Lock button behavior", &cv_cam_centertoggle[1], 101},
{IT_STRING | IT_CVAR, NULL, "Sideways movement", &cv_cam_lockedinput[1], 106},
{IT_STRING | IT_CVAR, NULL, "Targeting assist", &cv_cam_lockonboss[1], 111},
{IT_HEADER, NULL, "Display Options", NULL, 120},
{IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 126},
};
static menuitem_t OP_VideoOptionsMenu[] =
@ -1326,7 +1397,7 @@ static menuitem_t OP_OpenGLOptionsMenu[] =
{IT_STRING|IT_CVAR, NULL, "Model lighting", &cv_grmodellighting, 32},
{IT_HEADER, NULL, "General", NULL, 51},
{IT_STRING|IT_CVAR, NULL, "Field of view", &cv_grfov, 63},
{IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 63},
{IT_STRING|IT_CVAR, NULL, "Quality", &cv_scr_depth, 73},
{IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 83},
{IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode,93},
@ -1927,12 +1998,24 @@ menu_t OP_MainDef = DEFAULTMENUSTYLE(
menu_t OP_ChangeControlsDef = CONTROLMENUSTYLE(
MN_OP_MAIN + (MN_OP_CHANGECONTROLS << 12), // second level (<<6) set on runtime
OP_ChangeControlsMenu, &OP_MainDef);
menu_t OP_P1ControlsDef = DEFAULTMENUSTYLE(
menu_t OP_P1ControlsDef = {
MN_OP_MAIN + (MN_OP_P1CONTROLS << 6),
"M_CONTRO", OP_P1ControlsMenu, &OP_MainDef, 50, 30);
menu_t OP_P2ControlsDef = DEFAULTMENUSTYLE(
"M_CONTRO",
sizeof(OP_P1ControlsMenu)/sizeof(menuitem_t),
&OP_MainDef,
OP_P1ControlsMenu,
M_DrawControlsDefMenu,
50, 30, 0, NULL};
menu_t OP_P2ControlsDef = {
MN_OP_MAIN + (MN_OP_P2CONTROLS << 6),
"M_CONTRO", OP_P2ControlsMenu, &OP_MainDef, 50, 30);
"M_CONTRO",
sizeof(OP_P2ControlsMenu)/sizeof(menuitem_t),
&OP_MainDef,
OP_P2ControlsMenu,
M_DrawControlsDefMenu,
50, 30, 0, NULL};
menu_t OP_MouseOptionsDef = DEFAULTMENUSTYLE(
MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1MOUSE << 12),
"M_CONTRO", OP_MouseOptionsMenu, &OP_P1ControlsDef, 35, 30);
@ -1957,12 +2040,41 @@ menu_t OP_JoystickSetDef =
0,
NULL
};
menu_t OP_CameraOptionsDef = DEFAULTMENUSTYLE(
menu_t OP_CameraOptionsDef = {
MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1CAMERA << 12),
"M_CONTRO", OP_CameraOptionsMenu, &OP_P1ControlsDef, 35, 30);
menu_t OP_Camera2OptionsDef = DEFAULTMENUSTYLE(
"M_CONTRO",
sizeof (OP_CameraOptionsMenu)/sizeof (menuitem_t),
&OP_P1ControlsDef,
OP_CameraOptionsMenu,
M_DrawCameraOptionsMenu,
35, 30,
0,
NULL
};
menu_t OP_Camera2OptionsDef = {
MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2CAMERA << 12),
"M_CONTRO", OP_Camera2OptionsMenu, &OP_P2ControlsDef, 35, 30);
"M_CONTRO",
sizeof (OP_Camera2OptionsMenu)/sizeof (menuitem_t),
&OP_P2ControlsDef,
OP_Camera2OptionsMenu,
M_DrawCameraOptionsMenu,
35, 30,
0,
NULL
};
static menuitem_t OP_PlaystyleMenu[] = {{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandlePlaystyleMenu, 0}};
menu_t OP_PlaystyleDef = {
MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_PLAYSTYLE << 12),
NULL,
1,
&OP_P1ControlsDef,
OP_PlaystyleMenu,
M_DrawPlaystyleMenu,
0, 0, 0, NULL
};
menu_t OP_VideoOptionsDef =
@ -3079,7 +3191,7 @@ boolean M_Responder(event_t *ev)
}
else if (ev->type == ev_joystick && ev->data1 == 0 && joywait < I_GetTime())
{
const INT32 jdeadzone = (JOYAXISRANGE * cv_deadzone.value) / FRACUNIT;
const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT;
if (ev->data3 != INT32_MAX)
{
if (Joystick.bGamepadStyle || abs(ev->data3) > jdeadzone)
@ -4197,6 +4309,102 @@ static void M_DrawGenericMenu(void)
}
}
const char *PlaystyleNames[4] = {"Legacy", "Standard", "Simple", "Old Analog??"};
const char *PlaystyleDesc[4] = {
// Legacy
"The play style used for\n"
"old-school SRB2.\n"
"\n"
"This play style is identical\n"
"to Standard, except that the\n"
"player always looks in the\n"
"direction of the camera."
,
// Standard
"The default play style,\n"
"designed for full control\n"
"with a keyboard and mouse.\n"
"\n"
"The camera rotates only when\n"
"you tell it to. The player\n"
"looks in the direction they're\n"
"moving, but acts in the direction\n"
"the camera is facing.\n"
"\n"
"Mastery of this play style will\n"
"open up the highest level of play!"
,
// Simple
"A play style designed for\n"
"gamepads and hassle-free play.\n"
"\n"
"The camera rotates automatically\n"
"as you move, and the player faces\n"
"and acts in the direction\n"
"they're moving.\n"
"\n"
"Hold \x82" "Center View\x80 to lock the\n"
"camera behind the player!\n"
,
// Old Analog
"I see.\n"
"\n"
"You really liked the old analog mode,\n"
"so when 2.2 came out, you opened up\n"
"your config file and brought it back.\n"
"\n"
"That's absolutely valid, but I implore\n"
"you to try the new Simple play style\n"
"instead!"
};
static UINT8 playstyle_activeplayer = 0, playstyle_currentchoice = 0;
static void M_DrawControlsDefMenu(void)
{
UINT8 opt = 0;
M_DrawGenericMenu();
if (currentMenu == &OP_P1ControlsDef)
{
opt = cv_directionchar[0].value ? 1 : 0;
opt = playstyle_currentchoice = cv_useranalog[0].value ? 3 - opt : opt;
if (opt == 2)
{
OP_CameraOptionsDef.menuitems = OP_CameraExtendedOptionsMenu;
OP_CameraOptionsDef.numitems = sizeof (OP_CameraExtendedOptionsMenu) / sizeof (menuitem_t);
}
else
{
OP_CameraOptionsDef.menuitems = OP_CameraOptionsMenu;
OP_CameraOptionsDef.numitems = sizeof (OP_CameraOptionsMenu) / sizeof (menuitem_t);
}
}
else
{
opt = cv_directionchar[1].value ? 1 : 0;
opt = playstyle_currentchoice = cv_useranalog[1].value ? 3 - opt : opt;
if (opt == 2)
{
OP_Camera2OptionsDef.menuitems = OP_Camera2ExtendedOptionsMenu;
OP_Camera2OptionsDef.numitems = sizeof (OP_Camera2ExtendedOptionsMenu) / sizeof (menuitem_t);
}
else
{
OP_Camera2OptionsDef.menuitems = OP_Camera2OptionsMenu;
OP_Camera2OptionsDef.numitems = sizeof (OP_Camera2OptionsMenu) / sizeof (menuitem_t);
}
}
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + 80, V_YELLOWMAP, PlaystyleNames[opt]);
}
#define scrollareaheight 72
// note that alphakey is multiplied by 2 for scrolling menus to allow greater usage in UINT8 range.
@ -4208,7 +4416,9 @@ static void M_DrawGenericScrollMenu(void)
x = currentMenu->x;
y = currentMenu->y;
if ((currentMenu->menuitems[itemOn].alphaKey*2 - currentMenu->menuitems[0].alphaKey*2) <= scrollareaheight)
if (currentMenu->menuitems[currentMenu->numitems-1].alphaKey < scrollareaheight)
tempcentery = currentMenu->y; // Not tall enough to scroll, but this thinker is used in case it becomes so
else if ((currentMenu->menuitems[itemOn].alphaKey*2 - currentMenu->menuitems[0].alphaKey*2) <= scrollareaheight)
tempcentery = currentMenu->y - currentMenu->menuitems[0].alphaKey*2;
else if ((currentMenu->menuitems[currentMenu->numitems-1].alphaKey*2 - currentMenu->menuitems[itemOn].alphaKey*2) <= scrollareaheight)
tempcentery = currentMenu->y - currentMenu->menuitems[currentMenu->numitems-1].alphaKey*2 + 2*scrollareaheight;
@ -4756,6 +4966,9 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt)
if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
return true;
if (gt >= 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt]))
return true;
return false;
case LLM_LEVELSELECT:
@ -6684,6 +6897,8 @@ 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))
continue;
if (unlockables[j].conditionset == unlockables[check_on].conditionset)
continue;
break;
@ -6707,6 +6922,8 @@ 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))
continue;
if (j && unlockables[j].conditionset == unlockables[j-1].conditionset)
continue;
break;
@ -6744,7 +6961,8 @@ static void M_DrawChecklist(void)
while (i < MAXUNLOCKABLES)
{
if (unlockables[i].name[0] == 0 //|| unlockables[i].nochecklist
|| !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS)
|| !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS
|| (!unlockables[i].unlocked && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset)))
{
i += 1;
continue;
@ -6770,10 +6988,11 @@ static void M_DrawChecklist(void)
if (unlockables[i].objective[0] != '/')
{
addy(8);
V_DrawString(currentMenu->x, y,
addy(16);
V_DrawString(currentMenu->x, y-8,
V_ALLOWLOWERCASE,
va("\x1E %s", unlockables[i].objective));
y -= 8;
}
else
{
@ -7014,12 +7233,26 @@ static void M_EmblemHints(INT32 choice)
static void M_DrawEmblemHints(void)
{
INT32 i, j = 0;
UINT32 collected = 0;
INT32 i, j = 0, x, y;
UINT32 collected = 0, local = 0;
emblem_t *emblem;
const char *hint;
for (i = 0; i < numemblems; i++)
{
emblem = &emblemlocations[i];
if (emblem->level != gamemap || emblem->type > ET_SKIN)
continue;
if (++local >= NUMHINTS*2)
break;
}
x = (local > NUMHINTS ? 4 : 12);
y = 8;
if (!local)
V_DrawCenteredString(160, 48, V_YELLOWMAP, "No hidden emblems on this map.");
else for (i = 0; i < numemblems; i++)
{
emblem = &emblemlocations[i];
if (emblem->level != gamemap || emblem->type > ET_SKIN)
@ -7028,27 +7261,35 @@ static void M_DrawEmblemHints(void)
if (emblem->collected)
{
collected = V_GREENMAP;
V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
V_DrawMappedPatch(x, y+4, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE));
}
else
{
collected = 0;
V_DrawScaledPatch(12, 12+(28*j), 0, W_CachePatchName("NEEDIT", PU_PATCH));
V_DrawScaledPatch(x, y+4, 0, W_CachePatchName("NEEDIT", PU_PATCH));
}
if (emblem->hint[0])
hint = emblem->hint;
else
hint = M_GetText("No hints available.");
hint = M_GetText("No hint available for this emblem.");
hint = V_WordWrap(40, BASEVIDWIDTH-12, 0, hint);
V_DrawString(40, 8+(28*j), V_RETURN8|V_ALLOWLOWERCASE|collected, hint);
if (local > NUMHINTS)
V_DrawThinString(x+28, y, V_RETURN8|V_ALLOWLOWERCASE|collected, hint);
else
V_DrawString(x+28, y, V_RETURN8|V_ALLOWLOWERCASE|collected, hint);
if (++j >= NUMHINTS)
y += 28;
if (++j == NUMHINTS)
{
x = 4+(BASEVIDWIDTH/2);
y = 8;
}
else if (j >= NUMHINTS*2)
break;
}
if (!j)
V_DrawCenteredString(160, 48, V_YELLOWMAP, "No hidden emblems on this map.");
M_DrawGenericMenu();
}
@ -7641,7 +7882,7 @@ void M_TutorialSaveControlResponse(INT32 ch)
CV_Set(&cv_usemouse, cv_usemouse.defaultvalue);
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog, cv_analog.defaultvalue);
CV_Set(&cv_analog[0], cv_analog[0].defaultvalue);
S_StartSound(NULL, sfx_itemup);
}
else
@ -7659,13 +7900,13 @@ static void M_TutorialControlResponse(INT32 ch)
tutorialusemouse = cv_usemouse.value;
tutorialfreelook = cv_alwaysfreelook.value;
tutorialmousemove = cv_mousemove.value;
tutorialanalog = cv_analog.value;
tutorialanalog = cv_analog[0].value;
G_CopyControls(gamecontrol, gamecontroldefault[tutorialgcs], gcl_tutorial_full, num_gcl_tutorial_full);
CV_Set(&cv_usemouse, cv_usemouse.defaultvalue);
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog, cv_analog.defaultvalue);
CV_Set(&cv_analog[0], cv_analog[0].defaultvalue);
//S_StartSound(NULL, sfx_itemup);
}
@ -8983,7 +9224,10 @@ static void M_DrawStatsMaps(int location)
else
V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_PATCH));
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, va("%s", exemblem->description));
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE,
(!exemblem->collected && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset))
? M_CreateSecretMenuOption(exemblem->description)
: exemblem->description);
}
y += 8;
@ -9989,7 +10233,7 @@ static void M_DrawRoomMenu(void)
static void M_DrawConnectMenu(void)
{
UINT16 i;
const char *gt = "Unknown";
char *gt;
INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE;
for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++)
@ -10033,14 +10277,17 @@ static void M_DrawConnectMenu(void)
V_DrawSmallString(currentMenu->x, S_LINEY(i)+8, globalflags,
va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time)));
gt = "Unknown";
if (serverlist[slindex].info.gametype < NUMGAMETYPES)
gt = Gametype_Names[serverlist[slindex].info.gametype];
gt = serverlist[slindex].info.gametypename;
V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags,
va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer));
V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, va("Gametype: %s", gt));
if (strlen(gt) > 11)
gt = va("Gametype: %.11s...", gt);
else
gt = va("Gametype: %s", gt);
V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, gt);
MP_ConnectMenu[i+FIRSTSERVERLINE].status = IT_STRING | IT_CALL;
}
@ -10081,7 +10328,15 @@ SERVER_LIST_ENTRY_COMPARATOR(time)
SERVER_LIST_ENTRY_COMPARATOR(numberofplayer)
SERVER_LIST_ENTRY_COMPARATOR_REVERSE(numberofplayer)
SERVER_LIST_ENTRY_COMPARATOR_REVERSE(maxplayer)
SERVER_LIST_ENTRY_COMPARATOR(gametype)
static int ServerListEntryComparator_gametypename(const void *entry1, const void *entry2)
{
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2;
int c;
if (( c = strcasecmp(sa->info.gametypename, sb->info.gametypename) ))
return c;
return strcmp(sa->info.servername, sb->info.servername); \
}
// Special one for modified state.
static int ServerListEntryComparator_modified(const void *entry1, const void *entry2)
@ -10121,7 +10376,7 @@ void M_SortServerList(void)
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse);
break;
case 5: // Gametype.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametype);
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename);
break;
}
#endif
@ -11561,6 +11816,88 @@ static void M_ChangeControl(INT32 choice)
M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER);
}
static void M_Setup1PPlaystyleMenu(INT32 choice)
{
(void)choice;
playstyle_activeplayer = 0;
OP_PlaystyleDef.prevMenu = &OP_P1ControlsDef;
M_SetupNextMenu(&OP_PlaystyleDef);
}
static void M_Setup2PPlaystyleMenu(INT32 choice)
{
(void)choice;
playstyle_activeplayer = 1;
OP_PlaystyleDef.prevMenu = &OP_P2ControlsDef;
M_SetupNextMenu(&OP_PlaystyleDef);
}
static void M_DrawPlaystyleMenu(void)
{
size_t i;
for (i = 0; i < 4; i++)
{
if (i != 3)
V_DrawCenteredString((i+1)*BASEVIDWIDTH/4, 20, (i == playstyle_currentchoice) ? V_YELLOWMAP : 0, PlaystyleNames[i]);
if (i == playstyle_currentchoice)
{
V_DrawScaledPatch((i+1)*BASEVIDWIDTH/4 - 8, 10, 0, W_CachePatchName("M_CURSOR", PU_CACHE));
V_DrawString(30, 50, V_ALLOWLOWERCASE, PlaystyleDesc[i]);
}
}
}
static void M_HandlePlaystyleMenu(INT32 choice)
{
switch (choice)
{
case KEY_ESCAPE:
case KEY_BACKSPACE:
M_SetupNextMenu(currentMenu->prevMenu);
break;
case KEY_ENTER:
S_StartSound(NULL, sfx_menu1);
CV_SetValue((playstyle_activeplayer ? &cv_directionchar[1] : &cv_directionchar[0]), playstyle_currentchoice ? 1 : 0);
CV_SetValue((playstyle_activeplayer ? &cv_useranalog[1] : &cv_useranalog[0]), playstyle_currentchoice/2);
if (playstyle_activeplayer)
CV_UpdateCam2Dist();
else
CV_UpdateCamDist();
M_SetupNextMenu(currentMenu->prevMenu);
break;
case KEY_LEFTARROW:
S_StartSound(NULL, sfx_menu1);
playstyle_currentchoice = (playstyle_currentchoice+2)%3;
break;
case KEY_RIGHTARROW:
S_StartSound(NULL, sfx_menu1);
playstyle_currentchoice = (playstyle_currentchoice+1)%3;
break;
}
}
static void M_DrawCameraOptionsMenu(void)
{
M_DrawGenericScrollMenu();
if (gamestate == GS_LEVEL && (paused || P_AutoPause()))
{
if (currentMenu == &OP_Camera2OptionsDef && splitscreen && camera2.chase)
P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false);
if (currentMenu == &OP_CameraOptionsDef && camera.chase)
P_MoveChaseCamera(&players[displayplayer], &camera, false);
}
}
// ===============
// VIDEO MODE MENU
// ===============

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2019 by Sonic Team Junior.
//
// This program is free software distributed under the
@ -81,6 +81,8 @@ typedef enum
MN_OP_P2JOYSTICK,
MN_OP_P2CAMERA,
MN_OP_PLAYSTYLE,
MN_OP_VIDEO,
MN_OP_VIDEOMODE,
MN_OP_COLOR,
@ -372,6 +374,7 @@ typedef struct
UINT8 col[2];
char notes[441];
} gtdesc_t;
extern gtdesc_t gametypedesc[NUMGAMETYPES];
// mode descriptions for video mode menu
typedef struct

View file

@ -600,12 +600,12 @@ void M_SaveConfig(const char *filename)
CV_SetValue(&cv_usemouse, tutorialusemouse);
CV_SetValue(&cv_alwaysfreelook, tutorialfreelook);
CV_SetValue(&cv_mousemove, tutorialmousemove);
CV_SetValue(&cv_analog, tutorialanalog);
CV_SetValue(&cv_analog[0], tutorialanalog);
CV_SaveVariables(f);
CV_Set(&cv_usemouse, cv_usemouse.defaultvalue);
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog, cv_analog.defaultvalue);
CV_Set(&cv_analog[0], cv_analog[0].defaultvalue);
}
else
CV_SaveVariables(f);
@ -1779,7 +1779,7 @@ char *M_GetToken(const char *inputString)
|| stringToUse[startPos] == '\r'
|| stringToUse[startPos] == '\n'
|| stringToUse[startPos] == '\0'
|| stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
|| stringToUse[startPos] == '=' || stringToUse[startPos] == ';' // UDMF TEXTMAP.
|| inComment != 0)
&& startPos < stringLength)
{
@ -1837,6 +1837,23 @@ char *M_GetToken(const char *inputString)
texturesToken[1] = '\0';
return texturesToken;
}
// Return entire string within quotes, except without the quotes.
else if (stringToUse[startPos] == '"')
{
endPos = ++startPos;
while (stringToUse[endPos] != '"' && endPos < stringLength)
endPos++;
texturesTokenLength = endPos++ - startPos;
// Assign the memory. Don't forget an extra byte for the end of the string!
texturesToken = (char *)Z_Malloc((texturesTokenLength+1)*sizeof(char),PU_STATIC,NULL);
// Copy the string.
M_Memcpy(texturesToken, stringToUse+startPos, (size_t)texturesTokenLength);
// Make the final character NUL.
texturesToken[texturesTokenLength] = '\0';
return texturesToken;
}
// Now find the end of the token. This includes several additional characters that are okay to capture as one character, but not trailing at the end of another token.
endPos = startPos + 1;
@ -1847,7 +1864,7 @@ char *M_GetToken(const char *inputString)
&& stringToUse[endPos] != ','
&& stringToUse[endPos] != '{'
&& stringToUse[endPos] != '}'
&& stringToUse[endPos] != '"' // see above
&& stringToUse[endPos] != '=' && stringToUse[endPos] != ';' // UDMF TEXTMAP.
&& inComment == 0)
&& endPos < stringLength)
{
@ -1891,6 +1908,20 @@ void M_UnGetToken(void)
endPos = oldendPos;
}
/** Returns the current token's position.
*/
UINT32 M_GetTokenPos(void)
{
return endPos;
}
/** Sets the current token's position.
*/
void M_SetTokenPos(UINT32 newPos)
{
endPos = newPos;
}
/** Count bits in a number.
*/
UINT8 M_CountBits(UINT32 num, UINT8 size)

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2012-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2019 by Sonic Team Junior.
//
// This program is free software distributed under the

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2012-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2019 by Sonic Team Junior.
//
// This program is free software distributed under the

View file

@ -181,11 +181,9 @@ void A_SpawnObjectAbsolute(mobj_t *actor);
void A_SpawnObjectRelative(mobj_t *actor);
void A_ChangeAngleRelative(mobj_t *actor);
void A_ChangeAngleAbsolute(mobj_t *actor);
#ifdef ROTSPRITE
void A_RollAngle(mobj_t *actor);
void A_ChangeRollAngleRelative(mobj_t *actor);
void A_ChangeRollAngleAbsolute(mobj_t *actor);
#endif // ROTSPRITE
void A_PlaySound(mobj_t *actor);
void A_FindTarget(mobj_t *actor);
void A_FindTracer(mobj_t *actor);
@ -2263,7 +2261,7 @@ void A_CrushclawLaunch(mobj_t *actor)
while (chain)
{
P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz);
chain->watertop = chain->z;
chain->movefactor = chain->z;
idx += dx;
idy += dy;
idz += dz;
@ -4985,7 +4983,7 @@ void A_ThrownRing(mobj_t *actor)
continue;
// Don't home in on teammates.
if (gametype == GT_CTF
if ((gametyperules & GTR_TEAMFLAGS)
&& actor->target->player->ctfteam == player->ctfteam)
continue;
}
@ -6591,7 +6589,7 @@ void A_OldRingExplode(mobj_t *actor) {
if (changecolor)
{
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
mo->color = actor->target->color; //copy color
else if (actor->target->player->ctfteam == 2)
mo->color = skincolor_bluering;
@ -6607,7 +6605,7 @@ void A_OldRingExplode(mobj_t *actor) {
if (changecolor)
{
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
mo->color = actor->target->color; //copy color
else if (actor->target->player->ctfteam == 2)
mo->color = skincolor_bluering;
@ -6622,7 +6620,7 @@ void A_OldRingExplode(mobj_t *actor) {
if (changecolor)
{
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
mo->color = actor->target->color; //copy color
else if (actor->target->player->ctfteam == 2)
mo->color = skincolor_bluering;
@ -8627,7 +8625,6 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
actor->angle = FixedAngle(P_RandomRange(amin, amax));
}
#ifdef ROTSPRITE
// Function: A_RollAngle
//
// Description: Changes the roll angle.
@ -8663,16 +8660,10 @@ void A_RollAngle(mobj_t *actor)
//
void A_ChangeRollAngleRelative(mobj_t *actor)
{
// Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of
// getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result
// rather than the ranges, so <0 and >360 work as possible values. -Red
INT32 locvar1 = var1;
INT32 locvar2 = var2;
//angle_t angle = (P_RandomByte()+1)<<24;
const fixed_t amin = locvar1*FRACUNIT;
const fixed_t amax = locvar2*FRACUNIT;
//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_ChangeRollAngleRelative", actor))
return;
@ -8682,11 +8673,6 @@ void A_ChangeRollAngleRelative(mobj_t *actor)
if (amin > amax)
I_Error("A_ChangeRollAngleRelative: var1 is greater than var2");
#endif
/*
if (angle < amin)
angle = amin;
if (angle > amax)
angle = amax;*/
actor->rollangle += FixedAngle(P_RandomRange(amin, amax));
}
@ -8702,11 +8688,8 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
//angle_t angle = (P_RandomByte()+1)<<24;
const fixed_t amin = locvar1*FRACUNIT;
const fixed_t amax = locvar2*FRACUNIT;
//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_ChangeRollAngleAbsolute", actor))
return;
@ -8716,15 +8699,9 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor)
if (amin > amax)
I_Error("A_ChangeRollAngleAbsolute: var1 is greater than var2");
#endif
/*
if (angle < amin)
angle = amin;
if (angle > amax)
angle = amax;*/
actor->rollangle = FixedAngle(P_RandomRange(amin, amax));
}
#endif // ROTSPRITE
// Function: A_PlaySound
//
@ -13614,12 +13591,12 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing)
}
else
{ //Player on the top of the tornado.
P_ResetPlayer(player);
thing->z = dustdevil->z + dustdevil->height;
thrust = 20 * FRACUNIT;
player->powers[pw_nocontrol] = 0;
S_StartSound(thing, sfx_wdjump);
P_SetPlayerMobjState(thing, S_PLAY_FALL);
player->pflags &= ~PF_JUMPED;
}
thing->momz = thrust;
@ -14248,7 +14225,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
fixed_t c = FINECOSINE(fa)*locvar2;
fixed_t s = FINESINE(fa)*locvar2;
mobj_t *door;
mobjflag2_t ambush = (actor->flags & MF2_AMBUSH);
mobjflag2_t ambush = (actor->flags2 & MF2_AMBUSH);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_SaloonDoorSpawn", actor))
@ -14626,12 +14603,9 @@ void A_RolloutRock(mobj_t *actor)
if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health)
actor->flags |= MF_PUSHABLE;
if (!(actor->flags & MF_PUSHABLE)) // if being ridden, don't disappear
actor->fuse = 0;
else if (!actor->fuse && actor->movecount == 1) // otherwise if rock has moved, set its fuse
if (!(actor->flags & MF_PUSHABLE) || (actor->movecount != 1)) // if being ridden or haven't moved, don't disappear
actor->fuse = actor->info->painchance;
if (actor->fuse && actor->fuse < 2*TICRATE)
else if (actor->fuse < 2*TICRATE)
actor->flags2 ^= MF2_DONTDRAW;
}
@ -14712,20 +14686,35 @@ void A_DragonWing(mobj_t *actor)
void A_DragonSegment(mobj_t *actor)
{
mobj_t *target = actor->target;
fixed_t dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
fixed_t radius = actor->radius + target->radius;
angle_t hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
angle_t zangle = R_PointToAngle2(0, target->z, dist, actor->z);
fixed_t hdist = P_ReturnThrustX(target, zangle, radius);
fixed_t xdist = P_ReturnThrustX(target, hangle, hdist);
fixed_t ydist = P_ReturnThrustY(target, hangle, hdist);
fixed_t zdist = P_ReturnThrustY(target, zangle, radius);
fixed_t dist;
fixed_t radius;
angle_t hangle;
angle_t zangle;
fixed_t hdist;
fixed_t xdist;
fixed_t ydist;
fixed_t zdist;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DragonSegment", actor))
return;
#endif
if (target == NULL || !target->health)
{
P_RemoveMobj(actor);
return;
}
dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
radius = actor->radius + target->radius;
hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
zangle = R_PointToAngle2(0, target->z, dist, actor->z);
hdist = P_ReturnThrustX(target, zangle, radius);
xdist = P_ReturnThrustX(target, hangle, hdist);
ydist = P_ReturnThrustY(target, hangle, hdist);
zdist = P_ReturnThrustY(target, zangle, radius);
actor->angle = hangle;
P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
}

View file

@ -625,7 +625,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_AddPlayerScore(player, 1000);
if (gametype != GT_COOP || modeattacking) // score only?
if (!(gametyperules & GTR_SPECIALSTAGES) || modeattacking) // score only?
{
S_StartSound(toucher, sfx_chchng);
break;
@ -1451,7 +1451,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (player->starpostnum >= special->health)
return; // Already hit this post
if (cv_coopstarposts.value && gametype == GT_COOP && (netgame || multiplayer))
if (cv_coopstarposts.value && G_GametypeUsesCoopStarposts() && (netgame || multiplayer))
{
for (i = 0; i < MAXPLAYERS; i++)
{
@ -1807,7 +1807,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
case MT_MINECARTSPAWNER:
if (!player->bot && (special->fuse < TICRATE || player->powers[pw_carry] != CR_MINECART))
if (!player->bot && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART)
{
mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART);
P_SetTarget(&mcart->target, toucher);
@ -1888,7 +1888,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
char targetname[MAXPLAYERNAME+4];
char sourcename[MAXPLAYERNAME+4];
if (G_PlatformGametype())
if (!(gametyperules & (GTR_RINGSLINGER|GTR_HURTMESSAGES)))
return; // Not in coop, etc.
if (!player)
@ -2093,7 +2093,7 @@ void P_CheckTimeLimit(void)
if (!(multiplayer || netgame))
return;
if (G_PlatformGametype())
if (!(gametyperules & GTR_TIMELIMIT))
return;
if (leveltime < timelimitintics)
@ -2124,7 +2124,7 @@ void P_CheckTimeLimit(void)
}
//Optional tie-breaker for Match/CTF
else if (cv_overtime.value)
else if ((cv_overtime.value) && (gametyperules & GTR_OVERTIME))
{
INT32 playerarray[MAXPLAYERS];
INT32 tempplayer = 0;
@ -2206,7 +2206,7 @@ void P_CheckPointLimit(void)
if (!(multiplayer || netgame))
return;
if (G_PlatformGametype())
if (!(gametyperules & GTR_POINTLIMIT))
return;
// pointlimit is nonzero, check if it's been reached by this player
@ -2389,7 +2389,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording!
G_StopMetalRecording(true);
if (gametype == GT_MATCH // note, no team match suicide penalty
if ((gametyperules & GTR_DEATHPENALTY) // note, no team match suicide penalty
&& ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player)))
{ // Suicide penalty
if (target->player->score >= 50)
@ -2481,8 +2481,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
P_SetMobjState(scoremobj, scorestate);
// On ground? No chain starts.
if (source->player->powers[pw_invulnerability] || !P_IsObjectOnGround(source))
source->player->scoreadd = locscoreadd;
}
}
@ -2523,7 +2521,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->colorized = false;
G_GhostAddColor(GHC_NORMAL);
if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0))
if ((target->player->lives <= 1) && (netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value == 0))
;
else if (!target->player->bot && !target->player->spectator && (target->player->lives != INFLIVES)
&& G_GametypeUsesLives())
@ -2533,7 +2531,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if (target->player->lives <= 0) // Tails 03-14-2000
{
boolean gameovermus = false;
if ((netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value != 1))
if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value != 1))
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
@ -2978,7 +2976,7 @@ static void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
player->flyangle += 180; // Shuffle's BETTERNIGHTSMOVEMENT?
player->flyangle %= 360;
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
player->drillmeter -= 5*20;
else
{
@ -3005,9 +3003,7 @@ static void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN);
S_StartSound(target, sfx_nghurt);
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
if (oldnightstime > 10*TICRATE
&& player->nightstime < 10*TICRATE)
@ -3042,7 +3038,7 @@ static boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, IN
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE) || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
@ -3058,7 +3054,7 @@ static boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, IN
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE) || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
@ -3143,7 +3139,7 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
return false;
// In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on
if (!cv_friendlyfire.value && (G_PlatformGametype()))
if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && (G_PlatformGametype()))
{
if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only
{
@ -3166,7 +3162,7 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
{
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam)
if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && target->player->ctfteam == source->player->ctfteam)
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
@ -3203,9 +3199,11 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
player->powers[pw_carry] = CR_NONE;
// Burst weapons and emeralds in Match/CTF only
if (source && (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF))
if (source)
{
if ((gametyperules & GTR_RINGSLINGER) && !(gametyperules & GTR_TAG))
P_PlayerRingBurst(player, player->rings);
if (gametyperules & GTR_POWERSTONES)
P_PlayerEmeraldBurst(player, false);
}
@ -3224,7 +3222,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
player->mo->flags2 &= ~MF2_DONTDRAW;
P_SetPlayerMobjState(player->mo, player->mo->info->deathstate);
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
{
P_PlayerFlagBurst(player, false);
if (source && source->player)
@ -3349,7 +3347,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source,
else
S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss.
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
{
P_PlayerFlagBurst(player, false);
if (source && source->player)
@ -3383,7 +3381,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN
P_AddPlayerScore(source->player, 50);
}
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
{
P_PlayerFlagBurst(player, false);
if (source && source->player)
@ -3426,6 +3424,24 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super])
return;
if (!cv_friendlyfire.value)
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound);
}
}
if (source->player->ctfteam == player->ctfteam)
return;
}
if (inflictor->type == MT_LHRT)
return;
if (player->powers[pw_shield] || player->bot) //If One-Hit Shield
{
P_RemoveShield(player);
@ -3442,7 +3458,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
P_DoPlayerPain(player, inflictor, source);
if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))
if ((gametyperules & GTR_TEAMFLAGS) && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))
P_PlayerFlagBurst(player, false);
if (oldnightstime > 10*TICRATE
@ -3593,7 +3609,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{
if (source == target)
return false; // Don't hit yourself with your own paraloop, baka
if (source && source->player && !cv_friendlyfire.value
if (source && source->player && !(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE))
&& (gametype == GT_COOP
|| (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam)))
return false; // Don't run eachother over in special stages and team games and such
@ -3688,7 +3704,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// by friendly fire. Spilling their rings and other items is enough.
else if (!force && G_GametypeHasTeams()
&& source && source->player && (source->player->ctfteam == player->ctfteam)
&& cv_friendlyfire.value)
&& (cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)))
{
damage = 0;
P_ShieldDamage(player, inflictor, source, damage, damagetype);

View file

@ -120,6 +120,10 @@ extern consvar_t cv_cam_speed, cv_cam_rotate, cv_cam_rotspeed, cv_cam_turnmultip
extern consvar_t cv_cam2_dist, cv_cam2_still, cv_cam2_height;
extern consvar_t cv_cam2_speed, cv_cam2_rotate, cv_cam2_rotspeed, cv_cam2_turnmultiplier, cv_cam2_orbit, cv_cam2_adjust;
extern consvar_t cv_cam_savedist[2][2], cv_cam_saveheight[2][2];
void CV_UpdateCamDist(void);
void CV_UpdateCam2Dist(void);
extern fixed_t t_cam_dist, t_cam_height, t_cam_rotate;
extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate;
@ -181,16 +185,14 @@ fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move);
fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move);
void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction, UINT8 lockonflags);
mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet);
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
boolean P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_SuperReady(player_t *player);
void P_DoJump(player_t *player, boolean soundandstate);
#if 0
boolean P_AnalogMove(player_t *player);
#else
#define P_AnalogMove(player) (player->pflags & PF_ANALOGMODE)
#endif
#define P_AnalogMove(player) (P_ControlStyle(player) == CS_LMAOGALOG)
boolean P_TransferToNextMare(player_t *player);
UINT8 P_FindLowestMare(void);
void P_FindEmerald(void);

View file

@ -377,7 +377,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{
object->angle = object->player->drawangle = spring->angle;
if (!demoplayback || P_AnalogMove(object->player))
if (!demoplayback || P_ControlStyle(object->player) == CS_LMAOGALOG)
{
if (object->player == &players[consoleplayer])
localangle = spring->angle;
@ -426,7 +426,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
object->player->pflags |= pflags;
object->player->secondjump = secondjump;
}
else if (object->player->dashmode >= 3*TICRATE)
else if (object->player->dashmode >= DASHMODE_THRESHOLD)
P_SetPlayerMobjState(object, S_PLAY_DASH);
else if (P_IsObjectOnGround(object) && horizspeed >= FixedMul(object->player->runspeed, object->scale))
P_SetPlayerMobjState(object, S_PLAY_RUN);
@ -615,7 +615,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
// Why block opposing teams from tailsflying each other?
// Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows.
/*
if (gametype == GT_RACE || gametype == GT_COMPETITION
if ((gametyperules & GTR_RACE)
|| (netgame && (tails->spectator || sonic->spectator))
|| (G_TagGametype() && (!(tails->pflags & PF_TAGIT) != !(sonic->pflags & PF_TAGIT)))
|| (gametype == GT_MATCH)
@ -632,7 +632,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
&& P_MobjFlip(tails->mo)*sonic->mo->momz <= 0)
{
if (sonic-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, false);
CV_SetValue(&cv_analog[1], false);
P_ResetPlayer(sonic);
P_SetTarget(&sonic->mo->tracer, tails->mo);
sonic->powers[pw_carry] = CR_PLAYER;
@ -644,7 +644,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
}
else {
if (sonic-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, true);
CV_SetValue(&cv_analog[1], true);
P_SetTarget(&sonic->mo->tracer, NULL);
sonic->powers[pw_carry] = CR_NONE;
}
@ -746,8 +746,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->type == MT_NAMECHECK)
{
// Ignore things that aren't players, ignore spectators, ignore yourself.
// (also don't bother to check that tmthing->target->player is non-NULL because we're not actually using it here.)
if (!thing->player || thing->player->spectator || (tmthing->target && thing->player == tmthing->target->player))
if (!thing->player || !(tmthing->target && tmthing->target->player) || thing->player->spectator || (tmthing->target && thing->player == tmthing->target->player))
return true;
// Now check that you actually hit them.
@ -760,6 +759,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
#ifdef HAVE_BLUA
// REX HAS SEEN YOU
if (!LUAh_SeenPlayer(tmthing->target->player, thing->player))
return false;
#endif
seenplayer = thing->player;
return false;
}
@ -801,7 +806,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
// SF_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes.
if ((tmthing->player)
&& (((tmthing->player->charflags & SF_DASHMODE) && (tmthing->player->dashmode >= 3*TICRATE)
&& ((((tmthing->player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) && (tmthing->player->dashmode >= DASHMODE_THRESHOLD)
&& (thing->flags & (MF_MONITOR)
|| (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)))
@ -829,14 +834,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext)
if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(iter, tmthing, tmthing, 0);
return true;
}
else
{
thing->health = 0;
P_KillMobj(thing, tmthing, tmthing, 0);
}
if (P_DamageMobj(thing, tmthing, tmthing, 1, 0))
return true;
}
}
// vectorise metal - done in a special case as at this point neither has the right flags for touching
if (thing->type == MT_METALSONIC_BATTLE
@ -995,7 +1000,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_SALOONDOOR && tmthing->player)
{
mobj_t *ref = (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)) ? tmthing->tracer : tmthing;
if ((thing->flags & MF2_AMBUSH) || ref != tmthing)
if ((thing->flags2 & MF2_AMBUSH) || ref != tmthing)
{
fixed_t dm = min(FixedHypot(ref->momx, ref->momy), 16*FRACUNIT);
angle_t ang = R_PointToAngle2(0, 0, ref->momx, ref->momy) - thing->angle;
@ -1008,7 +1013,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_SALOONDOORCENTER && tmthing->player)
{
if ((thing->flags & MF2_AMBUSH) || (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)))
if ((thing->flags2 & MF2_AMBUSH) || (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)))
return true;
}
@ -1322,7 +1327,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
thing->angle = tmthing->angle;
if (!demoplayback || P_AnalogMove(thing->player))
if (!demoplayback || P_ControlStyle(thing->player) == CS_LMAOGALOG)
{
if (thing->player == &players[consoleplayer])
localangle = thing->angle;
@ -1621,7 +1626,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
else if (thing->player) {
if (thing->player-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, true);
CV_SetValue(&cv_analog[1], true);
if (thing->player->powers[pw_carry] == CR_PLAYER)
{
P_SetTarget(&thing->tracer, NULL);
@ -1943,6 +1948,19 @@ static boolean PIT_CheckLine(line_t *ld)
// this line is out of the if so upper and lower textures can be hit by a splat
blockingline = ld;
#ifdef HAVE_BLUA
{
UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, blockingline); // checks hook for thing's type
if (P_MobjWasRemoved(tmthing))
return true; // one of them was removed???
if (shouldCollide == 1)
return false; // force collide
else if (shouldCollide == 2)
return true; // force no collide
}
#endif
if (!ld->backsector) // one sided line
{
if (P_PointOnLineSide(tmthing->x, tmthing->y, ld))
@ -3491,7 +3509,7 @@ isblocking:
&& canclimb)
{
slidemo->angle = climbangle;
/*if (!demoplayback || P_AnalogMove(slidemo->player))
/*if (!demoplayback || P_ControlStyle(slidemo->player) == CS_LMAOGALOG)
{
if (slidemo->player == &players[consoleplayer])
localangle = slidemo->angle;

View file

@ -78,68 +78,37 @@ void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result)
return;
}
//
// P_ClosestPointOnLine3D
// Finds the closest point on a given line to the supplied point IN 3D!!!
//
void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result)
/// Similar to FV3_ClosestPointOnLine() except it actually works.
void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *Line, vector3_t *result)
{
fixed_t startx = line->v1->x;
fixed_t starty = line->v1->y;
fixed_t startz = line->v1->z;
fixed_t dx = line->dx;
fixed_t dy = line->dy;
fixed_t dz = line->v2->z - line->v1->z;
const vector3_t* v1 = &Line[0];
const vector3_t* v2 = &Line[1];
vector3_t c, V, n;
fixed_t t, d;
FV3_SubEx(v2, v1, &V);
FV3_SubEx(p, v1, &c);
// Determine t (the length of the vector from <20>Line[0]<5D> to <20>p<EFBFBD>)
fixed_t cx, cy, cz;
fixed_t vx, vy, vz;
fixed_t magnitude;
fixed_t t;
d = R_PointToDist2(0, v2->z, R_PointToDist2(v2->x, v2->y, v1->x, v1->y), v1->z);
FV3_Copy(&n, &V);
FV3_Divide(&n, d);
//Sub (p, &Line[0], &c);
cx = x - startx;
cy = y - starty;
cz = z - startz;
//Sub (&Line[1], &Line[0], &V);
vx = dx;
vy = dy;
vz = dz;
//Normalize (&V, &V);
magnitude = R_PointToDist2(0, line->v2->z, R_PointToDist2(line->v2->x, line->v2->y, startx, starty), startz);
vx = FixedDiv(vx, magnitude);
vy = FixedDiv(vy, magnitude);
vz = FixedDiv(vz, magnitude);
t = (FixedMul(vx, cx) + FixedMul(vy, cy) + FixedMul(vz, cz));
t = FV3_Dot(&n, &c);
// Set closest point to the end if it extends past -Red
if (t <= 0)
{
result->x = line->v1->x;
result->y = line->v1->y;
result->z = line->v1->z;
FV3_Copy(result, v1);
return;
}
else if (t >= magnitude)
else if (t >= d)
{
result->x = line->v2->x;
result->y = line->v2->y;
result->z = line->v2->z;
FV3_Copy(result, v2);
return;
}
// Return the point between <20>Line[0]<5D> and <20>Line[1]<5D>
vx = FixedMul(vx, t);
vy = FixedMul(vy, t);
vz = FixedMul(vz, t);
FV3_Mul(&n, t);
//Add (&Line[0], &V, out);
result->x = startx + vx;
result->y = starty + vy;
result->z = startz + vz;
FV3_AddEx(v1, &n, result);
return;
}

View file

@ -43,7 +43,7 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
FUNCMATH fixed_t P_AproxDistance(fixed_t dx, fixed_t dy);
void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result);
void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result);
void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *line, vector3_t *result);
INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line);
void P_MakeDivline(line_t *li, divline_t *dl);
void P_CameraLineOpening(line_t *plinedef);

File diff suppressed because it is too large Load diff

View file

@ -279,9 +279,7 @@ typedef struct mobj_s
// More drawing info: to determine current sprite.
angle_t angle; // orientation
#ifdef ROTSPRITE
angle_t rollangle;
#endif
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites
@ -402,9 +400,7 @@ typedef struct precipmobj_s
// More drawing info: to determine current sprite.
angle_t angle; // orientation
#ifdef ROTSPRITE
angle_t rollangle;
#endif
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites
@ -456,8 +452,10 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing);
void P_MovePlayerToStarpost(INT32 playernum);
void P_AfterPlayerSpawn(INT32 playernum);
void P_SpawnMapThing(mapthing_t *mthing);
void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime);
mobj_t *P_SpawnMapThing(mapthing_t *mthing);
void P_SpawnHoop(mapthing_t *mthing);
void P_SetBonusTime(mobj_t *mobj);
void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime);
void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle);
void P_SpawnPrecipitation(void);
void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter);

View file

@ -400,6 +400,8 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg)
// Find backfacings
for (s = 0; s < numsegs; s++)
{
if (segs[s].glseg)
continue;
if (segs[s].linedef == seg->linedef
&& segs[s].side == 1)
{
@ -436,6 +438,8 @@ newseg:
// seg's ending vertex.
for (i = 0; i < numsegs; ++i)
{
if (segs[i].glseg)
continue;
if (segs[i].side != 0) // needs to be frontfacing
continue;
if (segs[i].v1->x == seg->v2->x && segs[i].v1->y == seg->v2->y)
@ -460,6 +464,9 @@ newseg:
// Find backfacings
for (q = 0; q < numsegs; q++)
{
if (segs[q].glseg)
continue;
if (segs[q].linedef == segs[i].linedef
&& segs[q].side == 1)
{
@ -606,6 +613,9 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id)
INT32 poflags = POF_SOLID|POF_TESTHEIGHT|POF_RENDERSIDES;
INT32 parentID = 0, potrans = 0;
if (seg->glseg)
continue;
if (seg->side != 0) // needs to be frontfacing
continue;
@ -1341,9 +1351,9 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta,
if (turnthings == 2 || (turnthings == 1 && !mo->player)) {
mo->angle += delta;
if (mo->player == &players[consoleplayer])
localangle = mo->angle;
localangle += delta;
else if (mo->player == &players[secondarydisplayplayer])
localangle2 = mo->angle;
localangle2 += delta;
}
}
}
@ -1815,6 +1825,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
if (po->thinker == NULL)
po->thinker = &th->thinker;
/*
// Find out target first.
// We redo this each tic to make savegame compatibility easier.
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
@ -1833,6 +1844,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
break;
}
}
*/
target = th->target;
if (!target)
{
@ -2015,6 +2029,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
target = waypoint;
th->pointnum = target->health;
// Set the mobj as your target! -- Monster Iestyn 27/12/19
P_SetTarget(&th->target, target);
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
@ -2641,6 +2657,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
// Set pointnum
th->pointnum = target->health;
th->target = NULL; // set to NULL first so the below doesn't go wrong
// Set the mobj as your target! -- Monster Iestyn 27/12/19
P_SetTarget(&th->target, target);
// We don't deal with the mirror crap here, we'll
// handle that in the T_Thinker function.

View file

@ -161,6 +161,8 @@ typedef struct polywaypoint_s
fixed_t diffx;
fixed_t diffy;
fixed_t diffz;
mobj_t *target; // next waypoint mobj
} polywaypoint_t;
typedef struct polyslidedoor_s

View file

@ -777,14 +777,13 @@ static void P_NetArchiveWorld(void)
size_t i;
INT32 statsec = 0, statline = 0;
const line_t *li = lines;
const line_t *spawnli = spawnlines;
const side_t *si;
const side_t *spawnsi;
UINT8 *put;
// reload the map just to see difference
mapsector_t *ms;
mapsidedef_t *msd;
maplinedef_t *mld;
const sector_t *ss = sectors;
const sector_t *spawnss = spawnsectors;
UINT8 diff, diff2, diff3;
// initialize colormap vars because paranoia
@ -793,65 +792,45 @@ static void P_NetArchiveWorld(void)
WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
put = save_p;
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can get the data from the relevant lumps
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
#define retrieve_mapdata(d, f)\
d = Z_Malloc((f)->size, PU_CACHE, NULL); \
M_Memcpy(d, wadData + (f)->filepos, (f)->size)
retrieve_mapdata(ms, fileinfo + ML_SECTORS);
retrieve_mapdata(mld, fileinfo + ML_LINEDEFS);
retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS);
#undef retrieve_mapdata
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
{
ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE);
mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE);
msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE);
}
for (i = 0; i < numsectors; i++, ss++, ms++)
for (i = 0; i < numsectors; i++, ss++, spawnss++)
{
diff = diff2 = diff3 = 0;
if (ss->floorheight != SHORT(ms->floorheight)<<FRACBITS)
if (ss->floorheight != spawnss->floorheight)
diff |= SD_FLOORHT;
if (ss->ceilingheight != SHORT(ms->ceilingheight)<<FRACBITS)
if (ss->ceilingheight != spawnss->ceilingheight)
diff |= SD_CEILHT;
//
// flats
//
if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
if (ss->floorpic != spawnss->floorpic)
diff |= SD_FLOORPIC;
if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
if (ss->ceilingpic != spawnss->ceilingpic)
diff |= SD_CEILPIC;
if (ss->lightlevel != SHORT(ms->lightlevel))
if (ss->lightlevel != spawnss->lightlevel)
diff |= SD_LIGHT;
if (ss->special != SHORT(ms->special))
if (ss->special != spawnss->special)
diff |= SD_SPECIAL;
if (ss->floor_xoffs != ss->spawn_flr_xoffs)
if (ss->floor_xoffs != spawnss->floor_xoffs)
diff2 |= SD_FXOFFS;
if (ss->floor_yoffs != ss->spawn_flr_yoffs)
if (ss->floor_yoffs != spawnss->floor_yoffs)
diff2 |= SD_FYOFFS;
if (ss->ceiling_xoffs != ss->spawn_ceil_xoffs)
if (ss->ceiling_xoffs != spawnss->ceiling_xoffs)
diff2 |= SD_CXOFFS;
if (ss->ceiling_yoffs != ss->spawn_ceil_yoffs)
if (ss->ceiling_yoffs != spawnss->ceiling_yoffs)
diff2 |= SD_CYOFFS;
if (ss->floorpic_angle != ss->spawn_flrpic_angle)
if (ss->floorpic_angle != spawnss->floorpic_angle)
diff2 |= SD_FLOORANG;
if (ss->ceilingpic_angle != ss->spawn_flrpic_angle)
if (ss->ceilingpic_angle != spawnss->ceilingpic_angle)
diff2 |= SD_CEILANG;
if (ss->tag != SHORT(ms->tag))
if (ss->tag != spawnss->tag)
diff2 |= SD_TAG;
if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
if (ss->nexttag != spawnss->nexttag || ss->firsttag != spawnss->firsttag)
diff3 |= SD_TAGLIST;
if (ss->extra_colormap != ss->spawn_extra_colormap)
if (ss->extra_colormap != spawnss->extra_colormap)
diff3 |= SD_COLORMAP;
// Check if any of the sector's FOFs differ from how they spawned
@ -955,45 +934,41 @@ static void P_NetArchiveWorld(void)
WRITEUINT16(put, 0xffff);
// do lines
for (i = 0; i < numlines; i++, mld++, li++)
for (i = 0; i < numlines; i++, spawnli++, li++)
{
diff = diff2 = diff3 = 0;
if (li->special != SHORT(mld->special))
if (li->special != spawnli->special)
diff |= LD_SPECIAL;
if (SHORT(mld->special) == 321 || SHORT(mld->special) == 322) // only reason li->callcount would be non-zero is if either of these are involved
if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved
diff |= LD_CLLCOUNT;
if (li->sidenum[0] != 0xffff)
{
si = &sides[li->sidenum[0]];
if (si->textureoffset != SHORT(msd[li->sidenum[0]].textureoffset)<<FRACBITS)
spawnsi = &spawnsides[li->sidenum[0]];
if (si->textureoffset != spawnsi->textureoffset)
diff |= LD_S1TEXOFF;
//SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures.
if (R_CheckTextureNumForName(msd[li->sidenum[0]].toptexture) != -1
&& si->toptexture != R_TextureNumForName(msd[li->sidenum[0]].toptexture))
if (si->toptexture != spawnsi->toptexture)
diff |= LD_S1TOPTEX;
if (R_CheckTextureNumForName(msd[li->sidenum[0]].bottomtexture) != -1
&& si->bottomtexture != R_TextureNumForName(msd[li->sidenum[0]].bottomtexture))
if (si->bottomtexture != spawnsi->bottomtexture)
diff |= LD_S1BOTTEX;
if (R_CheckTextureNumForName(msd[li->sidenum[0]].midtexture) != -1
&& si->midtexture != R_TextureNumForName(msd[li->sidenum[0]].midtexture))
if (si->midtexture != spawnsi->midtexture)
diff |= LD_S1MIDTEX;
}
if (li->sidenum[1] != 0xffff)
{
si = &sides[li->sidenum[1]];
if (si->textureoffset != SHORT(msd[li->sidenum[1]].textureoffset)<<FRACBITS)
spawnsi = &spawnsides[li->sidenum[1]];
if (si->textureoffset != spawnsi->textureoffset)
diff2 |= LD_S2TEXOFF;
if (R_CheckTextureNumForName(msd[li->sidenum[1]].toptexture) != -1
&& si->toptexture != R_TextureNumForName(msd[li->sidenum[1]].toptexture))
if (si->toptexture != spawnsi->toptexture)
diff2 |= LD_S2TOPTEX;
if (R_CheckTextureNumForName(msd[li->sidenum[1]].bottomtexture) != -1
&& si->bottomtexture != R_TextureNumForName(msd[li->sidenum[1]].bottomtexture))
if (si->bottomtexture != spawnsi->bottomtexture)
diff2 |= LD_S2BOTTEX;
if (R_CheckTextureNumForName(msd[li->sidenum[1]].midtexture) != -1
&& si->midtexture != R_TextureNumForName(msd[li->sidenum[1]].midtexture))
if (si->midtexture != spawnsi->midtexture)
diff2 |= LD_S2MIDTEX;
if (diff2)
diff |= LD_DIFF2;
@ -1277,9 +1252,7 @@ typedef enum
MD2_SLOPE = 1<<11,
#endif
MD2_COLORIZED = 1<<12,
#ifdef ROTSPRITE
MD2_ROLLANGLE = 1<<13,
#endif
} mobj_diff2_t;
typedef enum
@ -1499,10 +1472,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
#endif
if (mobj->colorized)
diff2 |= MD2_COLORIZED;
#ifdef ROTSPRITE
if (mobj->rollangle)
diff2 |= MD2_ROLLANGLE;
#endif
if (diff2 != 0)
diff |= MD_MORE;
@ -1667,10 +1638,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
#endif
if (diff2 & MD2_COLORIZED)
WRITEUINT8(save_p, mobj->colorized);
#ifdef ROTSPRITE
if (diff2 & MD2_ROLLANGLE)
WRITEANGLE(save_p, mobj->rollangle);
#endif
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -2086,6 +2055,7 @@ static void SavePolywaypointThinker(const thinker_t *th, UINT8 type)
WRITEFIXED(save_p, ht->diffx);
WRITEFIXED(save_p, ht->diffy);
WRITEFIXED(save_p, ht->diffz);
WRITEUINT32(save_p, SaveMobjnum(ht->target));
}
//
@ -2563,7 +2533,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
{
P_SpawnHoopsAndRings(&mapthings[spawnpointnum], false);
P_SpawnHoop(&mapthings[spawnpointnum]);
return NULL;
}
@ -2747,12 +2717,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
#endif
if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p);
#ifdef ROTSPRITE
if (diff2 & MD2_ROLLANGLE)
mobj->rollangle = READANGLE(save_p);
else
mobj->rollangle = 0;
#endif
if (diff & MD_REDFLAG)
{
@ -3279,6 +3245,7 @@ static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker)
ht->diffx = READFIXED(save_p);
ht->diffy = READFIXED(save_p);
ht->diffz = READFIXED(save_p);
ht->target = LoadMobj(READUINT32(save_p));
return &ht->thinker;
}
@ -3573,6 +3540,7 @@ static void P_NetUnArchiveThinkers(void)
case tc_polywaypoint:
th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
restoreNum = true;
break;
case tc_polyslidedoor:
@ -3634,9 +3602,9 @@ static void P_NetUnArchiveThinkers(void)
if (restoreNum)
{
executor_t *delay = NULL;
polywaypoint_t *polywp = NULL;
UINT32 mobjnum;
for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN];
currentthinker = currentthinker->next)
for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next)
{
if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay)
continue;
@ -3645,6 +3613,15 @@ static void P_NetUnArchiveThinkers(void)
continue;
delay->caller = P_FindNewPosition(mobjnum);
}
for (currentthinker = thlist[THINK_POLYOBJ].next; currentthinker != &thlist[THINK_POLYOBJ]; currentthinker = currentthinker->next)
{
if (currentthinker->function.acp1 != (actionf_p1)T_PolyObjWaypoint)
continue;
polywp = (void *)currentthinker;
if (!(mobjnum = (UINT32)(size_t)polywp->target))
continue;
polywp->target = P_FindNewPosition(mobjnum);
}
}
}
@ -4099,7 +4076,7 @@ static inline boolean P_NetUnArchiveMisc(void)
tokenlist = READUINT32(save_p);
if (!P_SetupLevel(true))
if (!P_LoadLevel(true))
return false;
// get the time

File diff suppressed because it is too large Load diff

View file

@ -96,8 +96,8 @@ void P_SetupLevelSky(INT32 skynum, boolean global);
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_LoadThingsOnly(void);
boolean P_SetupLevel(boolean skipprecip);
void P_RespawnThings(void);
boolean P_LoadLevel(boolean fromnetsave);
#ifdef HWRENDER
void HWR_SetupLevel(void);
#endif

View file

@ -222,6 +222,9 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
fixed_t fracx, fracy;
#endif
if (seg->glseg)
continue;
// already checked other side?
if (line->validcount == validcount)
continue;

View file

@ -50,10 +50,10 @@ static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const v
// Set some defaults for a non-sloped "slope"
if (vec1.z == 0 && vec2.z == 0)
{
/// \todo Fix fully flat cases.
slope->zangle = slope->xydirection = 0;
slope->zdelta = slope->d.x = slope->d.y = 0;
slope->normal.x = slope->normal.y = 0;
slope->normal.z = FRACUNIT;
}
else
{
@ -445,10 +445,9 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
vx[i].x = mt->x << FRACBITS;
vx[i].y = mt->y << FRACBITS;
if (mt->extrainfo)
vx[i].z = mt->options << FRACBITS;
else
vx[i].z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight) + ((mt->options >> ZSHIFT) << FRACBITS);
vx[i].z = mt->z << FRACBITS;
if (!mt->extrainfo)
vx[i].z += R_PointInSubsector(vx[i].x, vx[i].y)->sector->floorheight;
}
ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]);
@ -459,8 +458,8 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
return ret;
}
/// Create vertex based slopes.
static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
/// Create vertex based slopes using tagged mapthings.
static void line_SpawnViaMapthingVertexes(const int linenum, const boolean spawnthinker)
{
line_t *line = lines + linenum;
side_t *side;
@ -508,6 +507,55 @@ static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
side->sector->hasslope = true;
}
/// Spawn textmap vertex slopes.
static void SpawnVertexSlopes(void)
{
line_t *l1, *l2;
sector_t* sc;
vertex_t *v1, *v2, *v3;
size_t i;
for (i = 0, sc = sectors; i < numsectors; i++, sc++)
{
// The vertex slopes only work for 3-vertex sectors (and thus 3-sided sectors).
if (sc->linecount != 3)
continue;
l1 = sc->lines[0];
l2 = sc->lines[1];
// Determine the vertexes.
v1 = l1->v1;
v2 = l1->v2;
if ((l2->v1 != v1) && (l2->v1 != v2))
v3 = l2->v1;
else
v3 = l2->v2;
if (v1->floorzset || v2->floorzset || v3->floorzset)
{
vector3_t vtx[3] = {
{v1->x, v1->y, v1->floorzset ? v1->floorz : sc->floorheight},
{v2->x, v2->y, v2->floorzset ? v2->floorz : sc->floorheight},
{v3->x, v3->y, v3->floorzset ? v3->floorz : sc->floorheight}};
pslope_t *slop = Slope_Add(0);
sc->f_slope = slop;
sc->hasslope = true;
ReconfigureViaVertexes(slop, vtx[0], vtx[1], vtx[2]);
}
if (v1->ceilingzset || v2->ceilingzset || v3->ceilingzset)
{
vector3_t vtx[3] = {
{v1->x, v1->y, v1->ceilingzset ? v1->ceilingz : sc->ceilingheight},
{v2->x, v2->y, v2->ceilingzset ? v2->ceilingz : sc->ceilingheight},
{v3->x, v3->y, v3->ceilingzset ? v3->ceilingz : sc->ceilingheight}};
pslope_t *slop = Slope_Add(0);
sc->c_slope = slop;
sc->hasslope = true;
ReconfigureViaVertexes(slop, vtx[0], vtx[1], vtx[2]);
}
}
}
//
// P_CopySectorSlope
@ -552,15 +600,16 @@ pslope_t *P_SlopeById(UINT16 id)
return ret;
}
/// Reset slopes and read them from special lines.
void P_ResetDynamicSlopes(const UINT32 fromsave) {
/// Initializes and reads the slopes from the map data.
void P_SpawnSlopes(const boolean fromsave) {
size_t i;
boolean spawnthinkers = !(boolean)fromsave;
slopelist = NULL;
slopecount = 0;
/// Generates vertex slopes.
SpawnVertexSlopes();
/// Generates line special-defined slopes.
for (i = 0; i < numlines; i++)
{
@ -574,14 +623,14 @@ void P_ResetDynamicSlopes(const UINT32 fromsave) {
case 711:
case 712:
case 713:
line_SpawnViaLine(i, spawnthinkers);
line_SpawnViaLine(i, !fromsave);
break;
case 704:
case 705:
case 714:
case 715:
line_SpawnViaVertexes(i, spawnthinkers);
line_SpawnViaMapthingVertexes(i, !fromsave);
break;
default:
@ -657,7 +706,9 @@ void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
// Handles slope ejection for objects
void P_SlopeLaunch(mobj_t *mo)
{
if (!(mo->standingslope->flags & SL_NOPHYSICS)) // If there's physics, time for launching.
if (!(mo->standingslope->flags & SL_NOPHYSICS) // If there's physics, time for launching.
&& (mo->standingslope->normal.x != 0
|| mo->standingslope->normal.y != 0))
{
// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
// vertical launch given from slopes while increasing the horizontal launch
@ -714,8 +765,7 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope)
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
{
vector3_t mom; // Ditto.
if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated.
if (slope->flags & SL_NOPHYSICS || (slope->normal.x == 0 && slope->normal.y == 0)) { // No physics, no need to make anything complicated.
if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope
{
thing->standingslope = slope;

View file

@ -23,7 +23,7 @@ extern UINT16 slopecount;
void P_LinkSlopeThinkers (void);
void P_CalculateSlopeNormal(pslope_t *slope);
void P_ResetDynamicSlopes(const UINT32 fromsave);
void P_SpawnSlopes(const boolean fromsave);
//
// P_CopySectorSlope

View file

@ -52,9 +52,6 @@ mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
// Amount (dx, dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5
// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize.
#define MAXFLATSIZE (2048<<FRACBITS)
/** Animated texture descriptor
* This keeps track of an animated texture or an animated flat.
* \sa P_UpdateSpecials, P_InitPicAnims, animdef_t
@ -1603,8 +1600,6 @@ static inline void P_InitTagLists(void)
size_t j = (unsigned)sectors[i].tag % numsectors;
sectors[i].nexttag = sectors[j].firsttag;
sectors[j].firsttag = (INT32)i;
sectors[i].spawn_nexttag = sectors[i].nexttag;
sectors[j].spawn_firsttag = sectors[j].firsttag;
}
for (i = numlines - 1; i != (size_t)-1; i--)
@ -1892,7 +1887,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
while (node)
{
mo = node->m_thing;
if (mo->flags & MF_PUSHABLE)
if ((mo->flags & MF_PUSHABLE) || ((mo->info->flags & MF_PUSHABLE) && mo->fuse))
numpush++;
node = node->m_thinglist_next;
}
@ -4619,7 +4614,7 @@ DoneSection2:
player->mo->angle = player->drawangle = lineangle;
if (!demoplayback || P_AnalogMove(player))
if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG)
{
if (player == &players[consoleplayer])
localangle = player->mo->angle;
@ -4694,7 +4689,7 @@ DoneSection2:
}
case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return
if (player->bot || !G_PlatformGametype())
if (player->bot || !(gametyperules & GTR_ALLOWEXIT))
break;
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6)
{
@ -4729,7 +4724,7 @@ DoneSection2:
break;
case 3: // Red Team's Base
if (gametype == GT_CTF && P_IsObjectOnGround(player->mo))
if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo))
{
if (player->ctfteam == 1 && (player->gotflag & GF_BLUEFLAG))
{
@ -4762,7 +4757,7 @@ DoneSection2:
break;
case 4: // Blue Team's Base
if (gametype == GT_CTF && P_IsObjectOnGround(player->mo))
if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo))
{
if (player->ctfteam == 2 && (player->gotflag & GF_REDFLAG))
{
@ -5043,8 +5038,7 @@ DoneSection2:
mobj_t *waypointlow = NULL;
mobj_t *mo2;
mobj_t *closest = NULL;
line_t junk;
vertex_t v1, v2, resulthigh, resultlow;
vector3_t p, line[2], resulthigh, resultlow;
mobj_t *highest = NULL;
if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ROPEHANG)
@ -5191,38 +5185,34 @@ DoneSection2:
// Next, we need to find the closest point on the line between each set, and determine which one we're
// closest to.
p.x = player->mo->x;
p.y = player->mo->y;
p.z = player->mo->z;
// Waypointmid and Waypointlow:
if (waypointlow)
{
v1.x = waypointmid->x;
v1.y = waypointmid->y;
v1.z = waypointmid->z;
v2.x = waypointlow->x;
v2.y = waypointlow->y;
v2.z = waypointlow->z;
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = v2.x - v1.x;
junk.dy = v2.y - v1.y;
line[0].x = waypointmid->x;
line[0].y = waypointmid->y;
line[0].z = waypointmid->z;
line[1].x = waypointlow->x;
line[1].y = waypointlow->y;
line[1].z = waypointlow->z;
P_ClosestPointOnLine3D(player->mo->x, player->mo->y, player->mo->z, &junk, &resultlow);
P_ClosestPointOnLine3D(&p, line, &resultlow);
}
// Waypointmid and Waypointhigh:
if (waypointhigh)
{
v1.x = waypointmid->x;
v1.y = waypointmid->y;
v1.z = waypointmid->z;
v2.x = waypointhigh->x;
v2.y = waypointhigh->y;
v2.z = waypointhigh->z;
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = v2.x - v1.x;
junk.dy = v2.y - v1.y;
line[0].x = waypointmid->x;
line[0].y = waypointmid->y;
line[0].z = waypointmid->z;
line[1].x = waypointhigh->x;
line[1].y = waypointhigh->y;
line[1].z = waypointhigh->z;
P_ClosestPointOnLine3D(player->mo->x, player->mo->y, player->mo->z, &junk, &resulthigh);
P_ClosestPointOnLine3D(&p, line, &resulthigh);
}
// 3D support now available. Disregard the previous notice here. -Red
@ -6363,7 +6353,7 @@ static void P_RunLevelLoadExecutors(void)
}
/** Before things are loaded, initialises certain stuff in case they're needed
* by P_ResetDynamicSlopes or P_LoadThings. This was split off from
* by P_SpawnSlopes or P_LoadThings. This was split off from
* P_SpawnSpecials, in case you couldn't tell.
*
* \sa P_SpawnSpecials, P_InitTagLists
@ -6405,22 +6395,16 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata
{
if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set
{
sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle;
sector->floorpic_angle = flatangle;
sector->floor_xoffs += xoffs;
sector->floor_yoffs += yoffs;
// saved for netgames
sector->spawn_flr_xoffs = sector->floor_xoffs;
sector->spawn_flr_yoffs = sector->floor_yoffs;
}
if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set
{
sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle;
sector->ceilingpic_angle = flatangle;
sector->ceiling_xoffs += xoffs;
sector->ceiling_yoffs += yoffs;
// saved for netgames
sector->spawn_ceil_xoffs = sector->ceiling_xoffs;
sector->spawn_ceil_yoffs = sector->ceiling_yoffs;
}
}
@ -6434,14 +6418,13 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata
* as they'll just be erased by UnArchiveThinkers.
* \sa P_SpawnPrecipitation, P_SpawnFriction, P_SpawnPushers, P_SpawnScrollers
*/
void P_SpawnSpecials(INT32 fromnetsave)
void P_SpawnSpecials(boolean fromnetsave)
{
sector_t *sector;
size_t i;
INT32 j;
thinkerlist_t *secthinkers;
thinker_t *th;
// This used to be used, and *should* be used in the future,
// but currently isn't.
(void)fromnetsave;
@ -7187,46 +7170,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
EV_AddLaserThinker(&sectors[s], &sectors[sec], lines + i, secthinkers);
break;
case 259: // Make-Your-Own FOF!
case 259: // Custom FOF
if (lines[i].sidenum[1] != 0xffff)
{
UINT8 *data;
UINT16 b;
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
fileinfo += ML_SIDEDEFS; // we only need the SIDEDEFS lump
data = Z_Malloc(fileinfo->size, PU_STATIC, NULL);
M_Memcpy(data, wadData + fileinfo->filepos, fileinfo->size); // copy data
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC);
for (b = 0; b < (INT16)numsides; b++)
{
register mapsidedef_t *msd = (mapsidedef_t *)data + b;
if (b == lines[i].sidenum[1])
{
if ((msd->toptexture[0] >= '0' && msd->toptexture[0] <= '9')
|| (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'F'))
{
ffloortype_e FOF_Flags = axtoi(msd->toptexture);
P_AddFakeFloorsByLine(i, FOF_Flags, secthinkers);
break;
ffloortype_e fofflags = sides[lines[i].sidenum[1]].toptexture;
P_AddFakeFloorsByLine(i, fofflags, secthinkers);
}
else
I_Error("Make-Your-Own-FOF (tag %d) needs a value in the linedef's second side upper texture field.", lines[i].tag);
}
}
Z_Free(data);
}
else
I_Error("Make-Your-Own FOF (tag %d) found without a 2nd linedef side!", lines[i].tag);
I_Error("Custom FOF (tag %d) found without a linedef back side!", lines[i].tag);
break;
case 300: // Linedef executor (combines with sector special 974/975) and commands
@ -7240,14 +7191,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
break;
case 308: // Race-only linedef executor. Triggers once.
if (gametype != GT_RACE && gametype != GT_COMPETITION)
if (!(gametyperules & GTR_RACE))
lines[i].special = 0;
break;
// Linedef executor triggers for CTF teams.
case 309:
case 311:
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
lines[i].special = 0;
break;
@ -9023,7 +8974,8 @@ void T_Pusher(pusher_t *p)
|| thing->type == MT_EXTRALARGEBUBBLE))
continue;
if (!(thing->flags & MF_PUSHABLE) && !(thing->type == MT_PLAYER
if (!((thing->flags & MF_PUSHABLE) || ((thing->info->flags & MF_PUSHABLE) && thing->fuse))
&& !(thing->type == MT_PLAYER
|| thing->type == MT_SMALLBUBBLE
|| thing->type == MT_MEDIUMBUBBLE
|| thing->type == MT_EXTRALARGEBUBBLE
@ -9176,7 +9128,7 @@ void T_Pusher(pusher_t *p)
thing->player->pflags |= PF_SLIDING;
thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR));
if (!demoplayback || P_AnalogMove(thing->player))
if (!demoplayback || P_ControlStyle(thing->player) == CS_LMAOGALOG)
{
if (thing->player == &players[consoleplayer])
{

View file

@ -27,6 +27,9 @@ extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
//
#define GETSECSPECIAL(i,j) ((i >> ((j-1)*4))&15)
// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize.
#define MAXFLATSIZE (2048<<FRACBITS)
// at game start
void P_InitPicAnims(void);
@ -35,7 +38,7 @@ void P_SetupLevelFlatAnims(void);
// at map load
void P_InitSpecials(void);
void P_SpawnSpecials(INT32 fromnetsave);
void P_SpawnSpecials(boolean fromnetsave);
// every tic
void P_UpdateSpecials(void);

View file

@ -629,6 +629,10 @@ void P_Ticker(boolean run)
if (demoplayback)
G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0);
#ifdef HAVE_BLUA
LUAh_PreThinkFrame();
#endif
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerThink(&players[i]);
@ -726,6 +730,10 @@ void P_Ticker(boolean run)
G_ConsGhostTic();
if (modeattacking)
G_GhostTicker();
#ifdef HAVE_BLUA
LUAh_PostThinkFrame();
#endif
}
P_MapEnd();
@ -745,6 +753,9 @@ void P_PreTicker(INT32 frames)
{
P_MapStart();
#ifdef HAVE_BLUA
LUAh_PreThinkFrame();
#endif
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
{
@ -779,6 +790,10 @@ void P_PreTicker(INT32 frames)
P_UpdateSpecials();
P_RespawnSpecials();
#ifdef HAVE_BLUA
LUAh_PostThinkFrame();
#endif
P_MapEnd();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1169,9 +1169,11 @@ static void R_Subsector(size_t num)
while (count--)
{
// CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime);
if (!line->glseg
#ifdef POLYOBJECTS
if (!line->polyseg) // ignore segs that belong to polyobjects
&& !line->polyseg // ignore segs that belong to polyobjects
#endif
)
R_AddLine(line);
line++;
curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */

View file

@ -571,7 +571,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
#ifndef NO_PNG_LUMPS
if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false);
realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL);
else
#endif
#ifdef WALLFLATS
@ -2710,14 +2710,29 @@ void R_PrecacheLevel(void)
for (j = 0; j < sprites[i].numframes; j++)
{
sf = &sprites[i].spriteframes[j];
for (k = 0; k < 8; k++)
{
// see R_InitSprites for more about lumppat,lumpid
lump = sf->lumppat[k];
if (devparm)
spritememory += W_LumpLength(lump);
W_CachePatchNum(lump, PU_PATCH);
#define cacheang(a) {\
lump = sf->lumppat[a];\
if (devparm)\
spritememory += W_LumpLength(lump);\
W_CachePatchNum(lump, PU_PATCH);\
}
// see R_InitSprites for more about lumppat,lumpid
switch (sf->rotate)
{
case SRF_SINGLE:
cacheang(0);
break;
case SRF_2D:
cacheang(2);
cacheang(6);
break;
default:
k = (sf->rotate & SRF_3DGE ? 16 : 8);
while (k--)
cacheang(k);
break;
}
#undef cacheang
}
}
free(spritepresent);

View file

@ -83,7 +83,9 @@ typedef struct extracolormap_s
*/
typedef struct
{
fixed_t x, y, z;
fixed_t x, y;
boolean floorzset, ceilingzset;
fixed_t floorz, ceilingz;
} vertex_t;
// Forward of linedefs, for sectors.
@ -384,17 +386,6 @@ typedef struct sector_s
// for fade thinker
INT16 spawn_lightlevel;
// these are saved for netgames, so do not let Lua touch these!
INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
// offsets sector spawned with (via linedef type 7)
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
fixed_t spawn_ceil_xoffs, spawn_ceil_yoffs;
// flag angles sector spawned with (via linedef type 7)
angle_t spawn_flrpic_angle;
angle_t spawn_ceilpic_angle;
// colormap structure
extracolormap_t *spawn_extra_colormap;
} sector_t;
@ -447,14 +438,10 @@ typedef struct line_s
polyobj_t *polyobj; // Belongs to a polyobject?
#endif
char *text; // a concatination of all front and back texture names, for linedef specials that require a string.
char *text; // a concatenation of all front and back texture names, for linedef specials that require a string.
INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0
} line_t;
//
// The SideDef.
//
typedef struct
{
// add this to the calculated texture column
@ -467,13 +454,16 @@ typedef struct
// We do not maintain names here.
INT32 toptexture, bottomtexture, midtexture;
// Sector the SideDef is facing.
// Linedef the sidedef belongs to
line_t *line;
// Sector the sidedef is facing.
sector_t *sector;
INT16 special; // the special of the linedef this side belongs to
INT16 repeatcnt; // # of times to repeat midtexture
char *text; // a concatination of all top, bottom, and mid texture names, for linedef specials that require a string.
char *text; // a concatenation of all top, bottom, and mid texture names, for linedef specials that require a string.
extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors.
} side_t;
@ -598,6 +588,7 @@ typedef struct seg_s
polyobj_t *polyseg;
boolean dontrenderme;
#endif
boolean glseg;
} seg_t;
//
@ -738,11 +729,8 @@ typedef struct
#ifdef ROTSPRITE
typedef struct
{
patch_t *patch[8][ROTANGLES];
boolean cached[8];
#ifdef HWRENDER
aatree_t *hardware_patch[8];
#endif/*HWRENDER*/
patch_t *patch[16][ROTANGLES];
UINT16 cached;
} rotsprite_t;
#endif/*ROTSPRITE*/
@ -750,9 +738,11 @@ typedef enum
{
SRF_SINGLE = 0, // 0-angle for all rotations
SRF_3D = 1, // Angles 1-8
SRF_LEFT = 2, // Left side uses single patch
SRF_RIGHT = 4, // Right side uses single patch
SRF_2D = SRF_LEFT|SRF_RIGHT, // 6
SRF_3DGE = 2, // 3DGE, ZDoom and Doom Legacy all have 16-angle support. Why not us?
SRF_3DMASK = SRF_3D|SRF_3DGE, // 3
SRF_LEFT = 4, // Left side uses single patch
SRF_RIGHT = 8, // Right side uses single patch
SRF_2D = SRF_LEFT|SRF_RIGHT, // 12
SRF_NONE = 0xff // Initial value
} spriterotateflags_t; // SRF's up!
@ -778,7 +768,7 @@ typedef struct patchinfo_s patchinfo_t;
// Sprites are patches with a special naming convention so they can be
// recognized by R_InitSprites.
// The base name is NNNNFx or NNNNFxFx, with x indicating the rotation,
// x = 0, 1-8, L/R
// x = 0, 1-8, 9+A-G, L/R
// The sprite and frame specified by a thing_t is range checked at run time.
// A sprite is a patch_t that is assumed to represent a three dimensional
// object and may have multiple rotations predrawn.
@ -795,12 +785,12 @@ typedef struct
// name eight times.
UINT8 rotate; // see spriterotateflags_t above
// Lump to use for view angles 0-7.
lumpnum_t lumppat[8]; // lump number 16 : 16 wad : lump
size_t lumpid[8]; // id in the spriteoffset, spritewidth, etc. tables
// Lump to use for view angles 0-7/15.
lumpnum_t lumppat[16]; // lump number 16 : 16 wad : lump
size_t lumpid[16]; // id in the spriteoffset, spritewidth, etc. tables
// Flip bits (1 = flip) to use for view angles 0-7.
UINT8 flip;
// Flip bits (1 = flip) to use for view angles 0-7/15.
UINT16 flip;
#ifdef ROTSPRITE
rotsprite_t rotsprite;

View file

@ -59,6 +59,7 @@ INT32 centerx, centery;
fixed_t centerxfrac, centeryfrac;
fixed_t projection;
fixed_t projectiony; // aspect ratio
fixed_t fovtan; // field of view
// just for profiling purposes
size_t framecount;
@ -108,10 +109,12 @@ static CV_PossibleValue_t drawdist_precip_cons_t[] = {
{1024, "1024"}, {1536, "1536"}, {2048, "2048"},
{0, "None"}, {0, NULL}};
static CV_PossibleValue_t fov_cons_t[] = {{60*FRACUNIT, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}};
static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card
static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}};
static void Fov_OnChange(void);
static void ChaseCam_OnChange(void);
static void ChaseCam2_OnChange(void);
static void FlipCam_OnChange(void);
@ -141,6 +144,7 @@ consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL,
consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
//consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fov = {"fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange, 0, NULL, NULL, 0, 0, NULL};
// Okay, whoever said homremoval causes a performance hit should be shot.
consvar_t cv_homremoval = {"homremoval", "No", CV_SAVE, homremoval_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -184,23 +188,31 @@ void SplitScreen_OnChange(void)
}
}
}
static void Fov_OnChange(void)
{
// Shouldn't be needed with render parity?
//if ((netgame || multiplayer) && !cv_debug && cv_fov.value != 90*FRACUNIT)
// CV_Set(&cv_fov, cv_fov.defaultvalue);
R_SetViewSize();
}
static void ChaseCam_OnChange(void)
{
if (!cv_chasecam.value || !cv_useranalog.value)
CV_SetValue(&cv_analog, 0);
if (!cv_chasecam.value || !cv_useranalog[0].value)
CV_SetValue(&cv_analog[0], 0);
else
CV_SetValue(&cv_analog, 1);
CV_SetValue(&cv_analog[0], 1);
}
static void ChaseCam2_OnChange(void)
{
if (botingame)
return;
if (!cv_chasecam2.value || !cv_useranalog2.value)
CV_SetValue(&cv_analog2, 0);
if (!cv_chasecam2.value || !cv_useranalog[1].value)
CV_SetValue(&cv_analog[1], 0);
else
CV_SetValue(&cv_analog2, 1);
CV_SetValue(&cv_analog[1], 1);
}
static void FlipCam_OnChange(void)
@ -448,8 +460,8 @@ static void R_InitTextureMapping(void)
//
// Calc focallength
// so FIELDOFVIEW angles covers SCREENWIDTH.
focallength = FixedDiv(centerxfrac,
FINETANGENT(FINEANGLES/4+/*cv_fov.value*/ FIELDOFVIEW/2));
focallength = FixedDiv(projection,
FINETANGENT(FINEANGLES/4+FIELDOFVIEW/2));
#ifdef ESLOPE
focallengthf = FIXED_TO_FLOAT(focallength);
@ -457,9 +469,9 @@ static void R_InitTextureMapping(void)
for (i = 0; i < FINEANGLES/2; i++)
{
if (FINETANGENT(i) > FRACUNIT*2)
if (FINETANGENT(i) > fovtan*2)
t = -1;
else if (FINETANGENT(i) < -FRACUNIT*2)
else if (FINETANGENT(i) < -fovtan*2)
t = viewwidth+1;
else
{
@ -563,6 +575,7 @@ void R_ExecuteSetViewSize(void)
INT32 j;
INT32 level;
INT32 startmapl;
angle_t fov;
setsizeneeded = false;
@ -585,9 +598,12 @@ void R_ExecuteSetViewSize(void)
centerxfrac = centerx<<FRACBITS;
centeryfrac = centery<<FRACBITS;
projection = centerxfrac;
//projectiony = (((vid.height*centerx*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width)<<FRACBITS;
projectiony = centerxfrac;
fov = FixedAngle(cv_fov.value/2) + ANGLE_90;
fovtan = FINETANGENT(fov >> ANGLETOFINESHIFT);
if (splitscreen == 1) // Splitscreen FOV should be adjusted to maintain expected vertical view
fovtan = 17*fovtan/10;
projection = projectiony = FixedDiv(centerxfrac, fovtan);
R_InitViewBuffer(scaledviewwidth, viewheight);
@ -613,7 +629,7 @@ void R_ExecuteSetViewSize(void)
for (i = 0; i < j; i++)
{
dy = ((i - viewheight*8)<<FRACBITS) + FRACUNIT/2;
dy = abs(dy);
dy = FixedMul(abs(dy), fovtan);
yslopetab[i] = FixedDiv(centerx*FRACUNIT, dy);
}
}
@ -698,6 +714,7 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
INT32 side, i;
size_t nodenum;
subsector_t *ret;
seg_t *seg;
// single subsector is a special case
if (numnodes == 0)
@ -713,10 +730,15 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
}
ret = &subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0; i < ret->numlines; i++)
//if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers
if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side)
for (i = 0, seg = &segs[ret->firstline]; i < ret->numlines; i++, seg++)
{
if (seg->glseg)
continue;
//if (R_PointOnSegSide(x, y, seg)) -- breaks in ogl because polyvertex_t cast over vertex pointers
if (P_PointOnLineSide(x, y, seg->linedef) != seg->side)
return 0;
}
return ret;
}
@ -728,7 +750,7 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
static mobj_t *viewmobj;
// WARNING: a should be unsigned but to add with 2048, it isn't!
#define AIMINGTODY(a) ((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)>>FRACBITS)
#define AIMINGTODY(a) FixedDiv((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)>>FRACBITS, fovtan)
// recalc necessary stuff for mouseaiming
// slopes are already calculated for the full possible view (which is 4*viewheight).
@ -1197,6 +1219,7 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_drawdist);
CV_RegisterVar(&cv_drawdist_nights);
CV_RegisterVar(&cv_drawdist_precip);
CV_RegisterVar(&cv_fov);
CV_RegisterVar(&cv_chasecam);
CV_RegisterVar(&cv_chasecam2);
@ -1228,6 +1251,16 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_cam2_orbit);
CV_RegisterVar(&cv_cam2_adjust);
CV_RegisterVar(&cv_cam_savedist[0][0]);
CV_RegisterVar(&cv_cam_savedist[0][1]);
CV_RegisterVar(&cv_cam_savedist[1][0]);
CV_RegisterVar(&cv_cam_savedist[1][1]);
CV_RegisterVar(&cv_cam_saveheight[0][0]);
CV_RegisterVar(&cv_cam_saveheight[0][1]);
CV_RegisterVar(&cv_cam_saveheight[1][0]);
CV_RegisterVar(&cv_cam_saveheight[1][1]);
CV_RegisterVar(&cv_showhud);
CV_RegisterVar(&cv_translucenthud);

View file

@ -84,6 +84,7 @@ extern conscar_t cv_shadowoffs;
#endif //#ifdef GLBADSHADOWS
extern consvar_t cv_translucency;
extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip;
extern consvar_t cv_fov;
extern consvar_t cv_skybox;
extern consvar_t cv_tailspickup;

View file

@ -2,8 +2,8 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 2005-2009 by Andrey "entryway" Budko.
// Copyright (C) 2018-2019 by Jaime "Lactozilla" Passos.
// Copyright (C) 2019 by Sonic Team Junior.
// Copyright (C) 2018-2020 by Jaime "Lactozilla" Passos.
// Copyright (C) 2019-2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -49,8 +49,6 @@
#endif
static unsigned char imgbuf[1<<26];
fixed_t cosang2rad[ROTANGLES];
fixed_t sinang2rad[ROTANGLES];
//
// R_CheckIfPatch
@ -201,11 +199,15 @@ void R_PatchToFlat(patch_t *patch, UINT8 *flat)
}
//
// R_PatchToFlat_16bpp
// R_PatchToMaskedFlat
//
// Convert a patch to a 16-bit flat.
// Convert a patch to a masked flat.
// Now, what is a "masked" flat anyway?
// It means the flat uses two bytes to store image data.
// The upper byte is used to store the transparent pixel,
// and the lower byte stores a palette index.
//
void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip)
void R_PatchToMaskedFlat(patch_t *patch, UINT16 *raw, boolean flip)
{
fixed_t col, ofs;
column_t *column;
@ -250,6 +252,9 @@ patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffse
UINT8 *colpointers, *startofspan;
size_t size = 0;
if (!raw)
return NULL;
// Write image size and offset
WRITEINT16(imgptr, width);
WRITEINT16(imgptr, height);
@ -349,16 +354,18 @@ patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffse
}
//
// R_FlatToPatch_16bpp
// R_MaskedFlatToPatch
//
// Convert a 16-bit flat to a patch.
// Convert a masked flat to a patch.
// Explanation of "masked" flats in R_PatchToMaskedFlat.
//
patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *size)
patch_t *R_MaskedFlatToPatch(UINT16 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize)
{
UINT32 x, y;
UINT8 *img;
UINT8 *imgptr = imgbuf;
UINT8 *colpointers, *startofspan;
size_t size = 0;
if (!raw)
return NULL;
@ -366,9 +373,8 @@ patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *s
// Write image size and offset
WRITEINT16(imgptr, width);
WRITEINT16(imgptr, height);
// no offsets
WRITEINT16(imgptr, 0);
WRITEINT16(imgptr, 0);
WRITEINT16(imgptr, leftoffset);
WRITEINT16(imgptr, topoffset);
// Leave placeholder to column pointers
colpointers = imgptr;
@ -452,9 +458,12 @@ patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *s
WRITEUINT8(imgptr, 0xFF);
}
*size = imgptr-imgbuf;
img = Z_Malloc(*size, PU_STATIC, NULL);
memcpy(img, imgbuf, *size);
size = imgptr-imgbuf;
img = Z_Malloc(size, PU_STATIC, NULL);
memcpy(img, imgbuf, size);
if (destsize != NULL)
*destsize = size;
return (patch_t *)img;
}
@ -677,6 +686,41 @@ static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topo
return flat;
}
// Convert a PNG with transparency to a raw image.
static UINT16 *PNG_MaskedRawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size)
{
UINT16 *flat;
png_uint_32 x, y;
png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, size);
png_uint_32 width = *w, height = *h;
size_t flatsize, i;
if (!row_pointers)
I_Error("PNG_MaskedRawConvert: conversion failed");
// Convert the image to 16bpp
flatsize = (width * height);
flat = Z_Malloc(flatsize * sizeof(UINT16), PU_LEVEL, NULL);
// can't memset here
for (i = 0; i < flatsize; i++)
flat[i] = 0xFF00;
for (y = 0; y < height; y++)
{
png_bytep row = row_pointers[y];
for (x = 0; x < width; x++)
{
png_bytep px = &(row[x * 4]);
if ((UINT8)px[3])
flat[((y * width) + x)] = NearestColor((UINT8)px[0], (UINT8)px[1], (UINT8)px[2]);
}
}
free(row_pointers);
return flat;
}
//
// R_PNGToFlat
//
@ -692,16 +736,16 @@ UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size)
//
// Convert a PNG to a patch.
//
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency)
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize)
{
UINT16 width, height;
INT16 topoffset = 0, leftoffset = 0;
UINT8 *raw = PNG_RawConvert(png, &width, &height, &topoffset, &leftoffset, size);
UINT16 *raw = PNG_MaskedRawConvert(png, &width, &height, &topoffset, &leftoffset, size);
if (!raw)
I_Error("R_PNGToPatch: conversion failed");
return R_FlatToPatch(raw, width, height, leftoffset, topoffset, destsize, transparency);
return R_MaskedFlatToPatch(raw, width, height, leftoffset, topoffset, destsize);
}
//
@ -789,11 +833,9 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
size_t sprinfoTokenLength;
char *frameChar = NULL;
UINT8 frameFrame = 0xFF;
#ifdef ROTSPRITE
INT16 frameXPivot = 0;
INT16 frameYPivot = 0;
rotaxis_t frameRotAxis = 0;
#endif
// Sprite identifier
sprinfoToken = M_GetToken(NULL);
@ -828,7 +870,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
}
while (strcmp(sprinfoToken,"}")!=0)
{
#ifdef ROTSPRITE
if (stricmp(sprinfoToken, "XPIVOT")==0)
{
Z_Free(sprinfoToken);
@ -852,7 +893,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
else if ((stricmp(sprinfoToken, "Z")==0) || (stricmp(sprinfoToken, "ZAXIS")==0) || (stricmp(sprinfoToken, "YAW")==0))
frameRotAxis = ROTAXIS_Z;
}
#endif
Z_Free(sprinfoToken);
sprinfoToken = M_GetToken(NULL);
@ -866,11 +906,9 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
}
// set fields
#ifdef ROTSPRITE
info->pivot[frameFrame].x = frameXPivot;
info->pivot[frameFrame].y = frameYPivot;
info->pivot[frameFrame].rotaxis = frameRotAxis;
#endif
}
//
@ -1093,16 +1131,60 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps)
for (i = 0; i < numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
// load SPRTINFO lumps
if (!stricmp(name, "SPRTINFO"))
// Load SPRTINFO and SPR_ lumps as SpriteInfo
if (!memcmp(name, "SPRTINFO", 8) || !memcmp(name, "SPR_", 4))
R_ParseSPRTINFOLump(wadnum, i);
// load SPR_ lumps (as DEHACKED lump)
else if (!memcmp(name, "SPR_", 4))
DEH_LoadDehackedLumpPwad(wadnum, i, false);
}
}
static UINT16 GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip)
{
fixed_t ofs;
column_t *column;
UINT8 *source;
if (x >= 0 && x < SHORT(patch->width))
{
INT32 topdelta, prevdelta = -1;
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[flip ? (patch->width-1-x) : x]));
while (column->topdelta != 0xff)
{
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
source = (UINT8 *)(column) + 3;
for (ofs = 0; ofs < column->length; ofs++)
{
if ((topdelta + ofs) == y)
return source[ofs];
}
column = (column_t *)((UINT8 *)column + column->length + 4);
}
}
return 0xFF00;
}
#ifdef ROTSPRITE
//
// R_GetRollAngle
//
// Angles precalculated in R_InitSprites.
//
fixed_t rollcosang[ROTANGLES];
fixed_t rollsinang[ROTANGLES];
INT32 R_GetRollAngle(angle_t rollangle)
{
INT32 ra = AngleFixed(rollangle)>>FRACBITS;
#if (ROTANGDIFF > 1)
ra += (ROTANGDIFF/2);
#endif
ra /= ROTANGDIFF;
ra %= ROTANGLES;
return ra;
}
//
// R_CacheRotSprite
//
@ -1115,7 +1197,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
patch_t *patch;
patch_t *newpatch;
UINT16 *rawsrc, *rawdst;
size_t size, size2;
size_t size;
INT32 bflip = (flip != 0x00);
#define SPRITE_XCENTER (leftoffset)
@ -1123,7 +1205,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
#define ROTSPRITE_XCENTER (newwidth / 2)
#define ROTSPRITE_YCENTER (newheight / 2)
if (!sprframe->rotsprite.cached[rot])
if (!(sprframe->rotsprite.cached & (1<<rot)))
{
INT32 dx, dy;
INT32 px, py;
@ -1168,15 +1250,15 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
for (i = 0; i < size; i++)
rawsrc[i] = 0xFF00;
R_PatchToFlat_16bpp(patch, rawsrc, bflip);
R_PatchToMaskedFlat(patch, rawsrc, bflip);
// Don't cache angle = 0
for (angle = 1; angle < ROTANGLES; angle++)
{
INT32 newwidth, newheight;
ca = cosang2rad[angle];
sa = sinang2rad[angle];
ca = rollcosang[angle];
sa = rollsinang[angle];
// Find the dimensions of the rotated patch.
{
@ -1237,17 +1319,15 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
#undef BOUNDARYADJUST
}
size2 = (newwidth * newheight);
if (!size2)
size2 = size;
// Draw the rotated sprite to a temporary buffer.
size = (newwidth * newheight);
if (!size)
size = (width * height);
rawdst = Z_Malloc(size2 * sizeof(UINT16), PU_STATIC, NULL);
// can't memset here
for (i = 0; i < size2; i++)
rawdst = Z_Malloc(size * sizeof(UINT16), PU_STATIC, NULL);
for (i = 0; i < size; i++)
rawdst[i] = 0xFF00;
// Draw the rotated sprite to a temporary buffer.
for (dy = 0; dy < newheight; dy++)
{
for (dx = 0; dx < newwidth; dx++)
@ -1259,12 +1339,12 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
sx >>= FRACBITS;
sy >>= FRACBITS;
if (sx >= 0 && sy >= 0 && sx < width && sy < height)
rawdst[(dy*newwidth)+dx] = rawsrc[(sy*width)+sx];
rawdst[(dy*newwidth)+dx] = GetPatchPixel(patch, sx, sy, bflip);
}
}
// make patch
newpatch = R_FlatToPatch_16bpp(rawdst, newwidth, newheight, &size);
newpatch = R_MaskedFlatToPatch(rawdst, newwidth, newheight, 0, 0, &size);
{
newpatch->leftoffset = (newpatch->width / 2) + (leftoffset - px);
newpatch->topoffset = (newpatch->height / 2) + (patch->topoffset - py);
@ -1280,9 +1360,11 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
#ifdef HWRENDER
if (rendermode == render_opengl)
{
GLPatch_t *grPatch = HWR_GetCachedGLRotSprite(sprframe->rotsprite.hardware_patch[rot], angle, newpatch);
HWR_MakePatch(newpatch, grPatch, grPatch->mipmap, false);
GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL);
grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL);
grPatch->rawpatch = newpatch;
sprframe->rotsprite.patch[rot][angle] = (patch_t *)grPatch;
HWR_MakePatch(newpatch, grPatch, grPatch->mipmap, false);
}
else
#endif // HWRENDER
@ -1293,10 +1375,9 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
}
// This rotation is cached now
sprframe->rotsprite.cached[rot] = true;
sprframe->rotsprite.cached |= (1<<rot);
// free image data
Z_Free(rawsrc);
Z_Free(patch);
}
#undef SPRITE_XCENTER
@ -1318,9 +1399,9 @@ void R_FreeSingleRotSprite(spritedef_t *spritedef)
for (frame = 0; frame < spritedef->numframes; frame++)
{
spriteframe_t *sprframe = &spritedef->spriteframes[frame];
for (rot = 0; rot < 8; rot++)
for (rot = 0; rot < 16; rot++)
{
if (sprframe->rotsprite.cached[rot])
if (sprframe->rotsprite.cached & (1<<rot))
{
for (ang = 0; ang < ROTANGLES; ang++)
{
@ -1351,7 +1432,7 @@ void R_FreeSingleRotSprite(spritedef_t *spritedef)
Z_Free(rotsprite);
}
}
sprframe->rotsprite.cached[rot] = false;
sprframe->rotsprite.cached &= ~(1<<rot);
}
}
}

View file

@ -18,7 +18,6 @@
#include "doomdef.h"
// Structs
#ifdef ROTSPRITE
typedef enum
{
ROTAXIS_X, // Roll (the default)
@ -31,13 +30,10 @@ typedef struct
INT32 x, y;
rotaxis_t rotaxis;
} spriteframepivot_t;
#endif
typedef struct
{
#ifdef ROTSPRITE
spriteframepivot_t pivot[64];
#endif
boolean available;
} spriteinfo_t;
@ -45,9 +41,9 @@ typedef struct
boolean R_CheckIfPatch(lumpnum_t lump);
void R_TextureToFlat(size_t tex, UINT8 *flat);
void R_PatchToFlat(patch_t *patch, UINT8 *flat);
void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip);
void R_PatchToMaskedFlat(patch_t *patch, UINT16 *raw, boolean flip);
patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency);
patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *size);
patch_t *R_MaskedFlatToPatch(UINT16 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize);
// Portable Network Graphics
boolean R_IsLumpPNG(const UINT8 *d, size_t s);
@ -55,7 +51,7 @@ boolean R_IsLumpPNG(const UINT8 *d, size_t s);
#ifndef NO_PNG_LUMPS
UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size);
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency);
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize);
boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
#endif
@ -66,12 +62,13 @@ void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum);
// Sprite rotation
#ifdef ROTSPRITE
INT32 R_GetRollAngle(angle_t rollangle);
void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip);
void R_FreeSingleRotSprite(spritedef_t *spritedef);
void R_FreeSkinRotSprite(size_t skinnum);
extern fixed_t rollcosang[ROTANGLES];
extern fixed_t rollsinang[ROTANGLES];
void R_FreeAllRotSprite(void);
extern fixed_t cosang2rad[ROTANGLES];
extern fixed_t sinang2rad[ROTANGLES];
#endif
#endif // __R_PATCH__

View file

@ -308,6 +308,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// for horizontal / vertical / diagonal. Diagonal?
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
curline = ds->curline;
frontsector = curline->frontsector;
backsector = curline->backsector;
texnum = R_GetTextureNum(curline->sidedef->midtexture);

View file

@ -63,6 +63,7 @@ extern seg_t *segs;
extern size_t numsectors;
extern sector_t *sectors;
extern sector_t *spawnsectors;
extern size_t numsubsectors;
extern subsector_t *subsectors;
@ -72,9 +73,11 @@ extern node_t *nodes;
extern size_t numlines;
extern line_t *lines;
extern line_t *spawnlines;
extern size_t numsides;
extern side_t *sides;
extern side_t *spawnsides;
//
// POV data.

View file

@ -105,29 +105,23 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
UINT8 rotation,
UINT8 flipped)
{
char cn = R_Frame2Char(frame); // for debugging
char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
INT32 r, ang;
lumpnum_t lumppat = wad;
lumppat <<= 16;
lumppat += lump;
if (frame >= 64 || !(R_ValidSpriteAngle(rotation)))
I_Error("R_InstallSpriteLump: Bad frame characters in lump %s", W_CheckNameForNum(lumppat));
if (maxframe ==(size_t)-1 || frame > maxframe)
maxframe = frame;
// rotsprite
#ifdef ROTSPRITE
for (r = 0; r < 8; r++)
sprtemp[frame].rotsprite.cached = 0;
for (r = 0; r < 16; r++)
{
sprtemp[frame].rotsprite.cached[r] = false;
for (ang = 0; ang < ROTANGLES; ang++)
sprtemp[frame].rotsprite.patch[r][ang] = NULL;
#ifdef HWRENDER
sprtemp[frame].rotsprite.hardware_patch[r] = M_AATreeAlloc(AATREE_ZUSER);
#endif/*HWRENDER*/
}
#endif/*ROTSPRITE*/
@ -136,16 +130,16 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
// the lump should be used for all rotations
if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8 and L/R rotations into one debug message.
else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message.
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn);
sprtemp[frame].rotate = SRF_SINGLE;
for (r = 0; r < 8; r++)
for (r = 0; r < 16; r++)
{
sprtemp[frame].lumppat[r] = lumppat;
sprtemp[frame].lumpid[r] = lumpid;
}
sprtemp[frame].flip = flipped ? 0xFF : 0; // 11111111 in binary
sprtemp[frame].flip = flipped ? 0xFFFF : 0; // 1111111111111111 in binary
return;
}
@ -154,54 +148,67 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
UINT8 rightfactor = ((rotation == ROT_R) ? 4 : 0);
// the lump should be used for half of all rotations
if (sprtemp[frame].rotate == SRF_SINGLE)
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
else if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate == SRF_3D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
else if (sprtemp[frame].rotate == SRF_3DGE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-G rotations\n", spritename, cn);
else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple L rotations\n", spritename, cn);
else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple R rotations\n", spritename, cn);
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
if (sprtemp[frame].rotate == (SRF_3D|SRF_2D))
sprtemp[frame].rotate = SRF_2D; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
sprtemp[frame].rotate &= ~SRF_3DMASK; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
for (r = 0; r < 4; r++) // Thanks to R_PrecacheLevel, we can't leave sprtemp[*].lumppat[*] == LUMPERROR... so we load into the front/back angle too.
// load into every relevant angle, including the front one
for (r = 0; r < 4; r++)
{
sprtemp[frame].lumppat[r + rightfactor] = lumppat;
sprtemp[frame].lumpid[r + rightfactor] = lumpid;
sprtemp[frame].lumppat[r + rightfactor + 8] = lumppat;
sprtemp[frame].lumpid[r + rightfactor + 8] = lumpid;
}
if (flipped)
sprtemp[frame].flip |= (0x0F<<rightfactor); // 00001111 or 11110000 in binary, depending on rotation being ROT_L or ROT_R
sprtemp[frame].flip |= (0x0F0F<<rightfactor); // 0000111100001111 or 1111000011110000 in binary, depending on rotation being ROT_L or ROT_R
else
sprtemp[frame].flip &= ~(0x0F<<rightfactor); // ditto
sprtemp[frame].flip &= ~(0x0F0F<<rightfactor); // ditto
return;
}
// the lump is only used for one rotation
if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8 rotations and a rot = 0 lump\n", spritename, cn);
else if ((sprtemp[frame].rotate != SRF_3D) && (sprtemp[frame].rotate != SRF_NONE))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
else if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8/G rotations and a rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate & SRF_2D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8/G rotations\n", spritename, cn);
// make 0 based
rotation--;
{
// SRF_3D|SRF_3DGE being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
UINT8 threedrot = (rotation > 7) ? SRF_3DGE : (sprtemp[frame].rotate & SRF_3DMASK);
if (!threedrot)
threedrot = SRF_3D;
if (rotation == 0 || rotation == 4) // Front or back...
sprtemp[frame].rotate = SRF_3D; // Prevent L and R changeover
else if (rotation > 3) // Right side
sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover
else // if (rotation <= 3) // Left side
sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover
sprtemp[frame].rotate = threedrot; // Prevent L and R changeover
else if ((rotation & 7) > 3) // Right side
sprtemp[frame].rotate = (threedrot | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover
else // if ((rotation & 7) <= 3) // Left side
sprtemp[frame].rotate = (threedrot | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover
}
if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation);
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, cr);
// lumppat & lumpid are the same for original Doom, but different
// when using sprites in pwad : the lumppat points the new graphics
@ -262,9 +269,9 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
if (memcmp(lumpinfo[l].name,sprname,4)==0)
{
frame = R_Char2Frame(lumpinfo[l].name[4]);
rotation = (UINT8)(lumpinfo[l].name[5] - '0');
rotation = R_Char2Rotation(lumpinfo[l].name[5]);
if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) // Give an actual NAME error -_-...
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
{
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue;
@ -284,7 +291,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
// lump is a png so convert it
if (R_IsLumpPNG((UINT8 *)png, len))
{
png = R_PNGToPatch((UINT8 *)png, len, NULL, true);
png = R_PNGToPatch((UINT8 *)png, len, NULL);
M_Memcpy(&patch, png, sizeof(INT16)*4);
}
Z_Free(png);
@ -311,7 +318,13 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
if (lumpinfo[l].name[6])
{
frame = R_Char2Frame(lumpinfo[l].name[6]);
rotation = (UINT8)(lumpinfo[l].name[7] - '0');
rotation = R_Char2Rotation(lumpinfo[l].name[7]);
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
{
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue;
}
R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
}
@ -372,18 +385,19 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
case SRF_2D: // both Left and Right rotations
// we test to see whether the left and right slots are present
if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations",
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (L-R mode)",
sprname, R_Frame2Char(frame));
break;
default:
// must have all 8 frames
for (rotation = 0; rotation < 8; rotation++)
// must have all 8/16 frames
rotation = ((sprtemp[frame].rotate & SRF_3DGE) ? 16 : 8);
while (rotation--)
// we test the patch lump, or the id lump whatever
// if it was not loaded the two are LUMPERROR
if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations",
sprname, R_Frame2Char(frame));
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (1-%c mode)",
sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
break;
}
}
@ -499,7 +513,7 @@ void R_InitSprites(void)
{
size_t i;
#ifdef ROTSPRITE
INT32 angle, realangle = 0;
INT32 angle;
float fa;
#endif
@ -507,12 +521,11 @@ void R_InitSprites(void)
negonearray[i] = -1;
#ifdef ROTSPRITE
for (angle = 0; angle < ROTANGLES; angle++)
for (angle = 1; angle < ROTANGLES; angle++)
{
fa = ANG2RAD(FixedAngle(realangle<<FRACBITS));
cosang2rad[angle] = FLOAT_TO_FIXED(cos(-fa));
sinang2rad[angle] = FLOAT_TO_FIXED(sin(-fa));
realangle += ROTANGDIFF;
fa = ANG2RAD(FixedAngle((ROTANGDIFF * angle)<<FRACBITS));
rollcosang[angle] = FLOAT_TO_FIXED(cos(-fa));
rollsinang[angle] = FLOAT_TO_FIXED(sin(-fa));
}
#endif
@ -1375,7 +1388,7 @@ static void R_ProjectSprite(mobj_t *thing)
size_t lump;
size_t rot;
UINT8 flip;
UINT16 flip;
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
INT32 lindex;
@ -1407,8 +1420,7 @@ static void R_ProjectSprite(mobj_t *thing)
fixed_t spr_offset, spr_topoffset;
#ifdef ROTSPRITE
patch_t *rotsprite = NULL;
angle_t arollangle = thing->rollangle;
UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS;
INT32 rollangle = 0;
#endif
// transform the origin point
@ -1500,7 +1512,7 @@ static void R_ProjectSprite(mobj_t *thing)
// use single rotation for all views
rot = 0; //Fab: for vis->patch below
lump = sprframe->lumpid[0]; //Fab: see note above
flip = sprframe->flip; // Will only be 0x00 or 0xFF
flip = sprframe->flip; // Will only be 0 or 0xFFFF
}
else
{
@ -1511,6 +1523,11 @@ static void R_ProjectSprite(mobj_t *thing)
rot = 6; // F7 slot
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
rot = 2; // F3 slot
else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
{
rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
rot = ((rot & 1)<<3)|(rot>>1);
}
else // Normal behaviour
rot = (ang+ANGLE_202h)>>29;
@ -1530,11 +1547,11 @@ static void R_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lump].topoffset;
#ifdef ROTSPRITE
if (rollangle > 0)
if (thing->rollangle)
{
if (!sprframe->rotsprite.cached[rot])
rollangle = R_GetRollAngle(thing->rollangle);
if (!(sprframe->rotsprite.cached & (1<<rot)))
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rollangle /= ROTANGDIFF;
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)
{
@ -3134,7 +3151,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
{
return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
|| (!skins[skinnum].availability)
|| ((playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
|| (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
|| (modeattacking) // If you have someone else's run you might as well take a look
|| (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1.
|| (netgame && (cv_forceskin.value == skinnum)) // Force 2.

View file

@ -20,10 +20,6 @@
#include "r_portal.h"
#include "r_defs.h"
// "Left" and "Right" character symbols for additional rotation functionality
#define ROT_L ('L' - '0')
#define ROT_R ('R' - '0')
// number of sprite lumps for spritewidth,offset,topoffset lookup tables
// Fab: this is a hack : should allocate the lookup tables per sprite
#define MAXVISSPRITES 2048 // added 2-2-98 was 128
@ -281,7 +277,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn)
if (cn == '+') return '\\' - 'A'; // PK3 can't use backslash, so use + instead
return cn - 'A';
#else
if (cn >= 'A' && cn <= 'Z') return cn - 'A';
if (cn >= 'A' && cn <= 'Z') return (cn - 'A');
if (cn >= '0' && cn <= '9') return (cn - '0') + 26;
if (cn >= 'a' && cn <= 'z') return (cn - 'a') + 36;
if (cn == '!') return 62;
@ -290,9 +286,26 @@ FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn)
#endif
}
FUNCMATH FUNCINLINE static ATTRINLINE boolean R_ValidSpriteAngle(UINT8 rotation)
// "Left" and "Right" character symbols for additional rotation functionality
#define ROT_L 17
#define ROT_R 18
FUNCMATH FUNCINLINE static ATTRINLINE char R_Rotation2Char(UINT8 rot)
{
return ((rotation <= 8) || (rotation == ROT_L) || (rotation == ROT_R));
if (rot <= 9) return '0' + rot;
if (rot <= 16) return 'A' + (rot - 10);
if (rot == ROT_L) return 'L';
if (rot == ROT_R) return 'R';
return '\xFF';
}
FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Rotation(char cn)
{
if (cn >= '0' && cn <= '9') return (cn - '0');
if (cn >= 'A' && cn <= 'G') return (cn - 'A') + 10;
if (cn == 'L') return ROT_L;
if (cn == 'R') return ROT_R;
return 255;
}
#endif //__R_THINGS__

View file

@ -187,6 +187,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"shield", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pity Shield"}, // generic GET!
{"wirlsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Whirlwind Shield"}, // Whirlwind GET!
{"forcsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Force Shield"}, // Force GET!
{"frcssg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Weak Force Shield"}, // Force GET...? (consider making a custom shield with this instead of a single-hit force shield!)
{"elemsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Elemental Shield"}, // Elemental GET!
{"armasg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon Shield"}, // Armaggeddon GET!
{"attrsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction Shield"}, // Attract GET!
@ -220,6 +221,9 @@ sfxinfo_t S_sfx[NUMSFX] =
{"sprong", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power spring"},
{"lvfal1", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rumble"},
{"pscree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "SCREE!"},
{"iceb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ice crack"},
{"shattr", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Shattering"},
{"antiri", true, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Depletion"},
// Menu, interface
{"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"},
@ -233,6 +237,9 @@ sfxinfo_t S_sfx[NUMSFX] =
{"wepchg", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Weapon change"}, // Weapon switch is identical to menu for now
{"wtrdng", true, 212, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"}, // make sure you can hear the DING DING! Tails 03-08-2000
{"zelda", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"},
{"adderr", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Error"},
{"notadd", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Reject"},
{"addfil", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accept"},
// NiGHTS
{"ideya", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Success"},
@ -427,24 +434,9 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s25e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s25f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s260", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s261", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s262", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s263", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s264", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s265", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s266", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s267", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s268", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s269", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s26a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s26b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s26c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s26d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s26e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s26f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s270", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
// S3&K sounds
{"s3k2b", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Emerald"}, // Got Emerald!
{"s3k33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, // stereo in original game, identical to latter
{"s3k34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, // mono in original game, identical to previous
{"s3k35", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"},
@ -566,6 +558,21 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3ka9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"},
{"s3kaa", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"},
{"s3kab", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kab9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kaba", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kabb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kabc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kabd", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kabe", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kabf", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"},
{"s3kac", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Continue"},
{"s3kad", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "GO!"},
{"s3kae", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pinball flipper"},
@ -604,7 +611,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3kc5l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Revving up"}, // ditto
{"s3kc6s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"},
{"s3kc6l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, // ditto
{"s3kc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"},
{"s3kc7s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"},
{"s3kc7l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, // ditto
{"s3kc8s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sliding"},
{"s3kc8l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sliding"}, // ditto
{"s3kc9s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging"},

View file

@ -236,6 +236,7 @@ typedef enum
sfx_shield,
sfx_wirlsg,
sfx_forcsg,
sfx_frcssg,
sfx_elemsg,
sfx_armasg,
sfx_attrsg,
@ -269,6 +270,9 @@ typedef enum
sfx_sprong,
sfx_lvfal1,
sfx_pscree,
sfx_iceb,
sfx_shattr,
sfx_antiri,
// Menu, interface
sfx_chchng,
@ -282,6 +286,9 @@ typedef enum
sfx_wepchg,
sfx_wtrdng,
sfx_zelda,
sfx_adderr,
sfx_notadd,
sfx_addfil,
// NiGHTS
sfx_ideya,
@ -476,24 +483,9 @@ typedef enum
sfx_s25e,
sfx_s25f,
sfx_s260,
sfx_s261,
sfx_s262,
sfx_s263,
sfx_s264,
sfx_s265,
sfx_s266,
sfx_s267,
sfx_s268,
sfx_s269,
sfx_s26a,
sfx_s26b,
sfx_s26c,
sfx_s26d,
sfx_s26e,
sfx_s26f,
sfx_s270,
// S3&K sounds
sfx_s3k2b,
sfx_s3k33,
sfx_s3k34,
sfx_s3k35,
@ -615,6 +607,21 @@ typedef enum
sfx_s3ka9,
sfx_s3kaa,
sfx_s3kab,
sfx_s3kab1,
sfx_s3kab2,
sfx_s3kab3,
sfx_s3kab4,
sfx_s3kab5,
sfx_s3kab6,
sfx_s3kab7,
sfx_s3kab8,
sfx_s3kab9,
sfx_s3kaba,
sfx_s3kabb,
sfx_s3kabc,
sfx_s3kabd,
sfx_s3kabe,
sfx_s3kabf,
sfx_s3kac,
sfx_s3kad,
sfx_s3kae,
@ -653,7 +660,8 @@ typedef enum
sfx_s3kc5l,
sfx_s3kc6s,
sfx_s3kc6l,
sfx_s3kc7,
sfx_s3kc7s,
sfx_s3kc7l,
sfx_s3kc8s,
sfx_s3kc8l,
sfx_s3kc9s,

View file

@ -694,7 +694,7 @@ static void ST_drawTime(void)
else
{
// Counting down the hidetime?
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime <= (hidetime*TICRATE)))
if ((gametyperules & GTR_STARTCOUNTDOWN) && (stplyr->realtime <= (hidetime*TICRATE)))
{
tics = (hidetime*TICRATE - stplyr->realtime);
if (tics < 3*TICRATE)
@ -705,11 +705,11 @@ static void ST_drawTime(void)
else
{
// Hidetime finish!
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime < ((hidetime+1)*TICRATE)))
if ((gametyperules & GTR_STARTCOUNTDOWN) && (stplyr->realtime < ((hidetime+1)*TICRATE)))
ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime);
// Time limit?
if (gametype != GT_COOP && gametype != GT_RACE && gametype != GT_COMPETITION && cv_timelimit.value && timelimitintics > 0)
if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0)
{
if (timelimitintics > stplyr->realtime)
{
@ -723,7 +723,7 @@ static void ST_drawTime(void)
downwards = true;
}
// Post-hidetime normal.
else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
else if (gametyperules & GTR_STARTCOUNTDOWN)
tics = stplyr->realtime - hidetime*TICRATE;
// "Shadow! What are you doing? Hurry and get back here
// right now before the island blows up with you on it!"
@ -845,26 +845,49 @@ static void ST_drawLivesArea(void)
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, faceprefix[stplyr->skin], colormap);
}
// Lives number
// Metal Sonic recording
if (metalrecording)
{
if (((2*leveltime)/TICRATE) & 1)
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8,
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_REDMAP|V_HUDTRANS, "REC");
}
else if (G_GametypeUsesLives() || gametype == GT_RACE)
// Spectator
else if (stplyr->spectator)
v_colmap = V_GRAYMAP;
// Tag
else if (gametyperules & GTR_TAG)
{
// x
V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10,
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex);
// lives number
if (gametype == GT_RACE)
if (stplyr->pflags & PF_TAGIT)
{
livescount = INFLIVES;
notgreyedout = true;
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "IT!");
v_colmap = V_ORANGEMAP;
}
else if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3)
}
// Team name
else if (G_GametypeHasTeams())
{
if (stplyr->ctfteam == 1)
{
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED");
v_colmap = V_REDMAP;
}
else if (stplyr->ctfteam == 2)
{
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE");
v_colmap = V_BLUEMAP;
}
}
// Lives number
else
{
boolean candrawlives = true;
// Co-op and Competition, normal life counter
if (G_GametypeUsesLives())
{
// Handle cooplives here
if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 3)
{
INT32 i;
livescount = 0;
@ -891,10 +914,31 @@ static void ST_drawLivesArea(void)
}
else
{
livescount = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? INFLIVES : stplyr->lives);
livescount = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? INFLIVES : stplyr->lives);
notgreyedout = true;
}
}
// Infinity symbol (Race)
else if (G_PlatformGametype() && !(gametyperules & GTR_LIVES))
{
livescount = INFLIVES;
notgreyedout = true;
}
// Otherwise nothing, sorry.
// Special Stages keep not showing lives,
// as G_GametypeUsesLives() returns false in
// Special Stages, and the infinity symbol
// cannot show up because Special Stages
// still have the GTR_LIVES gametype rule
// by default.
else
candrawlives = false;
// Draw the lives counter here.
if (candrawlives)
{
// x
V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex);
if (livescount == INFLIVES)
V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8,
'\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false);
@ -908,37 +952,15 @@ static void ST_drawLivesArea(void)
hudinfo[HUD_LIVES].f|V_PERPLAYER|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount));
}
}
// Spectator
else if (stplyr->spectator)
v_colmap = V_GRAYMAP;
// Tag
else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
{
if (stplyr->pflags & PF_TAGIT)
{
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "IT!");
v_colmap = V_ORANGEMAP;
}
}
// Team name
else if (G_GametypeHasTeams())
{
if (stplyr->ctfteam == 1)
{
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED");
v_colmap = V_REDMAP;
}
else if (stplyr->ctfteam == 2)
{
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE");
v_colmap = V_BLUEMAP;
}
#undef ST_drawLivesX
}
// name
v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER);
if (strlen(skins[stplyr->skin].hudname) <= 5)
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname);
else if (V_StringWidth(skins[stplyr->skin].hudname, v_colmap) <= 48)
V_DrawString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname);
else if (V_ThinStringWidth(skins[stplyr->skin].hudname, v_colmap) <= 40)
V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname);
else
@ -1157,10 +1179,20 @@ static void ST_drawInput(void)
"AUTOBRAKE");
y -= 8;
}
if (stplyr->pflags & PF_ANALOGMODE)
switch (P_ControlStyle(stplyr))
{
case CS_LMAOGALOG:
V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "ANALOG");
y -= 8;
break;
case CS_SIMPLE:
V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "SIMPLE");
y -= 8;
break;
default:
break;
}
}
if (!demosynced) // should always be last, so it doesn't push anything else around
@ -1177,21 +1209,33 @@ tic_t lt_exitticker = 0, lt_endtime = 0;
//
// Load the graphics for the title card.
// Don't let LJ see this
//
static void ST_cacheLevelTitle(void)
{
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE))
{
lt_patches[0] = (patch_t *)W_CachePatchName("LTACTBLU", PU_HUDGFX);
lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGZAG", PU_HUDGFX);
lt_patches[2] = (patch_t *)W_CachePatchName("LTZZTEXT", PU_HUDGFX);
}
else // boss map
{
lt_patches[0] = (patch_t *)W_CachePatchName("LTACTRED", PU_HUDGFX);
lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGRED", PU_HUDGFX);
lt_patches[2] = (patch_t *)W_CachePatchName("LTZZWARN", PU_HUDGFX);
}
#define SETPATCH(default, warning, custom, idx) \
{ \
lumpnum_t patlumpnum = LUMPERROR; \
if (mapheaderinfo[gamemap-1]->custom[0] != '\0') \
{ \
patlumpnum = W_CheckNumForName(mapheaderinfo[gamemap-1]->custom); \
if (patlumpnum != LUMPERROR) \
lt_patches[idx] = (patch_t *)W_CachePatchNum(patlumpnum, PU_HUDGFX); \
} \
if (patlumpnum == LUMPERROR) \
{ \
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) \
lt_patches[idx] = (patch_t *)W_CachePatchName(default, PU_HUDGFX); \
else \
lt_patches[idx] = (patch_t *)W_CachePatchName(warning, PU_HUDGFX); \
} \
}
SETPATCH("LTACTBLU", "LTACTRED", ltactdiamond, 0)
SETPATCH("LTZIGZAG", "LTZIGRED", ltzzpatch, 1)
SETPATCH("LTZZTEXT", "LTZZWARN", ltzztext, 2)
#undef SETPATCH
}
//
@ -1216,6 +1260,9 @@ void ST_startTitleCard(void)
//
void ST_preDrawTitleCard(void)
{
if (!G_IsTitleCardAvailable())
return;
if (lt_ticker >= (lt_endtime + TICRATE))
return;
@ -1231,6 +1278,9 @@ void ST_preDrawTitleCard(void)
//
void ST_runTitleCard(void)
{
if (!G_IsTitleCardAvailable())
return;
if (lt_ticker >= (lt_endtime + TICRATE))
return;
@ -1284,6 +1334,9 @@ void ST_drawTitleCard(void)
INT32 zzticker;
patch_t *actpat, *zigzag, *zztext;
if (!G_IsTitleCardAvailable())
return;
#ifdef HAVE_BLUA
if (!LUA_HudEnabled(hud_stagetitle))
goto luahook;
@ -1762,7 +1815,7 @@ static void ST_drawNiGHTSHUD(void)
ST_drawNiGHTSLink();
}
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
{
ST_drawScore();
ST_drawTime();
@ -2155,7 +2208,7 @@ static void ST_drawTextHUD(void)
#define textHUDdraw(str) \
{\
V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, str);\
V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP, str);\
y += 8;\
}
@ -2181,7 +2234,7 @@ static void ST_drawTextHUD(void)
donef12 = true;
}
}
else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) // Death overrides spectator text.
else if ((gametyperules & GTR_RESPAWNDELAY) && stplyr->playerstate == PST_DEAD && stplyr->lives) // Death overrides spectator text.
{
INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE;
@ -2203,7 +2256,9 @@ static void ST_drawTextHUD(void)
if (G_IsSpecialStage(gamemap))
textHUDdraw(M_GetText("\x82""Wait for the stage to end..."))
else if (gametype == GT_COOP)
else if (G_PlatformGametype())
{
if (G_GametypeUsesCoopLives())
{
if (stplyr->lives <= 0
&& cv_cooplives.value == 2
@ -2230,7 +2285,8 @@ static void ST_drawTextHUD(void)
else
textHUDdraw(M_GetText("Wait to respawn..."))
}
else
}
else if (G_GametypeHasSpectators())
textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game"))
}
@ -2273,12 +2329,13 @@ static void ST_drawTextHUD(void)
}
}
}
else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator))
else if ((gametyperules & GTR_TAG) && (!stplyr->spectator))
{
if (leveltime < hidetime * TICRATE)
{
if (stplyr->pflags & PF_TAGIT)
{
if (gametyperules & GTR_BLINDFOLDED)
textHUDdraw(M_GetText("\x82""You are blindfolded!"))
textHUDdraw(M_GetText("Waiting for players to hide..."))
}
@ -2294,6 +2351,7 @@ static void ST_drawTextHUD(void)
textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view"))
donef12 = true;
}
if (gametyperules & GTR_HIDEFROZEN)
textHUDdraw(M_GetText("You cannot move while hiding."))
}
}
@ -2316,21 +2374,27 @@ static void ST_drawTeamHUD(void)
if (F_GetPromptHideHud(0)) // y base is 0
return;
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
p = bflagico;
else
p = bmatcico;
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
p = rflagico;
else
p = rmatcico;
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
goto num;
{
INT32 i;
@ -2339,28 +2403,53 @@ static void ST_drawTeamHUD(void)
// Show which flags aren't at base.
for (i = 0; i < MAXPLAYERS; i++)
{
if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base
if (players[i].gotflag & GF_BLUEFLAG // Blue flag isn't at base
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon);
if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base
if (players[i].gotflag & GF_REDFLAG // Red flag isn't at base
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2);
whichflag |= players[i].gotflag;
if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG))
break; // both flags were found, let's stop early
}
// Display a countdown timer showing how much time left until the flag returns to base.
{
if (blueflag && blueflag->fuse > 1)
if (blueflag && blueflag->fuse > 1
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (blueflag->fuse / TICRATE)));
if (redflag && redflag->fuse > 1)
if (redflag && redflag->fuse > 1
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE)));
}
}
num:
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore));
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore));
#undef SEP
@ -2580,7 +2669,7 @@ static void ST_overlayDrawer(void)
INT32 i = MAXPLAYERS;
INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1));
if ((gametype == GT_COOP)
if (G_GametypeUsesCoopLives()
&& (netgame || multiplayer)
&& (cv_cooplives.value != 1))
{
@ -2633,7 +2722,7 @@ static void ST_overlayDrawer(void)
}
// If you are in overtime, put a big honkin' flashin' message on the screen.
if (G_RingSlingerGametype() && cv_overtime.value
if (((gametyperules & GTR_TIMELIMIT) && (gametyperules & GTR_OVERTIME)) && cv_overtime.value
&& (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0))
V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_PERPLAYER, M_GetText("OVERTIME!"));
@ -2648,7 +2737,7 @@ static void ST_overlayDrawer(void)
ST_drawMatchHUD();
// Race HUD Stuff
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
ST_drawRaceHUD();
// Emerald Hunt Indicators
@ -2756,7 +2845,7 @@ void ST_Drawer(void)
if (rendermode != render_none) ST_doPaletteStuff();
// Blindfold!
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
if ((gametyperules & GTR_BLINDFOLDED)
&& (leveltime < hidetime * TICRATE))
{
if (players[displayplayer].pflags & PF_TAGIT)

View file

@ -1465,6 +1465,21 @@ boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr)
return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr);
}
void W_FlushCachedPatches(void)
{
if (needpatchflush)
{
Z_FreeTag(PU_CACHE);
Z_FreeTag(PU_PATCH);
Z_FreeTag(PU_HUDGFX);
Z_FreeTag(PU_HWRPATCHINFO);
Z_FreeTag(PU_HWRMODELTEXTURE);
Z_FreeTag(PU_HWRCACHE);
Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRPATCHINFO_UNLOCKED);
}
needpatchflush = false;
}
// ==========================================================================
// W_CacheLumpName
// ==========================================================================
@ -1488,22 +1503,6 @@ void *W_CacheLumpName(const char *name, INT32 tag)
// Cache a patch into heap memory, convert the patch format as necessary
//
void W_FlushCachedPatches(void)
{
if (needpatchflush)
{
Z_FreeTag(PU_CACHE);
Z_FreeTag(PU_PATCH);
Z_FreeTag(PU_HUDGFX);
Z_FreeTag(PU_HWRPATCHINFO);
Z_FreeTag(PU_HWRMODELTEXTURE);
Z_FreeTag(PU_HWRCACHE);
Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRPATCHINFO_UNLOCKED);
}
needpatchflush = false;
}
// Software-only compile cache the data without conversion
void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
#ifdef HWRENDER
@ -1541,7 +1540,7 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
if (R_IsLumpPNG((UINT8 *)lumpdata, len))
{
size_t newlen;
srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen, true);
srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen);
ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]);
M_Memcpy(ptr, srcdata, newlen);
Z_Free(srcdata);
@ -1891,3 +1890,101 @@ int W_VerifyNMUSlumps(const char *filename)
};
return W_VerifyFile(filename, NMUSlist, false);
}
/** \brief Generates a virtual resource used for level data loading.
*
* \param lumpnum_t reference
* \return Virtual resource
*
*/
virtres_t* vres_GetMap(lumpnum_t lumpnum)
{
UINT32 i;
virtres_t* vres = NULL;
virtlump_t* vlumps = NULL;
size_t numlumps = 0;
if (W_IsLumpWad(lumpnum))
{
// Remember that we're assuming that the WAD will have a specific set of lumps in a specific order.
UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
numlumps = ((wadinfo_t *)wadData)->numlumps;
vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
// Build the lumps.
for (i = 0; i < numlumps; i++)
{
vlumps[i].size = (size_t)(((filelump_t *)(fileinfo + i))->size);
// Play it safe with the name in this case.
memcpy(vlumps[i].name, (fileinfo + i)->name, 8);
vlumps[i].name[8] = '\0';
vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that.
memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size);
}
Z_Free(wadData);
}
else
{
// Count number of lumps until the end of resource OR up until next "MAPXX" lump.
lumpnum_t lumppos = lumpnum + 1;
for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++)
if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0)
break;
numlumps++;
vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
for (i = 0; i < numlumps; i++, lumpnum++)
{
vlumps[i].size = W_LumpLength(lumpnum);
memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8);
vlumps[i].name[8] = '\0';
vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL);
}
}
vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL);
vres->vlumps = vlumps;
vres->numlumps = numlumps;
return vres;
}
/** \brief Frees zone memory for a given virtual resource.
*
* \param Virtual resource
*/
void vres_Free(virtres_t* vres)
{
while (vres->numlumps--)
Z_Free(vres->vlumps[vres->numlumps].data);
Z_Free(vres->vlumps);
Z_Free(vres);
}
/** (Debug) Prints lumps from a virtual resource into console.
*/
/*
static void vres_Diag(const virtres_t* vres)
{
UINT32 i;
for (i = 0; i < vres->numlumps; i++)
CONS_Printf("%s\n", vres->vlumps[i].name);
}
*/
/** \brief Finds a lump in a given virtual resource.
*
* \param Virtual resource
* \param Lump name to look for
* \return Virtual lump if found, NULL otherwise
*
*/
virtlump_t* vres_Find(const virtres_t* vres, const char* name)
{
UINT32 i;
for (i = 0; i < vres->numlumps; i++)
if (fastcmp(name, vres->vlumps[i].name))
return &vres->vlumps[i];
return NULL;
}

View file

@ -72,6 +72,25 @@ typedef struct
compmethod compression; // lump compression method
} lumpinfo_t;
// =========================================================================
// 'VIRTUAL' RESOURCES
// =========================================================================
typedef struct {
char name[9];
UINT8* data;
size_t size;
} virtlump_t;
typedef struct {
size_t numlumps;
virtlump_t* vlumps;
} virtres_t;
virtres_t* vres_GetMap(lumpnum_t);
void vres_Free(virtres_t*);
virtlump_t* vres_Find(const virtres_t*, const char*);
// =========================================================================
// DYNAMIC WAD LOADING
// =========================================================================

View file

@ -37,6 +37,10 @@
#include "m_cond.h" // condition sets
#include "lua_hook.h" // IntermissionThinker hook
#ifdef HAVE_BLUA
#include "lua_hud.h"
#endif
#ifdef HWRENDER
#include "hardware/hw_main.h"
#endif
@ -165,6 +169,7 @@ static INT32 tallydonetic = -1;
static INT32 endtic = -1;
intertype_t intertype = int_none;
intertype_t intermissiontypes[NUMGAMETYPES];
static void Y_RescaleScreenBuffer(void);
static void Y_AwardCoopBonuses(void);
@ -320,9 +325,18 @@ void Y_IntermissionDrawer(void)
// Bonus loops
INT32 i;
if (intertype == int_none || rendermode == render_none)
if (rendermode == render_none)
return;
if (intertype == int_none)
{
#ifdef HAVE_BLUA
LUAh_IntermissionHUD();
#endif
return;
}
if (!usebuffer)
// Lactozilla: Renderer switching
if (needpatchrecache)
{
@ -370,6 +384,12 @@ void Y_IntermissionDrawer(void)
else
V_DrawPatchFill(bgtile);
#ifdef HAVE_BLUA
LUAh_IntermissionHUD();
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;
#endif
dontdrawbg:
if (intertype == int_coop)
{
@ -924,6 +944,12 @@ dontdrawbg:
}
}
#ifdef HAVE_BLUA
skiptallydrawer:
if (!LUA_HudEnabled(hud_intermissionmessages))
return;
#endif
if (timer)
V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP,
va("start in %d seconds", timer/TICRATE));
@ -1206,7 +1232,9 @@ void Y_StartIntermission(void)
timer = 1;
}
if (gametype == GT_COOP)
if (intermissiontypes[gametype] != int_none)
intertype = intermissiontypes[gametype];
else if (gametype == GT_COOP)
intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop;
else if (gametype == GT_TEAMMATCH)
intertype = int_teammatch;
@ -1969,7 +1997,7 @@ static void Y_AwardCoopBonuses(void)
if (i == consoleplayer)
{
data.coop.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives);
data.coop.gotlife = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? 0 : ptlives);
M_Memcpy(&data.coop.bonuses, &localbonuses, sizeof(data.coop.bonuses));
}
}
@ -2024,7 +2052,7 @@ static void Y_AwardSpecialStageBonus(void)
if (i == consoleplayer)
{
data.spec.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives);
data.spec.gotlife = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? 0 : ptlives);
M_Memcpy(&data.spec.bonuses, &localbonuses, sizeof(data.spec.bonuses));
// Continues related

View file

@ -31,3 +31,4 @@ typedef enum
int_comp, // Competition
} intertype_t;
extern intertype_t intertype;
extern intertype_t intermissiontypes[NUMGAMETYPES];