Merge remote-tracking branch 'origin/next' into respawndelaygametyperule

This commit is contained in:
Jaime Passos 2019-12-28 21:39:38 -03:00
commit e63f77ea1a
31 changed files with 7826 additions and 6914 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

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

@ -1462,7 +1462,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

@ -127,7 +127,7 @@
#ifdef LOGMESSAGES
extern FILE *logstream;
extern char logfilename[1024];
extern char logfilename[1024];
#endif
//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3

View File

@ -1847,7 +1847,7 @@ void G_DoLoadLevel(boolean resetplayer)
}
// Setup the level.
if (!P_SetupLevel(false)) // this never returns false?
if (!P_LoadLevel(false)) // this never returns false?
{
// fail so reset game stuff
Command_ExitGame_f();

View File

@ -5501,17 +5501,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
@ -5618,11 +5613,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lumpoff].topoffset;
#ifdef ROTSPRITE
if (rollangle > 0)
if (thing->rollangle)
{
rollangle = R_GetRollAngle(thing->rollangle);
if (!sprframe->rotsprite.cached[rot])
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rollangle /= ROTANGDIFF;
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)
{

View File

@ -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
},

View File

@ -2466,3 +2466,92 @@ const char *M_FileError(FILE *fp)
else
return "end-of-file";
}
/** Return the number of parts of this path.
*/
int M_PathParts(const char *path)
{
int n;
const char *p;
const char *t;
for (n = 0, p = path ;; ++n)
{
t = p;
if (( p = strchr(p, PATHSEP[0]) ))
p += strspn(p, PATHSEP);
else
{
if (*t)/* there is something after the final delimiter */
n++;
break;
}
}
return n;
}
/** Check whether a path is an absolute path.
*/
boolean M_IsPathAbsolute(const char *path)
{
#ifdef _WIN32
return ( strncmp(&path[1], ":\\", 2) == 0 );
#else
return ( path[0] == '/' );
#endif
}
/** I_mkdir for each part of the path.
*/
void M_MkdirEachUntil(const char *cpath, int start, int end, int mode)
{
char path[MAX_WADPATH];
char *p;
char *t;
if (end > 0 && end <= start)
return;
strlcpy(path, cpath, sizeof path);
#ifdef _WIN32
if (strncmp(&path[1], ":\\", 2) == 0)
p = &path[3];
else
#endif
p = path;
if (end > 0)
end -= start;
for (; start > 0; --start)
{
p += strspn(p, PATHSEP);
if (!( p = strchr(p, PATHSEP[0]) ))
return;
}
p += strspn(p, PATHSEP);
for (;;)
{
if (end > 0 && !--end)
break;
t = p;
if (( p = strchr(p, PATHSEP[0]) ))
{
*p = '\0';
I_mkdir(path, mode);
*p = PATHSEP[0];
p += strspn(p, PATHSEP);
}
else
{
if (*t)
I_mkdir(path, mode);
break;
}
}
}
void M_MkdirEach(const char *path, int start, int mode)
{
M_MkdirEachUntil(path, start, -1, mode);
}

View File

@ -96,6 +96,11 @@ void M_SetupMemcpy(void);
const char *M_FileError(FILE *handle);
int M_PathParts (const char *path);
boolean M_IsPathAbsolute (const char *path);
void M_MkdirEach (const char *path, int start, int mode);
void M_MkdirEachUntil (const char *path, int start, int end, int mode);
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);

View File

@ -2261,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;

View File

@ -2962,7 +2962,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
Graue 12-22-2003 */
}
static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
static void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
{
player_t *player = target->player;
tic_t oldnightstime = player->nightstime;
@ -3026,7 +3026,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
}
}
static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
static boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{
player_t *player = target->player;
(void)damage; //unused parm
@ -3130,7 +3130,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
return true;
}
static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{
player_t *player = target->player;

View File

@ -9434,7 +9434,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
SINT8 sign = ((mobj->tics & 1) ? mobj->tics : -(SINT8)(mobj->tics));
while (chain)
{
chain->z = chain->watertop + sign*mobj->scale;
chain->z = chain->movefactor + sign*mobj->scale;
sign = -sign;
chain = chain->target;
}

View File

@ -4064,7 +4064,7 @@ static inline boolean P_NetUnArchiveMisc(void)
tokenlist = READUINT32(save_p);
if (!P_SetupLevel(true))
if (!P_LoadLevel(true))
return false;
// get the time

View File

@ -664,6 +664,7 @@ static void P_LoadRawSectors(UINT8 *data)
ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats);
ss->lightlevel = SHORT(ms->lightlevel);
ss->spawn_lightlevel = ss->lightlevel;
ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag);
ss->nexttag = ss->firsttag = -1;
@ -970,7 +971,7 @@ static void P_SpawnEmeraldHunt(void)
mobjinfo[MT_EMERHUNT].spawnstate+2);
}
static void P_LoadThings(boolean loademblems)
static void P_SpawnMapThings(boolean spawnemblems)
{
size_t i;
mapthing_t *mt;
@ -1000,7 +1001,7 @@ static void P_LoadThings(boolean loademblems)
|| mt->type == 1702) // MT_AXISTRANSFERLINE
continue; // These were already spawned
if (!loademblems && mt->type == mobjinfo[MT_EMBLEM].doomednum)
if (!spawnemblems && mt->type == mobjinfo[MT_EMBLEM].doomednum)
continue;
mt->mobj = NULL;
@ -2015,6 +2016,75 @@ static void P_LoadMapData(const virtres_t* virt)
memcpy(spawnsides, sides, numsides * sizeof (*sides));
}
/** Compute MD5 message digest for bytes read from memory source
*
* The resulting message digest number will be written into the 16 bytes
* beginning at RESBLOCK.
*
* \param filename path of file
* \param resblock resulting MD5 checksum
* \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found
*/
static INT32 P_MakeBufferMD5(const char* buffer, size_t len, void* resblock)
{
#ifdef NOMD5
(void)buffer;
(void)len;
memset(resblock, 0x00, 16);
return 1;
#else
tic_t t = I_GetTime();
CONS_Debug(DBG_SETUP, "Making MD5\n");
if (md5_buffer(buffer, len, resblock) == NULL)
return 1;
CONS_Debug(DBG_SETUP, "MD5 calc took %f seconds\n", (float)(I_GetTime() - t)/NEWTICRATE);
return 0;
#endif
}
static void P_MakeMapMD5(virtres_t* virt, void* dest)
{
unsigned char linemd5[16];
unsigned char sectormd5[16];
unsigned char thingmd5[16];
unsigned char sidedefmd5[16];
unsigned char resmd5[16];
UINT8 i;
// Create a hash for the current map
// get the actual lumps!
virtlump_t *virtlines = vres_Find(virt, "LINEDEFS");
virtlump_t *virtsectors = vres_Find(virt, "SECTORS");
virtlump_t *virtmthings = vres_Find(virt, "THINGS");
virtlump_t *virtsides = vres_Find(virt, "SIDEDEFS");
P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5);
P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5);
P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5);
P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5);
for (i = 0; i < 16; i++)
resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF;
M_Memcpy(dest, &resmd5, 16);
}
static void P_LoadMapFromFile(void)
{
virtres_t *virt = vres_GetMap(lastloadedmaplumpnum);
P_LoadMapData(virt);
P_LoadMapBSP(virt);
P_LoadMapLUT(virt);
P_LoadLineDefs2();
P_GroupLines();
P_MakeMapMD5(virt, &mapmd5);
vres_Free(virt);
}
#if 0
static char *levellumps[] =
{
@ -2083,7 +2153,7 @@ lumpnum_t lastloadedmaplumpnum; // for comparative savegame
//
// Some player initialization for map start.
//
static void P_LevelInitStuff(void)
static void P_InitLevelSettings(void)
{
INT32 i;
boolean canresetlives = true;
@ -2208,68 +2278,15 @@ void P_LoadThingsOnly(void)
P_RemoveMobj((mobj_t *)think);
}
P_LevelInitStuff();
P_InitLevelSettings();
P_LoadThings(true);
P_SpawnMapThings(true);
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0];
skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
}
/** Compute MD5 message digest for bytes read from memory source
*
* The resulting message digest number will be written into the 16 bytes
* beginning at RESBLOCK.
*
* \param filename path of file
* \param resblock resulting MD5 checksum
* \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found
*/
static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock)
{
#ifdef NOMD5
(void)buffer;
(void)len;
memset(resblock, 0x00, 16);
return 1;
#else
tic_t t = I_GetTime();
CONS_Debug(DBG_SETUP, "Making MD5\n");
if (md5_buffer(buffer, len, resblock) == NULL)
return 1;
CONS_Debug(DBG_SETUP, "MD5 calc took %f seconds\n", (float)(I_GetTime() - t)/NEWTICRATE);
return 0;
#endif
}
static void P_MakeMapMD5(virtres_t* virt, void *dest)
{
unsigned char linemd5[16];
unsigned char sectormd5[16];
unsigned char thingmd5[16];
unsigned char sidedefmd5[16];
unsigned char resmd5[16];
UINT8 i;
// Create a hash for the current map
// get the actual lumps!
virtlump_t* virtlines = vres_Find(virt, "LINEDEFS");
virtlump_t* virtsectors = vres_Find(virt, "SECTORS");
virtlump_t* virtmthings = vres_Find(virt, "THINGS");
virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS");
P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5);
P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5);
P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5);
P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5);
for (i = 0; i < 16; i++)
resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF;
M_Memcpy(dest, &resmd5, 16);
}
static void P_RunLevelScript(const char *scriptname)
{
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SCRIPTISFILE))
@ -2334,6 +2351,26 @@ static void P_ForceCharacter(const char *forcecharskin)
}
}
static void P_ResetSpawnpoints(void)
{
UINT8 i;
numdmstarts = numredctfstarts = numbluectfstarts = 0;
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
}
static void P_LoadRecordGhosts(void)
{
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
@ -2433,6 +2470,45 @@ static void P_LoadNightsGhosts(void)
free(gpath);
}
static void P_InitTagGametype(void)
{
UINT8 i;
INT32 realnumplayers = 0;
INT32 playersactive[MAXPLAYERS];
//I just realized how problematic this code can be.
//D_NumPlayers() will not always cover the scope of the netgame.
//What if one player is node 0 and the other node 31?
//The solution? Make a temp array of all players that are currently playing and pick from them.
//Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended?
//Also, you'd never have to loop through all 32 players slots to find anything ever again.
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
{
playersactive[realnumplayers] = i; //stores the player's node in the array.
realnumplayers++;
}
}
if (!realnumplayers) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked.
{
CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n"));
return;
}
i = P_RandomKey(realnumplayers);
players[playersactive[i]].pflags |= PF_TAGIT; //choose our initial tagger before map starts.
// Taken and modified from G_DoReborn()
// Remove the player so he can respawn elsewhere.
// first disassociate the corpse
if (players[playersactive[i]].mo)
P_RemoveMobj(players[playersactive[i]].mo);
G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location.
}
static void P_SetupCamera(void)
{
if (players[displayplayer].mo && (server || addedtogame))
@ -2463,6 +2539,52 @@ static void P_SetupCamera(void)
}
}
static void P_InitCamera(void)
{
if (!dedicated)
{
P_SetupCamera();
// Salt: CV_ClearChangedFlags() messes with your settings :(
/*if (!cv_cam_height.changed)
CV_Set(&cv_cam_height, cv_cam_height.defaultvalue);
if (!cv_cam2_height.changed)
CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue);
if (!cv_cam_dist.changed)
CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue);
if (!cv_cam2_dist.changed)
CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/
// Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P
if (!cv_cam_rotate.changed)
CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue);
if (!cv_cam2_rotate.changed)
CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue);
if (!cv_analog.changed)
CV_SetValue(&cv_analog, 0);
if (!cv_analog2.changed)
CV_SetValue(&cv_analog2, 0);
displayplayer = consoleplayer; // Start with your OWN view, please!
}
if (twodlevel)
{
CV_SetValue(&cv_analog, false);
CV_SetValue(&cv_analog2, false);
}
else
{
if (cv_useranalog.value)
CV_SetValue(&cv_analog, true);
if ((splitscreen && cv_useranalog2.value) || botingame)
CV_SetValue(&cv_analog2, true);
}
}
static boolean CanSaveLevel(INT32 mapnum)
{
if (ultimatemode) // never save in ultimate (probably redundant with cursaveslot also being checked)
@ -2478,21 +2600,187 @@ static boolean CanSaveLevel(INT32 mapnum)
return (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME || gamecomplete || !lastmaploaded);
}
static void P_RunSpecialStageWipe(void)
{
tic_t starttime = I_GetTime();
tic_t endtime = starttime + (3*TICRATE)/2;
tic_t nowtime;
S_StartSound(NULL, sfx_s3kaf);
// Fade music! Time it to S3KAF: 0.25 seconds is snappy.
if (RESETMUSIC ||
strnicmp(S_MusicName(),
(mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap - 1]->musname : mapmusname, 7))
S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)
F_WipeStartScreen();
wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE);
#ifdef HWRENDER
// uh..........
if (rendermode == render_opengl)
F_WipeColorFill(0);
#endif
F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_speclevel_towhite], false);
I_OsPolling();
I_FinishUpdate(); // page flip or blit buffer
if (moviemode)
M_SaveFrame();
nowtime = lastwipetic;
// Hold on white for extra effect.
while (nowtime < endtime)
{
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
lastwipetic = nowtime;
if (moviemode) // make sure we save frames for the white hold too
M_SaveFrame();
}
}
static void P_RunLevelWipe(void)
{
F_WipeStartScreen();
wipestyleflags |= WSF_FADEOUT;
#ifdef HWRENDER
// uh..........
if (rendermode == render_opengl)
F_WipeColorFill(31);
#endif
F_WipeEndScreen();
// for titlemap: run a specific wipe if specified
// needed for exiting time attack
if (wipetypepre != INT16_MAX)
F_RunWipe(
(wipetypepre >= 0 && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack],
false);
wipetypepre = -1;
}
static void P_InitPlayers(void)
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
// Start players with pity shields if possible
players[i].pity = -1;
players[i].mo = NULL;
if (!G_PlatformGametype())
G_DoReborn(i);
else // gametype is GT_COOP or GT_RACE
{
G_SpawnPlayer(i, players[i].starposttime);
if (players[i].starposttime)
P_ClearStarPost(players[i].starpostnum);
}
}
}
static void P_WriteLetter(void)
{
char *buf, *b;
if (!unlockables[27].unlocked) // pandora's box
return;
if (modeattacking)
return;
#ifndef DEVELOP
if (modifiedgame)
return;
#endif
if (netgame || multiplayer)
return;
if (gamemap != 0x1d35 - 016464)
return;
P_SpawnMobj(0640370000, 0x11000000, 0x3180000, MT_LETTER)->angle = ANGLE_90;
if (textprompts[199]->page[1].backcolor == 259)
return;
buf = W_CacheLumpName("WATERMAP", PU_STATIC);
b = buf;
while ((*b != 65) && (b - buf < 256))
{
*b = (*b - 65) & 255;
b++;
}
*b = '\0';
Z_Free(textprompts[199]->page[1].text);
textprompts[199]->page[1].text = Z_StrDup(buf);
textprompts[199]->page[1].lines = 4;
textprompts[199]->page[1].backcolor = 259;
Z_Free(buf);
}
static void P_InitGametype(void)
{
UINT8 i;
P_InitPlayers();
// restore time in netgame (see also g_game.c)
if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2)
{
// is this a hack? maybe
tic_t maxstarposttime = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].starposttime > maxstarposttime)
maxstarposttime = players[i].starposttime;
}
leveltime = maxstarposttime;
}
P_WriteLetter();
if (modeattacking == ATTACKING_RECORD && !demoplayback)
P_LoadRecordGhosts();
else if (modeattacking == ATTACKING_NIGHTS && !demoplayback)
P_LoadNightsGhosts();
if (G_TagGametype())
P_InitTagGametype();
else if (gametype == GT_RACE && server)
CV_StealthSetValue(&cv_numlaps,
(cv_basenumlaps.value)
? cv_basenumlaps.value
: mapheaderinfo[gamemap - 1]->numlaps);
}
/** Loads a level from a lump or external wad.
*
* \param skipprecip If true, don't spawn precipitation.
* \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot.
* \todo Clean up, refactor, split up; get rid of the bloat.
*/
boolean P_SetupLevel(boolean skipprecip)
boolean P_LoadLevel(boolean fromnetsave)
{
// use gamemap to get map number.
// 99% of the things already did, so.
// Map header should always be in place at this point
INT32 i, loadprecip = 1, ranspecialwipe = 0;
INT32 loademblems = 1;
INT32 fromnetsave = 0;
INT32 i, ranspecialwipe = 0;
sector_t *ss;
boolean chase;
levelloading = true;
// This is needed. Don't touch.
@ -2523,19 +2811,18 @@ boolean P_SetupLevel(boolean skipprecip)
if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#')
P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname);
P_LevelInitStuff();
P_InitLevelSettings();
postimgtype = postimgtype2 = postimg_none;
if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0')
P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter);
// chasecam on in chaos, race, coop
// chasecam off in match, tag, capture the flag
chase = (!(gametyperules & GTR_FIRSTPERSON)) || (maptol & TOL_2D);
if (!dedicated)
{
// chasecam on in first-person gametypes and 2D
boolean chase = (!(gametyperules & GTR_FIRSTPERSON)) || (maptol & TOL_2D);
// Salt: CV_ClearChangedFlags() messes with your settings :(
/*if (!cv_cam_speed.changed)
CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue);*/
@ -2562,48 +2849,7 @@ boolean P_SetupLevel(boolean skipprecip)
ranspecialwipe = 2;
else if (rendermode != render_none && G_IsSpecialStage(gamemap))
{
tic_t starttime = I_GetTime();
tic_t endtime = starttime + (3*TICRATE)/2;
tic_t nowtime;
S_StartSound(NULL, sfx_s3kaf);
// Fade music! Time it to S3KAF: 0.25 seconds is snappy.
if (RESETMUSIC ||
strnicmp(S_MusicName(),
(mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))
S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)
F_WipeStartScreen();
wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE);
#ifdef HWRENDER
// uh..........
if (rendermode == render_opengl)
F_WipeColorFill(0);
#endif
F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_speclevel_towhite], false);
I_OsPolling();
I_FinishUpdate(); // page flip or blit buffer
if (moviemode)
M_SaveFrame();
nowtime = lastwipetic;
// Hold on white for extra effect.
while (nowtime < endtime)
{
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
lastwipetic = nowtime;
if (moviemode) // make sure we save frames for the white hold too
M_SaveFrame();
}
P_RunSpecialStageWipe();
ranspecialwipe = 1;
}
@ -2629,25 +2875,7 @@ boolean P_SetupLevel(boolean skipprecip)
// Let's fade to black here
// But only if we didn't do the special stage wipe
if (rendermode != render_none && !ranspecialwipe)
{
F_WipeStartScreen();
wipestyleflags |= WSF_FADEOUT;
#ifdef HWRENDER
// uh..........
if (rendermode == render_opengl)
F_WipeColorFill(31);
#endif
F_WipeEndScreen();
// for titlemap: run a specific wipe if specified
// needed for exiting time attack
if (wipetypepre != INT16_MAX)
F_RunWipe(
(wipetypepre >= 0 && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack],
false);
wipetypepre = -1;
}
P_RunLevelWipe();
if (!titlemapinaction)
{
@ -2705,14 +2933,7 @@ boolean P_SetupLevel(boolean skipprecip)
P_InitThinkers();
P_InitCachedActions();
/// \note for not spawning precipitation, etc. when loading netgame snapshots
if (skipprecip)
{
fromnetsave = 1;
loadprecip = 0;
loademblems = 0;
}
else if (savedata.lives > 0)
if (!fromnetsave && savedata.lives > 0)
{
numgameovers = savedata.numgameovers;
players[consoleplayer].continues = savedata.continues;
@ -2726,9 +2947,7 @@ boolean P_SetupLevel(boolean skipprecip)
// internal game map
maplumpname = G_BuildMapName(gamemap);
//lastloadedmaplumpnum = LUMPERROR;
lastloadedmaplumpnum = W_CheckNumForName(maplumpname);
if (lastloadedmaplumpnum == INT16_MAX)
I_Error("Map %s not found.\n", maplumpname);
@ -2738,38 +2957,12 @@ boolean P_SetupLevel(boolean skipprecip)
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
numdmstarts = numredctfstarts = numbluectfstarts = 0;
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
P_ResetSpawnpoints();
P_MapStart();
if (lastloadedmaplumpnum)
{
virtres_t* virt = vres_GetMap(lastloadedmaplumpnum);
P_LoadMapData(virt);
P_LoadMapBSP(virt);
P_LoadMapLUT(virt);
P_LoadLineDefs2();
P_GroupLines();
P_MakeMapMD5(virt, &mapmd5);
vres_Free(virt);
}
P_LoadMapFromFile();
// init gravity, tag lists,
// anything that P_ResetDynamicSlopes/P_LoadThings needs to know
@ -2779,7 +2972,7 @@ boolean P_SetupLevel(boolean skipprecip)
P_ResetDynamicSlopes(fromnetsave);
#endif
P_LoadThings(loademblems);
P_SpawnMapThings(!fromnetsave);
skyboxmo[0] = skyboxviewpnts[0];
skyboxmo[1] = skyboxcenterpnts[0];
@ -2790,7 +2983,7 @@ boolean P_SetupLevel(boolean skipprecip)
// set up world state
P_SpawnSpecials(fromnetsave);
if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
if (!fromnetsave) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
P_SpawnPrecipitation();
#ifdef HWRENDER // not win32 only 19990829 by Kin
@ -2818,161 +3011,10 @@ boolean P_SetupLevel(boolean skipprecip)
// none of this needs to be done because it's not the beginning of the map when
// a netgame save is being loaded, and could actively be harmful by messing with
// the client's view of the data.)
if (fromnetsave)
goto netgameskip;
// ==========
if (!fromnetsave)
P_InitGametype();
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
// Start players with pity shields if possible
players[i].pity = -1;
if (!G_PlatformGametype())
{
players[i].mo = NULL;
G_DoReborn(i);
}
else // gametype is GT_COOP or GT_RACE
{
players[i].mo = NULL;
if (players[i].starposttime)
{
G_SpawnPlayer(i, true);
P_ClearStarPost(players[i].starpostnum);
}
else
G_SpawnPlayer(i, false);
}
}
// restore time in netgame (see also g_game.c)
if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2)
{
// is this a hack? maybe
tic_t maxstarposttime = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].starposttime > maxstarposttime)
maxstarposttime = players[i].starposttime;
}
leveltime = maxstarposttime;
}
if (unlockables[27].unlocked && !modeattacking // pandora's box
#ifndef DEVELOP
&& !modifiedgame
#endif
&& !(netgame || multiplayer) && gamemap == 0x1d35-016464)
{
P_SpawnMobj(0640370000, 0x11000000, 0x3180000, MT_LETTER)->angle = ANGLE_90;
if (textprompts[199]->page[1].backcolor != 259)
{
char *buf = W_CacheLumpName("WATERMAP", PU_STATIC), *b = buf;
while ((*b != 65) && (b-buf < 256)) { *b = (*b - 65)&255; b++; } *b = '\0';
Z_Free(textprompts[199]->page[1].text);
textprompts[199]->page[1].text = Z_StrDup(buf);
textprompts[199]->page[1].lines = 4;
textprompts[199]->page[1].backcolor = 259;
Z_Free(buf);
}
}
if (modeattacking == ATTACKING_RECORD && !demoplayback)
P_LoadRecordGhosts();
else if (modeattacking == ATTACKING_NIGHTS && !demoplayback)
P_LoadNightsGhosts();
if (G_TagGametype())
{
INT32 realnumplayers = 0;
INT32 playersactive[MAXPLAYERS];
//I just realized how problematic this code can be.
//D_NumPlayers() will not always cover the scope of the netgame.
//What if one player is node 0 and the other node 31?
//The solution? Make a temp array of all players that are currently playing and pick from them.
//Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended?
//Also, you'd never have to loop through all 32 players slots to find anything ever again.
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
{
playersactive[realnumplayers] = i; //stores the player's node in the array.
realnumplayers++;
}
}
if (realnumplayers) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked.
{
i = P_RandomKey(realnumplayers);
players[playersactive[i]].pflags |= PF_TAGIT; //choose our initial tagger before map starts.
// Taken and modified from G_DoReborn()
// Remove the player so he can respawn elsewhere.
// first dissasociate the corpse
if (players[playersactive[i]].mo)
P_RemoveMobj(players[playersactive[i]].mo);
G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location.
}
else
CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n"));
}
else if (gametype == GT_RACE && server)
CV_StealthSetValue(&cv_numlaps,
(cv_basenumlaps.value)
? cv_basenumlaps.value
: mapheaderinfo[gamemap - 1]->numlaps);
// ===========
// landing point for netgames.
netgameskip:
if (!dedicated)
{
P_SetupCamera();
// Salt: CV_ClearChangedFlags() messes with your settings :(
/*if (!cv_cam_height.changed)
CV_Set(&cv_cam_height, cv_cam_height.defaultvalue);
if (!cv_cam2_height.changed)
CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue);
if (!cv_cam_dist.changed)
CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue);
if (!cv_cam2_dist.changed)
CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/
// Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P
if (!cv_cam_rotate.changed)
CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue);
if (!cv_cam2_rotate.changed)
CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue);
if (!cv_analog.changed)
CV_SetValue(&cv_analog, 0);
if (!cv_analog2.changed)
CV_SetValue(&cv_analog2, 0);
displayplayer = consoleplayer; // Start with your OWN view, please!
}
if (cv_useranalog.value)
CV_SetValue(&cv_analog, true);
if (splitscreen && cv_useranalog2.value)
CV_SetValue(&cv_analog2, true);
else if (botingame)
CV_SetValue(&cv_analog2, true);
if (twodlevel)
{
CV_SetValue(&cv_analog2, false);
CV_SetValue(&cv_analog, false);
}
P_InitCamera();
// clear special respawning que
iquehead = iquetail = 0;
@ -3007,7 +3049,7 @@ boolean P_SetupLevel(boolean skipprecip)
lastmaploaded = gamemap; // HAS to be set after saving!!
if (loadprecip) // uglier hack
if (!fromnetsave) // uglier hack
{ // to make a newly loaded level start on the second frame.
INT32 buf = gametic % BACKUPTICS;
for (i = 0; i < MAXPLAYERS; i++)

View File

@ -97,7 +97,7 @@ void P_SetupLevelSky(INT32 skynum, boolean global);
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_LoadThingsOnly(void);
boolean P_SetupLevel(boolean skipprecip);
boolean P_LoadLevel(boolean fromnetsave);
boolean P_AddWadFile(const char *wadfilename);
boolean P_RunSOC(const char *socfilename);
void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);

View File

@ -553,11 +553,8 @@ pslope_t *P_SlopeById(UINT16 id)
}
/// Reset slopes and read them from special lines.
void P_ResetDynamicSlopes(const UINT32 fromsave) {
void P_ResetDynamicSlopes(const boolean fromsave) {
size_t i;
boolean spawnthinkers = !(boolean)fromsave;
slopelist = NULL;
slopecount = 0;
@ -574,14 +571,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_SpawnViaVertexes(i, !fromsave);
break;
default:

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_ResetDynamicSlopes(const boolean fromsave);
//
// P_CopySectorSlope

View File

@ -6426,7 +6426,7 @@ 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;

View File

@ -35,7 +35,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

@ -49,8 +49,6 @@
#endif
static unsigned char imgbuf[1<<26];
fixed_t cosang2rad[ROTANGLES];
fixed_t sinang2rad[ROTANGLES];
//
// R_CheckIfPatch
@ -1123,6 +1121,24 @@ static UINT16 GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip)
}
#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
//
@ -1180,12 +1196,12 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
leftoffset = width - leftoffset;
}
for (angle = 0; angle < ROTANGLES; angle++)
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.
{

View File

@ -62,11 +62,12 @@ 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 cosang2rad[ROTANGLES];
extern fixed_t sinang2rad[ROTANGLES];
extern fixed_t rollcosang[ROTANGLES];
extern fixed_t rollsinang[ROTANGLES];
#endif
#endif // __R_PATCH__

View File

@ -500,7 +500,7 @@ void R_InitSprites(void)
{
size_t i;
#ifdef ROTSPRITE
INT32 angle, ra;
INT32 angle;
float fa;
#endif
@ -508,14 +508,11 @@ void R_InitSprites(void)
negonearray[i] = -1;
#ifdef ROTSPRITE
for (angle = 0; angle < ROTANGLES; angle++)
for (angle = 1; angle < ROTANGLES; angle++)
{
ra = (ROTANGDIFF * angle);
if (!ra)
ra = (ROTANGDIFF / 2) + 1;
fa = ANG2RAD(FixedAngle(ra<<FRACBITS));
cosang2rad[angle] = FLOAT_TO_FIXED(cos(-fa));
sinang2rad[angle] = FLOAT_TO_FIXED(sin(-fa));
fa = ANG2RAD(FixedAngle((ROTANGDIFF * angle)<<FRACBITS));
rollcosang[angle] = FLOAT_TO_FIXED(cos(-fa));
rollsinang[angle] = FLOAT_TO_FIXED(sin(-fa));
}
#endif
@ -1129,8 +1126,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
#ifndef PROPERPAPER
@ -1262,11 +1258,11 @@ static void R_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lump].topoffset;
#ifdef ROTSPRITE
if (rollangle > 0)
if (thing->rollangle)
{
rollangle = R_GetRollAngle(thing->rollangle);
if (!sprframe->rotsprite.cached[rot])
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rollangle /= ROTANGDIFF;
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)
{
@ -2841,7 +2837,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,12 +20,17 @@
#include "../doomdef.h"
#include "../m_argv.h"
#include "../d_main.h"
#include "../m_misc.h"/* path shit */
#include "../i_system.h"
#ifdef __GNUC__
#if defined (__GNUC__) || defined (__unix__)
#include <unistd.h>
#endif
#ifdef __unix__
#include <errno.h>
#endif
#include "time.h" // For log timestamps
#ifdef HAVE_SDL
@ -47,7 +52,7 @@ extern int SDL_main(int argc, char *argv[]);
#ifdef LOGMESSAGES
FILE *logstream = NULL;
char logfilename[1024];
char logfilename[1024];
#endif
#ifndef DOXYGEN
@ -133,34 +138,86 @@ int main(int argc, char **argv)
{
time_t my_time;
struct tm * timeinfo;
char buf[26];
const char *format;
const char *reldir;
int left;
boolean fileabs;
#ifdef __unix__
const char *link;
#endif
logdir = D_Home();
my_time = time(NULL);
timeinfo = localtime(&my_time);
strftime(buf, 26, "%Y-%m-%d %H-%M-%S", timeinfo);
strcpy(logfilename, va("log-%s.txt", buf));
#ifdef DEFAULTDIR
if (logdir)
if (M_CheckParm("-logfile") && M_IsNextParm())
{
// Create dirs here because D_SRB2Main() is too late.
I_mkdir(va("%s%s"DEFAULTDIR, logdir, PATHSEP), 0755);
I_mkdir(va("%s%s"DEFAULTDIR"%slogs",logdir, PATHSEP, PATHSEP), 0755);
strcpy(logfilename, va("%s%s"DEFAULTDIR"%slogs%s%s",logdir, PATHSEP, PATHSEP, PATHSEP, logfilename));
format = M_GetNextParm();
fileabs = M_IsPathAbsolute(format);
}
else
#endif
{
I_mkdir("."PATHSEP"logs"PATHSEP, 0755);
strcpy(logfilename, va("."PATHSEP"logs"PATHSEP"%s", logfilename));
format = "log-%Y-%m-%d_%H-%M-%S.txt";
fileabs = false;
}
logstream = fopen(logfilename, "wt");
if (fileabs)
{
strftime(logfilename, sizeof logfilename, format, timeinfo);
}
else
{
if (M_CheckParm("-logdir") && M_IsNextParm())
reldir = M_GetNextParm();
else
reldir = "logs";
if (M_IsPathAbsolute(reldir))
{
left = snprintf(logfilename, sizeof logfilename,
"%s"PATHSEP, reldir);
}
else
#ifdef DEFAULTDIR
if (logdir)
{
left = snprintf(logfilename, sizeof logfilename,
"%s"PATHSEP DEFAULTDIR PATHSEP"%s"PATHSEP, logdir, reldir);
}
else
#endif/*DEFAULTDIR*/
{
left = snprintf(logfilename, sizeof logfilename,
"."PATHSEP"%s"PATHSEP, reldir);
}
#endif/*LOGMESSAGES*/
strftime(&logfilename[left], sizeof logfilename - left,
format, timeinfo);
}
M_MkdirEachUntil(logfilename,
M_PathParts(logdir) - 1,
M_PathParts(logfilename) - 1, 0755);
#ifdef __unix__
logstream = fopen(logfilename, "w");
#ifdef DEFAULTDIR
if (logdir)
link = va("%s/"DEFAULTDIR"/latest-log.txt", logdir);
else
#endif/*DEFAULTDIR*/
link = "latest-log.txt";
unlink(link);
if (symlink(logfilename, link) == -1)
{
I_OutputMsg("Error symlinking latest-log.txt: %s\n", strerror(errno));
}
#else/*__unix__*/
logstream = fopen("latest-log.txt", "wt+");
#endif/*__unix__*/
}
#endif
//I_OutputMsg("I_StartupSystem() ...\n");
I_StartupSystem();

View File

@ -2484,6 +2484,48 @@ void I_RemoveExitFunc(void (*func)())
}
}
#ifndef __unix__
static void Shittycopyerror(const char *name)
{
I_OutputMsg(
"Error copying log file: %s: %s\n",
name,
strerror(errno)
);
}
static void Shittylogcopy(void)
{
char buf[8192];
FILE *fp;
size_t r;
if (fseek(logstream, 0, SEEK_SET) == -1)
{
Shittycopyerror("fseek");
}
else if (( fp = fopen(logfilename, "wt") ))
{
while (( r = fread(buf, 1, sizeof buf, logstream) ))
{
if (fwrite(buf, 1, r, fp) < r)
{
Shittycopyerror("fwrite");
break;
}
}
if (ferror(logstream))
{
Shittycopyerror("fread");
}
fclose(fp);
}
else
{
Shittycopyerror(logfilename);
}
}
#endif/*__unix__*/
//
// Closes down everything. This includes restoring the initial
// palette and video mode, and removing whatever mouse, keyboard, and
@ -2506,6 +2548,9 @@ void I_ShutdownSystem(void)
if (logstream)
{
I_OutputMsg("I_ShutdownSystem(): end of logstream.\n");
#ifndef __unix__
Shittylogcopy();
#endif
fclose(logstream);
logstream = NULL;
}