diff --git a/.gitattributes b/.gitattributes index d45620912..7751149ac 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,12 @@ +#Source code +/src/*.c text=auto +/src/*.h text=auto +/src/*.s text=auto +/src/*.m text=auto +/src/*.xpm text=auto +/src/Makefile text=auto +/src/Make*.cfg text=auto +/src/CMakeLists.txt text=auto # Windows EOL *.cs -crlf -whitespace *.mk -crlf -whitespace diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 68ff0fdf9..881153682 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -13,11 +13,10 @@ set(SRB2_ASSET_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/installer" CACHE STRING "Path to directory that contains all asset files for the installer.") set(SRB2_ASSET_HASHED -"srb2.srb;\ +"srb2.pk3;\ player.dta;\ -rings.dta;\ -zones.dta;\ -patch.dta" +zones.pk3;\ +patch.pk3" CACHE STRING "Asset filenames to apply MD5 checks. No spaces between entries!" ) diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg new file mode 100644 index 000000000..de5b2ea6c --- /dev/null +++ b/extras/conf/SRB2-22.cfg @@ -0,0 +1,6482 @@ +/*********************************************************\ + Zone Builder Game Configuration + For Sonic Robo Blast 2 Version 2.2 + Contributors (alphabetical): + * Foxboy + * JJames19119 + * Kalaron + * Kristos + * MascaraSnake + * mazmazz + * Morpheus + * Neo Chaotikal + * Nev3r + * Oogaland + * Rob + * Shadow Hog + * Spherallic + * SRB2-Playah + * SSNTails + * SteelT + * ST218 + * toaster + * Viola +\*********************************************************/ + +// 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"; + +//GZDB specific. Don't try to load lumps that don't exist. +basegame = 0; + +// This is the simplified game engine/sourceport name +engine = "zdoom"; + +// When this is set to true, sectors with the same tag will light up when a line is highlighted +linetagindicatesectors = true; + +// The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder +formatinterface = "SRB2MapSetIO"; + +//Sky textures for vanilla maps +defaultskytextures +{ + SKY1 = "MAP01,MAP02,MAP03,MAP50,MAPA1,MAPA2,MAPA5,MAPA6,MAPA9,MAPAA,MAPAB,MAPAC,MAPAD,MAPAE,MAPAG,MAPAJ,MAPAK,MAPF0,MAPF1,MAPFA,MAPM0,MAPM8,MAPMA,MAPMB,MAPMC"; + SKY4 = "MAP04,MAP06,MAP51,MAPF8,MAPM1"; + SKY6 = "MAP05"; + SKY7 = "MAP07,MAP08,MAP09,MAP52,MAPM2,MAPM5"; + SKY10 = "MAP12,MAP53,MAPM3"; + SKY11 = "MAP10,MAP11,MAP16,MAP55,MAPF2,MAPF5,MAPF6,MAPF9,MAPM7"; + SKY13 = "MAP13,MAP54,MAPAS"; + SKY21 = "MAPAF,MAPF7,MAPM4"; + SKY22 = "MAP22,MAP23,MAP24,MAP25,MAP56,MAPAN,MAPAO,MAPF4,MAPM6"; + SKY29 = "MAP58,MAPAV"; + SKY30 = "MAP30"; + SKY35 = "MAP41"; + SKY40 = "MAP40"; + SKY55 = "MAPF3,MAPM9"; + SKY66 = "MAPAT"; + SKY99 = "MAP57"; + SKY103 = "MAPA3,MAPA4,MAPAU"; + SKY107 = "MAPA7,MAPA8"; + SKY117 = "MAPAH,MAPAI"; + SKY127 = "MAPAR"; + SKY132 = "MAPAW"; +} + +// Default lump name for new map +defaultlumpname = "MAP01"; + +// Default testing parameters +testparameters = "-file \"%AP\" \"%F\" -warp %L"; +testshortpaths = true; + +// Default nodebuilder configurations +defaultsavecompiler = "zennode_normal"; +defaulttestcompiler = "zennode_fast"; + +// Skill levels +skills +{ + 1 = "Normal"; +} + +// Skins +skins +{ + Sonic; + Tails; + Knuckles; + Metalsonic; + Fang; + Amy; +} + +// 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"; +} + +// Special linedefs +soundlinedefflag = 64; // See linedefflags +singlesidedflag = 1; // See linedefflags +doublesidedflag = 4; // See linedefflags +impassableflag = 1; +upperunpeggedflag = 8; +lowerunpeggedflag = 16; +repeatmidtextureflag = 1024; +pegmidtextureflag = 256; + +// Generalized actions +generalizedlinedefs = false; +generalizedsectors = true; + +// Texture loading options +defaultwalltexture = "GFZROCK"; +defaultfloortexture = "GFZFLR01"; +defaultceilingtexture = "F_SKY1"; +mixtexturesflats = true; +defaulttexturescale = 1.0f; +defaultflatscale = 1.0f; + +// Thing number for start position in 3D Mode +start3dmode = 3328; + + + + +/* +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. +Kalaron: and now TX_START +*/ + +// 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"; + } +} + + +/* +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 +{ + ~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; + } +} + +scriptlumpnames +{ + MAINCFG + { + script = "SOC.cfg"; + } + + OBJCTCFG + { + script = "SOC.cfg"; + } + + SOC_ + { + script = "SOC.cfg"; + isprefix = true; + } + + LUA_ + { + script = "Lua.cfg"; + isprefix = true; + } +} + +// 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; +} + +// SECTOR TYPES----------------------------------------------------------------- +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"; +} + + +// GENERALISED SECTOR TYPES----------------------------------------------------------------- +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"; + } +} + +// LINEDEF FLAGS +linedefflags +{ + 1 = "[0] Impassable"; + 2 = "[1] Block Enemies"; + 4 = "[2] Double-Sided"; + 8 = "[3] Upper Unpegged"; + 16 = "[4] Lower Unpegged"; + 32 = "[5] Slope Skew (E1)"; + 64 = "[6] Not Climbable"; + 128 = "[7] No Midtexture Skew (E2)"; + 256 = "[8] Peg Midtexture (E3)"; + 512 = "[9] Solid Midtexture (E4)"; + 1024 = "[10] Repeat Midtexture (E5)"; + 2048 = "[11] Netgame Only"; + 4096 = "[12] No Netgame"; + 8192 = "[13] Effect 6"; + 16384 = "[14] Bouncy Wall"; + 32768 = "[15] Transfer Line"; +} + +// Linedef flags UDMF translation table +// This is needed for copy/paste and prefabs to work properly +// When the UDMF field name is prefixed with ! it is inverted +linedefflagstranslation +{ + 1 = "blocking"; + 2 = "blockmonsters"; + 4 = "twosided"; + 8 = "dontpegtop"; + 16 = "dontpegbottom"; + 32 = "secret"; + 64 = "blocksound"; + 128 = "dontdraw"; + 256 = "mapped"; +} + +// LINEDEF ACTIVATIONS +linedefactivations +{ +} + +// LINEDEF TYPES +linedeftypes +{ + misc + { + title = "Miscellaneous"; + + 0 + { + title = "None"; + prefix = "(0)"; + } + + 1 + { + title = "Per-Sector Gravity"; + prefix = "(1)"; + flags64text = "[6] Flip in reverse gravity"; + } + + 5 + { + title = "Camera Scanner"; + prefix = "(5)"; + } + + 7 + { + title = "Sector Flat Alignment"; + prefix = "(7)"; + flags2048text = "[11] Don't align floor"; + flags4096text = "[12] Don't align ceiling"; + flags8192text = "[13] Use texture offsets"; + } + + 10 + { + title = "Culling Plane"; + prefix = "(10)"; + flags64text = "[6] Cull only while in sector"; + } + + 13 + { + title = "Heat Wave Effect"; + prefix = "(13)"; + } + + 40 + { + title = "Visual Portal Between Tagged Linedefs"; + prefix = "(40)"; + } + + 41 + { + title = "Horizon Effect"; + prefix = "(41)"; + } + + 50 + { + title = "Instantly Lower Floor on Level Load"; + prefix = "(50)"; + } + + 51 + { + title = "Instantly Raise Ceiling on Level Load"; + prefix = "(51)"; + } + + 63 + { + title = "Fake Floor/Ceiling Planes"; + prefix = "(63)"; + } + + 540 + { + title = "Floor Friction"; + prefix = "(540)"; + } + } + + parameters + { + title = "Parameters"; + + 2 + { + title = "Custom Exit"; + prefix = "(2)"; + flags2text = "[1] Check emeralds"; + flags64text = "[6] Skip score tally"; + } + + 3 + { + title = "Zoom Tube Parameters"; + prefix = "(3)"; + flags512text = "[9] Ignore player direction"; + } + + 4 + { + title = "Speed Pad Parameters"; + prefix = "(4)"; + flags512text = "[9] No teleport to center"; + flags1024text = "[10] Force spinning frames"; + } + + 8 + { + title = "Special Sector Properties"; + prefix = "(8)"; + flags32text = "[5] Invert precipitation"; + flags64text = "[6] Touch only ceiling"; + flags128text = "[7] Allow opposite gravity"; + flags256text = "[8] Touch sector edge"; + flags512text = "[9] Touch floor or ceiling"; + } + + 9 + { + title = "Chain Parameters"; + prefix = "(9)"; + flags32text = "[5] Swing instead of spin"; + flags64text = "[6] Player-turnable chain"; + flags128text = "[7] Make chain from maces"; + flags256text = "[8] Spawn mace at origin"; + flags512text = "[9] Don't clip inside ground"; + flags1024text = "[10] No distance check"; + } + + 11 + { + title = "Rope Hang Parameters"; + prefix = "(11)"; + flags32text = "[5] Don't loop"; + flags64text = "[6] Static"; + } + + 12 + { + title = "Rock Spawner Parameters"; + prefix = "(12)"; + flags64text = "[6] Randomize speed"; + } + + 14 + { + title = "Bustable Block Parameters"; + prefix = "(14)"; + flags32text = "[5] Particles launch from center"; + } + + 15 + { + title = "Fan Particle Spawner Parameters"; + prefix = "(15)"; + } + + 16 + { + title = "Minecart Parameters"; + prefix = "(16)"; + } + + 64 + { + title = "Continuously Appearing/Disappearing FOF"; + prefix = "(64)"; + flags2text = "[1] Use control sector tag"; + flags64text = "[6] No sound effect"; + } + + 65 + { + title = "Bridge Thinker "; + prefix = "(65)"; + } + } + + polyobject + { + title = "PolyObject"; + + 20 + { + title = "First Line"; + prefix = "(20)"; + } + + 21 + { + title = "Explicitly Include Line "; + prefix = "(21)"; + } + + 22 + { + title = "Parameters"; + prefix = "(22)"; + flags64text = "[6] Trigger linedef executor"; + flags128text = "[7] Intangible"; + flags256text = "[8] Stopped by pushables"; + flags512text = "[9] Render flats"; + } + + 30 + { + title = "Waving Flag"; + prefix = "(30)"; + } + + 31 + { + title = "Displacement by Front Sector"; + prefix = "(31)"; + } + + 32 + { + title = "Angular Displacement by Front Sector"; + prefix = "(32)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't turn players"; + flags512text = "[9] Turn all objects"; + } + } + + planemove + { + title = "Plane Movement"; + + 52 + { + title = "Continuously Falling Sector"; + prefix = "(52)"; + flags64text = "[6] Continuously rising"; + } + + 53 + { + title = "Continuous Floor/Ceiling Mover"; + prefix = "(53)"; + } + + 54 + { + title = "Continuous Floor Mover"; + prefix = "(54)"; + } + + 55 + { + title = "Continuous Ceiling Mover"; + prefix = "(55)"; + } + + 56 + { + title = "Continuous Two-Speed Floor/Ceiling Mover"; + prefix = "(56)"; + } + + 57 + { + title = "Continuous Two-Speed Floor Mover"; + prefix = "(57)"; + } + + 58 + { + title = "Continuous Two-Speed Ceiling Mover"; + prefix = "(58)"; + } + + 59 + { + title = "Activate Moving Platform"; + prefix = "(59)"; + flags64text = "[6] Move upwards at start"; + } + + 60 + { + title = "Activate Moving Platform (Adjustable Speed)"; + prefix = "(60)"; + flags64text = "[6] Move upwards at start"; + } + + 61 + { + title = "Crusher (Ceiling to Floor)"; + prefix = "(61)"; + flags512text = "[9] Double, constant speed"; + } + + 62 + { + title = "Crusher (Floor to Ceiling)"; + prefix = "(62)"; + flags512text = "[9] Double, constant speed"; + } + + 66 + { + title = "Move Floor by Displacement"; + prefix = "(66)"; + flags64text = "[6] Inverse movement"; + } + + 67 + { + title = "Move Ceiling by Displacement"; + prefix = "(67)"; + flags64text = "[6] Inverse movement"; + } + + 68 + { + title = "Move Floor and Ceiling by Displacement"; + prefix = "(68)"; + flags64text = "[6] Inverse movement"; + } + } + + fofsolid + { + title = "FOF (solid)"; + + 100 + { + title = "Solid, Opaque"; + prefix = "(100)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "19F"; + } + + 101 + { + title = "Solid, Opaque, No Shadow"; + prefix = "(101)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "1DF"; + } + + 102 + { + title = "Solid, Translucent"; + prefix = "(102)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Render insides"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "195F"; + flags643dfloorflagsadd = "7C80"; + } + + 103 + { + title = "Solid, Sides Only"; + prefix = "(103)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "1CF"; + } + + 104 + { + title = "Solid, No Sides"; + prefix = "(104)"; + flags32text = "[5] Only block player"; + flags64text = "[6] Cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "1D7"; + flags643dfloorflagsremove = "40"; + } + + 105 + { + title = "Solid, Invisible"; + prefix = "(105)"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "47"; + } + + 140 + { + title = "Intangible from Bottom, Opaque"; + prefix = "(140)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "200841F"; + flags643dfloorflagsadd = "40"; + } + + 141 + { + title = "Intangible from Bottom, Translucent"; + prefix = "(141)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Render insides/block non-plr"; + 3dfloor = true; + 3dfloorflags = "200191F"; + flags1283dfloorflagsadd = "7C80"; + flags643dfloorflagsadd = "40"; + } + + 142 + { + title = "Intangible from Bottom, Translucent, No Sides"; + prefix = "(142)"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Render insides/block non-plr"; + 3dfloor = true; + 3dfloorflags = "2001917"; + flags1283dfloorflagsadd = "7C80"; + flags643dfloorflagsadd = "40"; + } + + 143 + { + title = "Intangible from Top, Opaque"; + prefix = "(143)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "400841F"; + flags643dfloorflagsadd = "40"; + } + + 144 + { + title = "Intangible from Top, Translucent"; + prefix = "(144)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Render insides/block non-plr"; + 3dfloor = true; + 3dfloorflags = "400191F"; + flags1283dfloorflagsadd = "7C80"; + flags643dfloorflagsadd = "40"; + } + + 145 + { + title = "Intangible from Top, Translucent, No Sides"; + prefix = "(145)"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Render insides/block non-plr"; + 3dfloor = true; + 3dfloorflags = "4001917"; + flags1283dfloorflagsadd = "7C80"; + flags643dfloorflagsadd = "40"; + } + + 146 + { + title = "Only Tangible from Sides"; + prefix = "(146)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "600800F"; + } + } + + fofintangible + { + title = "FOF (intangible)"; + + 120 + { + title = "Water, Opaque"; + prefix = "(120)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Use two light levels"; + flags512text = "[9] Use target light level"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "8F39"; + flags643dfloorflagsadd = "20000"; + flags5123dfloorflagsadd = "80000000"; + flags10243dfloorflagsadd = "40000000"; + } + + 121 + { + title = "Water, Translucent"; + prefix = "(121)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Use two light levels"; + flags512text = "[9] Use target light level"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "9F39"; + flags643dfloorflagsadd = "20000"; + flags5123dfloorflagsadd = "80000000"; + flags10243dfloorflagsadd = "40000000"; + } + + 122 + { + title = "Water, Opaque, No Sides"; + prefix = "(122)"; + flags64text = "[6] Use two light levels"; + flags512text = "[9] Use target light level"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "F31"; + flags643dfloorflagsadd = "20000"; + flags5123dfloorflagsadd = "80000000"; + flags10243dfloorflagsadd = "40000000"; + } + + 123 + { + title = "Water, Translucent, No Sides"; + prefix = "(123)"; + flags64text = "[6] Use two light levels"; + flags512text = "[9] Use target light level"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "1F31"; + flags643dfloorflagsadd = "20000"; + flags5123dfloorflagsadd = "80000000"; + flags10243dfloorflagsadd = "40000000"; + } + + 124 + { + title = "Goo Water, Translucent"; + prefix = "(124)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Use two light levels"; + flags512text = "[9] Use target light level"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "209F39"; + flags643dfloorflagsadd = "20000"; + flags5123dfloorflagsadd = "80000000"; + flags10243dfloorflagsadd = "40000000"; + } + + 125 + { + title = "Goo Water, Translucent, No Sides"; + prefix = "(125)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Use two light levels"; + flags512text = "[9] Use target light level"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "201F31"; + flags643dfloorflagsadd = "20000"; + flags5123dfloorflagsadd = "80000000"; + flags10243dfloorflagsadd = "40000000"; + } + + 220 + { + title = "Intangible, Opaque"; + prefix = "(220)"; + flags8text = "[3] Slope skew sides"; + 3dfloor = true; + 3dfloorflags = "8F19"; + } + + 221 + { + title = "Intangible, Translucent"; + prefix = "(221)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Cast shadow"; + 3dfloor = true; + 3dfloorflags = "1B59"; + flags643dfloorflagsremove = "40"; + } + + 222 + { + title = "Intangible, Sides Only"; + prefix = "(222)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Cast shadow"; + 3dfloor = true; + 3dfloorflags = "8249"; + flags643dfloorflagsremove = "240"; + } + + 223 + { + title = "Intangible, Invisible"; + prefix = "(223)"; + 3dfloor = true; + 3dfloorflags = "41"; + } + } + + fofmoving + { + title = "FOF (moving)"; + + 150 + { + title = "Air Bobbing"; + prefix = "(150)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "19F"; + } + + 151 + { + title = "Air Bobbing (Adjustable)"; + prefix = "(151)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "19F"; + } + + 152 + { + title = "Reverse Air Bobbing (Adjustable)"; + prefix = "(152)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "19F"; + } + + 160 + { + title = "Floating, Bobbing"; + prefix = "(160)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "4019F"; + } + + 190 + { + title = "Rising Platform, Solid, Opaque"; + prefix = "(190)"; + flags2text = "[1] Sink when stepped on"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "19F"; + } + + 191 + { + title = "Rising Platform, Solid, Opaque, No Shadow"; + prefix = "(191)"; + flags2text = "[1] Sink when stepped on"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "1DF"; + } + + 192 + { + title = "Rising Platform, Solid, Translucent"; + prefix = "(192)"; + flags2text = "[1] Sink when stepped on"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "195F"; + } + + 193 + { + title = "Rising Platform, Solid, Invisible"; + prefix = "(193)"; + flags2text = "[1] Sink when stepped on"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "47"; + } + + 194 + { + title = "Rising Platform, Intangible from Bottom, Opaque"; + prefix = "(194)"; + flags2text = "[1] Sink when stepped on"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash, no shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "200841F"; + flags643dfloorflagsadd = "40"; + } + + 195 + { + title = "Rising Platform, Intangible from Bottom, Translucent"; + prefix = "(195)"; + flags2text = "[1] Sink when stepped on"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash, no shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "2009D1F"; + flags643dfloorflagsadd = "40"; + } + } + + fofcrumbling + { + title = "FOF (crumbling)"; + + 170 + { + title = "Crumbling, Respawn"; + prefix = "(170)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "10019F"; + } + + 171 + { + title = "Crumbling, No Respawn"; + prefix = "(171)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "80019F"; + } + + 172 + { + title = "Crumbling, Respawn, Intangible from Bottom"; + prefix = "(172)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "210841F"; + flags643dfloorflagsadd = "40"; + } + + 173 + { + title = "Crumbling, No Respawn, Intangible from Bottom"; + prefix = "(173)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "218841F"; + flags643dfloorflagsadd = "40"; + } + + 174 + { + title = "Crumbling, Respawn, Int. from Bottom, Translucent"; + prefix = "(174)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "210959F"; + flags643dfloorflagsadd = "40"; + } + + 175 + { + title = "Crumbling, No Respawn, Int. from Bottom, Translucent"; + prefix = "(175)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Don't cast shadow"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "218959F"; + flags643dfloorflagsadd = "40"; + } + + 176 + { + title = "Crumbling, Respawn, Floating, Bobbing"; + prefix = "(176)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "14019F"; + } + + 177 + { + title = "Crumbling, No Respawn, Floating, Bobbing"; + prefix = "(177)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "1C019F"; + } + + 178 + { + title = "Crumbling, Respawn, Floating"; + prefix = "(178)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "14019F"; + } + + 179 + { + title = "Crumbling, No Respawn, Floating"; + prefix = "(179)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "1C019F"; + } + + 180 + { + title = "Crumbling, Respawn, Air Bobbing"; + prefix = "(180)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags64text = "[6] Spindash to move"; + flags128text = "[7] Only block non-players"; + 3dfloor = true; + 3dfloorflags = "10019F"; + } + } + + fofspecial + { + title = "FOF (special)"; + + 200 + { + title = "Light Block"; + prefix = "(200)"; + 3dfloor = true; + 3dfloorflags = "20201"; + } + + 201 + { + title = "Half Light Block"; + prefix = "(201)"; + 3dfloor = true; + 3dfloorflags = "201"; + } + + 202 + { + title = "Fog Block"; + prefix = "(202)"; + 3dfloor = true; + 3dfloorflags = "3EF19"; + } + + 250 + { + title = "Mario Block"; + prefix = "(250)"; + flags32text = "[5] Invisible block"; + flags64text = "[6] Brick block"; + 3dfloor = true; + 3dfloorflags = "40019F"; + } + + 251 + { + title = "Thwomp Block"; + prefix = "(251)"; + flags512text = "[9] Custom crushing sound"; + flags1024text = "[10] Custom speed"; + 3dfloor = true; + 3dfloorflags = "19F"; + } + + 252 + { + title = "Shatter Block"; + prefix = "(252)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Shatter only from below"; + flags512text = "[9] Shattered by pushables"; + flags1024text = "[10] Trigger linedef executor"; + 3dfloor = true; + 3dfloorflags = "8800019"; + flags643dfloorflagsadd = "200006"; + } + + 253 + { + title = "Shatter Block, Translucent"; + prefix = "(253)"; + flags8text = "[3] Slope skew sides"; + flags512text = "[9] Shattered by pushables"; + flags1024text = "[10] Trigger linedef executor"; + 3dfloor = true; + 3dfloorflags = "8801019"; + } + + 254 + { + title = "Bustable Block"; + prefix = "(254)"; + flags8text = "[3] Slope skew sides"; + flags64text = "[6] Strong characters only"; + flags128text = "[7] Only block non-players"; + flags512text = "[9] Shattered by pushables"; + flags1024text = "[10] Trigger linedef executor"; + 3dfloor = true; + 3dfloorflags = "80001F"; + flags643dfloorflagsadd = "20000000"; + } + + 255 + { + title = "Spin-Bustable Block"; + prefix = "(255)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + flags512text = "[9] Shattered by pushables"; + flags1024text = "[10] Trigger linedef executor"; + 3dfloor = true; + 3dfloorflags = "1080001F"; + } + + 256 + { + title = "Spin-Bustable Block, Translucent"; + prefix = "(256)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + flags512text = "[9] Shattered by pushables"; + flags1024text = "[10] Trigger linedef executor"; + 3dfloor = true; + 3dfloorflags = "1080101F"; + } + + 257 + { + title = "Quicksand"; + prefix = "(257)"; + flags8text = "[3] Slope skew sides"; + flags1024text = "[10] Ripple effect"; + 3dfloor = true; + 3dfloorflags = "1008219"; + flags10243dfloorflagsadd = "40000000"; + } + + 258 + { + title = "Laser"; + prefix = "(258)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Don't damage bosses"; + 3dfloor = true; + 3dfloorflags = "959"; + } + + 259 + { + title = "Custom FOF"; + prefix = "(259)"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; + flags512text = "[9] Shattered by pushables"; + flags1024text = "[10] Trigger linedef executor"; + 3dfloor = true; + 3dfloorcustom = true; + } + } + + linedeftrigger + { + title = "Linedef Executor Trigger"; + + 300 + { + title = "Continuous"; + prefix = "(300)"; + } + + 301 + { + title = "Each Time"; + prefix = "(301)"; + flags16384text = "[14] Also trigger on exit"; + } + + 302 + { + title = "Once"; + prefix = "(302)"; + } + + 303 + { + title = "Ring Count - Continuous"; + prefix = "(303)"; + flags2text = "[1] Rings greater or equal"; + flags64text = "[6] Rings less or equal"; + flags512text = "[9] Consider all players"; + } + + 304 + { + title = "Ring Count - Once"; + prefix = "(304)"; + flags2text = "[1] Rings greater or equal"; + flags64text = "[6] Rings less or equal"; + flags512text = "[9] Consider all players"; + } + + 305 + { + title = "Character Ability - Continuous"; + prefix = "(305)"; + } + + 306 + { + title = "Character Ability - Each Time"; + prefix = "(306)"; + flags16384text = "[14] Also trigger on exit"; + } + + 307 + { + title = "Character Ability - Once"; + prefix = "(307)"; + } + + 308 + { + title = "Race Only - Once"; + prefix = "(308)"; + } + + 309 + { + title = "CTF Red Team - Continuous"; + prefix = "(309)"; + } + + 310 + { + title = "CTF Red Team - Each Time"; + prefix = "(310)"; + flags16384text = "[14] Also trigger on exit"; + } + + 311 + { + title = "CTF Blue Team - Continuous"; + prefix = "(311)"; + } + + 312 + { + title = "CTF Blue Team - Each Time"; + prefix = "(312)"; + flags16384text = "[14] Also trigger on exit"; + } + + 313 + { + title = "No More Enemies - Once"; + prefix = "(313)"; + } + + 314 + { + title = "Number of Pushables - Continuous"; + prefix = "(314)"; + flags64text = "[6] Number greater or equal"; + flags512text = "[9] Number less"; + } + + 315 + { + title = "Number of Pushables - Once"; + prefix = "(315)"; + flags64text = "[6] Number greater or equal"; + flags512text = "[9] Number less"; + } + + 317 + { + title = "Condition Set Trigger - Continuous"; + prefix = "(317)"; + } + + 318 + { + title = "Condition Set Trigger - Once"; + prefix = "(318)"; + } + + 319 + { + title = "Unlockable - Continuous"; + prefix = "(319)"; + } + + 320 + { + title = "Unlockable - Once"; + prefix = "(320)"; + } + + 321 + { + title = "Trigger After X Calls - Continuous"; + prefix = "(321)"; + flags64text = "[6] Trigger more than once"; + + } + + 322 + { + title = "Trigger After X Calls - Each Time"; + prefix = "(322)"; + flags64text = "[6] Trigger more than once"; + } + + 323 + { + title = "NiGHTSerize - Each Time"; + prefix = "(323)"; + flags2text = "[1] Mare >= Front X Offset"; + flags8text = "[3] Run only if player is NiGHTS"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + flags16384text = "[14] Run if no more mares"; + flags32768text = "[15] Run if player is not NiGHTS"; + } + + 324 + { + title = "NiGHTSerize - Once"; + flags2text = "[1] Mare >= Front X Offset"; + flags8text = "[3] Run only if player is NiGHTS"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + flags16384text = "[14] Run if no more mares"; + flags32768text = "[15] Run if player is not NiGHTS"; + prefix = "(324)"; + } + + 325 + { + title = "De-NiGHTSerize - Each Time"; + flags2text = "[1] Mare >= Front X Offset"; + flags8text = "[3] Run if anyone is NiGHTS"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + flags32768text = "[15] Run if no one is NiGHTS"; + prefix = "(325)"; + } + + 326 + { + title = "De-NiGHTSerize - Once"; + flags2text = "[1] Mare >= Front X Offset"; + flags8text = "[3] Run if anyone is NiGHTS"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + flags32768text = "[15] Run if no one is NiGHTS"; + prefix = "(326)"; + } + + 327 + { + title = "NiGHTS Lap - Each Time"; + flags2text = "[1] Mare >= Front X Offset"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + prefix = "(327)"; + } + + 328 + { + title = "NiGHTS Lap - Once"; + flags2text = "[1] Mare >= Front X Offset"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + prefix = "(328)"; + } + + 329 + { + title = "Ideya Capture Touch - Each Time"; + flags2text = "[1] Mare >= Front X Offset"; + flags8text = "[3] Run regardless of spheres"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + flags16384text = "[14] Only if not enough spheres"; + flags32768text = "[15] Run when entering Capture"; + prefix = "(329)"; + } + + 330 + { + title = "Ideya Capture Touch - Once"; + flags2text = "[1] Mare >= Front X Offset"; + flags8text = "[3] Run regardless of spheres"; + flags16text = "[4] Count from lowest of players"; + flags32text = "[5] Lap <= Front Y Offset"; + flags64text = "[6] Mare <= Front X Offset"; + flags128text = "[7] Lap >= Front Y Offset"; + flags256text = "[8] Count laps from Bonus Time"; + flags512text = "[9] Count from triggering player"; + flags16384text = "[14] Only if not enough spheres"; + flags32768text = "[15] Run when entering Capture"; + prefix = "(330)"; + } + + 331 + { + title = "Player Skin - Continuous"; + flags64text = "[6] Disable for this skin"; + prefix = "(331)"; + } + + 332 + { + title = "Player Skin - Each Time"; + flags64text = "[6] Disable for this skin"; + prefix = "(332)"; + } + + 333 + { + title = "Player Skin - Once"; + flags64text = "[6] Disable for this skin"; + prefix = "(333)"; + } + + 399 + { + title = "Level Load"; + prefix = "(399)"; + } + } + + linedefexecsector + { + title = "Linedef Executor (sector)"; + + 400 + { + title = "Set Tagged Sector's Floor Height/Texture"; + prefix = "(400)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Keep floor flat"; + } + + 401 + { + title = "Set Tagged Sector's Ceiling Height/Texture"; + prefix = "(401)"; + flags8text = "[3] Set delay by backside sector"; + } + + 402 + { + title = "Set Tagged Sector's Light Level"; + prefix = "(402)"; + flags8text = "[3] Set delay by backside sector"; + } + + 409 + { + title = "Change Tagged Sector's Tag"; + prefix = "(409)"; + flags8text = "[3] Set delay by backside sector"; + } + + 410 + { + title = "Change Front Sector's Tag"; + prefix = "(410)"; + flags8text = "[3] Set delay by backside sector"; + } + + 416 + { + title = "Start Adjustable Flickering Light"; + prefix = "(416)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Second level from back"; + } + + 417 + { + title = "Start Adjustable Pulsating Light"; + prefix = "(417)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Second level from back"; + } + + 418 + { + title = "Start Adjustable Blinking Light (unsynchronized)"; + prefix = "(418)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Second level from back"; + } + + 419 + { + title = "Start Adjustable Blinking Light (synchronized)"; + prefix = "(419)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Second level from back"; + } + + 420 + { + title = "Fade Light Level"; + prefix = "(420)"; + flags8text = "[3] Set delay by backside sector"; + flags16text = "[4] Set params by X/Y offsets"; + flags512text = "[9] Speed = Tic Duration"; + flags1024text = "[10] Override existing fade"; + } + + 421 + { + title = "Stop Lighting Effect"; + prefix = "(421)"; + flags8text = "[3] Set delay by backside sector"; + } + + 435 + { + title = "Change Plane Scroller Direction"; + prefix = "(435)"; + flags8text = "[3] Set delay by backside sector"; + } + } + + linedefexecplane + { + title = "Linedef Executor (plane movement)"; + + 403 + { + title = "Move Tagged Sector's Floor"; + prefix = "(403)"; + flags2text = "[1] Trigger linedef executor"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Change floor flat"; + } + + 404 + { + title = "Move Tagged Sector's Ceiling"; + prefix = "(404)"; + flags2text = "[1] Trigger linedef executor"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Change ceiling flat"; + } + + 405 + { + title = "Move Floor According to Front Texture Offsets"; + prefix = "(405)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Move instantly"; + } + + 407 + { + title = "Move Ceiling According to Front Texture Offsets"; + prefix = "(407)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Move instantly"; + } + + 411 + { + title = "Stop Plane Movement"; + prefix = "(411)"; + flags8text = "[3] Set delay by backside sector"; + } + + 428 + { + title = "Start Platform Movement"; + prefix = "(428)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Move upwards at start"; + } + + 429 + { + title = "Crush Ceiling Once"; + prefix = "(429)"; + flags8text = "[3] Set delay by backside sector"; + flags512text = "[9] Double, constant speed"; + } + + 430 + { + title = "Crush Floor Once"; + prefix = "(430)"; + flags8text = "[3] Set delay by backside sector"; + } + + 431 + { + title = "Crush Floor and Ceiling Once"; + prefix = "(431)"; + flags8text = "[3] Set delay by backside sector"; + flags512text = "[9] Double, constant speed"; + } + } + + linedefexecplayer + { + title = "Linedef Executor (player/object)"; + + 412 + { + title = "Teleporter"; + prefix = "(412)"; + flags2text = "[1] Silent"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Retain angle"; + flags256text = "[8] Relative, silent"; + flags512text = "[9] Retain momentum"; + } + + 425 + { + title = "Change Object State"; + prefix = "(425)"; + flags8text = "[3] Set delay by backside sector"; + } + + 426 + { + title = "Stop Object"; + prefix = "(426)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Teleport to sector center"; + } + + 427 + { + title = "Award Score"; + prefix = "(427)"; + flags8text = "[3] Set delay by backside sector"; + } + + 432 + { + title = "Enable/Disable 2D Mode"; + prefix = "(432)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Return to 3D"; + } + + 433 + { + title = "Enable/Disable Gravity Flip"; + prefix = "(433)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Return to normal"; + } + + 434 + { + title = "Award Power-Up"; + prefix = "(434)"; + flags2text = "[1] Use back upper texture"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] No time limit"; + } + + 437 + { + title = "Disable Player Control"; + prefix = "(437)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Allow jumping"; + } + + 438 + { + title = "Change Object Size"; + prefix = "(438)"; + flags8text = "[3] Set delay by backside sector"; + } + + 442 + { + title = "Change Object Type State"; + prefix = "(442)"; + flags8text = "[3] Set delay by backside sector"; + } + + 457 + { + title = "Track Object's Angle"; + prefix = "(457)"; + flags8text = "[3] Set delay by backside sector"; + flags128text = "[7] Don't stop after first fail"; + } + + 458 + { + title = "Stop Tracking Object's Angle"; + prefix = "(458)"; + flags8text = "[3] Set delay by backside sector"; + } + + 460 + { + title = "Award Rings"; + prefix = "(460)"; + } + + 461 + { + title = "Spawn Object"; + prefix = "(461)"; + flags64text = "[6] Spawn inside a range"; + } + } + + linedefexecmisc + { + title = "Linedef Executor (misc.)"; + + 413 + { + title = "Change Music"; + prefix = "(413)"; + flags2text = "[1] Keep after death"; + flags8text = "[3] Set delay by backside sector"; + flags32text = "[5] Seek to current song position"; + flags64text = "[6] For everyone"; + flags128text = "[7] Fade to custom volume"; + flags512text = "[9] Don't loop"; + flags16384text = "[14] Force music reload"; + } + + 414 + { + title = "Play Sound Effect"; + prefix = "(414)"; + flags2text = "[1] From calling sector"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] From nowhere for triggerer"; + flags512text = "[9] For everyone"; + flags1024text = "[10] From tagged sectors"; + } + + 415 + { + title = "Run Script"; + prefix = "(415)"; + flags8text = "[3] Set delay by backside sector"; + } + + 422 + { + title = "Switch to Cut-Away View"; + prefix = "(422)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Adjust pitch"; + } + + 423 + { + title = "Change Sky"; + prefix = "(423)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] For everyone"; + } + + 424 + { + title = "Change Weather"; + prefix = "(424)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] For everyone"; + } + + 436 + { + title = "Shatter FOF"; + prefix = "(436)"; + flags8text = "[3] Set delay by backside sector"; + } + + 439 + { + title = "Change Tagged Linedef's Textures"; + prefix = "(439)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Only existing"; + } + + 440 + { + title = "Start Metal Sonic Race"; + prefix = "(440)"; + flags8text = "[3] Set delay by backside sector"; + } + + 441 + { + title = "Condition Set Trigger"; + prefix = "(441)"; + flags8text = "[3] Set delay by backside sector"; + } + + 443 + { + title = "Call Lua Function"; + prefix = "(443)"; + flags8text = "[3] Set delay by backside sector"; + } + + 444 + { + title = "Earthquake"; + prefix = "(444)"; + flags8text = "[3] Set delay by backside sector"; + } + + + 445 + { + title = "Make FOF Disappear/Reappear"; + prefix = "(445)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Reappear"; + } + + 446 + { + title = "Make FOF Crumble"; + prefix = "(446)"; + flags2text = "[1] Flags determine respawn"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't respawn"; + } + + 447 + { + title = "Change Tagged Sector's Colormap"; + prefix = "(447)"; + flags8text = "[3] Set delay by backside sector"; + flags16text = "[4] Front X/Y = Alpha"; + flags32text = "[5] Subtract Red value"; + flags64text = "[6] Subtract Green value"; + flags128text = "[7] Subtract Blue value"; + flags256text = "[8] Calc relative values"; + flags32768text = "[15] Use back side colormap"; + } + + 448 + { + title = "Change Skybox"; + prefix = "(448)"; + flags2text = "[1] Change centerpoint"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] For everyone"; + flags512text = "[9] Don't change viewpoint"; + } + + 450 + { + title = "Execute Linedef Executor (specific tag)"; + prefix = "(450)"; + flags8text = "[3] Set delay by backside sector"; + } + + 451 + { + title = "Execute Linedef Executor (random tag in range)"; + prefix = "(451)"; + flags8text = "[3] Set delay by backside sector"; + } + + 452 + { + title = "Set FOF Translucency"; + prefix = "(452)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Do not handle FF_TRANS"; + flags256text = "[8] Set relative to current val"; + } + + 453 + { + title = "Fade FOF"; + prefix = "(453)"; + flags2text = "[1] Do not handle FF_EXISTS"; + flags8text = "[3] Set delay by backside sector"; + flags32text = "[5] No collision during fade"; + flags64text = "[6] Do not handle FF_TRANS"; + flags128text = "[7] Do not handle lighting"; + flags256text = "[8] Set relative to current val"; + flags512text = "[9] Speed = Tic Duration"; + flags1024text = "[10] Override existing fade"; + flags16384text = "[14] Do not handle collision"; + flags32768text = "[15] Use exact alpha in OGL"; + } + + 454 + { + title = "Stop Fading FOF"; + prefix = "(454)"; + flags2text = "[1] Do not finalize collision"; + flags8text = "[3] Set delay by backside sector"; + } + + 455 + { + title = "Fade Tagged Sector's Colormap"; + prefix = "(455)"; + flags8text = "[3] Set delay by backside sector"; + flags16text = "[4] Front X/Y = Alpha"; + flags32text = "[5] Subtract Red value"; + flags64text = "[6] Subtract Green value"; + flags128text = "[7] Subtract Blue value"; + flags256text = "[8] Calc relative values"; + flags512text = "[9] Speed = Tic Duration"; + flags1024text = "[10] Override existing fade"; + flags16384text = "[14] Fade from invisible black"; + flags32768text = "[15] Use back side colormap"; + } + + 456 + { + title = "Stop Fading Tagged Sector's Colormap"; + prefix = "(456)"; + flags8text = "[3] Set delay by backside sector"; + } + + 459 + { + title = "Control Text Prompt"; + prefix = "(459)"; + flags2text = "[1] Close text prompt"; + flags8text = "[3] Set delay by backside sector"; + flags32text = "[5] Run executor tag on close"; + flags64text = "[6] For everyone"; + flags128text = "[7] Do not block controls"; + flags256text = "[8] Do not freeze time"; + flags32768text = "[15] Find prompt by name"; + } + } + + linedefexecpoly + { + title = "Linedef Executor (polyobject)"; + + 480 + { + title = "Door Slide"; + prefix = "(480)"; + flags8text = "[3] Set delay by backside sector"; + } + + 481 + { + title = "Door Swing"; + prefix = "(481)"; + flags8text = "[3] Set delay by backside sector"; + } + + 482 + { + title = "Move"; + prefix = "(482)"; + flags8text = "[3] Set delay by backside sector"; + } + + 483 + { + title = "Move, Override"; + prefix = "(483)"; + flags8text = "[3] Set delay by backside sector"; + } + + 484 + { + title = "Rotate Right"; + prefix = "(484)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't turn players"; + flags512text = "[9] Turn all objects"; + } + + 485 + { + title = "Rotate Right, Override"; + prefix = "(485)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't turn players"; + flags512text = "[9] Turn all objects"; + } + + 486 + { + title = "Rotate Left"; + prefix = "(486)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't turn players"; + flags512text = "[9] Turn all objects"; + } + + 487 + { + title = "Rotate Left, Override"; + prefix = "(487)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't turn players"; + flags512text = "[9] Turn all objects"; + } + + 488 + { + title = "Move by Waypoints"; + prefix = "(488)"; + flags8text = "[3] Set delay by backside sector"; + flags32text = "[5] Reverse order"; + flags128text = "[7] There and back"; + flags256text = "[8] Return when done"; + flags512text = "[9] Loop movement"; + } + + 489 + { + title = "Turn Invisible, Intangible"; + prefix = "(489)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Only invisible"; + } + + 490 + { + title = "Turn Visible, Tangible"; + prefix = "(490)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Only visible"; + } + + 491 + { + title = "Set Translucency"; + prefix = "(491)"; + flags8text = "[3] Set delay by backside sector"; + flags16text = "[4] Set raw alpha by Front X"; + flags256text = "[8] Calc relative values"; + } + + 492 + { + title = "Fade Translucency"; + prefix = "(492)"; + flags8text = "[3] Set delay by backside sector"; + flags16text = "[4] Set raw alpha by Front X"; + flags32text = "[5] No collision during fade"; + flags256text = "[8] Calc relative values"; + flags512text = "[9] Speed = Tic Duration"; + flags1024text = "[10] Override existing fade"; + flags16384text = "[14] Do not handle collision"; + } + } + + wallscroll + { + title = "Wall Scrolling"; + + 500 + { + title = "Scroll Wall Front Side Left"; + prefix = "(500)"; + } + + 501 + { + title = "Scroll Wall Front Side Right"; + prefix = "(501)"; + } + + 502 + { + title = "Scroll Wall According to Linedef"; + prefix = "(502)"; + } + + 503 + { + title = "Scroll Wall According to Linedef (Accelerative)"; + prefix = "(503)"; + } + + 504 + { + title = "Scroll Wall According to Linedef (Displacement)"; + prefix = "(504)"; + } + + 505 + { + title = "Scroll Texture by Front Side Offsets"; + prefix = "(505)"; + } + + 506 + { + title = "Scroll Texture by Back Side Offsets"; + prefix = "(506)"; + } + } + + planescroll + { + title = "Plane Scrolling"; + + 510 + { + title = "Scroll Floor Texture"; + prefix = "(510)"; + } + + 511 + { + title = "Scroll Floor Texture (Accelerative)"; + prefix = "(511)"; + } + + 512 + { + title = "Scroll Floor Texture (Displacement)"; + prefix = "(512)"; + } + + 513 + { + title = "Scroll Ceiling Texture"; + prefix = "(513)"; + } + + 514 + { + title = "Scroll Ceiling Texture (Accelerative)"; + prefix = "(514)"; + } + + 515 + { + title = "Scroll Ceiling Texture (Displacement)"; + prefix = "(515)"; + } + + 520 + { + title = "Carry Objects on Floor"; + prefix = "(520)"; + } + + 521 + { + title = "Carry Objects on Floor (Accelerative)"; + prefix = "(521)"; + flags64text = "[6] Even across edges"; + } + + 522 + { + title = "Carry Objects on Floor (Displacement)"; + prefix = "(522)"; + } + + 523 + { + title = "Carry Objects on Ceiling"; + prefix = "(523)"; + flags64text = "[6] Even across edges"; + } + + 524 + { + title = "Carry Objects on Ceiling (Accelerative)"; + prefix = "(524)"; + } + + 525 + { + title = "Carry Objects on Ceiling (Displacement)"; + prefix = "(525)"; + } + + 530 + { + title = "Scroll Floor Texture and Carry Objects"; + prefix = "(530)"; + flags64text = "[6] Even across edges"; + } + + 531 + { + title = "Scroll Floor Texture and Carry Objects (Accelerative)"; + prefix = "(531)"; + } + + 532 + { + title = "Scroll Floor Texture and Carry Objects (Displacement)"; + prefix = "(532)"; + } + + 533 + { + title = "Scroll Ceiling Texture and Carry Objects"; + prefix = "(533)"; + flags64text = "[6] Even across edges"; + } + + 534 + { + title = "Scroll Ceiling Texture and Carry Objects (Accelerative)"; + prefix = "(534)"; + } + + 535 + { + title = "Scroll Ceiling Texture and Carry Objects (Displacement)"; + prefix = "(535)"; + } + } + + pusher + { + title = "Pusher"; + + 541 + { + title = "Wind"; + prefix = "(541)"; + flags512text = "[9] Player slides"; + flags64text = "[6] Even across edges"; + } + + 542 + { + title = "Upwards Wind"; + prefix = "(542)"; + flags512text = "[9] Player slides"; + flags64text = "[6] Even across edges"; + } + + 543 + { + title = "Downwards Wind"; + prefix = "(543)"; + flags512text = "[9] Player slides"; + flags64text = "[6] Even across edges"; + } + + 544 + { + title = "Current"; + prefix = "(544)"; + flags512text = "[9] Player slides"; + flags64text = "[6] Even across edges"; + } + + 545 + { + title = "Upwards Current"; + prefix = "(545)"; + flags512text = "[9] Player slides"; + flags64text = "[6] Even across edges"; + } + + 546 + { + title = "Downwards Current"; + prefix = "(546)"; + flags512text = "[9] Player slides"; + flags64text = "[6] Even across edges"; + } + + 547 + { + title = "Push/Pull"; + prefix = "(547)"; + } + } + + light + { + title = "Lighting"; + + 600 + { + title = "Floor Lighting"; + prefix = "(600)"; + } + + 601 + { + title = "Ceiling Lighting"; + prefix = "(601)"; + } + + 602 + { + title = "Adjustable Pulsating Light"; + prefix = "(602)"; + } + + 603 + { + title = "Adjustable Flickering Light"; + prefix = "(603)"; + } + + 604 + { + title = "Adjustable Blinking Light (unsynchronized)"; + prefix = "(604)"; + } + + 605 + { + title = "Adjustable Blinking Light (synchronized)"; + prefix = "(605)"; + } + + 606 + { + title = "Colormap"; + prefix = "(606)"; + } + } + + slope + { + title = "Slope"; + + 700 + { + title = "Slope Frontside Floor"; + prefix = "(700)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 1; + } + + 701 + { + title = "Slope Frontside Ceiling"; + prefix = "(701)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 2; + } + + 702 + { + title = "Slope Frontside Floor and Ceiling"; + prefix = "(702)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 3; + } + + 703 + { + title = "Slope Frontside Floor and Backside Ceiling"; + prefix = "(703)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 9; + } + + 704 + { + title = "Slope Frontside Floor by 3 Tagged Vertex Things"; + prefix = "(704)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + flags8192text = "[13] Use tag and offsets"; + slope = "vertex"; + slopeargs = 0; + } + + 705 + { + title = "Slope Frontside Ceiling by 3 Tagged Vertex Things"; + prefix = "(705)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + flags8192text = "[13] Use tag and offsets"; + slope = "vertex"; + slopeargs = 1; + } + + 710 + { + title = "Slope Backside Floor"; + prefix = "(710)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 4; + } + + 711 + { + title = "Slope Backside Ceiling"; + prefix = "(711)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 8; + } + + 712 + { + title = "Slope Backside Floor and Ceiling"; + prefix = "(712)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 12; + } + + 713 + { + title = "Slope Backside Floor and Frontside Ceiling"; + prefix = "(713)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + slope = "regular"; + slopeargs = 6; + } + + 714 + { + title = "Slope Backside Floor by 3 Tagged Vertex Things"; + prefix = "(714)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + flags8192text = "[13] Use tag and offsets"; + slope = "vertex"; + slopeargs = 2; + } + + 715 + { + title = "Slope Backside Ceiling by 3 Tagged Vertex Things"; + prefix = "(715)"; + flags2048text = "[11] No physics"; + flags4096text = "[12] Dynamic"; + flags8192text = "[13] Use tag and offsets"; + slope = "vertex"; + slopeargs = 3; + } + + 720 + { + title = "Copy Frontside Floor Slope from Line Tag"; + prefix = "(720)"; + slope = "copy"; + slopeargs = 1; + } + + 721 + { + title = "Copy Frontside Ceiling Slope from Line Tag"; + prefix = "(721)"; + slope = "copy"; + slopeargs = 2; + } + + 722 + { + title = "Copy Frontside Floor and Ceiling Slope from Line Tag"; + prefix = "(722)"; + slope = "copy"; + slopeargs = 3; + } + + 799 + { + title = "Set Tagged Dynamic Slope Vertex to Front Sector Height"; + prefix = "(799)"; + } + } + + transwall + { + title = "Translucent Wall"; + + 900 + { + title = "90% Opaque"; + prefix = "(900)"; + } + + 901 + { + title = "80% Opaque"; + prefix = "(901)"; + } + + 902 + { + title = "70% Opaque"; + prefix = "(902)"; + } + + 903 + { + title = "60% Opaque"; + prefix = "(903)"; + } + + 904 + { + title = "50% Opaque"; + prefix = "(904)"; + } + + 905 + { + title = "40% Opaque"; + prefix = "(905)"; + } + + 906 + { + title = "30% Opaque"; + prefix = "(906)"; + } + + 907 + { + title = "20% Opaque"; + prefix = "(907)"; + } + + 908 + { + title = "10% Opaque"; + prefix = "(908)"; + } + + 909 + { + title = "Fog Wall"; + prefix = "(909)"; + } + } +} + + +// THING FLAGS +thingflags +{ + 1 = "[1] Extra"; + 2 = "[2] Flip"; + 4 = "[4] Special"; + 8 = "[8] 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 = "skill1"; + 2 = "skill2"; + 4 = "skill3"; + 8 = "ambush"; +} + +// THING FLAGS ERROR MASK +// Mask for the thing flags which indicates the options +// that make the same thing appear in the same modes +thingflagsmask1 = 7; // 1 + 2 + 4 +thingflagsmask2 = 0; + + +// THING TYPES------------------------------------------------------------------ +// Color values: 1-Dark_Blue 2-Dark_Green 3-Turqoise 4-Dark_Red 5-Purple 6-Brown 7-Gray +// 8-Dark_Gray 9-Blue 10-Green 11-Cyan 12-Red 13-Magenta +// 14-Yellow 15-White 16-Pink 17-Orange 18-Gold 19-Cream +thingtypes +{ + editor + { + color = 15; // White + arrow = 1; + title = ""; + error = -1; + width = 8; + height = 16; + sort = 1; + + 3328 = "3D Mode Start"; + } + + starts + { + color = 1; // Blue + arrow = 1; + title = "Player Starts"; + width = 16; + height = 48; + flags8text = "[8] Spawn on ceiling"; + sprite = "PLAYA0"; + + 1 + { + title = "Player 01 Start"; + sprite = "PLAYA0"; + } + 2 + { + title = "Player 02 Start"; + sprite = "PLAYA0"; + } + 3 + { + title = "Player 03 Start"; + sprite = "PLAYA0"; + } + 4 + { + title = "Player 04 Start"; + sprite = "PLAYA0"; + } + 5 + { + title = "Player 05 Start"; + sprite = "PLAYA0"; + } + 6 + { + title = "Player 06 Start"; + sprite = "PLAYA0"; + } + 7 + { + title = "Player 07 Start"; + sprite = "PLAYA0"; + } + 8 + { + title = "Player 08 Start"; + sprite = "PLAYA0"; + } + 9 + { + title = "Player 09 Start"; + sprite = "PLAYA0"; + } + 10 + { + title = "Player 10 Start"; + sprite = "PLAYA0"; + } + 11 + { + title = "Player 11 Start"; + sprite = "PLAYA0"; + } + 12 + { + title = "Player 12 Start"; + sprite = "PLAYA0"; + } + 13 + { + title = "Player 13 Start"; + sprite = "PLAYA0"; + } + 14 + { + title = "Player 14 Start"; + sprite = "PLAYA0"; + } + 15 + { + title = "Player 15 Start"; + sprite = "PLAYA0"; + } + 16 + { + title = "Player 16 Start"; + sprite = "PLAYA0"; + } + 17 + { + title = "Player 17 Start"; + sprite = "PLAYA0"; + } + 18 + { + title = "Player 18 Start"; + sprite = "PLAYA0"; + } + 19 + { + title = "Player 19 Start"; + sprite = "PLAYA0"; + } + 20 + { + title = "Player 20 Start"; + sprite = "PLAYA0"; + } + 21 + { + title = "Player 21 Start"; + sprite = "PLAYA0"; + } + 22 + { + title = "Player 22 Start"; + sprite = "PLAYA0"; + } + 23 + { + title = "Player 23 Start"; + sprite = "PLAYA0"; + } + 24 + { + title = "Player 24 Start"; + sprite = "PLAYA0"; + } + 25 + { + title = "Player 25 Start"; + sprite = "PLAYA0"; + } + 26 + { + title = "Player 26 Start"; + sprite = "PLAYA0"; + } + 27 + { + title = "Player 27 Start"; + sprite = "PLAYA0"; + } + 28 + { + title = "Player 28 Start"; + sprite = "PLAYA0"; + } + 29 + { + title = "Player 29 Start"; + sprite = "PLAYA0"; + } + 30 + { + title = "Player 30 Start"; + sprite = "PLAYA0"; + } + 31 + { + title = "Player 31 Start"; + sprite = "PLAYA0"; + } + 32 + { + title = "Player 32 Start"; + sprite = "PLAYA0"; + } + 33 + { + title = "Match Start"; + sprite = "NDRNA2A8"; + } + 34 + { + title = "CTF Red Team Start"; + sprite = "SIGNG0"; + } + 35 + { + title = "CTF Blue Team Start"; + sprite = "SIGNE0"; + } + } + + enemies + { + color = 9; // Light_Blue + arrow = 1; + title = "Enemies"; + + 100 + { + title = "Crawla (Blue)"; + sprite = "POSSA1"; + width = 24; + height = 32; + } + 101 + { + title = "Crawla (Red)"; + sprite = "SPOSA1"; + width = 24; + height = 32; + } + 102 + { + title = "Stupid Dumb Unnamed RoboFish"; + sprite = "FISHA0"; + width = 8; + height = 28; + angletext = "Jump strength"; + } + 103 + { + title = "Buzz (Gold)"; + sprite = "BUZZA1"; + width = 28; + height = 40; + flags8text = "[8] Cannot move"; + } + 104 + { + title = "Buzz (Red)"; + sprite = "RBUZA1"; + width = 28; + height = 40; + flags8text = "[8] Cannot move"; + } + 108 + { + title = "Deton"; + sprite = "DETNA1"; + width = 20; + height = 32; + } + 110 + { + title = "Turret"; + sprite = "TRETA1"; + width = 16; + height = 32; + } + 111 + { + title = "Pop-up Turret"; + sprite = "TURRI1"; + width = 12; + height = 64; + angletext = "Firing delay"; + } + 122 + { + title = "Spring Shell (Green)"; + sprite = "SSHLA1"; + width = 24; + height = 40; + } + 125 + { + title = "Spring Shell (Yellow)"; + sprite = "SSHLI1"; + width = 24; + height = 40; + } + 109 + { + title = "Skim"; + sprite = "SKIMA1"; + width = 16; + height = 24; + } + 113 + { + title = "Jet Jaw"; + sprite = "JJAWA3A7"; + width = 12; + height = 20; + } + 126 + { + title = "Crushstacean"; + sprite = "CRABA0"; + width = 24; + height = 32; + flags8text = "[8] Move left from spawn"; + } + 138 + { + title = "Banpyura"; + sprite = "CR2BA0"; + width = 24; + height = 32; + flags8text = "[8] Move left from spawn"; + } + 117 + { + title = "Robo-Hood"; + sprite = "ARCHA1"; + width = 24; + height = 32; + } + 118 + { + title = "CastleBot FaceStabber"; + sprite = "CBFSA1"; + width = 32; + height = 72; + } + 1113 + { + title = "Suspicious FaceStabber Statue"; + sprite = "CBBSA1"; + width = 32; + height = 72; + } + 119 + { + title = "Egg Guard"; + sprite = "ESHIA1"; + width = 16; + height = 48; + flags1text = "[1] 90 degrees counter-clockwise"; + flags4text = "[4] 90 degrees clockwise"; + flags8text = "[8] Double speed"; + } + 115 + { + title = "Bird Aircraft Strike Hazard"; + sprite = "VLTRF1"; + width = 12; + height = 24; + } + 120 + { + title = "Green Snapper"; + sprite = "GSNPA1"; + width = 24; + height = 24; + } + 121 + { + title = "Minus"; + sprite = "MNUSA1"; + width = 24; + height = 32; + } + 134 + { + title = "Canarivore"; + sprite = "CANAA0"; + width = 12; + height = 80; + hangs = 1; + } + 123 + { + title = "Unidus"; + sprite = "UNIDA1"; + width = 18; + height = 36; + } + 135 + { + title = "Pterabyte Spawner"; + sprite = "PTERA2A8"; + width = 16; + height = 16; + parametertext = "No. Pterabytes"; + } + 136 + { + title = "Pyre Fly"; + sprite = "PYREA0"; + width = 24; + height = 34; + flags8text = "[8] Start on fire"; + } + 105 + { + title = "Jetty-Syn Bomber"; + sprite = "JETBB1"; + width = 20; + height = 50; + flags8text = "[8] Cannot move"; + } + 106 + { + title = "Jetty-Syn Gunner"; + sprite = "JETGB1"; + width = 20; + height = 48; + flags8text = "[8] Cannot move"; + } + 112 + { + title = "Spincushion"; + sprite = "SHRPA1"; + width = 16; + height = 24; + } + 114 + { + title = "Snailer"; + sprite = "SNLRA3A7"; + width = 24; + height = 48; + } + 129 + { + title = "Penguinator"; + sprite = "PENGA1"; + width = 24; + height = 32; + } + 130 + { + title = "Pophat"; + sprite = "POPHA1"; + width = 24; + height = 32; + } + 107 + { + title = "Crawla Commander"; + sprite = "CCOMA1"; + width = 16; + height = 32; + } + 131 + { + title = "Spinbobert"; + sprite = "SBOBB0"; + width = 32; + height = 32; + } + 132 + { + title = "Cacolantern"; + sprite = "CACOA0"; + width = 32; + height = 32; + flags8text = "[8] Cannot move"; + } + 133 + { + title = "Hangster"; + sprite = "HBATC1"; + width = 24; + height = 24; + hangs = 1; + } + 127 + { + title = "Hive Elemental"; + sprite = "HIVEA0"; + width = 32; + height = 80; + parametertext = "No. bees"; + } + 128 + { + title = "Bumblebore"; + sprite = "BUMBA1"; + width = 16; + height = 32; + } + 124 + { + title = "AquaBuzz"; + sprite = "BBUZA1"; + width = 20; + height = 24; + } + 116 + { + title = "Pointy"; + sprite = "PNTYA1"; + width = 8; + height = 16; + } + } + + bosses + { + color = 8; // Dark_Gray + arrow = 1; + title = "Bosses"; + + 200 + { + title = "Egg Mobile"; + sprite = "EGGMA1"; + width = 24; + height = 76; + flags4text = "[4] End level on death"; + flags8text = "[8] Alternate laser attack"; + } + 201 + { + title = "Egg Slimer"; + sprite = "EGGNA1"; + width = 24; + height = 76; + flags4text = "[4] End level on death"; + flags8text = "[8] Speed up when hit"; + } + 202 + { + title = "Sea Egg"; + sprite = "EGGOA1"; + width = 32; + height = 116; + flags4text = "[4] End level on death"; + } + 203 + { + title = "Egg Colosseum"; + sprite = "EGGPA1"; + width = 24; + height = 76; + flags4text = "[4] End level on death"; + } + 204 + { + title = "Fang"; + sprite = "FANGA1"; + width = 24; + height = 60; + flags1text = "[1] Grayscale mode"; + flags4text = "[4] End level on death"; + } + 206 + { + title = "Brak Eggman (Old)"; + sprite = "BRAKB1"; + width = 48; + height = 160; + flags4text = "[4] End level on death"; + } + 207 + { + title = "Metal Sonic (Race)"; + sprite = "METLI1"; + width = 16; + height = 48; + flags1text = "[1] Grayscale mode"; + } + 208 + { + title = "Metal Sonic (Battle)"; + sprite = "METLC1"; + width = 16; + height = 48; + flags1text = "[1] Grayscale mode"; + flags4text = "[4] End level on death"; + } + 209 + { + title = "Brak Eggman"; + sprite = "BRAK01"; + width = 48; + height = 160; + flags4text = "[4] End level on death"; + flags8text = "[8] Electric barrier"; + } + 290 + { + arrow = 0; + title = "Boss Escape Point"; + width = 8; + height = 16; + sprite = "internal:eggmanend"; + } + 291 + { + arrow = 0; + title = "Egg Capsule Center"; + width = 8; + height = 16; + sprite = "internal:capsule"; + } + 292 + { + arrow = 0; + title = "Boss Waypoint"; + width = 8; + height = 16; + flags8text = "[8] Sea Egg shooting point"; + sprite = "internal:eggmanway"; + angletext = "No. (Sea Egg)"; + flagsvaluetext = "No. (Brak)"; + parametertext = "Next"; + } + 293 + { + title = "Metal Sonic Gather Point"; + sprite = "internal:metal"; + width = 8; + height = 16; + } + 294 + { + title = "Fang Waypoint"; + flags8text = "[8] Center waypoint"; + sprite = "internal:eggmanway"; + width = 8; + height = 16; + } + } + + rings + { + color = 14; // Yellow + title = "Rings and Weapon Panels"; + width = 24; + height = 24; + flags8height = 24; + flags8text = "[8] Float"; + sprite = "RINGA0"; + + 300 + { + title = "Ring"; + sprite = "RINGA0"; + width = 16; + } + 301 + { + title = "Bounce Ring"; + sprite = "internal:RNGBA0"; + } + 302 + { + title = "Rail Ring"; + sprite = "internal:RNGRA0"; + } + 303 + { + title = "Infinity Ring"; + sprite = "internal:RNGIA0"; + } + 304 + { + title = "Automatic Ring"; + sprite = "internal:RNGAA0"; + } + 305 + { + title = "Explosion Ring"; + sprite = "internal:RNGEA0"; + } + 306 + { + title = "Scatter Ring"; + sprite = "internal:RNGSA0"; + } + 307 + { + title = "Grenade Ring"; + sprite = "internal:RNGGA0"; + } + 308 + { + title = "CTF Team Ring (Red)"; + sprite = "internal:RRNGA0"; + width = 16; + } + 309 + { + title = "CTF Team Ring (Blue)"; + sprite = "internal:BRNGA0"; + width = 16; + } + 330 + { + title = "Bounce Ring Panel"; + sprite = "internal:PIKBA0"; + } + 331 + { + title = "Rail Ring Panel"; + sprite = "internal:PIKRA0"; + } + 332 + { + title = "Automatic Ring Panel"; + sprite = "internal:PIKAA0"; + } + 333 + { + title = "Explosion Ring Panel"; + sprite = "internal:PIKEA0"; + } + 334 + { + title = "Scatter Ring Panel"; + sprite = "internal:PIKSA0"; + } + 335 + { + title = "Grenade Ring Panel"; + sprite = "internal:PIKGA0"; + } + } + + collectibles + { + color = 10; // Light_Green + title = "Other Collectibles"; + width = 16; + height = 32; + sort = 1; + sprite = "CEMGA0"; + + 310 + { + title = "CTF Red Flag"; + sprite = "RFLGA0"; + width = 24; + height = 64; + } + 311 + { + title = "CTF Blue Flag"; + sprite = "BFLGA0"; + width = 24; + height = 64; + } + 312 + { + title = "Emerald Token"; + sprite = "TOKEA0"; + width = 16; + height = 32; + flags8height = 24; + flags8text = "[8] Float"; + } + 313 + { + title = "Chaos Emerald 1 (Green)"; + sprite = "CEMGA0"; + } + 314 + { + title = "Chaos Emerald 2 (Purple)"; + sprite = "CEMGB0"; + } + 315 + { + title = "Chaos Emerald 3 (Blue)"; + sprite = "CEMGC0"; + } + 316 + { + title = "Chaos Emerald 4 (Cyan)"; + sprite = "CEMGD0"; + } + 317 + { + title = "Chaos Emerald 5 (Orange)"; + sprite = "CEMGE0"; + } + 318 + { + title = "Chaos Emerald 6 (Red)"; + sprite = "CEMGF0"; + } + 319 + { + title = "Chaos Emerald 7 (Gray)"; + sprite = "CEMGG0"; + } + 320 + { + title = "Emerald Hunt Location"; + sprite = "SHRDA0"; + } + 321 + { + title = "Match Chaos Emerald Spawn"; + sprite = "CEMGA0"; + flags8height = 24; + flags8text = "[8] Float"; + } + 322 + { + title = "Emblem"; + sprite = "EMBMA0"; + width = 16; + height = 30; + flags8height = 24; + flags8text = "[8] Float"; + angletext = "Tag"; + } + } + + boxes + { + color = 7; // Gray + blocking = 2; + title = "Monitors"; + width = 18; + height = 40; + flags1text = "[1] Run Linedef Executor on pop"; + flags4text = "[4] Random (Strong)"; + flags8text = "[8] Random (Weak)"; + + 400 + { + title = "Super Ring (10 Rings)"; + sprite = "TVRIA0"; + } + 401 + { + title = "Pity Shield"; + sprite = "TVPIA0"; + } + 402 + { + title = "Attraction Shield"; + sprite = "TVATA0"; + } + 403 + { + title = "Force Shield"; + sprite = "TVFOA0"; + } + 404 + { + title = "Armageddon Shield"; + sprite = "TVARA0"; + } + 405 + { + title = "Whirlwind Shield"; + sprite = "TVWWA0"; + } + 406 + { + title = "Elemental Shield"; + sprite = "TVELA0"; + } + 407 + { + title = "Super Sneakers"; + sprite = "TVSSA0"; + } + 408 + { + title = "Invincibility"; + sprite = "TVIVA0"; + } + 409 + { + title = "Extra Life"; + sprite = "TV1UA0"; + flags4text = "[4] Random (Strong) / 10k points"; + flags8text = "[8] Random (Weak) / 10k points"; + } + 410 + { + title = "Eggman"; + sprite = "TVEGA0"; + flags4text = "[4] Special"; + flags8text = "[8] Ambush"; + } + 411 + { + title = "Teleporter"; + sprite = "TVMXA0"; + } + 413 + { + title = "Gravity Boots"; + sprite = "TVGVA0"; + flags4text = "[4] Special"; + flags8text = "[8] Ambush"; + } + 414 + { + title = "CTF Team Ring Monitor (Red)"; + sprite = "TRRIA0"; + flags4text = "[4] Special"; + flags8text = "[8] Ambush"; + } + 415 + { + title = "CTF Team Ring Monitor (Blue)"; + sprite = "TBRIA0"; + flags4text = "[4] Special"; + flags8text = "[8] Ambush"; + } + 416 + { + title = "Recycler"; + sprite = "TVRCA0"; + } + 418 + { + title = "Score (1,000 Points)"; + sprite = "TV1KA0"; + flags4text = "[4] Special"; + flags8text = "[8] Ambush"; + } + 419 + { + title = "Score (10,000 Points)"; + sprite = "TVTKA0"; + flags4text = "[4] Special"; + flags8text = "[8] Ambush"; + } + 420 + { + title = "Flame Shield"; + sprite = "TVFLA0"; + } + 421 + { + title = "Water Shield"; + sprite = "TVBBA0"; + } + 422 + { + title = "Lightning Shield"; + sprite = "TVZPA0"; + } + } + + boxes2 + { + color = 18; // Gold + blocking = 2; + title = "Monitors (Respawning)"; + width = 20; + height = 44; + flags1text = "[1] Run Linedef Executor on pop"; + + 431 + { + title = "Pity Shield (Respawn)"; + sprite = "TVPIB0"; + } + 432 + { + title = "Attraction Shield (Respawn)"; + sprite = "TVATB0"; + } + 433 + { + title = "Force Shield (Respawn)"; + sprite = "TVFOB0"; + } + 434 + { + title = "Armageddon Shield (Respawn)"; + sprite = "TVARB0"; + } + 435 + { + title = "Whirlwind Shield (Respawn)"; + sprite = "TVWWB0"; + } + 436 + { + title = "Elemental Shield (Respawn)"; + sprite = "TVELB0"; + } + 437 + { + title = "Super Sneakers (Respawn)"; + sprite = "TVSSB0"; + } + 438 + { + title = "Invincibility (Respawn)"; + sprite = "TVIVB0"; + } + 440 + { + title = "Eggman (Respawn)"; + sprite = "TVEGB0"; + } + 443 + { + title = "Gravity Boots (Respawn)"; + sprite = "TVGVB0"; + } + 450 + { + title = "Flame Shield (Respawn)"; + sprite = "TVFLB0"; + } + 451 + { + title = "Water Shield (Respawn)"; + sprite = "TVBBB0"; + } + 452 + { + title = "Lightning Shield (Respawn)"; + sprite = "TVZPB0"; + } + } + + generic + { + color = 11; // Light_Cyan + title = "Generic Items & Hazards"; + + 500 + { + title = "Air Bubble Patch"; + sprite = "BUBLE0"; + width = 8; + height = 16; + flags8text = "[8] No distance check"; + } + 501 + { + title = "Signpost"; + sprite = "SIGND0"; + width = 8; + height = 32; + } + 502 + { + arrow = 1; + title = "Star Post"; + sprite = "STPTA0M0"; + width = 64; + height = 128; + angletext = "Angle/Order"; + } + 520 + { + title = "Bomb Sphere"; + sprite = "SPHRD0"; + width = 16; + height = 24; + flags8height = 24; + flags8text = "[8] Float"; + unflippable = true; + } + 521 + { + title = "Spikeball"; + sprite = "SPIKA0"; + width = 12; + height = 8; + flags8height = 24; + flags8text = "[8] Float"; + } + 522 + { + title = "Wall Spike"; + sprite = "WSPKALAR"; + width = 16; + height = 14; + flags1text = "[1] Start retracted"; + flags4text = "[4] Retractable"; + flags8text = "[8] Intangible"; + parametertext = "Initial delay"; + } + 523 + { + title = "Spike"; + sprite = "USPKA0"; + width = 8; + height = 32; + flags1text = "[1] Start retracted"; + flags4text = "[4] Retractable"; + flags8text = "[8] Intangible"; + angletext = "Retraction interval"; + parametertext = "Initial delay"; + } + 1130 + { + title = "Small Mace"; + sprite = "SMCEA0"; + width = 17; + height = 34; + } + 1131 + { + title = "Big Mace"; + sprite = "BMCEA0"; + width = 34; + height = 68; + } + 1136 + { + title = "Small Fireball"; + sprite = "SFBRA0"; + width = 17; + height = 34; + } + 1137 + { + title = "Large Fireball"; + sprite = "BFBRA0"; + width = 34; + height = 68; + } + } + + springs + { + color = 12; // Light_Red + title = "Springs and Fans"; + width = 20; + height = 16; + sprite = "RSPRD2"; + + 540 + { + title = "Fan"; + sprite = "FANSA0D0"; + width = 16; + height = 8; + flags4text = "[4] Invisible"; + flags8text = "[8] No distance check"; + angletext = "Lift height"; + } + 541 + { + title = "Gas Jet"; + sprite = "STEMD0"; + flags8text = "[8] No sounds"; + width = 32; + } + 542 + { + title = "Bumper"; + sprite = "BUMPA0"; + width = 32; + height = 64; + angletext = "Strength"; + } + 543 + { + title = "Balloon"; + sprite = "BLONA0"; + width = 32; + height = 64; + flags8text = "[8] Respawn"; + angletext = "Color"; + } + 550 + { + title = "Yellow Spring"; + sprite = "SPRYA0"; + } + 551 + { + title = "Red Spring"; + sprite = "SPRRA0"; + } + 552 + { + title = "Blue Spring"; + sprite = "SPRBA0"; + } + 555 + { + arrow = 1; + title = "Diagonal Yellow Spring"; + sprite = "YSPRD2"; + width = 16; + flags4text = "[4] Ignore gravity"; + flags8text = "[8] Rotate 22.5° CCW"; + } + 556 + { + arrow = 1; + title = "Diagonal Red Spring"; + sprite = "RSPRD2"; + width = 16; + flags4text = "[4] Ignore gravity"; + flags8text = "[8] Rotate 22.5° CCW"; + } + 557 + { + arrow = 1; + title = "Diagonal Blue Spring"; + sprite = "BSPRD2"; + width = 16; + flags4text = "[4] Ignore gravity"; + flags8text = "[8] Rotate 22.5° CCW"; + } + 558 + { + arrow = 1; + title = "Horizontal Yellow Spring"; + sprite = "SSWYD2D8"; + flags8height = 16; + flags8text = "[8] Float"; + width = 16; + height = 32; + } + 559 + { + arrow = 1; + title = "Horizontal Red Spring"; + sprite = "SSWRD2D8"; + flags8height = 16; + flags8text = "[8] Float"; + width = 16; + height = 32; + } + 560 + { + arrow = 1; + title = "Horizontal Blue Spring"; + sprite = "SSWBD2D8"; + flags8height = 16; + flags8text = "[8] Float"; + width = 16; + height = 32; + } + 1134 + { + title = "Yellow Spring Ball"; + sprite = "YSPBA0"; + width = 17; + height = 34; + } + 1135 + { + title = "Red Spring Ball"; + sprite = "RSPBA0"; + width = 17; + height = 34; + } + 544 + { + arrow = 1; + title = "Yellow Boost Panel"; + sprite = "BSTYA0"; + flags8text = "[8] Force spin"; + width = 28; + height = 2; + } + 545 + { + arrow = 1; + title = "Red Boost Panel"; + sprite = "BSTRA0"; + flags8text = "[8] Force spin"; + width = 28; + height = 2; + } + } + + patterns + { + color = 5; // Magenta + arrow = 1; + title = "Special Placement Patterns"; + width = 16; + height = 384; + sprite = "RINGA0"; + + 600 + { + arrow = 0; + title = "5 Vertical Rings (Yellow Spring)"; + sprite = "RINGA0"; + } + 601 + { + arrow = 0; + title = "5 Vertical Rings (Red Spring)"; + sprite = "RINGA0"; + height = 1024; + } + 602 + { + title = "5 Diagonal Rings (Yellow Spring)"; + sprite = "RINGA0"; + height = 32; + } + 603 + { + title = "10 Diagonal Rings (Red Spring)"; + sprite = "RINGA0"; + height = 32; + } + 604 + { + title = "Circle of Rings"; + sprite = "RINGA0"; + width = 96; + height = 192; + unflippable = true; + centerHitbox = true; + } + 605 + { + title = "Circle of Rings (Big)"; + sprite = "RINGA0"; + width = 192; + unflippable = true; + centerHitbox = true; + } + 606 + { + title = "Circle of Blue Spheres"; + sprite = "SPHRA0"; + width = 96; + height = 192; + unflippable = true; + centerHitbox = true; + } + 607 + { + title = "Circle of Blue Spheres (Big)"; + sprite = "SPHRA0"; + width = 192; + unflippable = true; + centerHitbox = true; + } + 608 + { + title = "Circle of Rings and Spheres"; + sprite = "SPHRA0"; + width = 96; + height = 192; + unflippable = true; + centerHitbox = true; + } + 609 + { + title = "Circle of Rings and Spheres (Big)"; + sprite = "SPHRA0"; + width = 192; + unflippable = true; + centerHitbox = true; + } + } + + invisible + { + color = 15; // White + title = "Misc. Invisible"; + width = 8; + height = 16; + sprite = "UNKNA0"; + + 700 + { + title = "Water Ambience A (Large)"; + sprite = "internal:ambiance"; + } + + 701 + { + title = "Water Ambience B (Large)"; + sprite = "internal:ambiance"; + } + + 702 + { + title = "Water Ambience C (Medium)"; + sprite = "internal:ambiance"; + } + + 703 + { + title = "Water Ambience D (Medium)"; + sprite = "internal:ambiance"; + } + + 704 + { + title = "Water Ambience E (Small)"; + sprite = "internal:ambiance"; + } + + 705 + { + title = "Water Ambience F (Small)"; + sprite = "internal:ambiance"; + } + + 706 + { + title = "Water Ambience G (Extra Large)"; + sprite = "internal:ambiance"; + } + + 707 + { + title = "Water Ambience H (Extra Large)"; + sprite = "internal:ambiance"; + } + + 708 + { + title = "Disco Ambience"; + sprite = "internal:ambiance"; + } + + 709 + { + title = "Volcano Ambience"; + sprite = "internal:ambiance"; + } + + 710 + { + title = "Machine Ambience"; + sprite = "internal:ambiance"; + } + + 750 + { + title = "Slope Vertex"; + sprite = "internal:vertexslope"; + angletext = "Tag"; + } + + 751 + { + arrow = 1; + title = "Teleport Destination"; + sprite = "internal:tele"; + } + + 752 + { + arrow = 1; + title = "Alternate View Point"; + sprite = "internal:view"; + } + + 753 + { + title = "Zoom Tube Waypoint"; + sprite = "internal:zoom"; + angletext = "Order"; + } + + 754 + { + title = "Push Point"; + flags4text = "[4] Fades using XY"; + flags8text = "[8] Push using XYZ"; + sprite = "GWLGA0"; + angletext = "Radius"; + } + 755 + { + title = "Pull Point"; + flags4text = "[4] Fades using XY"; + flags8text = "[8] Pull using XYZ"; + sprite = "GWLRA0"; + angletext = "Radius"; + } + 756 + { + title = "Blast Linedef Executor"; + sprite = "TOADA0"; + width = 32; + height = 16; + } + 757 + { + title = "Fan Particle Generator"; + sprite = "PRTLA0"; + width = 8; + height = 16; + angletext = "Tag"; + } + 758 + { + title = "Object Angle Anchor"; + sprite = "internal:view"; + } + 760 + { + title = "PolyObject Anchor"; + sprite = "internal:polyanchor"; + angletext = "ID"; + } + + 761 + { + title = "PolyObject Spawn Point"; + sprite = "internal:polycenter"; + angletext = "ID"; + } + + 762 + { + title = "PolyObject Spawn Point (Crush)"; + sprite = "internal:polycentercrush"; + angletext = "ID"; + } + 780 + { + title = "Skybox View Point"; + sprite = "internal:skyb"; + flags4text = "[4] In-map centerpoint"; + parametertext = "ID"; + } + } + + greenflower + { + color = 10; // Green + title = "Greenflower"; + + 800 + { + title = "GFZ Flower"; + sprite = "FWR1A0"; + width = 16; + height = 40; + } + 801 + { + title = "Sunflower"; + sprite = "FWR2A0"; + width = 16; + height = 96; + } + 802 + { + title = "Budding Flower"; + sprite = "FWR3A0"; + width = 8; + height = 32; + } + 803 + { + title = "Blueberry Bush"; + sprite = "BUS3A0"; + width = 16; + height = 32; + } + 804 + { + title = "Berry Bush"; + sprite = "BUS1A0"; + width = 16; + height = 32; + } + 805 + { + title = "Bush"; + sprite = "BUS2A0"; + width = 16; + height = 32; + } + 806 + { + title = "GFZ Tree"; + sprite = "TRE1A0"; + width = 20; + height = 128; + } + 807 + { + title = "GFZ Berry Tree"; + sprite = "TRE1B0"; + width = 20; + height = 128; + } + 808 + { + title = "GFZ Cherry Tree"; + sprite = "TRE1C0"; + width = 20; + height = 128; + } + 809 + { + title = "Checkered Tree"; + sprite = "TRE2A0"; + width = 20; + height = 200; + } + 810 + { + title = "Checkered Tree (Sunset)"; + sprite = "TRE2B0"; + width = 20; + height = 200; + } + 811 + { + title = "Polygon Tree"; + sprite = "TRE4A0"; + width = 20; + height = 200; + } + 812 + { + title = "Bush Tree"; + sprite = "TRE5A0"; + width = 20; + height = 200; + } + 813 + { + title = "Red Bush Tree"; + sprite = "TRE5B0"; + width = 20; + height = 200; + } + } + + technohill + { + color = 10; // Green + title = "Techno Hill"; + + 900 + { + title = "THZ Steam Flower"; + sprite = "THZPA0"; + width = 8; + height = 32; + } + 901 + { + title = "Alarm"; + sprite = "ALRMA0"; + width = 8; + height = 16; + hangs = 1; + } + 902 + { + title = "THZ Spin Flower (Red)"; + sprite = "FWR5A0"; + width = 16; + height = 64; + } + 903 + { + title = "THZ Spin Flower (Yellow)"; + sprite = "FWR6A0"; + width = 16; + height = 64; + } + 904 + { + arrow = 1; + title = "Whistlebush"; + sprite = "THZTA0"; + width = 16; + height = 64; + } + } + + deepsea + { + color = 10; // Green + title = "Deep Sea"; + + 1000 + { + arrow = 1; + blocking = 2; + title = "Gargoyle"; + sprite = "GARGA1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1009 + { + arrow = 1; + blocking = 2; + title = "Gargoyle (Big)"; + sprite = "GARGB1"; + width = 32; + height = 80; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1001 + { + title = "Seaweed"; + sprite = "SEWEA0"; + width = 24; + height = 56; + } + 1002 + { + title = "Dripping Water"; + sprite = "DRIPD0"; + width = 8; + height = 16; + hangs = 1; + angletext = "Dripping interval"; + } + 1003 + { + title = "Coral (Green)"; + sprite = "CORLA0"; + width = 29; + height = 40; + } + 1004 + { + title = "Coral (Red)"; + sprite = "CORLB0"; + width = 30; + height = 53; + } + 1005 + { + title = "Coral (Orange)"; + sprite = "CORLC0"; + width = 28; + height = 41; + } + 1006 + { + title = "Blue Crystal"; + sprite = "BCRYA1"; + width = 8; + height = 16; + } + 1007 + { + title = "Kelp"; + sprite = "KELPA0"; + width = 16; + height = 292; + flags4text = "[4] Double size"; + } + 1008 + { + title = "Stalagmite (DSZ1)"; + sprite = "DSTGA0"; + width = 8; + height = 116; + flags4text = "[4] Double size"; + } + 1010 + { + arrow = 1; + title = "Light Beam"; + sprite = "LIBEARAL"; + width = 16; + height = 16; + } + 1011 + { + title = "Stalagmite (DSZ2)"; + sprite = "DSTGA0"; + width = 8; + height = 116; + flags4text = "[4] Double size"; + } + 1012 + { + arrow = 1; + title = "Big Floating Mine"; + width = 28; + height = 56; + sprite = "BMNEA1"; + } + 1013 + { + title = "Animated Kelp"; + sprite = "ALGAA0"; + width = 48; + height = 120; + } + 1014 + { + title = "Large Coral (Brown)"; + sprite = "CORLD0"; + width = 56; + height = 112; + } + 1015 + { + title = "Large Coral (Beige)"; + sprite = "CORLE0"; + width = 56; + height = 112; + } + } + + castleeggman + { + color = 10; // Green + title = "Castle Eggman"; + + 1100 + { + title = "Chain (Decorative)"; + sprite = "CHANA0"; + width = 4; + height = 128; + hangs = 1; + } + 1101 + { + title = "Torch"; + sprite = "FLAMA0E0"; + width = 8; + height = 32; + flags1text = "[1] Add corona"; + } + 1102 + { + arrow = 1; + blocking = 2; + title = "Eggman Statue"; + sprite = "ESTAA1"; + width = 32; + height = 240; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1103 + { + title = "CEZ Flower"; + sprite = "FWR4A0"; + width = 16; + height = 40; + } + 1104 + { + title = "Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + flags8text = "[8] Double size"; + angletext = "Tag"; + } + 1105 + { + title = "Chain with Maces Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + flags8text = "[8] Double size"; + angletext = "Tag"; + } + 1106 + { + title = "Chained Spring Spawnpoint"; + sprite = "YSPBA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + flags8text = "[8] Red spring"; + angletext = "Tag"; + } + 1107 + { + title = "Chain Spawnpoint"; + sprite = "BMCHA0"; + width = 17; + height = 34; + flags8text = "[8] Double size"; + angletext = "Tag"; + } + 1108 + { + arrow = 1; + title = "Hidden Chain Spawnpoint"; + sprite = "internal:chain3"; + width = 17; + height = 34; + flags8text = "[8] Double size"; + } + 1109 + { + title = "Firebar Spawnpoint"; + sprite = "BFBRA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + flags8text = "[8] Double size"; + angletext = "Tag"; + } + 1110 + { + title = "Custom Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + angletext = "Tag"; + } + 1111 + { + arrow = 1; + blocking = 2; + title = "Crawla Statue"; + sprite = "CSTAA1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1112 + { + arrow = 1; + blocking = 2; + title = "FaceStabber Statue"; + sprite = "CBBSA1"; + width = 32; + height = 72; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1114 + { + title = "Pine Tree"; + sprite = "PINEA0"; + width = 16; + height = 628; + } + 1115 + { + title = "CEZ Shrub (Small)"; + sprite = "CEZBA0"; + width = 16; + height = 24; + } + 1116 + { + title = "CEZ Shrub (Large)"; + sprite = "CEZBB0"; + width = 32; + height = 48; + } + 1117 + { + arrow = 1; + title = "Pole Banner (Red)"; + sprite = "BANRA0"; + width = 40; + height = 224; + } + 1118 + { + arrow = 1; + title = "Pole Banner (Blue)"; + sprite = "BANRA0"; + width = 40; + height = 224; + } + 1119 + { + title = "Candle"; + sprite = "CNDLA0"; + width = 8; + height = 48; + flags1text = "[1] Add corona"; + } + 1120 + { + title = "Candle Pricket"; + sprite = "CNDLB0"; + width = 8; + height = 176; + flags1text = "[1] Add corona"; + } + 1121 + { + title = "Flame Holder"; + sprite = "FLMHA0"; + width = 24; + height = 80; + flags1text = "[1] Add corona"; + flags4text = "[4] No flame"; + } + 1122 + { + title = "Fire Torch"; + sprite = "CTRCA0"; + width = 16; + height = 80; + } + 1123 + { + title = "Cannonball Launcher"; + sprite = "internal:cannonball"; + width = 8; + height = 16; + } + 1124 + { + blocking = 2; + title = "Cannonball"; + sprite = "CBLLA0"; + width = 20; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1125 + { + title = "Brambles"; + sprite = "CABRALAR"; + width = 48; + height = 32; + } + 1126 + { + title = "Invisible Lockon Object"; + sprite = "LCKNC0"; + width = 16; + height = 32; + } + 1127 + { + title = "Spectator Eggrobo"; + sprite = "EGR1A1"; + width = 20; + height = 72; + } + 1128 + { + arrow = 1; + title = "Waving Flag (Red)"; + sprite = "CFLGA0"; + width = 8; + height = 208; + } + 1129 + { + arrow = 1; + title = "Waving Flag (Blue)"; + sprite = "CFLGA0"; + width = 8; + height = 208; + } + } + + aridcanyon + { + color = 10; // Green + title = "Arid Canyon"; + + 1200 + { + title = "Tumbleweed (Big)"; + sprite = "BTBLA0"; + width = 24; + height = 48; + flags8text = "[8] Moves perpetually"; + } + 1201 + { + title = "Tumbleweed (Small)"; + sprite = "STBLA0"; + width = 12; + height = 24; + flags8text = "[8] Moves perpetually"; + } + 1202 + { + arrow = 1; + title = "Rock Spawner"; + sprite = "ROIAA0"; + width = 8; + height = 16; + angletext = "Tag"; + } + 1203 + { + title = "Tiny Red Flower Cactus"; + sprite = "CACTA0"; + width = 13; + height = 24; + } + 1204 + { + title = "Small Red Flower Cactus"; + sprite = "CACTB0"; + width = 15; + height = 52; + } + 1205 + { + title = "Tiny Blue Flower Cactus"; + sprite = "CACTC0"; + width = 13; + height = 24; + } + 1206 + { + title = "Small Blue Flower Cactus"; + sprite = "CACTD0"; + width = 15; + height = 52; + } + 1207 + { + title = "Prickly Pear"; + sprite = "CACTE0"; + width = 32; + height = 96; + } + 1208 + { + title = "Barrel Cactus"; + sprite = "CACTF0"; + width = 20; + height = 128; + } + 1209 + { + title = "Tall Barrel Cactus"; + sprite = "CACTG0"; + width = 24; + height = 224; + } + 1210 + { + title = "Armed Cactus"; + sprite = "CACTH0"; + width = 24; + height = 256; + } + 1211 + { + title = "Ball Cactus"; + sprite = "CACTI0"; + width = 48; + height = 96; + } + 1212 + { + title = "Caution Sign"; + sprite = "WWSGAR"; + width = 22; + height = 64; + } + 1213 + { + title = "Cacti Sign"; + sprite = "WWS2AR"; + width = 22; + height = 64; + } + 1214 + { + title = "Sharp Turn Sign"; + sprite = "WWS3ALAR"; + width = 16; + height = 192; + } + 1215 + { + title = "Mine Oil Lamp"; + sprite = "OILLA0"; + width = 22; + height = 64; + hangs = 1; + } + 1216 + { + title = "TNT Barrel"; + sprite = "BARRA1"; + width = 24; + height = 63; + } + 1217 + { + title = "TNT Proximity Shell"; + sprite = "REMTA0"; + width = 64; + height = 40; + } + 1218 + { + title = "Dust Devil"; + sprite = "TAZDCR"; + width = 80; + height = 416; + } + 1219 + { + title = "Minecart Spawner"; + sprite = "MCRTCLFR"; + width = 22; + height = 32; + } + 1220 + { + title = "Minecart Stopper"; + sprite = "MCRTIR"; + width = 32; + height = 32; + } + 1221 + { + title = "Minecart Saloon Door"; + sprite = "SALDARAL"; + width = 96; + height = 160; + flags8text = "[8] Allow non-minecart players"; + } + 1222 + { + title = "Train Cameo Spawner"; + sprite = "TRAEBRBL"; + width = 28; + height = 32; + } + 1223 + { + title = "Train Dust Spawner"; + sprite = "ADSTA0"; + width = 4; + height = 4; + } + 1224 + { + title = "Train Steam Spawner"; + sprite = "STEAA0"; + width = 4; + height = 4; + } + 1229 + { + title = "Minecart Switch Point"; + sprite = "internal:zoom"; + width = 8; + height = 16; + flags8text = "[8] Enable switching"; + } + 1230 + { + title = "Tiny Cactus"; + sprite = "CACTJ0"; + width = 13; + height = 28; + } + 1231 + { + title = "Small Cactus"; + sprite = "CACTK0"; + width = 15; + height = 60; + } + } + + redvolcano + { + color = 10; // Green + title = "Red Volcano"; + + 1300 + { + arrow = 1; + title = "Flame Jet (Horizontal)"; + sprite = "internal:flameh"; + width = 16; + height = 40; + flags8text = "[8] Waves vertically"; + angletext = "On/Off time"; + parametertext = "Strength"; + } + 1301 + { + title = "Flame Jet (Vertical)"; + sprite = "internal:flamev"; + width = 16; + height = 40; + flags8text = "[8] Shoot downwards"; + angletext = "On/Off time"; + parametertext = "Strength"; + } + 1302 + { + title = "Spinning Flame Jet (Counter-Clockwise)"; + sprite = "internal:flame2"; + width = 16; + height = 24; + } + 1303 + { + title = "Spinning Flame Jet (Clockwise)"; + sprite = "internal:flame1"; + width = 16; + height = 24; + } + 1304 + { + title = "Lavafall"; + sprite = "LFALF0"; + width = 30; + height = 32; + angletext = "Initial delay"; + flags8text = "[8] Double size"; + } + 1305 + { + title = "Rollout Rock"; + sprite = "PUMIA1A5"; + width = 30; + height = 60; + flags8text = "[8] Non-buoyant"; + } + 1306 + { + title = "Big Fern"; + sprite = "JPLAB0"; + width = 32; + height = 48; + } + 1307 + { + title = "Jungle Palm"; + sprite = "JPLAC0"; + width = 32; + height = 48; + } + 1308 + { + title = "Torch Flower"; + sprite = "TFLOA0"; + width = 14; + height = 110; + } + 1309 + { + title = "RVZ1 Wall Vine (Long)"; + sprite = "WVINALAR"; + width = 1; + height = 288; + } + 1310 + { + title = "RVZ1 Wall Vine (Short)"; + sprite = "WVINBLBR"; + width = 1; + height = 288; + } + } + + botanicserenity + { + color = 10; // Green + title = "Botanic Serenity"; + width = 16; + height = 32; + sprite = "BSZ1A0"; + 1400 + { + title = "Tall Flower (Red)"; + sprite = "BSZ1A0"; + } + 1401 + { + title = "Tall Flower (Purple)"; + sprite = "BSZ1B0"; + } + 1402 + { + title = "Tall Flower (Blue)"; + sprite = "BSZ1C0"; + } + 1403 + { + title = "Tall Flower (Cyan)"; + sprite = "BSZ1D0"; + } + 1404 + { + title = "Tall Flower (Yellow)"; + sprite = "BSZ1E0"; + } + 1405 + { + title = "Tall Flower (Orange)"; + sprite = "BSZ1F0"; + } + 1410 + { + title = "Medium Flower (Red)"; + sprite = "BSZ2A0"; + } + 1411 + { + title = "Medium Flower (Purple)"; + sprite = "BSZ2B0"; + } + 1412 + { + title = "Medium Flower (Blue)"; + sprite = "BSZ2C0"; + } + 1413 + { + title = "Medium Flower (Cyan)"; + sprite = "BSZ2D0"; + } + 1414 + { + title = "Medium Flower (Yellow)"; + sprite = "BSZ2E0"; + } + 1415 + { + title = "Medium Flower (Orange)"; + sprite = "BSZ2F0"; + } + 1420 + { + title = "Short Flower (Red)"; + sprite = "BSZ3A0"; + } + 1421 + { + title = "Short Flower (Purple)"; + sprite = "BSZ3B0"; + } + 1422 + { + title = "Short Flower (Blue)"; + sprite = "BSZ3C0"; + } + 1423 + { + title = "Short Flower (Cyan)"; + sprite = "BSZ3D0"; + } + 1424 + { + title = "Short Flower (Yellow)"; + sprite = "BSZ3E0"; + } + 1425 + { + title = "Short Flower (Orange)"; + sprite = "BSZ3F0"; + } + 1430 + { + title = "Tulip (Red)"; + sprite = "BST1A0"; + } + 1431 + { + title = "Tulip (Purple)"; + sprite = "BST2A0"; + } + 1432 + { + title = "Tulip (Blue)"; + sprite = "BST3A0"; + } + 1433 + { + title = "Tulip (Cyan)"; + sprite = "BST4A0"; + } + 1434 + { + title = "Tulip (Yellow)"; + sprite = "BST5A0"; + } + 1435 + { + title = "Tulip (Orange)"; + sprite = "BST6A0"; + } + 1440 + { + title = "Cluster (Red)"; + sprite = "BSZ5A0"; + } + 1441 + { + title = "Cluster (Purple)"; + sprite = "BSZ5B0"; + } + 1442 + { + title = "Cluster (Blue)"; + sprite = "BSZ5C0"; + } + 1443 + { + title = "Cluster (Cyan)"; + sprite = "BSZ5D0"; + } + 1444 + { + title = "Cluster (Yellow)"; + sprite = "BSZ5E0"; + } + 1445 + { + title = "Cluster (Orange)"; + sprite = "BSZ5F0"; + } + 1450 + { + title = "Bush (Red)"; + sprite = "BSZ6A0"; + } + 1451 + { + title = "Bush (Purple)"; + sprite = "BSZ6B0"; + } + 1452 + { + title = "Bush (Blue)"; + sprite = "BSZ6C0"; + } + 1453 + { + title = "Bush (Cyan)"; + sprite = "BSZ6D0"; + } + 1454 + { + title = "Bush (Yellow)"; + sprite = "BSZ6E0"; + } + 1455 + { + title = "Bush (Orange)"; + sprite = "BSZ6F0"; + } + 1460 + { + title = "Vine (Red)"; + sprite = "BSZ7A0"; + } + 1461 + { + title = "Vine (Purple)"; + sprite = "BSZ7B0"; + } + 1462 + { + title = "Vine (Blue)"; + sprite = "BSZ7C0"; + } + 1463 + { + title = "Vine (Cyan)"; + sprite = "BSZ7D0"; + } + 1464 + { + title = "Vine (Yellow)"; + sprite = "BSZ7E0"; + } + 1465 + { + title = "Vine (Orange)"; + sprite = "BSZ7F0"; + } + 1470 + { + title = "BSZ Shrub"; + sprite = "BSZ8A0"; + } + 1471 + { + title = "BSZ Clover"; + sprite = "BSZ8B0"; + } + 1473 + { + title = "Palm Tree (Big)"; + width = 16; + height = 160; + sprite = "BSZ8D0"; + } + 1475 + { + title = "Palm Tree (Small)"; + width = 16; + height = 80; + sprite = "BSZ8F0"; + } + } + + azuretemple + { + color = 10; // Green + title = "Azure Temple"; + + 1500 + { + arrow = 1; + blocking = 2; + title = "Trapgoyle"; + sprite = "GARGA1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1501 + { + arrow = 1; + blocking = 2; + title = "Trapgoyle (Up)"; + sprite = "GARGA1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1502 + { + arrow = 1; + blocking = 2; + title = "Trapgoyle (Down)"; + sprite = "GARGA1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1503 + { + arrow = 1; + blocking = 2; + title = "Trapgoyle (Long)"; + sprite = "GARGA1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1504 + { + title = "ATZ Target"; + sprite = "RCRYB0"; + width = 24; + height = 32; + } + } + + dreamhill + { + color = 10; // Green + title = "Dream Hill"; + + 1600 + { + title = "Spring Tree"; + sprite = "TRE6A0"; + width = 16; + height = 32; + } + 1601 + { + title = "Shleep"; + sprite = "SHLPA0"; + width = 24; + height = 32; + } + 1602 + { + title = "Pian"; + sprite = "NTPNALAR"; + width = 16; + height = 32; + } + } + + nightstrk + { + color = 13; // Pink + title = "NiGHTS Track"; + width = 8; + height = 4096; + sprite = "UNKNA0"; + + 1700 + { + title = "Axis"; + sprite = "internal:axis1"; + circle = 1; + unflippable = true; + ignoreZ = true; + flagsvaluetext = "Order"; + angletext = "Radius/Direction"; + parametertext = "Mare"; + } + 1701 + { + title = "Axis Transfer"; + sprite = "internal:axis2"; + unflippable = true; + ignoreZ = true; + flagsvaluetext = "Order"; + parametertext = "Mare"; + } + 1702 + { + title = "Axis Transfer Line"; + sprite = "internal:axis3"; + unflippable = true; + ignoreZ = true; + flagsvaluetext = "Order"; + parametertext = "Mare"; + } + 1710 + { + title = "Ideya Capture"; + sprite = "CAPSA0"; + width = 72; + height = 144; + angletext = "Rings"; + parametertext = "Mare"; + } + } + + nights + { + color = 13; // Pink + title = "NiGHTS Items"; + width = 16; + height = 32; + + 1703 + { + title = "Ideya Drone"; + sprite = "NDRNA1"; + width = 16; + height = 56; + flags1text = "[1] Align player to middle"; + flags4text = "[4] Align player to top"; + flags8text = "[8] Die upon time up"; + angletext = "Time limit"; + parametertext = "Height"; + } + 1704 + { + arrow = 1; + title = "NiGHTS Bumper"; + sprite = "NBMPG3G7"; + width = 32; + height = 64; + unflippable = true; + flagsvaluetext = "Pitch"; + angletext = "Yaw"; + } + 1705 + { + arrow = 1; + title = "Hoop (Generic)"; + sprite = "HOOPA0"; + width = 80; + height = 160; + unflippable = true; + centerHitbox = true; + flagsvaluetext = "Height"; + angletext = "Pitch/Yaw"; + } + 1706 + { + title = "Blue Sphere"; + sprite = "SPHRA0"; + width = 16; + height = 24; + flags8height = 24; + flags8text = "[8] Float"; + unflippable = true; + } + 1707 + { + title = "Super Paraloop"; + sprite = "NPRUA0"; + flags4text = "[4] Bonus time only"; + flags8text = "[8] Spawn immediately"; + } + 1708 + { + title = "Drill Refill"; + sprite = "NPRUB0"; + flags4text = "[4] Bonus time only"; + flags8text = "[8] Spawn immediately"; + } + 1709 + { + title = "Nightopian Helper"; + sprite = "NPRUC0"; + flags4text = "[4] Bonus time only"; + flags8text = "[8] Spawn immediately"; + } + 1711 + { + title = "Extra Time"; + sprite = "NPRUD0"; + flags4text = "[4] Bonus time only"; + flags8text = "[8] Spawn immediately"; + } + 1712 + { + title = "Link Freeze"; + sprite = "NPRUE0"; + flags4text = "[4] Bonus time only"; + flags8text = "[8] Spawn immediately"; + } + 1713 + { + arrow = 1; + title = "Hoop (Customizable)"; + flags1text = "[1] Radius +16"; + flags2text = "[2] Radius +32"; + flags4text = "[4] Radius +64"; + flags8text = "[8] Radius +128"; + sprite = "HOOPA0"; + width = 80; + height = 160; + unflippable = true; + centerHitbox = true; + } + 1714 + { + title = "Ideya Anchor Point"; + sprite = "internal:axis1"; + width = 8; + height = 16; + parametertext = "Ideya"; + } + } + + mario + { + color = 6; // Brown + title = "Mario"; + + 1800 + { + title = "Coin"; + sprite = "COINA0"; + width = 16; + height = 24; + flags8height = 24; + flags8text = "[8] Float"; + } + 1801 + { + arrow = 1; + title = "Goomba"; + sprite = "GOOMA0"; + width = 24; + height = 32; + } + 1802 + { + arrow = 1; + title = "Goomba (Blue)"; + sprite = "BGOMA0"; + width = 24; + height = 32; + } + 1803 + { + title = "Fire Flower"; + sprite = "FFWRB0"; + width = 16; + height = 32; + } + 1804 + { + title = "Koopa Shell"; + sprite = "SHLLA1"; + width = 16; + height = 20; + } + 1805 + { + title = "Puma (Jumping Fireball)"; + sprite = "PUMAA0"; + width = 8; + height = 16; + angletext = "Jump strength"; + } + 1806 + { + title = "King Bowser"; + sprite = "KOOPA0"; + width = 16; + height = 48; + } + 1807 + { + title = "Axe"; + sprite = "MAXEA0"; + width = 8; + height = 16; + } + 1808 + { + title = "Bush (Short)"; + sprite = "MUS1A0"; + width = 16; + height = 32; + } + 1809 + { + title = "Bush (Tall)"; + sprite = "MUS2A0"; + width = 16; + height = 32; + } + 1810 + { + title = "Toad"; + sprite = "TOADA0"; + width = 8; + height = 32; + } + } + + christmasdisco + { + color = 10; // Green + title = "Christmas & Disco"; + + 1850 + { + title = "Christmas Pole"; + sprite = "XMS1A0"; + width = 16; + height = 40; + } + 1851 + { + title = "Candy Cane"; + sprite = "XMS2A0"; + width = 8; + height = 32; + } + 1852 + { + blocking = 2; + title = "Snowman"; + sprite = "XMS3A0"; + width = 16; + height = 64; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1853 + { + blocking = 2; + title = "Snowman (With Hat)"; + sprite = "XMS3B0"; + width = 16; + height = 80; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + 1854 + { + title = "Lamp Post"; + sprite = "XMS4A0"; + width = 8; + height = 120; + } + 1855 + { + title = "Lamp Post (Snow)"; + sprite = "XMS4B0"; + width = 8; + height = 120; + } + 1856 + { + title = "Hanging Star"; + sprite = "XMS5A0"; + width = 4; + height = 80; + hangs = 1; + } + 1857 + { + title = "Berry Bush (Snow)"; + sprite = "BUS1B0"; + width = 16; + height = 32; + } + 1858 + { + title = "Bush (Snow)"; + sprite = "BUS2B0"; + width = 16; + height = 32; + } + 1859 + { + title = "Blueberry Bush (Snow)"; + sprite = "BUS3B0"; + width = 16; + height = 32; + } + 1875 + { + title = "Disco Ball"; + sprite = "DBALA0"; + width = 16; + height = 54; + hangs = 1; + } + 1876 + { + arrow = 1; + blocking = 2; + title = "Eggman Disco Statue"; + sprite = "ESTAB1"; + width = 20; + height = 96; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } + } + + stalagmites + { + color = 10; // Green + title = "Stalagmites"; + width = 16; + height = 40; + + 1900 + { + title = "Brown Stalagmite (Tall)"; + sprite = "STLGA0"; + width = 16; + height = 40; + } + 1901 + { + title = "Brown Stalagmite"; + sprite = "STLGB0"; + width = 16; + height = 40; + } + 1902 + { + title = "Orange Stalagmite (Tall)"; + sprite = "STLGC0"; + width = 16; + height = 40; + } + 1903 + { + title = "Orange Stalagmite"; + sprite = "STLGD0"; + width = 16; + height = 40; + } + 1904 + { + title = "Red Stalagmite (Tall)"; + sprite = "STLGE0"; + width = 16; + height = 40; + } + 1905 + { + title = "Red Stalagmite"; + sprite = "STLGF0"; + width = 16; + height = 40; + } + 1906 + { + title = "Gray Stalagmite (Tall)"; + sprite = "STLGG0"; + width = 24; + height = 96; + } + 1907 + { + title = "Gray Stalagmite"; + sprite = "STLGH0"; + width = 16; + height = 40; + } + 1908 + { + title = "Blue Stalagmite (Tall)"; + sprite = "STLGI0"; + width = 16; + height = 40; + } + 1909 + { + title = "Blue Stalagmite"; + sprite = "STLGJ0"; + width = 16; + height = 40; + } + } + + hauntedheights + { + color = 10; // Green + title = "Haunted Heights"; + + 2000 + { + title = "Smashing Spikeball"; + sprite = "FMCEA0"; + width = 18; + height = 28; + angletext = "Initial delay"; + } + 2001 + { + title = "HHZ Grass"; + sprite = "HHZMA0"; + width = 16; + height = 40; + } + 2002 + { + title = "HHZ Tentacle 1"; + sprite = "HHZMB0"; + width = 16; + height = 40; + } + 2003 + { + title = "HHZ Tentacle 2"; + sprite = "HHZMC0"; + width = 16; + height = 40; + } + 2004 + { + title = "HHZ Stalagmite (Tall)"; + sprite = "HHZME0"; + width = 16; + height = 40; + } + 2005 + { + title = "HHZ Stalagmite (Short)"; + sprite = "HHZMF0"; + width = 16; + height = 40; + } + 2006 + { + title = "Jack-o'-lantern 1"; + sprite = "PUMKA0"; + width = 16; + height = 40; + flags1text = "Don't flicker"; + } + 2007 + { + title = "Jack-o'-lantern 2"; + sprite = "PUMKB0"; + width = 16; + height = 40; + flags1text = "Don't flicker"; + } + 2008 + { + title = "Jack-o'-lantern 3"; + sprite = "PUMKC0"; + width = 16; + height = 40; + flags1text = "Don't flicker"; + } + 2009 + { + title = "Purple Mushroom"; + sprite = "SHRMD0"; + width = 16; + height = 48; + } + 2010 + { + title = "HHZ Tree"; + sprite = "HHPLC0"; + width = 12; + height = 40; + } + } + + frozenhillside + { + color = 10; // Green + title = "Frozen Hillside"; + + 2100 + { + title = "Ice Shard (Small)"; + sprite = "FHZIA0"; + width = 8; + height = 32; + } + 2101 + { + title = "Ice Shard (Large)"; + sprite = "FHZIB0"; + width = 8; + height = 32; + } + 2102 + { + title = "Crystal Tree (Aqua)"; + sprite = "TRE3A0"; + width = 20; + height = 200; + } + 2103 + { + title = "Crystal Tree (Pink)"; + sprite = "TRE3B0"; + width = 20; + height = 200; + } + 2104 + { + title = "Amy Cameo"; + sprite = "ROSYA1"; + width = 16; + height = 48; + flags1text = "[1] Grayscale mode"; + } + 2105 + { + title = "Mistletoe"; + sprite = "XMS6A0"; + width = 52; + height = 106; + } + } + + flickies + { + color = 10; // Green + title = "Flickies"; + width = 8; + height = 20; + flags1text = "[1] Move aimlessly"; + flags4text = "[4] No movement"; + flags8text = "[8] Hop"; + angletext = "Radius"; + + 2200 + { + title = "Bluebird"; + sprite = "FL01A1"; + } + 2201 + { + title = "Rabbit"; + sprite = "FL02A1"; + } + 2202 + { + title = "Chicken"; + sprite = "FL03A1"; + } + 2203 + { + title = "Seal"; + sprite = "FL04A1"; + } + 2204 + { + title = "Pig"; + sprite = "FL05A1"; + } + 2205 + { + title = "Chipmunk"; + sprite = "FL06A1"; + } + 2206 + { + title = "Penguin"; + sprite = "FL07A1"; + } + 2207 + { + title = "Fish"; + sprite = "FL08A1"; + parametertext = "Color"; + } + 2208 + { + title = "Ram"; + sprite = "FL09A1"; + } + 2209 + { + title = "Puffin"; + sprite = "FL10A1"; + } + 2210 + { + title = "Cow"; + sprite = "FL11A1"; + } + 2211 + { + title = "Rat"; + sprite = "FL12A1"; + } + 2212 + { + title = "Bear"; + sprite = "FL13A1"; + } + 2213 + { + title = "Dove"; + sprite = "FL14A1"; + } + 2214 + { + title = "Cat"; + sprite = "FL15A1"; + } + 2215 + { + title = "Canary"; + sprite = "FL16A1"; + } + 2216 + { + title = "Spider"; + sprite = "FS01A1"; + } + 2217 + { + title = "Bat"; + sprite = "FS02A0"; + } + } +} + +//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; + } + + } +} diff --git a/libs/SDL2/test/Makefile.os2 b/libs/SDL2/test/Makefile.os2 new file mode 100644 index 000000000..59866a056 --- /dev/null +++ b/libs/SDL2/test/Makefile.os2 @@ -0,0 +1,91 @@ +BINPATH = . + +TARGETS = testatomic.exe testdisplayinfo.exe testbounds.exe testdraw2.exe & + testdrawchessboard.exe testdropfile.exe testerror.exe testfile.exe & + testfilesystem.exe testgamecontroller.exe testgesture.exe & + testhittesting.exe testhotplug.exe testiconv.exe testime.exe & + testintersections.exe testjoystick.exe testkeys.exe testloadso.exe & + testlock.exe testmessage.exe testoverlay2.exe testplatform.exe & + testpower.exe testsensor.exe testrelative.exe testrendercopyex.exe & + testrendertarget.exe testrumble.exe testscale.exe testsem.exe & + testshader.exe testshape.exe testsprite2.exe testspriteminimal.exe & + teststreaming.exe testthread.exe testtimer.exe testver.exe & + testviewport.exe testwm2.exe torturethread.exe checkkeys.exe & + controllermap.exe testhaptic.exe testqsort.exe testresample.exe & + testaudioinfo.exe testaudiocapture.exe loopwave.exe loopwavequeue.exe & + testyuv.exe testgl2.exe testvulkan.exe testautomation.exe + +# SDL2test.lib sources (../src/test) + +CSRCS = SDL_test_assert.c SDL_test_common.c SDL_test_compare.c & + SDL_test_crc32.c SDL_test_font.c SDL_test_fuzzer.c SDL_test_harness.c & + SDL_test_imageBlit.c SDL_test_imageBlitBlend.c SDL_test_imageFace.c & + SDL_test_imagePrimitives.c SDL_test_imagePrimitivesBlend.c & + SDL_test_log.c SDL_test_md5.c SDL_test_random.c SDL_test_memory.c +TESTLIB = SDL2test.lib + +# testautomation sources + +TASRCS = testautomation.c testautomation_audio.c testautomation_clipboard.c & + testautomation_events.c testautomation_hints.c & + testautomation_keyboard.c testautomation_main.c & + testautomation_mouse.c testautomation_pixels.c & + testautomation_platform.c testautomation_rect.c & + testautomation_render.c testautomation_rwops.c & + testautomation_sdltest.c testautomation_stdlib.c & + testautomation_surface.c testautomation_syswm.c & + testautomation_timer.c testautomation_video.c + +OBJS = $(TARGETS:.exe=.obj) +COBJS = $(CSRCS:.c=.obj) +TAOBJS = $(TASRCS:.c=.obj) + +all: $(TARGETS) + +INCPATH = -I$(%WATCOM)/h/os2 -I$(%WATCOM)/h -I../include + +CFLAGS = $(INCPATH) -bt=os2 -d0 -q -bm -5s -fp5 -fpi87 -sg -oteanbmier -ei + +LIBPATH = .. +LIBS = SDL2.lib $(TESTLIB) + +#CFLAGS+= -DHAVE_SDL_TTF +#LIBS_TTF = SDL2ttf.lib + +.c: ../src/test + +$(TESTLIB): $(COBJS) + wlib -q -b -n $@ $(COBJS) + +.obj.exe: + @%make $(TESTLIB) + wlink SYS os2v2 libpath $(LIBPATH) lib {$(LIBS)} op q op el file {$<} name $@ + +.c.obj: + wcc386 $(CFLAGS) -wcd=107 -fo=$^@ $< + +# specials +testautomation.exe: $(TAOBJS) + @%make $(TESTLIB) + wlink SYS os2v2 libpath $(LIBPATH) lib {$(LIBS)} op q op el file {$<} name $@ + +testoverlay2.exe: testoverlay2.obj testyuv_cvt.obj + @%make $(TESTLIB) + wlink SYS os2v2 libpath $(LIBPATH) lib {$(LIBS)} op q op el file {$<} name $@ + +testyuv.exe: testyuv.obj testyuv_cvt.obj + @%make $(TESTLIB) + wlink SYS os2v2 libpath $(LIBPATH) lib {$(LIBS)} op q op el file {$<} name $@ + +testime.exe: testime.obj + @%make $(TESTLIB) + wlink SYS os2v2 libpath $(LIBPATH) lib {$(LIBS) $(LIBS_TTF)} op q op el file {$<} name $@ + +clean: .SYMBOLIC + @echo * Clean tests in $(BINPATH) + @if exist *.obj rm *.obj + @if exist *.err rm *.err + +distclean: .SYMBOLIC clean + @if exist *.exe rm *.exe + @if exist $(TESTLIB) rm $(TESTLIB) diff --git a/libs/SDL2/test/configure.ac b/libs/SDL2/test/configure.ac new file mode 100644 index 000000000..2e237262e --- /dev/null +++ b/libs/SDL2/test/configure.ac @@ -0,0 +1,200 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(README) + +dnl Detect the canonical build and host environments +AC_CONFIG_AUX_DIRS($srcdir/../build-scripts) +AC_CANONICAL_HOST + +dnl Check for tools + +AC_PROG_CC + +dnl Check for compiler environment + +AC_C_CONST + +dnl We only care about this for building testnative at the moment, so these +dnl values shouldn't be considered absolute truth. +dnl (Haiku, for example, sets none of these.) +ISUNIX="false" +ISWINDOWS="false" +ISMACOSX="false" + +dnl Figure out which math library to use +case "$host" in + *-*-cygwin* | *-*-mingw32*) + ISWINDOWS="true" + EXE=".exe" + MATHLIB="" + SYS_GL_LIBS="-lopengl32" + ;; + *-*-haiku*) + EXE="" + MATHLIB="" + SYS_GL_LIBS="-lGL" + ;; + *-*-darwin* ) + ISMACOSX="true" + EXE="" + MATHLIB="" + SYS_GL_LIBS="-Wl,-framework,OpenGL" + ;; + *-*-aix*) + ISUNIX="true" + EXE="" + if test x$ac_cv_prog_gcc = xyes; then + CFLAGS="-mthreads" + fi + SYS_GL_LIBS="" + ;; + *-*-mint*) + EXE="" + MATHLIB="" + AC_PATH_PROG(OSMESA_CONFIG, osmesa-config, no) + if test "x$OSMESA_CONFIG" = "xyes"; then + OSMESA_CFLAGS=`$OSMESA_CONFIG --cflags` + OSMESA_LIBS=`$OSMESA_CONFIG --libs` + CFLAGS="$CFLAGS $OSMESA_CFLAGS" + SYS_GL_LIBS="$OSMESA_LIBS" + else + SYS_GL_LIBS="-lOSMesa" + fi + ;; + *-*-qnx*) + EXE="" + MATHLIB="" + SYS_GL_LIBS="-lGLES_CM" + ;; + *-*-emscripten* ) + dnl This should really be .js, but we need to specify extra flags when compiling to js + EXE=".bc" + MATHLIB="" + SYS_GL_LIBS="" + ;; + *) + dnl Oh well, call it Unix... + ISUNIX="true" + EXE="" + MATHLIB="-lm" + SYS_GL_LIBS="-lGL" + ;; +esac +AC_SUBST(EXE) +AC_SUBST(MATHLIB) +AC_SUBST(ISMACOSX) +AC_SUBST(ISWINDOWS) +AC_SUBST(ISUNIX) + +dnl Check for SDL +SDL_VERSION=2.0.0 +AM_PATH_SDL2($SDL_VERSION, + :, + AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]) +) +CFLAGS="$CFLAGS $SDL_CFLAGS" +LIBS="$LIBS -lSDL2_test $SDL_LIBS" + +dnl Check for X11 path, needed for OpenGL on some systems +AC_PATH_X +if test x$have_x = xyes; then + if test x$ac_x_includes = xno || test "x$ac_x_includes" = xNone || test "x$ac_x_includes" = x; then + : + else + CFLAGS="$CFLAGS -I$ac_x_includes" + fi + if test x$ac_x_libraries = xno || test "x$ac_x_libraries" = xNone; then + : + else + if test "x$ac_x_libraries" = x; then + XPATH="" + XLIB="-lX11" + else + XPATH="-L$ac_x_libraries" + XLIB="-L$ac_x_libraries -lX11" + fi + fi +fi + +dnl Check for OpenGL +AC_MSG_CHECKING(for OpenGL support) +have_opengl=no +AC_TRY_COMPILE([ + #include "SDL_opengl.h" +],[ +],[ +have_opengl=yes +]) +AC_MSG_RESULT($have_opengl) + +dnl Check for OpenGL ES +AC_MSG_CHECKING(for OpenGL ES support) +have_opengles=no +AC_TRY_COMPILE([ + #if defined (__IPHONEOS__) + #include + #else + #include + #endif /* __QNXNTO__ */ +],[ +],[ +have_opengles=yes +]) +AC_MSG_RESULT($have_opengles) + +dnl Check for OpenGL ES2 +AC_MSG_CHECKING(for OpenGL ES2 support) +have_opengles2=no +AC_TRY_COMPILE([ + #if defined (__IPHONEOS__) + #include + #include + #else + #include + #include + #endif +],[ +],[ +have_opengles2=yes +]) +AC_MSG_RESULT($have_opengles2) + +GLLIB="" +GLESLIB="" +GLES2LIB="" +OPENGLES1_TARGETS="UNUSED" +OPENGLES2_TARGETS="UNUSED" +OPENGL_TARGETS="UNUSED" +if test x$have_opengles = xyes; then + CFLAGS="$CFLAGS -DHAVE_OPENGLES" + GLESLIB="$XPATH -lGLESv1_CM" + OPENGLES1_TARGETS="TARGETS" +fi +if test x$have_opengles2 = xyes; then + CFLAGS="$CFLAGS -DHAVE_OPENGLES2" + #GLES2LIB="$XPATH -lGLESv2" + OPENGLES2_TARGETS="TARGETS" +fi +if test x$have_opengl = xyes; then + CFLAGS="$CFLAGS -DHAVE_OPENGL" + GLLIB="$XPATH $SYS_GL_LIBS" + OPENGL_TARGETS="TARGETS" +fi + +AC_SUBST(OPENGLES1_TARGETS) +AC_SUBST(OPENGLES2_TARGETS) +AC_SUBST(OPENGL_TARGETS) +AC_SUBST(GLLIB) +AC_SUBST(GLESLIB) +AC_SUBST(GLES2LIB) +AC_SUBST(XLIB) + +dnl Check for SDL_ttf +AC_CHECK_LIB(SDL2_ttf, TTF_Init, have_SDL_ttf=yes) +if test x$have_SDL_ttf = xyes; then + CFLAGS="$CFLAGS -DHAVE_SDL_TTF" + SDL_TTF_LIB="-lSDL2_ttf" +fi +AC_SUBST(SDL_TTF_LIB) + +dnl Finally create all the generated files +AC_OUTPUT([Makefile]) diff --git a/libs/libopenmpt/SRB2NOTE.md b/libs/libopenmpt/SRB2NOTE.md index d664ddd7e..7eac9183b 100644 --- a/libs/libopenmpt/SRB2NOTE.md +++ b/libs/libopenmpt/SRB2NOTE.md @@ -1,6 +1,6 @@ # libopenmpt mingw-w64 binary info -Current built version as of 2019/05/23 is 0.4.4+r11531.pkg +Current built version as of 2019/09/27 is 0.4.7+r12088.pkg * mingw binaries (.dll): `bin/[x86 or x86_64]/mingw` * mingw import libraries (.dll.a): `lib/[x86 or x86_64]/mingw` diff --git a/libs/libopenmpt/bin/x86/libopenmpt.dll b/libs/libopenmpt/bin/x86/libopenmpt.dll index 0fc9e7656..8ad64fdfd 100644 Binary files a/libs/libopenmpt/bin/x86/libopenmpt.dll and b/libs/libopenmpt/bin/x86/libopenmpt.dll differ diff --git a/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll b/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll index 5fa364256..945b475e6 100644 Binary files a/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll and b/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll differ diff --git a/libs/libopenmpt/bin/x86/openmpt-mpg123.dll b/libs/libopenmpt/bin/x86/openmpt-mpg123.dll index 79148a40e..b068ddd0c 100644 Binary files a/libs/libopenmpt/bin/x86/openmpt-mpg123.dll and b/libs/libopenmpt/bin/x86/openmpt-mpg123.dll differ diff --git a/libs/libopenmpt/bin/x86/openmpt-ogg.dll b/libs/libopenmpt/bin/x86/openmpt-ogg.dll index 6b5a42e8f..a5b460063 100644 Binary files a/libs/libopenmpt/bin/x86/openmpt-ogg.dll and b/libs/libopenmpt/bin/x86/openmpt-ogg.dll differ diff --git a/libs/libopenmpt/bin/x86/openmpt-vorbis.dll b/libs/libopenmpt/bin/x86/openmpt-vorbis.dll index 486b30731..1ebed9b0e 100644 Binary files a/libs/libopenmpt/bin/x86/openmpt-vorbis.dll and b/libs/libopenmpt/bin/x86/openmpt-vorbis.dll differ diff --git a/libs/libopenmpt/bin/x86/openmpt-zlib.dll b/libs/libopenmpt/bin/x86/openmpt-zlib.dll index b6e028ab4..41bc22d2f 100644 Binary files a/libs/libopenmpt/bin/x86/openmpt-zlib.dll and b/libs/libopenmpt/bin/x86/openmpt-zlib.dll differ diff --git a/libs/libopenmpt/bin/x86_64/libopenmpt.dll b/libs/libopenmpt/bin/x86_64/libopenmpt.dll index 536492798..ffbb4b19a 100644 Binary files a/libs/libopenmpt/bin/x86_64/libopenmpt.dll and b/libs/libopenmpt/bin/x86_64/libopenmpt.dll differ diff --git a/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll b/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll index 3f6bea95f..018ae8276 100644 Binary files a/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll and b/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll differ diff --git a/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll b/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll index f96d446f2..9a0fca874 100644 Binary files a/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll and b/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll differ diff --git a/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll b/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll index 3fd951414..4bc1a336b 100644 Binary files a/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll and b/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll differ diff --git a/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll b/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll index 56047c82f..ebe8ef9b3 100644 Binary files a/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll and b/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll differ diff --git a/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll b/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll index 562d8e6a9..319b646ff 100644 Binary files a/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll and b/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll differ diff --git a/libs/libopenmpt/changelog.md b/libs/libopenmpt/changelog.md index 9847be119..0b7279558 100644 --- a/libs/libopenmpt/changelog.md +++ b/libs/libopenmpt/changelog.md @@ -5,6 +5,44 @@ Changelog {#changelog} For fully detailed change log, please see the source repository directly. This is just a high-level summary. +### libopenmpt 0.4.7 (2019-09-23) + + * [**Bug**] Compilation fix for various platforms that do not provide + `std::aligned_alloc` in C++17 mode. The problematic dependency has been + removed. This should fix build problems on MinGW, OpenBSD, Haiku, and others + for good. + + * J2B: Ignore notes with non-existing instrument (fixes Ending.j2b). + + * mpg123: Update to v1.25.13 (2019-08-24). + * ogg: Update to v1.3.4. (2019-08-31). + * flac: Update to v1.3.3. (2019-08-04). + +### libopenmpt 0.4.6 (2019-08-10) + + * [**Bug**] Compilation fix for OpenBSD. + * [**Bug**] Compilation fix for NO_PLUGINS being defined. + + * in_openmpt: Correct documentation. `openmpt-mpg123.dll` must be placed into + the Winamp directory. + + * Detect IT files unpacked with early UNMO3 versions. + + * mpg123: Update to v1.25.11 (2019-07-18). + * minimp3: Update to commit 977514a6dfc4960d819a103f43b358e58ac6c28f + (2019-07-24). + * miniz: Update to v2.1.0 (2019-05-05). + * stb_vorbis: Update to v1.17 (2019-08-09). + +### libopenmpt 0.4.5 (2019-05-27) + + * [**Sec**] Possible crash during playback due out-of-bounds read in XM and + MT2 files (r11608). + + * Breaking out of a sustain loop through Note-Off sometimes didn't continue in + the regular sample loop. + * Seeking did not stop notes playing with XM Key Off (Kxx) effect. + ### libopenmpt 0.4.4 (2019-04-07) * [**Bug**] Channel VU meters were swapped. diff --git a/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h b/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h index 5ca7f21d0..4bb90278c 100644 --- a/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h +++ b/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h @@ -19,7 +19,7 @@ /*! \brief libopenmpt minor version number */ #define OPENMPT_API_VERSION_MINOR 4 /*! \brief libopenmpt patch version number */ -#define OPENMPT_API_VERSION_PATCH 4 +#define OPENMPT_API_VERSION_PATCH 7 /*! \brief libopenmpt pre-release tag */ #define OPENMPT_API_VERSION_PREREL "" /*! \brief libopenmpt pre-release flag */ diff --git a/libs/libopenmpt/lib/x86/libopenmpt.lib b/libs/libopenmpt/lib/x86/libopenmpt.lib index 3f814528a..c81c4c4ed 100644 Binary files a/libs/libopenmpt/lib/x86/libopenmpt.lib and b/libs/libopenmpt/lib/x86/libopenmpt.lib differ diff --git a/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a b/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a index e3fa0c58f..1d7637253 100644 Binary files a/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a and b/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a differ diff --git a/libs/libopenmpt/lib/x86_64/libopenmpt.lib b/libs/libopenmpt/lib/x86_64/libopenmpt.lib index 75e3849fa..216d93b45 100644 Binary files a/libs/libopenmpt/lib/x86_64/libopenmpt.lib and b/libs/libopenmpt/lib/x86_64/libopenmpt.lib differ diff --git a/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a b/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a index 729403722..c6eda119f 100644 Binary files a/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a and b/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a differ diff --git a/srb2.png b/srb2.png index 72a08f664..3bbe2c3e6 100644 Binary files a/srb2.png and b/srb2.png differ diff --git a/src/Makefile b/src/Makefile index 3015aa5d6..8e9e1816d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -86,10 +86,7 @@ D_DIR?=../bin/Resources D_FILES=$(D_DIR)/srb2.pk3 \ $(D_DIR)/player.dta \ - $(D_DIR)/rings.wpn \ - $(D_DIR)/drill.dta \ - $(D_DIR)/soar.dta \ - $(D_DIR)/zones.dta \ + $(D_DIR)/zones.pk3 \ $(D_DIR)/music.dta \ PKG_CONFIG?=pkg-config diff --git a/src/am_map.c b/src/am_map.c index 6d7042f1c..a184ea768 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -62,7 +62,7 @@ static const UINT8 NOCLIMBYELLOWS = (11*16); #define NOCLIMBCDWALLCOLORS NOCLIMBYELLOWS #define THINGCOLORS GREENS #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) -#define XHAIRCOLORS GRAYS +#define XHAIRCOLORS DWHITE // controls #define AM_PANUPKEY KEY_UPARROW @@ -111,11 +111,6 @@ typedef struct mpoint_t a, b; } mline_t; -typedef struct -{ - fixed_t slp, islp; -} islope_t; - // // The vector graphics for the automap. // A line drawing of the player pointing right, @@ -137,16 +132,14 @@ static const mline_t player_arrow[] = { #undef R #define NUMPLYRLINES (sizeof (player_arrow)/sizeof (mline_t)) -#if 0 #define R (FRACUNIT) -static mline_t triangle_guy[] = { - { { (fixed_t)-.867f*R, (fixed_t)-.5f*R }, { (fixed_t) .867f*R, (fixed_t)-.5f*R } }, - { { (fixed_t) .867f*R, (fixed_t)-.5f*R }, { (fixed_t) 0, (fixed_t) R } }, - { { (fixed_t) 0, (fixed_t) R }, { (fixed_t)-.867f*R, (fixed_t)-.5f*R } } +static const mline_t cross_mark[] = +{ + { { -R, 0 }, { R, 0} }, + { { 0, -R }, { 0, R } }, }; #undef R -#define NUMTRIANGLEGUYLINES (sizeof (triangle_guy)/sizeof (mline_t)) -#endif +#define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) #define R (FRACUNIT) static const mline_t thintriangle_guy[] = { @@ -206,7 +199,7 @@ static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow -static INT32 followplayer = true; // specifies whether to follow the player around +static boolean followplayer = true; // specifies whether to follow the player around // function for drawing lines, depends on rendermode typedef void (*AMDRAWFLINEFUNC) (const fline_t *fl, INT32 color); @@ -816,17 +809,18 @@ static void AM_drawGrid(INT32 color) fixed_t x, y; fixed_t start, end; mline_t ml; + fixed_t gridsize = (MAPBLOCKUNITS<>FRACTOMAPBITS)) % gridsize) + start += gridsize - ((start - (bmaporgx>>FRACTOMAPBITS)) % gridsize); end = m_x + m_w; // draw vertical gridlines ml.a.y = m_y; ml.b.y = m_y + m_h; - for (x = start; x < end; x += (MAPBLOCKUNITS<>FRACTOMAPBITS)) % gridsize) + start += gridsize - ((start - (bmaporgy>>FRACTOMAPBITS)) % gridsize); end = m_y + m_h; // draw horizontal gridlines ml.a.x = m_x; ml.b.x = m_x + m_w; - for (y = start; y < end; y += (MAPBLOCKUNITS<mo->angle, DWHITE, plr->mo->x, plr->mo->y); + AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 16<mo->angle, DWHITE, plr->mo->x, plr->mo->y); return; } @@ -1053,7 +1047,7 @@ static inline void AM_drawPlayers(void) if (p->skincolor > 0) color = R_GetTranslationColormap(TC_DEFAULT, p->skincolor, GTC_CACHE)[GREENS + 8]; - AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, color, p->mo->x, p->mo->y); + AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 16<mo->angle, color, p->mo->x, p->mo->y); } } @@ -1073,13 +1067,30 @@ static inline void AM_drawThings(UINT8 colors) } } -/** Draws the crosshair, actually just a dot in software mode. +/** Draws the crosshair. * * \param color Color for the crosshair. */ static inline void AM_drawCrosshair(UINT8 color) { - V_DrawFill(f_w/2 + f_x, f_h/2 + f_y, 1, 1, color|V_NOSCALESTART); + const fixed_t scale = 4<> FRACBITS; + fl.a.y = FixedMul(cross_mark[i].a.y, scale) >> FRACBITS; + fl.b.x = FixedMul(cross_mark[i].b.x, scale) >> FRACBITS; + fl.b.y = FixedMul(cross_mark[i].b.y, scale) >> FRACBITS; + + fl.a.x += f_x + (f_w / 2); + fl.a.y += f_y + (f_h / 2); + fl.b.x += f_x + (f_w / 2); + fl.b.y += f_y + (f_h / 2); + + AM_drawFline(&fl, color); + } } /** Draws the automap. @@ -1095,5 +1106,5 @@ void AM_Drawer(void) AM_drawPlayers(); AM_drawThings(THINGCOLORS); - AM_drawCrosshair(XHAIRCOLORS); + if (!followplayer) AM_drawCrosshair(XHAIRCOLORS); } diff --git a/src/am_map.h b/src/am_map.h index 4e8c782a9..d59532819 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -26,11 +26,6 @@ typedef struct fpoint_t a, b; } fline_t; -// Used by ST StatusBar stuff. -#define AM_MSGHEADER (('a'<<24)+('m'<<16)) -#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) -#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) - extern boolean am_recalc; // true if screen size changes extern boolean automapactive; // In AutoMap mode? diff --git a/src/b_bot.c b/src/b_bot.c index 17211b353..651aeb03d 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -140,6 +140,9 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin) { + // don't try to do stuff if your sonic is in a minecart or something + if (players[consoleplayer].powers[pw_carry]) + return; // Turn the virtual keypresses into ticcmd_t. if (twodlevel || mo->flags2 & MF2_TWOD) { if (players[consoleplayer].climbing @@ -218,7 +221,12 @@ boolean B_CheckRespawn(player_t *player) return false; // Low ceiling, do not want! - if (sonic->ceilingz - sonic->z < 2*sonic->height) + if (sonic->eflags & MFE_VERTICALFLIP) + { + if (sonic->z - sonic->floorz < (sonic->player->exiting ? 5 : 2)*sonic->height) + return false; + } + else if (sonic->ceilingz - sonic->z < (sonic->player->exiting ? 6 : 3)*sonic->height) return false; // If you're dead, wait a few seconds to respawn. @@ -252,11 +260,11 @@ void B_RespawnBot(INT32 playernum) y = sonic->y; if (sonic->eflags & MFE_VERTICALFLIP) { tails->eflags |= MFE_VERTICALFLIP; - z = sonic->z - FixedMul(512*FRACUNIT,sonic->scale); + z = sonic->z - (512*sonic->scale); if (z < sonic->floorz) z = sonic->floorz; } else { - z = sonic->z + sonic->height + FixedMul(512*FRACUNIT,sonic->scale); + z = sonic->z + sonic->height + (512*sonic->scale); if (z > sonic->ceilingz - sonic->height) z = sonic->ceilingz - sonic->height; } diff --git a/src/command.c b/src/command.c index cfb36f02f..d39730f98 100644 --- a/src/command.c +++ b/src/command.c @@ -49,6 +49,7 @@ static void COM_Exec_f(void); static void COM_Wait_f(void); static void COM_Help_f(void); static void COM_Toggle_f(void); +static void COM_Add_f(void); static void CV_EnforceExecVersion(void); static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr); @@ -291,6 +292,7 @@ void COM_Init(void) COM_AddCommand("wait", COM_Wait_f); COM_AddCommand("help", COM_Help_f); COM_AddCommand("toggle", COM_Toggle_f); + COM_AddCommand("add", COM_Add_f); RegisterNetXCmd(XD_NETVAR, Got_NetVar); } @@ -709,15 +711,21 @@ static void COM_Help_f(void) if (COM_Argc() > 1) { - cvar = CV_FindVar(COM_Argv(1)); + const char *help = COM_Argv(1); + cvar = CV_FindVar(help); if (cvar) { - CONS_Printf(M_GetText("Variable %s:\n"), cvar->name); + boolean floatmode = false; + const char *cvalue = NULL; + CONS_Printf("\x82""Variable %s:\n", cvar->name); CONS_Printf(M_GetText(" flags :")); if (cvar->flags & CV_SAVE) CONS_Printf("AUTOSAVE "); if (cvar->flags & CV_FLOAT) + { CONS_Printf("FLOAT "); + floatmode = true; + } if (cvar->flags & CV_NETVAR) CONS_Printf("NETVAR "); if (cvar->flags & CV_CALL) @@ -727,59 +735,113 @@ static void COM_Help_f(void) CONS_Printf("\n"); if (cvar->PossibleValue) { - if (stricmp(cvar->PossibleValue[0].strvalue, "MIN") == 0) - { - for (i = 1; cvar->PossibleValue[i].strvalue != NULL; i++) - if (!stricmp(cvar->PossibleValue[i].strvalue, "MAX")) - break; - CONS_Printf(M_GetText(" range from %d to %d\n"), cvar->PossibleValue[0].value, - cvar->PossibleValue[i].value); - CONS_Printf(M_GetText(" Current value: %d\n"), cvar->value); - } + CONS_Printf(" Possible values:\n"); + if (cvar->PossibleValue == CV_YesNo) + CONS_Printf(" Yes or No (On or Off, 1 or 0)\n"); + else if (cvar->PossibleValue == CV_OnOff) + CONS_Printf(" On or Off (Yes or No, 1 or 0)\n"); else { - const char *cvalue = NULL; - CONS_Printf(M_GetText(" possible value : %s\n"), cvar->name); +#define MINVAL 0 +#define MAXVAL 1 + if (!stricmp(cvar->PossibleValue[MINVAL].strvalue, "MIN")) + { + if (floatmode) + CONS_Printf(" range from %f to %f\n", FIXED_TO_FLOAT(cvar->PossibleValue[MINVAL].value), + FIXED_TO_FLOAT(cvar->PossibleValue[MAXVAL].value)); + else + CONS_Printf(" range from %d to %d\n", cvar->PossibleValue[MINVAL].value, + cvar->PossibleValue[MAXVAL].value); + i = MAXVAL+1; + } +#undef MINVAL +#undef MAXVAL + + //CONS_Printf(M_GetText(" possible value : %s\n"), cvar->name); while (cvar->PossibleValue[i].strvalue) { - CONS_Printf(" %-2d : %s\n", cvar->PossibleValue[i].value, - cvar->PossibleValue[i].strvalue); + if (floatmode) + CONS_Printf(" %-2f : %s\n", FIXED_TO_FLOAT(cvar->PossibleValue[i].value), + cvar->PossibleValue[i].strvalue); + else + CONS_Printf(" %-2d : %s\n", cvar->PossibleValue[i].value, + cvar->PossibleValue[i].strvalue); if (cvar->PossibleValue[i].value == cvar->value) cvalue = cvar->PossibleValue[i].strvalue; i++; } - if (cvalue) - CONS_Printf(M_GetText(" Current value: %s\n"), cvalue); - else - CONS_Printf(M_GetText(" Current value: %d\n"), cvar->value); } } + + if (cvalue) + CONS_Printf(" Current value: %s\n", cvalue); + else if (cvar->string) + CONS_Printf(" Current value: %s\n", cvar->string); else - CONS_Printf(M_GetText(" Current value: %d\n"), cvar->value); + CONS_Printf(" Current value: %d\n", cvar->value); } else - CONS_Printf(M_GetText("No help for this command/variable\n")); + { + for (cmd = com_commands; cmd; cmd = cmd->next) + { + if (strcmp(cmd->name, help)) + continue; + + CONS_Printf("\x82""Command %s:\n", cmd->name); + CONS_Printf(" help is not available for commands"); + CONS_Printf("\x82""\nCheck wiki.srb2.org for more or try typing without arguments\n"); + return; + } + + CONS_Printf("No exact match, searching...\n"); + + // variables + CONS_Printf("\x82""Variables:\n"); + for (cvar = consvar_vars; cvar; cvar = cvar->next) + { + if ((cvar->flags & CV_NOSHOWHELP) || (!strstr(cvar->name, help))) + continue; + CONS_Printf("%s ", cvar->name); + i++; + } + + // commands + CONS_Printf("\x82""\nCommands:\n"); + for (cmd = com_commands; cmd; cmd = cmd->next) + { + if (!strstr(cmd->name, help)) + continue; + CONS_Printf("%s ",cmd->name); + i++; + } + + CONS_Printf("\x82""\nCheck wiki.srb2.org for more or type help \n"); + + CONS_Debug(DBG_GAMELOGIC, "\x87Total : %d\n", i); + } + return; } else { + // variables + CONS_Printf("\x82""Variables:\n"); + for (cvar = consvar_vars; cvar; cvar = cvar->next) + { + if (cvar->flags & CV_NOSHOWHELP) + continue; + CONS_Printf("%s ", cvar->name); + i++; + } + // commands - CONS_Printf("\x82%s", M_GetText("Commands\n")); + CONS_Printf("\x82""\nCommands:\n"); for (cmd = com_commands; cmd; cmd = cmd->next) { CONS_Printf("%s ",cmd->name); i++; } - // variables - CONS_Printf("\n\x82%s", M_GetText("Variables\n")); - for (cvar = consvar_vars; cvar; cvar = cvar->next) - { - if (!(cvar->flags & CV_NOSHOWHELP)) - CONS_Printf("%s ", cvar->name); - i++; - } - - CONS_Printf("\n\x82%s", M_GetText("Read help file for more or type help \n")); + CONS_Printf("\x82""\nCheck wiki.srb2.org for more or type help \n"); CONS_Debug(DBG_GAMELOGIC, "\x82Total : %d\n", i); } @@ -816,6 +878,30 @@ static void COM_Toggle_f(void) CV_AddValue(cvar, +1); } +/** Command variant of CV_AddValue + */ +static void COM_Add_f(void) +{ + consvar_t *cvar; + + if (COM_Argc() != 3) + { + CONS_Printf(M_GetText("Add : Add to the value of a cvar. Negative values work too!\n")); + return; + } + cvar = CV_FindVar(COM_Argv(1)); + if (!cvar) + { + CONS_Alert(CONS_NOTICE, M_GetText("%s is not a cvar\n"), COM_Argv(1)); + return; + } + + if (( cvar->flags & CV_FLOAT )) + CV_Set(cvar, va("%f", FIXED_TO_FLOAT (cvar->value) + atof(COM_Argv(2)))); + else + CV_AddValue(cvar, atoi(COM_Argv(2))); +} + // ========================================================================= // VARIABLE SIZE BUFFERS // ========================================================================= @@ -1123,32 +1209,42 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) if (var->PossibleValue[0].strvalue && !stricmp(var->PossibleValue[0].strvalue, "MIN")) // bounded cvar { +#define MINVAL 0 +#define MAXVAL 1 INT32 i; - // search for maximum - for (i = 1; var->PossibleValue[i].strvalue; i++) - if (!stricmp(var->PossibleValue[i].strvalue, "MAX")) - break; #ifdef PARANOIA - if (!var->PossibleValue[i].strvalue) + if (!var->PossibleValue[MAXVAL].strvalue) I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); #endif - if ((v != INT32_MIN && v < var->PossibleValue[0].value) || !stricmp(valstr, "MIN")) + // search for other + for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++) + if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr)) + { + var->value = var->PossibleValue[i].value; + var->string = var->PossibleValue[i].strvalue; + goto finish; + } + + + if ((v != INT32_MIN && v < var->PossibleValue[MINVAL].value) || !stricmp(valstr, "MIN")) { - v = var->PossibleValue[0].value; - valstr = var->PossibleValue[0].strvalue; + v = var->PossibleValue[MINVAL].value; + valstr = var->PossibleValue[MINVAL].strvalue; override = true; overrideval = v; } - else if ((v != INT32_MIN && v > var->PossibleValue[i].value) || !stricmp(valstr, "MAX")) + else if ((v != INT32_MIN && v > var->PossibleValue[MAXVAL].value) || !stricmp(valstr, "MAX")) { - v = var->PossibleValue[i].value; - valstr = var->PossibleValue[i].strvalue; + v = var->PossibleValue[MAXVAL].value; + valstr = var->PossibleValue[MAXVAL].strvalue; override = true; overrideval = v; } if (v == INT32_MIN) goto badinput; +#undef MINVAL +#undef MAXVAL } else { @@ -1515,6 +1611,9 @@ void CV_AddValue(consvar_t *var, INT32 increment) { INT32 newvalue, max; + if (!increment) + return; + // count pointlimit better if (var == &cv_pointlimit && (gametype == GT_MATCH)) increment *= 50; @@ -1538,13 +1637,11 @@ void CV_AddValue(consvar_t *var, INT32 increment) if (var->PossibleValue) { -#define MINVAL 0 if (var == &cv_nextmap) { // Special case for the nextmap variable, used only directly from the menu INT32 oldvalue = var->value - 1, gt; gt = cv_newgametype.value; - if (increment != 0) // Going up! { newvalue = var->value - 1; do @@ -1575,21 +1672,58 @@ void CV_AddValue(consvar_t *var, INT32 increment) return; } } +#define MINVAL 0 +#define MAXVAL 1 else if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN")) { - // search the next to last - for (max = 0; var->PossibleValue[max+1].strvalue; max++) - ; +#ifdef PARANOIA + if (!var->PossibleValue[MAXVAL].strvalue) + I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); +#endif - if (newvalue < var->PossibleValue[MINVAL].value) // add the max+1 - newvalue += var->PossibleValue[max].value - var->PossibleValue[MINVAL].value + 1; + if (newvalue < var->PossibleValue[MINVAL].value || newvalue > var->PossibleValue[MAXVAL].value) + { + INT32 currentindice = -1, newindice; + for (max = MAXVAL+1; var->PossibleValue[max].strvalue; max++) + { + if (var->PossibleValue[max].value == newvalue) + { + increment = 0; + currentindice = max; + } + else if (var->PossibleValue[max].value == var->value) + currentindice = max; + } - newvalue = var->PossibleValue[MINVAL].value + (newvalue - var->PossibleValue[MINVAL].value) - % (var->PossibleValue[max].value - var->PossibleValue[MINVAL].value + 1); + if (increment) + { + increment = (increment > 0) ? 1 : -1; + if (currentindice == -1 && max != MAXVAL+1) + newindice = ((increment > 0) ? MAXVAL : max) + increment; + else + newindice = currentindice + increment; - CV_SetValue(var, newvalue); -#undef MINVAL + if (newindice >= max || newindice <= MAXVAL) + { + if (var == &cv_pointlimit && (gametype == GT_MATCH) && increment > 0) + CV_SetValue(var, 50); + else + { + newvalue = var->PossibleValue[((increment > 0) ? MINVAL : MAXVAL)].value; + CV_SetValue(var, newvalue); + } + } + else + CV_Set(var, var->PossibleValue[newindice].strvalue); + } + else + CV_Set(var, var->PossibleValue[currentindice].strvalue); + } + else + CV_SetValue(var, newvalue); } +#undef MINVAL +#undef MAXVAL else { INT32 currentindice = -1, newindice; @@ -1599,8 +1733,6 @@ void CV_AddValue(consvar_t *var, INT32 increment) if (var->PossibleValue[max].value == var->value) currentindice = max; - max--; - if (var == &cv_chooseskin) { // Special case for the chooseskin variable, used only directly from the menu @@ -1632,7 +1764,7 @@ void CV_AddValue(consvar_t *var, INT32 increment) var->value); #endif - newindice = (currentindice + increment + max + 1) % (max+1); + newindice = (currentindice + increment + max) % max; CV_Set(var, var->PossibleValue[newindice].strvalue); } } diff --git a/src/config.h.in b/src/config.h.in index fc32aef82..58d07e26d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -13,7 +13,7 @@ #define ASSET_HASH_SRB2_PK3 "${SRB2_ASSET_srb2.pk3_HASH}" #define ASSET_HASH_PLAYER_DTA "${SRB2_ASSET_player.dta_HASH}" -#define ASSET_HASH_ZONES_DTA "${SRB2_ASSET_zones.dta_HASH}" +#define ASSET_HASH_ZONES_PK3 "${SRB2_ASSET_zones.pk3_HASH}" #ifdef USE_PATCH_DTA #define ASSET_HASH_PATCH_PK3 "${SRB2_ASSET_patch.pk3_HASH}" #endif @@ -30,7 +30,7 @@ * Last updated 2018 / ?? / ?? - v2.2 - patch.pk3 */ #define ASSET_HASH_SRB2_PK3 "c1b9577687f8a795104aef4600720ea7" -#define ASSET_HASH_ZONES_DTA "303838c6c534d9540288360fa49cca60" +#define ASSET_HASH_ZONES_PK3 "303838c6c534d9540288360fa49cca60" #define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799" #ifdef USE_PATCH_DTA #define ASSET_HASH_PATCH_PK3 "dbbf8bc6121618ee3be2d5b14650429b" diff --git a/src/console.c b/src/console.c index 09a6cab45..11e236696 100644 --- a/src/console.c +++ b/src/console.c @@ -175,11 +175,11 @@ static void CONS_Clear_f(void) // Choose english keymap // -static void CONS_English_f(void) +/*static void CONS_English_f(void) { shiftxform = english_shiftxform; CONS_Printf(M_GetText("%s keymap.\n"), M_GetText("English")); -} +}*/ static char *bindtable[NUMINPUTS]; @@ -394,7 +394,7 @@ void CON_Init(void) // register our commands // COM_AddCommand("cls", CONS_Clear_f); - COM_AddCommand("english", CONS_English_f); + //COM_AddCommand("english", CONS_English_f); // set console full screen for game startup MAKE SURE VID_Init() done !!! con_destlines = vid.height; con_curlines = vid.height; diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e0feb036f..411d847b5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -83,11 +83,9 @@ tic_t jointimeout = (10*TICRATE); static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? -#ifdef NEWPING UINT16 pingmeasurecount = 1; UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. -#endif SINT8 nodetoplayer[MAXNETNODES]; SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen @@ -621,6 +619,10 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->friction = LONG(players[i].mo->friction); rsp->movefactor = LONG(players[i].mo->movefactor); + rsp->sprite = (spritenum_t)LONG(players[i].mo->sprite); + rsp->frame = LONG(players[i].mo->frame); + rsp->sprite2 = players[i].mo->sprite2; + rsp->anim_duration = SHORT(players[i].mo->anim_duration); rsp->tics = LONG(players[i].mo->tics); rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :( rsp->eflags = (UINT16)SHORT(players[i].mo->eflags); @@ -767,8 +769,17 @@ static void resynch_read_player(resynch_pak *rsp) players[i].mo->momy = LONG(rsp->momy); players[i].mo->momz = LONG(rsp->momz); players[i].mo->movefactor = LONG(rsp->movefactor); + + // Don't use P_SetMobjStateNF to restore state, write/read all the values manually! + // This should stop those stupid console errors, hopefully. + // -- Monster Iestyn + players[i].mo->sprite = (spritenum_t)LONG(rsp->sprite); + players[i].mo->frame = LONG(rsp->frame); + players[i].mo->sprite2 = rsp->sprite2; + players[i].mo->anim_duration = SHORT(rsp->anim_duration); players[i].mo->tics = LONG(rsp->tics); - P_SetMobjStateNF(players[i].mo, LONG(rsp->statenum)); + players[i].mo->state = &states[LONG(rsp->statenum)]; + players[i].mo->x = LONG(rsp->x); players[i].mo->y = LONG(rsp->y); players[i].mo->z = LONG(rsp->z); @@ -1253,7 +1264,8 @@ static boolean CL_SendJoin(void) netbuffer->u.clientcfg.localplayers = localplayers; netbuffer->u.clientcfg.version = VERSION; netbuffer->u.clientcfg.subversion = SUBVERSION; - + 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)); } @@ -1312,33 +1324,13 @@ static void SV_SendPlayerInfo(INT32 node) continue; } - netbuffer->u.playerinfo[i].node = (UINT8)playernode[i]; + netbuffer->u.playerinfo[i].node = i; strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1); netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0'; //fetch IP address - { - const char *claddress; - UINT32 numericaddress[4]; - - memset(netbuffer->u.playerinfo[i].address, 0, 4); - if (playernode[i] == 0) - { - //127.0.0.1 - netbuffer->u.playerinfo[i].address[0] = 127; - netbuffer->u.playerinfo[i].address[3] = 1; - } - else if (playernode[i] > 0 && I_GetNodeAddress && (claddress = I_GetNodeAddress(playernode[i])) != NULL) - { - if (sscanf(claddress, "%d.%d.%d.%d", &numericaddress[0], &numericaddress[1], &numericaddress[2], &numericaddress[3]) < 4) - goto badaddress; - netbuffer->u.playerinfo[i].address[0] = (UINT8)numericaddress[0]; - netbuffer->u.playerinfo[i].address[1] = (UINT8)numericaddress[1]; - netbuffer->u.playerinfo[i].address[2] = (UINT8)numericaddress[2]; - netbuffer->u.playerinfo[i].address[3] = (UINT8)numericaddress[3]; - } - } - badaddress: + //No, don't do that, you fuckface. + memset(netbuffer->u.playerinfo[i].address, 0, 4); if (G_GametypeHasTeams()) { @@ -2417,7 +2409,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) // the remaining players. if (G_IsSpecialStage(gamemap)) { - INT32 i, count, increment, spheres; + INT32 i, count, sincrement, spheres, rincrement, rings; for (i = 0, count = 0; i < MAXPLAYERS; i++) { @@ -2427,18 +2419,35 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) count--; spheres = players[playernum].spheres; - increment = spheres/count; + rings = players[playernum].rings; + sincrement = spheres/count; + rincrement = rings/count; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && i != playernum) { - if (spheres < increment) + if (spheres < 2*sincrement) + { P_GivePlayerSpheres(&players[i], spheres); + spheres = 0; + } else - P_GivePlayerSpheres(&players[i], increment); + { + P_GivePlayerSpheres(&players[i], sincrement); + spheres -= sincrement; + } - spheres -= increment; + if (rings < 2*rincrement) + { + P_GivePlayerRings(&players[i], rings); + rings = 0; + } + else + { + P_GivePlayerRings(&players[i], rincrement); + rings -= rincrement; + } } } } @@ -2853,12 +2862,10 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false); kickreason = KR_KICK; break; -#ifdef NEWPING case KICK_MSG_PING_HIGH: HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false); kickreason = KR_PINGLIMIT; break; -#endif case KICK_MSG_CON_FAIL: HU_AddChatText(va("\x82*%s left the game (Synch Failure)", player_names[pnum]), false); kickreason = KR_SYNCH; @@ -2931,10 +2938,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) D_StartTitle(); if (msg == KICK_MSG_CON_FAIL) M_StartMessage(M_GetText("Server closed connection\n(synch failure)\nPress ESC\n"), NULL, MM_NOTHING); -#ifdef NEWPING else if (msg == KICK_MSG_PING_HIGH) M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING); -#endif else if (msg == KICK_MSG_BANNED) M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING); else if (msg == KICK_MSG_CUSTOM_KICK) @@ -2952,7 +2957,7 @@ consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, N consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; consvar_t cv_resynchattempts = {"resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; @@ -3182,6 +3187,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (!splitscreen && !botingame) CL_ClearPlayer(newplayernum); playeringame[newplayernum] = true; + READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); G_AddPlayer(newplayernum); if (newplayernum+1 > doomcom->numslots) doomcom->numslots = (INT16)(newplayernum+1); @@ -3214,10 +3220,10 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) { const char *address; if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL) - HU_AddChatText(va("\x82*Player %d has joined the game (node %d) (%s)", newplayernum+1, node, address), false); // merge join notification + IP to avoid clogging console/chat. + HU_AddChatText(va("\x82*%s has joined the game (node %d) (%s)", player_names[newplayernum], node, address), false); // merge join notification + IP to avoid clogging console/chat. } else - HU_AddChatText(va("\x82*Player %d has joined the game (node %d)", newplayernum+1, node), false); // if you don't wanna see the join address. + HU_AddChatText(va("\x82*%s has joined the game (node %d)", player_names[newplayernum], node), false); // if you don't wanna see the join address. } if (server && multiplayer && motd[0] != '\0') @@ -3228,10 +3234,11 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) #endif } -static boolean SV_AddWaitingPlayers(void) +static boolean SV_AddWaitingPlayers(const char *name, const char *name2) { INT32 node, n, newplayer = false; - UINT8 buf[2]; + UINT8 buf[2 + MAXPLAYERNAME]; + UINT8 *p; UINT8 newplayernum = 0; // What is the reason for this? Why can't newplayernum always be 0? @@ -3314,18 +3321,23 @@ static boolean SV_AddWaitingPlayers(void) playernode[newplayernum] = (UINT8)node; + p = buf + 2; buf[0] = (UINT8)node; buf[1] = newplayernum; if (playerpernode[node] < 1) + { nodetoplayer[node] = newplayernum; + WRITESTRINGN(p, name, MAXPLAYERNAME); + } else { nodetoplayer2[node] = newplayernum; buf[1] |= 0x80; + WRITESTRINGN(p, name2, MAXPLAYERNAME); } playerpernode[node]++; - SendNetXCmd(XD_ADDPLAYER, &buf, 2); + SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); // use the next free slot (we can't put playeringame[newplayernum] = true here) @@ -3387,7 +3399,7 @@ boolean SV_SpawnServer(void) else doomcom->numslots = 1; } - return SV_AddWaitingPlayers(); + return SV_AddWaitingPlayers(cv_playername.zstring, cv_playername2.zstring); } void SV_StopServer(void) @@ -3458,6 +3470,9 @@ static size_t TotalTextCmdPerTic(tic_t tic) */ static void HandleConnect(SINT8 node) { + char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; + INT32 i; + if (bannednode && bannednode[node]) SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server")); else if (netbuffer->u.clientcfg.version != VERSION @@ -3477,6 +3492,16 @@ static void HandleConnect(SINT8 node) boolean newnode = false; #endif + for (i = 0; i < netbuffer->u.clientcfg.localplayers - playerpernode[node]; i++) + { + strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); + if (!EnsurePlayerNameIsGood(names[i], -1)) + { + SV_SendRefuse(node, "Bad player name"); + return; + } + } + // client authorised to join nodewaiting[node] = (UINT8)(netbuffer->u.clientcfg.localplayers - playerpernode[node]); if (!nodeingame[node]) @@ -3517,7 +3542,7 @@ static void HandleConnect(SINT8 node) SV_SendSaveGame(node); // send a complete game state DEBFILE("send savegame\n"); } - SV_AddWaitingPlayers(); + SV_AddWaitingPlayers(names[0], names[1]); player_joining = true; } #else @@ -3824,7 +3849,7 @@ static void HandlePacketFromPlayer(SINT8 node) break; // Ignore tics from those not synched - if (resynch_inprogress[node]) + if (resynch_inprogress[node] && nettics[node] == gametic) break; // To save bytes, only the low byte of tic numbers are sent @@ -4158,7 +4183,6 @@ static void HandlePacketFromPlayer(SINT8 node) resynch_local_inprogress = true; CL_AcknowledgeResynch(&netbuffer->u.resynchpak); break; -#ifdef NEWPING case PT_PING: // Only accept PT_PING from the server. if (node != servernode) @@ -4186,7 +4210,6 @@ static void HandlePacketFromPlayer(SINT8 node) } break; -#endif case PT_SERVERCFG: break; case PT_FILEFRAGMENT: @@ -4682,7 +4705,7 @@ void TryRunTics(tic_t realtics) if (player_joining) return; - if (neededtic > gametic) + if (neededtic > gametic && !resynch_local_inprogress) { if (advancedemo) D_StartTitle(); @@ -4700,7 +4723,6 @@ void TryRunTics(tic_t realtics) } } -#ifdef NEWPING static inline void PingUpdate(void) { INT32 i; @@ -4758,7 +4780,6 @@ static inline void PingUpdate(void) pingmeasurecount = 1; //Reset count } -#endif void NetUpdate(void) { @@ -4783,7 +4804,6 @@ void NetUpdate(void) gametime = nowtime; -#ifdef NEWPING if (server) { if (netgame && !(gametime % 255)) @@ -4794,7 +4814,6 @@ void NetUpdate(void) realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); pingmeasurecount++; } -#endif if (client) maketic = neededtic; @@ -4836,8 +4855,13 @@ void NetUpdate(void) for (i = 0; i < MAXNETNODES; ++i) if (resynch_inprogress[i]) { - SV_SendResynch(i); - counts = -666; + if (!nodeingame[i] || nettics[i] == gametic) + { + SV_SendResynch(i); + counts = -666; + } + else + counts = 0; // Let the client catch up with the server } // Do not make tics while resynching diff --git a/src/d_clisrv.h b/src/d_clisrv.h index d09d2aa48..d7c210895 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -15,6 +15,7 @@ #include "d_ticcmd.h" #include "d_netcmd.h" +#include "d_net.h" #include "tables.h" #include "d_player.h" @@ -73,9 +74,7 @@ typedef enum PT_LOGIN, // Login attempt from the client. -#ifdef NEWPING PT_PING, // Packet sent to tell clients the other client's latency to server. -#endif NUMPACKETTYPE } packettype_t; @@ -265,6 +264,10 @@ typedef struct fixed_t friction; fixed_t movefactor; + spritenum_t sprite; + UINT32 frame; + UINT8 sprite2; + UINT16 anim_duration; INT32 tics; statenum_t statenum; UINT32 flags; @@ -322,6 +325,7 @@ typedef struct UINT8 subversion; // Contains build version UINT8 localplayers; UINT8 mode; + char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; } ATTRPACK clientconfig_pak; #define MAXSERVERNAME 32 @@ -421,9 +425,7 @@ typedef struct msaskinfo_pak msaskinfo; // 22 bytes plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38) plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE) -#ifdef NEWPING UINT32 pingtable[MAXPLAYERS]; // 128 bytes -#endif } u; // This is needed to pack diff packet types data together } ATTRPACK doomdata_t; @@ -457,9 +459,7 @@ extern consvar_t cv_playbackspeed; #define KICK_MSG_PLAYER_QUIT 3 #define KICK_MSG_TIMEOUT 4 #define KICK_MSG_BANNED 5 -#ifdef NEWPING #define KICK_MSG_PING_HIGH 6 -#endif #define KICK_MSG_CUSTOM_KICK 7 #define KICK_MSG_CUSTOM_BAN 8 @@ -484,11 +484,9 @@ extern SINT8 servernode; void Command_Ping_f(void); extern tic_t connectiontimeout; extern tic_t jointimeout; -#ifdef NEWPING extern UINT16 pingmeasurecount; extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; -#endif extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed; diff --git a/src/d_main.c b/src/d_main.c index 9fa506bee..52f1d2997 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -129,6 +129,7 @@ char srb2home[256] = "."; char srb2path[256] = "."; boolean usehome = true; const char *pandf = "%s" PATHSEP "%s"; +static char addonsdir[MAX_WADPATH]; // // EVENT HANDLING @@ -358,7 +359,7 @@ static void D_Display(void) // clean up border stuff // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide)) + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap))) { // draw the view directly @@ -716,6 +717,7 @@ void D_StartTitle(void) botskin = 0; cv_debug = 0; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); lastmaploaded = 0; // In case someone exits out at the same time they start a time attack run, @@ -850,7 +852,7 @@ static void IdentifyVersion(void) // checking in D_SRB2Main // Add the maps - D_AddFile(va(pandf,srb2waddir,"zones.dta")); + D_AddFile(va(pandf,srb2waddir,"zones.pk3")); // Add the players D_AddFile(va(pandf,srb2waddir, "player.dta")); @@ -1038,7 +1040,6 @@ void D_SRB2Main(void) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); - I_mkdir(srb2home, 0700); #else snprintf(srb2home, sizeof srb2home, "%s", userhome); snprintf(downloaddir, sizeof downloaddir, "%s", userhome); @@ -1055,6 +1056,10 @@ void D_SRB2Main(void) configfile[sizeof configfile - 1] = '\0'; } + // Create addons dir + snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); + I_mkdir(addonsdir, 0755); + // rand() needs seeded regardless of password srand((unsigned int)time(NULL)); @@ -1140,10 +1145,10 @@ void D_SRB2Main(void) // Check MD5s of autoloaded files W_VerifyFileMD5(mainwads++, ASSET_HASH_SRB2_PK3); // srb2.pk3 - W_VerifyFileMD5(mainwads++, ASSET_HASH_ZONES_DTA); // zones.dta + W_VerifyFileMD5(mainwads++, ASSET_HASH_ZONES_PK3); // zones.pk3 W_VerifyFileMD5(mainwads++, ASSET_HASH_PLAYER_DTA); // player.dta #ifdef USE_PATCH_DTA - W_VerifyFileMD5(mainwads++, ASSET_HASH_PATCH_DTA); // patch.dta + W_VerifyFileMD5(mainwads++, ASSET_HASH_PATCH_DTA); // patch.pk3 #endif // don't check music.dta because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. @@ -1152,7 +1157,7 @@ void D_SRB2Main(void) #else mainwads++; // srb2.pk3 - mainwads++; // zones.dta + mainwads++; // zones.pk3 mainwads++; // player.dta #ifdef USE_PATCH_DTA mainwads++; // patch.dta @@ -1239,24 +1244,40 @@ void D_SRB2Main(void) sound_disabled = true; midi_disabled = digital_disabled = true; } + if (M_CheckParm("-noaudio")) // combines -nosound and -nomusic + { + sound_disabled = true; + digital_disabled = true; + midi_disabled = true; + } else + { + if (M_CheckParm("-nosound")) + sound_disabled = true; + if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic + { + digital_disabled = true; + midi_disabled = true; + } + else + { + if (M_CheckParm("-nomidimusic")) + midi_disabled = true; // WARNING: DOS version initmusic in I_StartupSound + if (M_CheckParm("-nodigmusic")) + digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound + } + } + if (!( sound_disabled && digital_disabled +#ifndef NO_MIDI + && midi_disabled +#endif + )) { CONS_Printf("S_InitSfxChannels(): Setting up sound channels.\n"); + I_StartupSound(); + I_InitMusic(); + S_InitSfxChannels(cv_soundvolume.value); } - if (M_CheckParm("-nosound")) - sound_disabled = true; - if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic - midi_disabled = digital_disabled = true; - else - { - if (M_CheckParm("-nomidimusic")) - midi_disabled = true; // WARNING: DOS version initmusic in I_StartupSound - if (M_CheckParm("-nodigmusic")) - digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound - } - I_StartupSound(); - I_InitMusic(); - S_InitSfxChannels(cv_soundvolume.value); CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); diff --git a/src/d_net.c b/src/d_net.c index 9f68c187c..cbfef7726 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -185,22 +185,10 @@ typedef struct UINT8 nextacknum; UINT8 flags; -#ifndef NEWPING - // jacobson tcp timeout evaluation algorithm (Karn variation) - fixed_t ping; - fixed_t varping; - INT32 timeout; // computed with ping and varping -#endif } node_t; static node_t nodes[MAXNETNODES]; -#ifndef NEWPING -#define PINGDEFAULT ((200*TICRATE*FRACUNIT)/1000) -#define VARPINGDEFAULT ((50*TICRATE*FRACUNIT)/1000) -#define TIMEOUT(p,v) (p+4*v+FRACUNIT/2)>>FRACBITS; -#else -#define NODETIMEOUT 14 //What the above boiled down to... -#endif +#define NODETIMEOUT 14 #ifndef NONET // return <0 if a < b (mod 256) @@ -320,19 +308,7 @@ static UINT8 GetAcktosend(INT32 node) static void RemoveAck(INT32 i) { INT32 node = ackpak[i].destinationnode; -#ifndef NEWPING - fixed_t trueping = (I_GetTime() - ackpak[i].senttime)<>FRACBITS,(double)FIXED_TO_FLOAT(nodes[node].ping),(double)FIXED_TO_FLOAT(nodes[node].varping),nodes[node].timeout)); -#else DEBFILE(va("Remove ack %d\n",ackpak[i].acknum)); -#endif ackpak[i].acknum = 0; if (nodes[node].flags & NF_CLOSE) Net_CloseConnection(node); @@ -519,11 +495,7 @@ void Net_AckTicker(void) { const INT32 nodei = ackpak[i].destinationnode; node_t *node = &nodes[nodei]; -#ifdef NEWPING if (ackpak[i].acknum && ackpak[i].senttime + NODETIMEOUT < I_GetTime()) -#else - if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime()) -#endif { if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE)) { @@ -534,13 +506,8 @@ void Net_AckTicker(void) ackpak[i].acknum = 0; continue; } -#ifdef NEWPING DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime, NODETIMEOUT, I_GetTime())); -#else - DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime, - node->timeout, I_GetTime())); -#endif M_Memcpy(netbuffer, ackpak[i].pak.raw, ackpak[i].length); ackpak[i].senttime = I_GetTime(); ackpak[i].resentnum++; @@ -658,11 +625,6 @@ void Net_WaitAllAckReceived(UINT32 timeout) static void InitNode(node_t *node) { node->acktosend_head = node->acktosend_tail = 0; -#ifndef NEWPING - node->ping = PINGDEFAULT; - node->varping = VARPINGDEFAULT; - node->timeout = TIMEOUT(node->ping, node->varping); -#endif node->firstacktosend = 0; node->nextacknum = 1; node->remotefirstack = 0; @@ -843,9 +805,7 @@ static const char *packettypename[NUMPACKETTYPE] = "CLIENTJOIN", "NODETIMEOUT", "RESYNCHING", -#ifdef NEWPING "PING" -#endif }; static void DebugPrintpacket(const char *header) @@ -1384,30 +1344,73 @@ boolean D_CheckNetGame(void) return ret; } +struct pingcell +{ + INT32 num; + INT32 ms; +}; + +static int pingcellcmp(const void *va, const void *vb) +{ + const struct pingcell *a, *b; + a = va; + b = vb; + return ( a->ms - b->ms ); +} + +/* +New ping command formatted nicely to present ping in +ascending order. And with equally spaced columns. +The caller's ping is presented at the bottom too, for +convenience. +*/ + void Command_Ping_f(void) { -#ifndef NEWPING - if(server) + struct pingcell pingv[MAXPLAYERS]; + INT32 pingc; + + int name_width = 0; + int ms_width = 0; + + int n; + INT32 i; + + pingc = 0; + for (i = 1; i < MAXPLAYERS; ++i) + if (playeringame[i]) { -#endif - INT32 i; - for (i = 0; i < MAXPLAYERS;i++) - { -#ifndef NEWPING - const INT32 node = playernode[i]; - if (playeringame[i] && node != 0) - CONS_Printf(M_GetText("%.2d : %s\n %d tics, %d ms.\n"), i, player_names[i], - GetLag(node), G_TicsToMilliseconds(GetLag(node))); -#else - if (playeringame[i] && i != 0) - CONS_Printf(M_GetText("%.2d : %s\n %d ms\n"), i, player_names[i], playerpingtable[i]); -#endif - } -#ifndef NEWPING + n = strlen(player_names[i]); + if (n > name_width) + name_width = n; + + n = playerpingtable[i]; + if (n > ms_width) + ms_width = n; + + pingv[pingc].num = i; + pingv[pingc].ms = playerpingtable[i]; + pingc++; + } + + if (ms_width < 10) ms_width = 1; + else if (ms_width < 100) ms_width = 2; + else ms_width = 3; + + qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp); + + for (i = 0; i < pingc; ++i) + { + CONS_Printf("%02d : %-*s %*d ms\n", + pingv[i].num, + name_width, player_names[pingv[i].num], + ms_width, pingv[i].ms); + } + + if (!server && playeringame[consoleplayer]) + { + CONS_Printf("\nYour ping is %d ms\n", playerpingtable[consoleplayer]); } - else - CONS_Printf(M_GetText("Only the server can use this.\n")); -#endif } void D_CloseConnection(void) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d0296e7fc..b14f92b33 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -74,6 +74,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum); static void PointLimit_OnChange(void); static void TimeLimit_OnChange(void); static void NumLaps_OnChange(void); +static void BaseNumLaps_OnChange(void); static void Mute_OnChange(void); static void Hidetime_OnChange(void); @@ -210,7 +211,7 @@ consvar_t cv_allowteamchange = {"allowteamchange", "Yes", CV_NETVAR, CV_YesNo, N consvar_t cv_startinglives = {"startinglives", "3", CV_NETVAR|CV_CHEAT, startingliveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t respawntime_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t respawntime_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "Off"}, {0, NULL}}; consvar_t cv_respawntime = {"respawndelay", "3", CV_NETVAR|CV_CHEAT, respawntime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_competitionboxes = {"competitionboxes", "Mystery", CV_NETVAR|CV_CHEAT, competitionboxes_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -246,20 +247,20 @@ INT32 cv_debug; consvar_t cv_usemouse = {"use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_usejoystick = {"use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, +consvar_t cv_usejoystick = {"use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_usejoystick2 = {"use_joystick2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, +consvar_t cv_usejoystick2 = {"use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2, 0, NULL, NULL, 0, 0, NULL}; #if (defined (LJOYSTICK) || defined (HAVE_SDL)) #ifdef LJOYSTICK -consvar_t cv_joyport = {"joyport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_joyport2 = {"joyport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: for later +consvar_t cv_joyport = {"padport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_joyport2 = {"padport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: for later #endif -consvar_t cv_joyscale = {"joyscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_joyscale2 = {"joyscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_joyscale = {"padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_joyscale2 = {"padscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2, 0, NULL, NULL, 0, 0, NULL}; #else -consvar_t cv_joyscale = {"joyscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save -consvar_t cv_joyscale2 = {"joyscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save +consvar_t cv_joyscale = {"padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save +consvar_t cv_joyscale2 = {"padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save #endif #if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) consvar_t cv_mouse2port = {"mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -315,16 +316,17 @@ consvar_t cv_timetic = {"timerres", "Classic", CV_SAVE, timetic_cons_t, NULL, 0, static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}}; consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}}; -consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, +static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, {0, "None"}, {0, NULL}}; +consvar_t cv_pointlimit = {"pointlimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t timelimit_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; -consvar_t cv_timelimit = {"timelimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, +static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}}; +consvar_t cv_timelimit = {"timelimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t numlaps_cons_t[] = {{0, "MIN"}, {50, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, NULL}}; consvar_t cv_numlaps = {"numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_usemapnumlaps = {"usemaplaps", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +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}; // 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}; @@ -340,9 +342,7 @@ static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; -#ifdef NEWPING consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; -#endif // Intermission time Tails 04-19-2002 static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}}; consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -363,7 +363,7 @@ consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; +consvar_t cv_sleep = {"cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; INT16 gametype = GT_COOP; boolean splitscreen = false; @@ -497,7 +497,7 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_friendlyfire); CV_RegisterVar(&cv_pointlimit); CV_RegisterVar(&cv_numlaps); - CV_RegisterVar(&cv_usemapnumlaps); + CV_RegisterVar(&cv_basenumlaps); CV_RegisterVar(&cv_hazardlog); @@ -573,9 +573,7 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_sleep); -#ifdef NEWPING CV_RegisterVar(&cv_maxping); -#endif #ifdef SEENAMES CV_RegisterVar(&cv_allowseenames); @@ -637,6 +635,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_screenshot_folder); CV_RegisterVar(&cv_screenshot_colorprofile); CV_RegisterVar(&cv_moviemode); + CV_RegisterVar(&cv_movie_option); + CV_RegisterVar(&cv_movie_folder); // PNG variables CV_RegisterVar(&cv_zlib_level); CV_RegisterVar(&cv_zlib_memory); @@ -738,6 +738,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_chasefreelook); CV_RegisterVar(&cv_chasefreelook2); CV_RegisterVar(&cv_tutorialprompt); + CV_RegisterVar(&cv_showfocuslost); + CV_RegisterVar(&cv_pauseifunfocused); // g_input.c CV_RegisterVar(&cv_sideaxis); @@ -877,7 +879,7 @@ void D_RegisterClientCommands(void) * \sa CleanupPlayerName, SetPlayerName, Got_NameAndColor * \author Graue */ -static boolean IsNameGood(char *name, INT32 playernum) +boolean EnsurePlayerNameIsGood(char *name, INT32 playernum) { INT32 ix; @@ -918,14 +920,14 @@ static boolean IsNameGood(char *name, INT32 playernum) if (len > 1) { name[len-1] = '\0'; - if (!IsNameGood (name, playernum)) + if (!EnsurePlayerNameIsGood (name, playernum)) return false; } else if (len == 1) // Agh! { // Last ditch effort... sprintf(name, "%d", M_RandomKey(10)); - if (!IsNameGood (name, playernum)) + if (!EnsurePlayerNameIsGood (name, playernum)) return false; } else @@ -1054,12 +1056,12 @@ static void CleanupPlayerName(INT32 playernum, const char *newname) * \param newname New name for that player. Should be good, but won't * necessarily be if the client is maliciously modified or * buggy. - * \sa CleanupPlayerName, IsNameGood + * \sa CleanupPlayerName, EnsurePlayerNameIsGood * \author Graue */ static void SetPlayerName(INT32 playernum, char *newname) { - if (IsNameGood(newname, playernum)) + if (EnsurePlayerNameIsGood(newname, playernum)) { if (strcasecmp(newname, player_names[playernum]) != 0) { @@ -1184,12 +1186,12 @@ static void SendNameAndColor(void) && !strcmp(cv_skin.string, skins[players[consoleplayer].skin].name)) return; + players[consoleplayer].availabilities = R_GetSkinAvailabilities(); + // We'll handle it later if we're not playing. if (!Playing()) return; - players[consoleplayer].availabilities = R_GetSkinAvailabilities(); - // If you're not in a netgame, merely update the skin, color, and name. if (!netgame) { @@ -1302,12 +1304,12 @@ static void SendNameAndColor2(void) CV_StealthSet(&cv_playercolor2, cv_playercolor2.defaultvalue); } + players[secondplaya].availabilities = R_GetSkinAvailabilities(); + // We'll handle it later if we're not playing. if (!Playing()) return; - players[secondplaya].availabilities = R_GetSkinAvailabilities(); - // If you're not in a netgame, merely update the skin, color, and name. if (botingame) { @@ -1690,7 +1692,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese // Kick bot from special stages if (botskin) { - if (G_IsSpecialStage(mapnum)) + if (G_IsSpecialStage(mapnum) || (mapheaderinfo[mapnum-1] && (mapheaderinfo[mapnum-1]->typeoflevel & TOL_NIGHTS))) { if (botingame) { @@ -1916,7 +1918,10 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) precache = false; if (resetplayer && !FLS) + { emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); + } if (modeattacking) { @@ -2027,8 +2032,6 @@ static void Command_Suicide(void) UINT8 buf[4]; UINT8 *cp = buf; - WRITEINT32(cp, consoleplayer); - if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)) { CONS_Printf(M_GetText("You must be in a level to use this.\n")); @@ -2048,6 +2051,7 @@ static void Command_Suicide(void) return; } + WRITEINT32(cp, consoleplayer); SendNetXCmd(XD_SUICIDE, &buf, 4); } @@ -2714,14 +2718,6 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } } - // Clear player score and rings if a spectator. - if (players[playernum].spectator) - { - players[playernum].score = players[playernum].rings = 0; - if (players[playernum].mo) - players[playernum].mo->health = 1; - } - // In tag, check to see if you still have a game. if (G_TagGametype()) P_CheckSurvivors(); @@ -3608,7 +3604,7 @@ static void CoopLives_OnChange(void) { case 0: CONS_Printf(M_GetText("Players can now respawn indefinitely.\n")); - return; + break; case 1: CONS_Printf(M_GetText("Lives are now per-player.\n")); return; @@ -4111,6 +4107,7 @@ void Command_ExitGame_f(void) botskin = 0; cv_debug = 0; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); if (dirmenu) closefilemenu(true); @@ -4467,3 +4464,14 @@ static void Command_ShowTime_f(void) CONS_Printf(M_GetText("The current time is %f.\nThe timelimit is %f\n"), (double)leveltime/TICRATE, (double)timelimitintics/TICRATE); } + +static void BaseNumLaps_OnChange(void) +{ + if (gametype == GT_RACE) + { + if (cv_basenumlaps.value) + CONS_Printf(M_GetText("Number of laps will be changed to map defaults next round.\n")); + else + CONS_Printf(M_GetText("Number of laps will be changed to %d next round.\n"), cv_basenumlaps.value); + } +} diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 5076c8afa..e789e5b50 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -66,7 +66,7 @@ extern consvar_t cv_friendlyfire; extern consvar_t cv_pointlimit; extern consvar_t cv_timelimit; extern consvar_t cv_numlaps; -extern consvar_t cv_usemapnumlaps; +extern consvar_t cv_basenumlaps; extern UINT32 timelimitintics; extern consvar_t cv_allowexitlevel; @@ -107,9 +107,7 @@ extern consvar_t cv_ringslinger, cv_soundtest; extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes; -#ifdef NEWPING extern consvar_t cv_maxping; -#endif extern consvar_t cv_skipmapcheck; @@ -190,6 +188,7 @@ typedef union { // add game commands, needs cleanup void D_RegisterServerCommands(void); void D_RegisterClientCommands(void); +boolean EnsurePlayerNameIsGood(char *name, INT32 playernum); void D_SendPlayerConfig(void); void Command_ExitGame_f(void); void Command_Retry_f(void); diff --git a/src/d_netfil.c b/src/d_netfil.c index ed2d11138..5e7f59310 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -752,11 +752,9 @@ void Got_Filetxpak(void) nameonly(filename); if (!(strcmp(filename, "srb2.pk3") - && strcmp(filename, "srb2.srb") - && strcmp(filename, "srb2.wad") - && strcmp(filename, "zones.dta") + && strcmp(filename, "zones.pk3") && strcmp(filename, "player.dta") - && strcmp(filename, "patch.dta") + && strcmp(filename, "patch.pk3") && strcmp(filename, "music.dta") )) I_Error("Tried to download \"%s\"", filename); diff --git a/src/d_player.h b/src/d_player.h index 69080bd9d..f2fdda050 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -234,7 +234,9 @@ typedef enum CR_ZOOMTUBE, CR_ROPEHANG, CR_MACESPIN, - CR_MINECART + CR_MINECART, + CR_ROLLOUT, + CR_PTERABYTE } carrytype_t; // pw_carry // Player powers. (don't edit this comment) @@ -250,6 +252,8 @@ typedef enum pw_spacetime, // In space, no one can hear you spin! pw_extralife, // Extra Life timer pw_pushing, + pw_justsprung, + pw_noautobrake, pw_super, // Are you super? pw_gravityboots, // gravity boots @@ -509,6 +513,10 @@ typedef struct player_s #endif } player_t; +// Values for dashmode +#define DASHMODE_THRESHOLD (3*TICRATE) +#define DASHMODE_MAX (DASHMODE_THRESHOLD + 3) + // Value for infinite lives #define INFLIVES 0x7F diff --git a/src/dehacked.c b/src/dehacked.c index 37995cc9f..34ee1f170 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -313,7 +313,13 @@ static boolean findFreeSlot(INT32 *num) if (*num >= MAXSKINS) return false; - description[*num].picname[0] = '\0'; // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) + // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) + description[*num].picname[0] = '\0'; + description[*num].nametag[0] = '\0'; + description[*num].displayname[0] = '\0'; + description[*num].oppositecolor = SKINCOLOR_NONE; + description[*num].tagtextcolor = SKINCOLOR_NONE; + description[*num].tagoutlinecolor = SKINCOLOR_NONE; // Found one! ^_^ return (description[*num].used = true); @@ -326,9 +332,16 @@ static void readPlayer(MYFILE *f, INT32 num) char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *word; char *word2; + char *displayname = ZZ_Alloc(MAXLINELEN+1); INT32 i; boolean slotfound = false; + #define SLOTFOUND \ + if (!slotfound && (slotfound = findFreeSlot(&num)) == false) \ + goto done; + + displayname[MAXLINELEN] = '\0'; + do { if (myfgets(s, MAXLINELEN, f)) @@ -336,6 +349,17 @@ static void readPlayer(MYFILE *f, INT32 num) if (s[0] == '\n') break; + for (i = 0; i < MAXLINELEN-3; i++) + { + char *tmp; + if (s[i] == '=') + { + tmp = &s[i+2]; + strncpy(displayname, tmp, SKINNAMESIZE); + break; + } + } + word = strtok(s, " "); if (word) strupr(word); @@ -346,8 +370,7 @@ static void readPlayer(MYFILE *f, INT32 num) { char *playertext = NULL; - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; + SLOTFOUND for (i = 0; i < MAXLINELEN-3; i++) { @@ -395,11 +418,54 @@ static void readPlayer(MYFILE *f, INT32 num) if (fastcmp(word, "PICNAME")) { - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; - + SLOTFOUND strncpy(description[num].picname, word2, 8); } + // new character select + else if (fastcmp(word, "DISPLAYNAME")) + { + SLOTFOUND + // replace '#' with line breaks + // (also remove any '\n') + { + char *cur = NULL; + + // remove '\n' + cur = strchr(displayname, '\n'); + if (cur) + *cur = '\0'; + + // turn '#' into '\n' + cur = strchr(displayname, '#'); + while (cur) + { + *cur = '\n'; + cur = strchr(cur, '#'); + } + } + // copy final string + strncpy(description[num].displayname, displayname, SKINNAMESIZE); + } + else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR")) + { + SLOTFOUND + description[num].oppositecolor = (UINT8)get_number(word2); + } + else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME")) + { + SLOTFOUND + strncpy(description[num].nametag, word2, 8); + } + else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR")) + { + SLOTFOUND + description[num].tagtextcolor = (UINT8)get_number(word2); + } + else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR")) + { + SLOTFOUND + description[num].tagoutlinecolor = (UINT8)get_number(word2); + } else if (fastcmp(word, "STATUS")) { /* @@ -417,9 +483,7 @@ static void readPlayer(MYFILE *f, INT32 num) else if (fastcmp(word, "SKINNAME")) { // Send to free slot. - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; - + SLOTFOUND strlcpy(description[num].skinname, word2, sizeof description[num].skinname); strlwr(description[num].skinname); } @@ -427,8 +491,9 @@ static void readPlayer(MYFILE *f, INT32 num) deh_warning("readPlayer %d: unknown word '%s'", num, word); } } while (!myfeof(f)); // finish when the line is empty - + #undef SLOTFOUND done: + Z_Free(displayname); Z_Free(s); } @@ -2325,6 +2390,7 @@ static actionpointer_t actionpointers[] = {{A_Boss1Spikeballs}, "A_BOSS1SPIKEBALLS"}, {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, {{A_Boss3Path}, "A_BOSS3PATH"}, + {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, @@ -2431,6 +2497,7 @@ static actionpointer_t actionpointers[] = {{A_Boss5CheckFalling}, "A_BOSS5CHECKFALLING"}, {{A_Boss5PinchShot}, "A_BOSS5PINCHSHOT"}, {{A_Boss5MakeItRain}, "A_BOSS5MAKEITRAIN"}, + {{A_Boss5MakeJunk}, "A_BOSS5MAKEJUNK"}, {{A_LookForBetter}, "A_LOOKFORBETTER"}, {{A_Boss5BombExplode}, "A_BOSS5BOMBEXPLODE"}, {{A_DustDevilThink}, "A_DUSTDEVILTHINK"}, @@ -2445,6 +2512,14 @@ static actionpointer_t actionpointers[] = {{A_SaloonDoorSpawn}, "A_SALOONDOORSPAWN"}, {{A_MinecartSparkThink}, "A_MINECARTSPARKTHINK"}, {{A_ModuloToState}, "A_MODULOTOSTATE"}, + {{A_LavafallRocks}, "A_LAVAFALLROCKS"}, + {{A_LavafallLava}, "A_LAVAFALLLAVA"}, + {{A_FallingLavaCheck}, "A_FALLINGLAVACHECK"}, + {{A_FireShrink}, "A_FIRESHRINK"}, + {{A_SpawnPterabytes}, "A_SPAWNPTERABYTES"}, + {{A_PterabyteHover}, "A_PTERABYTEHOVER"}, + {{A_RolloutSpawn}, "A_ROLLOUTSPAWN"}, + {{A_RolloutRock}, "A_ROLLOUTROCK"}, {{NULL}, "NONE"}, // This NULL entry must be the last in the list @@ -4183,6 +4258,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // CA_GLIDEANDCLIMB "S_PLAY_GLIDE", + "S_PLAY_GLIDE_LANDING", "S_PLAY_CLING", "S_PLAY_CLIMB", @@ -4282,6 +4358,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_TAILSOVERLAY_GASP", "S_TAILSOVERLAY_EDGE", + // [: + "S_JETFUMEFLASH", + // Blue Crawla "S_POSS_STND", "S_POSS_RUN1", @@ -4430,6 +4509,21 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CRUSHCLAW_WAIT", "S_CRUSHCHAIN", + // Banpyura + "S_BANPYURA_ROAM1", + "S_BANPYURA_ROAM2", + "S_BANPYURA_ROAM3", + "S_BANPYURA_ROAM4", + "S_BANPYURA_ROAMPAUSE", + "S_CDIAG1", + "S_CDIAG2", + "S_CDIAG3", + "S_CDIAG4", + "S_CDIAG5", + "S_CDIAG6", + "S_CDIAG7", + "S_CDIAG8", + // Jet Jaw "S_JETJAW_ROAM1", "S_JETJAW_ROAM2", @@ -4616,6 +4710,22 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CANARIVOREGAS_7", "S_CANARIVOREGAS_8", + // Pyre Fly + "S_PYREFLY_FLY", + "S_PYREFLY_BURN", + "S_PYREFIRE1", + "S_PYREFIRE2", + + // Pterabyte + "S_PTERABYTESPAWNER", + "S_PTERABYTEWAYPOINT", + "S_PTERABYTE_FLY1", + "S_PTERABYTE_FLY2", + "S_PTERABYTE_FLY3", + "S_PTERABYTE_FLY4", + "S_PTERABYTE_SWOOPDOWN", + "S_PTERABYTE_SWOOPUP", + // Boss Explosion "S_BOSSEXPLODE", @@ -4742,6 +4852,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BOSSSEBH1", "S_BOSSSEBH2", + // Boss 3 Shockwave + + "S_SHOCKWAVE1", + "S_SHOCKWAVE2", + // Boss 4 "S_EGGMOBILE4_STND", "S_EGGMOBILE4_LATK1", @@ -4784,6 +4899,25 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGROBOJET", // Boss 5 + "S_FANG_SETUP", + "S_FANG_INTRO0", + "S_FANG_INTRO1", + "S_FANG_INTRO2", + "S_FANG_INTRO3", + "S_FANG_INTRO4", + "S_FANG_INTRO5", + "S_FANG_INTRO6", + "S_FANG_INTRO7", + "S_FANG_INTRO8", + "S_FANG_INTRO9", + "S_FANG_INTRO10", + "S_FANG_INTRO11", + "S_FANG_INTRO12", + "S_FANG_CLONE1", + "S_FANG_CLONE2", + "S_FANG_CLONE3", + "S_FANG_CLONE4", + "S_FANG_IDLE0", "S_FANG_IDLE1", "S_FANG_IDLE2", "S_FANG_IDLE3", @@ -4855,6 +4989,26 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FANG_FLEEBOUNCE2", "S_FANG_KO", + "S_BROKENROBOTRANDOM", + "S_BROKENROBOTA", + "S_BROKENROBOTB", + "S_BROKENROBOTC", + "S_BROKENROBOTD", + "S_BROKENROBOTE", + "S_BROKENROBOTF", + + "S_ALART1", + "S_ALART2", + + "S_VWREF", + "S_VWREB", + + "S_PROJECTORLIGHT1", + "S_PROJECTORLIGHT2", + "S_PROJECTORLIGHT3", + "S_PROJECTORLIGHT4", + "S_PROJECTORLIGHT5", + "S_FBOMB1", "S_FBOMB2", "S_FBOMB_EXPL1", @@ -5578,14 +5732,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_DRIPC1", "S_DRIPC2", - // Coral 1 + // Coral "S_CORAL1", - - // Coral 2 "S_CORAL2", - - // Coral 3 "S_CORAL3", + "S_CORAL4", + "S_CORAL5", // Blue Crystal "S_BLUECRYSTAL1", @@ -5593,6 +5745,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Kelp, "S_KELP", + // Animated algae + "S_ANIMALGAETOP1", + "S_ANIMALGAETOP2", + "S_ANIMALGAESEG", + // DSZ Stalagmites "S_DSZSTALAGMITE", "S_DSZ2STALAGMITE", @@ -5737,6 +5894,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CACTI7", "S_CACTI8", "S_CACTI9", + "S_CACTI10", + "S_CACTI11", + "S_CACTITINYSEG", + "S_CACTISMALLSEG", // Warning signs sprites "S_ARIDSIGN_CAUTION", @@ -5808,7 +5969,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Saloon door "S_SALOONDOOR", - "S_SALOONDOORTHINKER", + "S_SALOONDOORCENTER", // Train cameo "S_TRAINCAMEOSPAWNER_1", @@ -5829,6 +5990,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLAMEJETFLAME1", "S_FLAMEJETFLAME2", "S_FLAMEJETFLAME3", + "S_FLAMEJETFLAME4", + "S_FLAMEJETFLAME5", + "S_FLAMEJETFLAME6", + "S_FLAMEJETFLAME7", + "S_FLAMEJETFLAME8", + "S_FLAMEJETFLAME9", // Spinning flame jets "S_FJSPINAXISA1", // Counter-clockwise @@ -5841,6 +6008,28 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLAMEJETFLAMEB2", "S_FLAMEJETFLAMEB3", + // Lavafall + "S_LAVAFALL_DORMANT", + "S_LAVAFALL_TELL", + "S_LAVAFALL_SHOOT", + "S_LAVAFALL_LAVA1", + "S_LAVAFALL_LAVA2", + "S_LAVAFALL_LAVA3", + "S_LAVAFALLROCK", + + // Rollout Rock + "S_ROLLOUTSPAWN", + "S_ROLLOUTROCK", + + // RVZ scenery + "S_BIGFERNLEAF", + "S_BIGFERN1", + "S_BIGFERN2", + "S_JUNGLEPALM", + "S_TORCHFLOWER", + "S_WALLVINE_LONG", + "S_WALLVINE_SHORT", + // Trapgoyles "S_TRAPGOYLE", "S_TRAPGOYLE_CHECK", @@ -5872,6 +6061,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_TARGET_RESPAWN", "S_TARGET_ALLDONE", + // ATZ's green flame + "S_GREENFLAME", + // Stalagmites "S_STG0", "S_STG1", @@ -5892,6 +6084,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_LAMPPOST1", // normal "S_LAMPPOST2", // with snow "S_HANGSTAR", + "S_MISTLETOE", // Xmas GFZ bushes "S_XMASBLUEBERRYBUSH", "S_XMASBERRYBUSH", @@ -5899,6 +6092,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // FHZ "S_FHZICE1", "S_FHZICE2", + "S_ROSY_IDLE1", + "S_ROSY_IDLE2", + "S_ROSY_IDLE3", + "S_ROSY_IDLE4", + "S_ROSY_JUMP", + "S_ROSY_WALK", + "S_ROSY_HUG", + "S_ROSY_PAIN", + "S_ROSY_STND", + "S_ROSY_UNHAPPY", // Halloween Scenery // Pumpkins @@ -6550,6 +6753,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BHORIZ7", "S_BHORIZ8", + "S_BOOSTERSOUND", + "S_YELLOWBOOSTERROLLER", + "S_YELLOWBOOSTERSEG_LEFT", + "S_YELLOWBOOSTERSEG_RIGHT", + "S_YELLOWBOOSTERSEG_FACE", + "S_REDBOOSTERROLLER", + "S_REDBOOSTERSEG_LEFT", + "S_REDBOOSTERSEG_RIGHT", + "S_REDBOOSTERSEG_FACE", + // Rain "S_RAIN1", "S_RAINRETURN", @@ -6570,6 +6783,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SPLISH8", "S_SPLISH9", + // Lava splish + "S_LAVASPLISH", + // added water splash "S_SPLASH1", "S_SPLASH2", @@ -7181,6 +7397,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_THOK", // Thok! mobj "MT_PLAYER", "MT_TAILSOVERLAY", // c: + "MT_METALJETFUME", // [: // Enemies "MT_BLUECRAWLA", // Crawla (Blue) @@ -7199,6 +7416,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CRUSHSTACEAN", // Crushstacean "MT_CRUSHCLAW", // Big meaty claw "MT_CRUSHCHAIN", // Chain + "MT_BANPYURA", // Banpyura + "MT_BANPSPRING", // Banpyura spring "MT_JETJAW", // Jet Jaw "MT_SNAILER", // Snailer "MT_VULTURE", // BASH @@ -7220,6 +7439,11 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_UNIBALL", // Unidus Ball "MT_CANARIVORE", // Canarivore "MT_CANARIVORE_GAS", // Canarivore gas + "MT_PYREFLY", // Pyre Fly + "MT_PYREFLY_FIRE", // Pyre Fly fire + "MT_PTERABYTESPAWNER", // Pterabyte spawner + "MT_PTERABYTEWAYPOINT", // Pterabyte waypoint + "MT_PTERABYTE", // Pterabyte // Generic Boss Items "MT_BOSSEXPLODE", @@ -7246,7 +7470,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Boss 3 "MT_EGGMOBILE3", "MT_FAKEMOBILE", - "MT_SHOCK", + "MT_SHOCKWAVE", // Boss 4 "MT_EGGMOBILE4", @@ -7257,6 +7481,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Boss 5 "MT_FANG", + "MT_BROKENROBOT", + "MT_VWREF", + "MT_VWREB", + "MT_PROJECTORLIGHT", "MT_FBOMB", "MT_TNTDUST", // also used by barrel "MT_FSGNA", @@ -7327,6 +7555,11 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_REDHORIZ", "MT_BLUEHORIZ", + "MT_BOOSTERSEG", + "MT_BOOSTERROLLER", + "MT_YELLOWBOOSTER", + "MT_REDBOOSTER", + // Interactive Objects "MT_BUBBLES", // Bubble source "MT_SIGN", // Level end sign @@ -7455,11 +7688,15 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SEAWEED", // DSZ Seaweed "MT_WATERDRIP", // Dripping Water source "MT_WATERDROP", // Water drop from dripping water - "MT_CORAL1", // Coral 1 - "MT_CORAL2", // Coral 2 - "MT_CORAL3", // Coral 3 + "MT_CORAL1", // Coral + "MT_CORAL2", + "MT_CORAL3", + "MT_CORAL4", + "MT_CORAL5", "MT_BLUECRYSTAL", // Blue Crystal "MT_KELP", // Kelp + "MT_ANIMALGAETOP", // Animated algae top + "MT_ANIMALGAESEG", // Animated algae segment "MT_DSZSTALAGMITE", // Deep Sea 1 Stalagmite "MT_DSZ2STALAGMITE", // Deep Sea 2 Stalagmite "MT_LIGHTBEAM", // DSZ Light beam @@ -7519,6 +7756,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CACTI7", "MT_CACTI8", "MT_CACTI9", + "MT_CACTI10", + "MT_CACTI11", + "MT_CACTITINYSEG", + "MT_CACTISMALLSEG", "MT_ARIDSIGN_CAUTION", "MT_ARIDSIGN_CACTI", "MT_ARIDSIGN_SHARPTURN", @@ -7536,7 +7777,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_MINECARTSIDEMARK", "MT_MINECARTSPARK", "MT_SALOONDOOR", - "MT_SALOONDOORTHINKER", + "MT_SALOONDOORCENTER", "MT_TRAINCAMEOSPAWNER", "MT_TRAINSEG", "MT_TRAINDUSTSPAWNER", @@ -7553,6 +7794,20 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_FLAMEJETFLAMEB", // Blade's flame + "MT_LAVAFALL", + "MT_LAVAFALL_LAVA", + "MT_LAVAFALLROCK", + + "MT_ROLLOUTSPAWN", + "MT_ROLLOUTROCK", + + "MT_BIGFERNLEAF", + "MT_BIGFERN", + "MT_JUNGLEPALM", + "MT_TORCHFLOWER", + "MT_WALLVINE_LONG", + "MT_WALLVINE_SHORT", + // Dark City Scenery // Egg Rock Scenery @@ -7563,6 +7818,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_TRAPGOYLEDOWN", "MT_TRAPGOYLELONG", "MT_TARGET", + "MT_GREENFLAME", // Stalagmites "MT_STALAGMITE0", @@ -7584,6 +7840,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_LAMPPOST1", // normal "MT_LAMPPOST2", // with snow "MT_HANGSTAR", + "MT_MISTLETOE", // Xmas GFZ bushes "MT_XMASBLUEBERRYBUSH", "MT_XMASBERRYBUSH", @@ -7591,6 +7848,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // FHZ "MT_FHZICE1", "MT_FHZICE2", + "MT_ROSY", + "MT_CDLHRT", // Halloween Scenery // Pumpkins @@ -7719,6 +7978,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_RAIN", // Rain "MT_SNOWFLAKE", // Snowflake "MT_SPLISH", // Water splish! + "MT_LAVASPLISH", // Lava splish! "MT_SMOKE", "MT_SMALLBUBBLE", // small bubble "MT_MEDIUMBUBBLE", // medium bubble @@ -8204,6 +8464,8 @@ static const char *const POWERS_LIST[] = { "SPACETIME", // In space, no one can hear you spin! "EXTRALIFE", // Extra Life timer "PUSHING", + "JUSTSPRUNG", + "NOAUTOBRAKE", "SUPER", // Are you super? "GRAVITYBOOTS", // gravity boots @@ -8544,6 +8806,8 @@ struct { {"CR_ROPEHANG",CR_ROPEHANG}, {"CR_MACESPIN",CR_MACESPIN}, {"CR_MINECART",CR_MINECART}, + {"CR_ROLLOUT", CR_ROLLOUT}, + {"CR_PTERABYTE",CR_PTERABYTE}, // Ring weapons (ringweapons_t) // Useful for A_GiveWeapon @@ -8765,9 +9029,9 @@ struct { {"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top. {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. {"FF_INTANGABLEFLATS",FF_INTANGABLEFLATS}, ///< Both flats are intangable, but the sides are still solid. - {"FF_SHATTER",FF_SHATTER}, ///< Used with ::FF_BUSTUP. Thinks everyone's Knuckles. - {"FF_SPINBUST",FF_SPINBUST}, ///< Used with ::FF_BUSTUP. Jump or fall onto it while curled in a ball. - {"FF_ONLYKNUX",FF_ONLYKNUX}, ///< Used with ::FF_BUSTUP. Only Knuckles can break this rock. + {"FF_SHATTER",FF_SHATTER}, ///< Used with ::FF_BUSTUP. Bustable on mere touch. + {"FF_SPINBUST",FF_SPINBUST}, ///< Used with ::FF_BUSTUP. Also bustable if you're in your spinning frames. + {"FF_STRONGBUST",FF_STRONGBUST }, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee). {"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. @@ -8898,6 +9162,7 @@ struct { {"V_OFFSET",V_OFFSET}, {"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE}, {"V_FLIP",V_FLIP}, + {"V_CENTERNAMETAG",V_CENTERNAMETAG}, {"V_SNAPTOTOP",V_SNAPTOTOP}, {"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM}, {"V_SNAPTOLEFT",V_SNAPTOLEFT}, @@ -8931,6 +9196,7 @@ struct { {"TC_ALLWHITE",TC_ALLWHITE}, {"TC_RAINBOW",TC_RAINBOW}, {"TC_BLINK",TC_BLINK}, + {"TC_DASHMODE",TC_DASHMODE}, #endif {NULL,0} @@ -9917,6 +10183,23 @@ static inline int lib_getenum(lua_State *L) } 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; diff --git a/src/doomdef.h b/src/doomdef.h index 4a0174369..676c86e0d 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -506,13 +506,20 @@ INT32 I_GetKey(void); #define max(x, y) (((x) > (y)) ? (x) : (y)) #endif +// Max gamepad/joysticks that can be detected/used. +#define MAX_JOYSTICKS 4 + +#ifndef M_PIl +#define M_PIl 3.1415926535897932384626433832795029L +#endif + // Floating point comparison epsilons from float.h #ifndef FLT_EPSILON #define FLT_EPSILON 1.1920928955078125e-7f #endif #ifndef DBL_EPSILON -#define DBL_EPSILON 2.2204460492503131e-16 +#define DBL_EPSILON 2.2204460492503131e-16l #endif // An assert-type mechanism. @@ -558,9 +565,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Polyobject fake flat code #define POLYOBJECTS_PLANES -/// Improved way of dealing with ping values and a ping limit. -#define NEWPING - /// See name of player in your crosshair #define SEENAMES diff --git a/src/doomstat.h b/src/doomstat.h index a70a122a6..7d06f03e2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -327,7 +327,7 @@ typedef struct // Music stuff. UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds char musintername[7]; ///< Intermission screen music. - + char muspostbossname[7]; ///< Post-bossdeath music. UINT16 muspostbosstrack; ///< Post-bossdeath track. UINT32 muspostbosspos; ///< Post-bossdeath position @@ -420,6 +420,10 @@ extern UINT16 emeralds; #define EMERALD7 64 #define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) +// yes, even in non HAVE_BLUA +#define NUM_LUABANKS 16 // please only make this number go up between versions, never down. you'll break saves otherwise. also, must fit in UINT8 +extern INT32 luabanks[NUM_LUABANKS]; + extern INT32 nummaprings; //keep track of spawned rings/coins /** Time attack information, currently a very small structure. @@ -429,6 +433,7 @@ typedef struct tic_t time; ///< Time in which the level was finished. UINT32 score; ///< Score when the level was finished. UINT16 rings; ///< Rings when the level was finished. + boolean gotperfect; ///< Got perfect bonus? } recorddata_t; /** Setup for one NiGHTS map. diff --git a/src/f_finale.c b/src/f_finale.c index e44add4d1..eb1415042 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -75,6 +75,7 @@ INT32 curbgcolor; INT32 curbgxspeed; INT32 curbgyspeed; boolean curbghide; +boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus static UINT8 curDemo = 0; static UINT32 demoDelayLeft; @@ -637,6 +638,7 @@ static void F_IntroDrawScene(void) } else { + menuanimtimer = animtimer; // Reusing this variable for the intro to fix the scrolling sky, better than changing the function around. F_SkyScroll(80*4, 0, "TITLESKY"); if (timetonext == 6) { @@ -1584,15 +1586,15 @@ void F_StartEnding(void) UINT8 skinnum = players[consoleplayer].skin; spritedef_t *sprdef; spriteframe_t *sprframe; - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 7) + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= (XTRA_ENDING+2)+1) { sprdef = &skins[skinnum].sprites[SPR2_XTRA]; // character head, skin specific - sprframe = &sprdef->spriteframes[4]; + sprframe = &sprdef->spriteframes[XTRA_ENDING]; endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[5]; + sprframe = &sprdef->spriteframes[XTRA_ENDING+1]; endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[6]; + sprframe = &sprdef->spriteframes[XTRA_ENDING+2]; endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); } else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this) @@ -2097,12 +2099,12 @@ void F_InitMenuPresValues(void) curfadevalue = 16; curhidepics = hidetitlepics; curbgcolor = -1; - curbgxspeed = titlescrollxspeed; - curbgyspeed = titlescrollyspeed; - curbghide = true; + curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; + curbgyspeed = (gamestate == GS_TIMEATTACK) ? 22 : titlescrollyspeed; + curbghide = (gamestate == GS_TIMEATTACK) ? false : true; // Find current presentation values - M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "SRB2BACK" : "TITLESKY"); + M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "RECATTBG" : "TITLESKY"); M_SetMenuCurFadeValue(16); M_SetMenuCurHideTitlePics(); } @@ -2465,6 +2467,11 @@ void F_TitleDemoTicker(void) // ========== // CONTINUE // ========== + +static skin_t *contskins[2]; +static UINT8 cont_spr2[2][6]; +static UINT8 *contcolormaps[2]; + void F_StartContinue(void) { I_Assert(!netgame && !multiplayer); @@ -2488,7 +2495,44 @@ void F_StartContinue(void) S_ChangeMusicInternal("_conti", false); S_StopSounds(); - timetonext = TICRATE*11; + contskins[0] = &skins[players[consoleplayer].skin]; + cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL); + cont_spr2[0][2] = contskins[0]->contangle & 7; + contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE); + cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes; + cont_spr2[0][5] = max(1, contskins[0]->contspeed); + + if (botskin) + { + INT32 secondplaya; + + if (secondarydisplayplayer != consoleplayer) + secondplaya = secondarydisplayplayer; + else // HACK + secondplaya = 1; + + contskins[1] = &skins[players[secondplaya].skin]; + cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL); + cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7; + contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE); + cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes; + if (cont_spr2[1][0] == SPR2_CNT4) + cont_spr2[1][5] = 4; // sorry, this one is hardcoded + else + cont_spr2[1][5] = max(1, contskins[1]->contspeed); + } + else + { + contskins[1] = NULL; + contcolormaps[1] = NULL; + cont_spr2[1][0] = cont_spr2[1][2] = cont_spr2[1][4] = cont_spr2[1][5] = 0; + } + + cont_spr2[0][1] = cont_spr2[0][3] =\ + cont_spr2[1][1] = cont_spr2[1][3] = 0; + + timetonext = (11*TICRATE)+11; + continuetime = 0; } // @@ -2497,47 +2541,198 @@ void F_StartContinue(void) // void F_ContinueDrawer(void) { - patch_t *contsonic; - INT32 i, x = (BASEVIDWIDTH/2) + 4, ncontinues = players[consoleplayer].continues; - if (ncontinues > 20) - ncontinues = 20; + spritedef_t *sprdef; + spriteframe_t *sprframe; + patch_t *patch; + INT32 i, x = (BASEVIDWIDTH>>1), ncontinues = players[consoleplayer].continues; + char numbuf[9] = "CONTNUM*"; + tic_t timeleft = (timetonext/TICRATE); + INT32 offsx = 0, offsy = 0, lift[2] = {0, 0}; - if (imcontinuing) - contsonic = W_CachePatchName("CONT2", PU_CACHE); - else - contsonic = W_CachePatchName("CONT1", PU_CACHE); + if (continuetime >= 3*TICRATE) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); + return; + } V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - V_DrawCenteredString(BASEVIDWIDTH/2, 100, 0, "CONTINUE?"); - // Draw a Sonic! - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(contsonic->width))/2, 32, 0, contsonic); + if (timetonext >= (11*TICRATE)+10) + return; - // Draw the continue markers! Show continues minus one. - x -= ncontinues * 6; - for (i = 0; i < ncontinues; ++i) - V_DrawContinueIcon(x + (i*12), 140, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); + V_DrawLevelTitle(x - (V_LevelNameWidth("CONTINUE")>>1), 16, 0, "CONTINUE"); - V_DrawCenteredString(BASEVIDWIDTH/2, 168, 0, va("\x82*\x80" " %02d " "\x82*\x80", timetonext/TICRATE)); + // Two stars... + patch = W_CachePatchName("CONTSTAR", PU_CACHE); + V_DrawScaledPatch(x-32, 160, 0, patch); + V_DrawScaledPatch(x+32, 160, 0, patch); + + // Time left! + if (timeleft > 9) + { + numbuf[7] = '1'; + V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + numbuf[7] = '0'; + V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + } + else + { + numbuf[7] = '0'+timeleft; + V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + } + + // Draw the continue markers! Show continues. + if (ncontinues > 10) + { + if (!(continuetime & 1) || continuetime > 17) + V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); + V_DrawScaledPatch(x+12, 68-2, 0, stlivex); + V_DrawRightAlignedString(x+36, 69-5, 0, + va("%d",(imcontinuing ? ncontinues-1 : ncontinues))); + } + else + { + x += (ncontinues/2) * 30; + if (!(ncontinues & 1)) + x -= 15; + for (i = 0; i < ncontinues; ++i) + { + if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17)) + continue; + V_DrawContinueIcon(x - (i*30), 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); + } + x = BASEVIDWIDTH>>1; + } + + // Spotlight + V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_CACHE)); + + // warping laser + if (continuetime) + { + INT32 w = min(continuetime, 28), brightness = (continuetime>>1) & 7; + if (brightness > 3) + brightness = 8-brightness; + V_DrawFadeFill(x-w, 0, w<<1, 140, 0, 0, (3+brightness)); + } + + if (contskins[1]) + { + if (continuetime > 15) + { + angle_t work = FixedAngle((10*(continuetime-15))<>ANGLETOFINESHIFT; + offsy = FINESINE(work)<<1; + offsx = (27*FINECOSINE(work))>>1; + } + else + offsx = 27<<(FRACBITS-1); + lift[1] = continuetime-10; + if (lift[1] < 0) + lift[1] = 0; + else if (lift[1] > TICRATE+5) + lift[1] = TICRATE+5; + } + + lift[0] = continuetime-5; + if (lift[0] < 0) + lift[0] = 0; + else if (lift[0] > TICRATE+5) + lift[0] = TICRATE+5; + +#define drawchar(dx, dy, n) {\ + 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_CACHE);\ + V_DrawFixedPatch((dx), (dy), FRACUNIT, (sprframe->flip & (1<= 0) + drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])< (11*TICRATE)) + V_DrawFadeScreen(31, timetonext-(11*TICRATE)); + if (continuetime > ((3*TICRATE) - 10)) + V_DrawFadeScreen(0, (continuetime - ((3*TICRATE) - 10))); } void F_ContinueTicker(void) { if (!imcontinuing) { - // note the setup to prevent 2x reloading - if (timetonext >= 0) - timetonext--; - if (timetonext == 0) - Command_ExitGame_f(); + if (timetonext > 0) + { + if (!(--timetonext)) + { + Command_ExitGame_f(); + return; + } + } } else { - // note the setup to prevent 2x reloading - if (continuetime >= 0) - continuetime--; - if (continuetime == 0) + if (++continuetime == 3*TICRATE) + { G_Continue(); + return; + } + + if (continuetime > 5 && ((continuetime & 1) || continuetime > TICRATE) && (++cont_spr2[0][2]) >= 8) + cont_spr2[0][2] = 0; + + if (continuetime > 10 && (!(continuetime & 1) || continuetime > TICRATE+5) && (++cont_spr2[1][2]) >= 8) + cont_spr2[1][2] = 0; + + if (continuetime == (3*TICRATE)-10) + S_StartSound(NULL, sfx_cdfm56); // or 31 + else if (continuetime == 5) + { + cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT2, NULL); + cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes; + cont_spr2[0][1] = cont_spr2[0][3] = 0; + cont_spr2[0][5] = 2; + } + else if (continuetime == TICRATE) + { + cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT3, NULL); + cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes; + cont_spr2[0][1] = cont_spr2[0][3] = 0; + } + else if (contskins[1]) + { + if (continuetime == 10) + { + cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT2, NULL); + cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes; + cont_spr2[1][1] = cont_spr2[1][3] = 0; + cont_spr2[1][5] = 2; + } + else if (continuetime == TICRATE+5) + { + cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT3, NULL); + cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes; + cont_spr2[1][1] = cont_spr2[1][3] = 0; + } + } + } + + if ((++cont_spr2[0][3]) >= cont_spr2[0][5]) + { + cont_spr2[0][3] = 0; + if (++cont_spr2[0][1] >= cont_spr2[0][4]) + cont_spr2[0][1] = 0; + } + + if (contskins[1] && (++cont_spr2[1][3]) >= cont_spr2[1][5]) + { + cont_spr2[1][3] = 0; + if (++cont_spr2[1][1] >= cont_spr2[1][4]) + cont_spr2[1][1] = 0; } } @@ -2568,8 +2763,9 @@ boolean F_ContinueResponder(event_t *event) keypressed = true; imcontinuing = true; - continuetime = TICRATE; - S_StartSound(NULL, sfx_itemup); + S_StartSound(NULL, sfx_kc6b); + I_FadeSong(0, MUSICRATE, &S_StopMusic); + return true; } diff --git a/src/f_finale.h b/src/f_finale.h index d640abc8a..58c492c3d 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -94,6 +94,7 @@ extern INT32 curbgcolor; extern INT32 curbgxspeed; extern INT32 curbgyspeed; extern boolean curbghide; +extern boolean hidetitlemap; #define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0]) diff --git a/src/filesrch.c b/src/filesrch.c index 8f157bdd5..13d73b6f4 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -751,7 +751,7 @@ boolean preparefilemenu(boolean samedepth) } else if (ext == EXT_TXT) { - if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + if (!strncmp(dent->d_name, "log-", 4) || !strcmp(dent->d_name, "errorlog.txt")) ext |= EXT_LOADED; } diff --git a/src/g_game.c b/src/g_game.c index 55154c3e6..e2f43e4f2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -172,6 +172,7 @@ static boolean retrying = false; UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage. UINT16 emeralds; +INT32 luabanks[NUM_LUABANKS]; // yes, even in non HAVE_BLUA UINT32 token; // Number of tokens collected in a level UINT32 tokenlist; // List of tokens collected boolean gottoken; // Did you get a token? Used for end of act @@ -215,7 +216,7 @@ UINT16 spacetimetics = 11*TICRATE + (TICRATE/2); UINT16 extralifetics = 4*TICRATE; UINT16 nightslinktics = 2*TICRATE; -INT32 gameovertics = 15*TICRATE; +INT32 gameovertics = 11*TICRATE; UINT8 ammoremovaltics = 2*TICRATE; @@ -360,6 +361,8 @@ consvar_t cv_chatbacktint = {"chatbacktint", "On", CV_SAVE, CV_OnOff, NULL, 0, N static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}}; consvar_t cv_consolechat = {"chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +// Pause game upon window losing focus +consvar_t cv_pauseifunfocused = {"pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_crosshair = {"crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_crosshair2 = {"crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -885,6 +888,7 @@ static fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) { boolean forcestrafe = false; + boolean forcefullinput = false; INT32 tspeed, forward, side, axis, altaxis, i; const INT32 speed = 1; // these ones used for multiple conditions @@ -960,8 +964,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) } if (twodlevel || (player->mo && (player->mo->flags2 & MF2_TWOD)) - || (!demoplayback && (player->climbing - || (player->powers[pw_carry] == CR_NIGHTSMODE) + || (!demoplayback && (player->pflags & PF_SLIDING))) + forcefullinput = true; + if (twodlevel + || (player->mo && (player->mo->flags2 & MF2_TWOD)) + || (!demoplayback && ((player->powers[pw_carry] == CR_NIGHTSMODE) || (player->pflags & (PF_SLIDING|PF_FORCESTRAFE))))) // Analog forcestrafe = true; if (forcestrafe) @@ -1142,8 +1149,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) if (!mouseaiming && cv_mousemove.value) forward += mousey; - if ((!demoplayback && (player->climbing - || (player->pflags & PF_SLIDING)))) // Analog for mouse + if ((!demoplayback && (player->pflags & PF_SLIDING))) // Analog for mouse side += mousex*2; else if (cv_analog.value) { @@ -1171,11 +1177,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // No additional acceleration when moving forward/backward and strafing simultaneously. // do this AFTER we cap to MAXPLMOVE so people can't find ways to cheese around this. - // 9-18-2017: ALSO, only do this when using keys to move. Gamepad analog sticks get severely gimped by this - if (!forcestrafe && (((movefkey || movebkey) && side) || ((strafelkey || straferkey) && forward))) + if (!forcefullinput && forward && side) { - forward = FixedMul(forward, 3*FRACUNIT/4); - side = FixedMul(side, 3*FRACUNIT/4); + angle_t angle = R_PointToAngle2(0, 0, side << FRACBITS, forward << FRACBITS); + INT32 maxforward = abs(P_ReturnThrustY(NULL, angle, MAXPLMOVE)); + INT32 maxside = abs(P_ReturnThrustX(NULL, angle, MAXPLMOVE)); + forward = max(min(forward, maxforward), -maxforward); + side = max(min(side, maxside), -maxside); } //Silly hack to make 2d mode *somewhat* playable with no chasecam. @@ -1211,6 +1219,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) { boolean forcestrafe = false; + boolean forcefullinput = false; INT32 tspeed, forward, side, axis, altaxis, i; const INT32 speed = 1; // these ones used for multiple conditions @@ -1282,6 +1291,10 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); } + if (twodlevel + || (player->mo && (player->mo->flags2 & MF2_TWOD)) + || (!demoplayback && (player->pflags & PF_SLIDING))) + forcefullinput = true; if (twodlevel || (player->mo && (player->mo->flags2 & MF2_TWOD)) || player->climbing @@ -1492,11 +1505,13 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) // No additional acceleration when moving forward/backward and strafing simultaneously. // do this AFTER we cap to MAXPLMOVE so people can't find ways to cheese around this. - // 9-18-2017: ALSO, only do this when using keys to move. Gamepad analog sticks get severely gimped by this - if (!forcestrafe && (((movefkey || movebkey) && side) || ((strafelkey || straferkey) && forward))) + if (!forcefullinput && forward && side) { - forward = FixedMul(forward, 3*FRACUNIT/4); - side = FixedMul(side, 3*FRACUNIT/4); + angle_t angle = R_PointToAngle2(0, 0, side << FRACBITS, forward << FRACBITS); + INT32 maxforward = abs(P_ReturnThrustY(NULL, angle, MAXPLMOVE)); + INT32 maxside = abs(P_ReturnThrustX(NULL, angle, MAXPLMOVE)); + forward = max(min(forward, maxforward), -maxforward); + side = max(min(side, maxside), -maxside); } //Silly hack to make 2d mode *somewhat* playable with no chasecam. @@ -1698,65 +1713,6 @@ static INT32 camtoggledelay, camtoggledelay2 = 0; // boolean G_Responder(event_t *ev) { - // allow spy mode changes even during the demo - if (gamestate == GS_LEVEL && ev->type == ev_keydown - && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) - { - if (splitscreen || !netgame) - displayplayer = consoleplayer; - else - { - // spy mode - do - { - displayplayer++; - if (displayplayer == MAXPLAYERS) - displayplayer = 0; - - if (!playeringame[displayplayer]) - continue; - - if (players[displayplayer].spectator) - continue; - - if (G_GametypeHasTeams()) - { - if (players[consoleplayer].ctfteam - && players[displayplayer].ctfteam != players[consoleplayer].ctfteam) - continue; - } - else if (gametype == GT_HIDEANDSEEK) - { - if (players[consoleplayer].pflags & PF_TAGIT) - continue; - } - // Other Tag-based gametypes? - else if (G_TagGametype()) - { - if (!players[consoleplayer].spectator - && (players[consoleplayer].pflags & PF_TAGIT) != (players[displayplayer].pflags & PF_TAGIT)) - continue; - } - else if (G_GametypeHasSpectators() && G_RingSlingerGametype()) - { - if (!players[consoleplayer].spectator) - continue; - } - - break; - } while (displayplayer != consoleplayer); - - // change statusbar also if playing back demo - if (singledemo) - ST_changeDemoView(); - - // tell who's the view - CONS_Printf(M_GetText("Viewpoint: %s\n"), player_names[displayplayer]); - - return true; - } - } - // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) @@ -1833,6 +1789,65 @@ boolean G_Responder(event_t *ev) if (HU_Responder(ev)) return true; // chat ate the event + // allow spy mode changes even during the demo + if (gamestate == GS_LEVEL && ev->type == ev_keydown + && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) + { + if (splitscreen || !netgame) + displayplayer = consoleplayer; + else + { + // spy mode + do + { + displayplayer++; + if (displayplayer == MAXPLAYERS) + displayplayer = 0; + + if (!playeringame[displayplayer]) + continue; + + if (players[displayplayer].spectator) + continue; + + if (G_GametypeHasTeams()) + { + if (players[consoleplayer].ctfteam + && players[displayplayer].ctfteam != players[consoleplayer].ctfteam) + continue; + } + else if (gametype == GT_HIDEANDSEEK) + { + if (players[consoleplayer].pflags & PF_TAGIT) + continue; + } + // Other Tag-based gametypes? + else if (G_TagGametype()) + { + if (!players[consoleplayer].spectator + && (players[consoleplayer].pflags & PF_TAGIT) != (players[displayplayer].pflags & PF_TAGIT)) + continue; + } + else if (G_GametypeHasSpectators() && G_RingSlingerGametype()) + { + if (!players[consoleplayer].spectator) + continue; + } + + break; + } while (displayplayer != consoleplayer); + + // change statusbar also if playing back demo + if (singledemo) + ST_changeDemoView(); + + // tell who's the view + CONS_Printf(M_GetText("Viewpoint: %s\n"), player_names[displayplayer]); + + return true; + } + } + // update keys current state G_MapEventsToControls(ev); @@ -2099,7 +2114,7 @@ static inline void G_PlayerFinishLevel(INT32 player) // G_PlayerReborn // Called after a player dies. Almost everything is cleared and initialized. // -void G_PlayerReborn(INT32 player) +void G_PlayerReborn(INT32 player, boolean betweenmaps) { player_t *p; INT32 score; @@ -2147,6 +2162,8 @@ void G_PlayerReborn(INT32 player) boolean outofcoop; INT16 bot; SINT8 pity; + INT16 rings; + INT16 spheres; score = players[player].score; lives = players[player].lives; @@ -2202,6 +2219,17 @@ void G_PlayerReborn(INT32 player) bot = players[player].bot; pity = players[player].pity; + if (betweenmaps || !G_IsSpecialStage(gamemap)) + { + rings = (ultimatemode ? 0 : mapheaderinfo[gamemap-1]->startrings); + spheres = 0; + } + else + { + rings = players[player].rings; + spheres = players[player].spheres; + } + p = &players[player]; memset(p, 0, sizeof (*p)); @@ -2256,6 +2284,8 @@ void G_PlayerReborn(INT32 player) if (bot) p->bot = 1; // reset to AI-controlled p->pity = pity; + p->rings = rings; + p->spheres = spheres; // Don't do anything immediately p->pflags |= PF_USEDOWN; @@ -2263,12 +2293,33 @@ void G_PlayerReborn(INT32 player) p->pflags |= PF_JUMPDOWN; p->playerstate = PST_LIVE; - p->rings = p->spheres = 0; // 0 rings p->panim = PA_IDLE; // standing animation //if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there //p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent + // Check to make sure their color didn't change somehow... + if (G_GametypeHasTeams()) + { + if (p->ctfteam == 1 && p->skincolor != skincolor_redteam) + { + if (p == &players[consoleplayer]) + CV_SetValue(&cv_playercolor, skincolor_redteam); + else if (p == &players[secondarydisplayplayer]) + CV_SetValue(&cv_playercolor2, skincolor_redteam); + } + else if (p->ctfteam == 2 && p->skincolor != skincolor_blueteam) + { + if (p == &players[consoleplayer]) + CV_SetValue(&cv_playercolor, skincolor_blueteam); + else if (p == &players[secondarydisplayplayer]) + CV_SetValue(&cv_playercolor2, skincolor_blueteam); + } + } + + if (betweenmaps) + return; + if (p-players == consoleplayer) { if (mapmusflags & MUSIC_RELOADRESET) @@ -2288,9 +2339,6 @@ void G_PlayerReborn(INT32 player) if (gametype == GT_COOP) P_FindEmerald(); // scan for emeralds to hunt for - // Reset Nights score and max link to 0 on death - p->marescore = p->maxlink = 0; - // If NiGHTS, find lowest mare to start with. p->mare = P_FindLowestMare(); @@ -2298,27 +2346,6 @@ void G_PlayerReborn(INT32 player) if (p->mare == 255) p->mare = 0; - - p->marelap = p->marebonuslap = 0; - - // Check to make sure their color didn't change somehow... - if (G_GametypeHasTeams()) - { - if (p->ctfteam == 1 && p->skincolor != skincolor_redteam) - { - if (p == &players[consoleplayer]) - CV_SetValue(&cv_playercolor, skincolor_redteam); - else if (p == &players[secondarydisplayplayer]) - CV_SetValue(&cv_playercolor2, skincolor_redteam); - } - else if (p->ctfteam == 2 && p->skincolor != skincolor_blueteam) - { - if (p == &players[consoleplayer]) - CV_SetValue(&cv_playercolor, skincolor_blueteam); - else if (p == &players[secondarydisplayplayer]) - CV_SetValue(&cv_playercolor2, skincolor_blueteam); - } - } } // @@ -2374,8 +2401,6 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) P_SpawnPlayer(playernum); - players[playernum].rings = mapheaderinfo[gamemap-1]->startrings; - if (starpost) //Don't even bother with looking for a place to spawn. { P_MovePlayerToStarpost(playernum); @@ -2598,7 +2623,7 @@ void G_DoReborn(INT32 playernum) if (countdowntimeup || (!(netgame || multiplayer) && gametype == GT_COOP)) resetlevel = true; - else if (gametype == GT_COOP && (netgame || multiplayer)) + else if (gametype == GT_COOP && (netgame || multiplayer) && !G_IsSpecialStage(gamemap)) { boolean notgameover = true; @@ -3316,6 +3341,7 @@ void G_LoadGameData(void) UINT32 recscore; tic_t rectime; UINT16 recrings; + boolean gotperf; UINT8 recmares; INT32 curmare; @@ -3408,6 +3434,7 @@ void G_LoadGameData(void) recscore = READUINT32(save_p); rectime = (tic_t)READUINT32(save_p); recrings = READUINT16(save_p); + gotperf = (boolean)READUINT8(save_p); if (recrings > 10000 || recscore > MAXSCORE) goto datacorrupt; @@ -3419,6 +3446,9 @@ void G_LoadGameData(void) mainrecords[i]->time = rectime; mainrecords[i]->rings = recrings; } + + if (gotperf) + mainrecords[i]->gotperfect = gotperf; } // Nights records @@ -3550,12 +3580,14 @@ void G_SaveGameData(void) WRITEUINT32(save_p, mainrecords[i]->score); WRITEUINT32(save_p, mainrecords[i]->time); WRITEUINT16(save_p, mainrecords[i]->rings); + WRITEUINT8(save_p, mainrecords[i]->gotperfect); } else { WRITEUINT32(save_p, 0); WRITEUINT32(save_p, 0); WRITEUINT16(save_p, 0); + WRITEUINT8(save_p, 0); } } @@ -3788,7 +3820,29 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) // File end marker check CHECKPOS - if (READUINT8(save_p) != 0x1d) BADSAVE; + switch (READUINT8(save_p)) + { + case 0xb7: + { + UINT8 i, banksinuse; + CHECKPOS + banksinuse = READUINT8(save_p); + CHECKPOS + if (banksinuse > NUM_LUABANKS) + BADSAVE + for (i = 0; i < banksinuse; i++) + { + (void)READINT32(save_p); + CHECKPOS + } + if (READUINT8(save_p) != 0x1d) + BADSAVE + } + case 0x1d: + break; + default: + BADSAVE + } // done saved = FIL_WriteFile(backup, savebuffer, length); diff --git a/src/g_game.h b/src/g_game.h index e161bc8ed..198cbc396 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -59,6 +59,8 @@ extern boolean pausebreakkey; extern boolean promptactive; +extern consvar_t cv_pauseifunfocused; + // used in game menu extern consvar_t cv_tutorialprompt; extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard; @@ -100,7 +102,7 @@ extern INT32 localaiming, localaiming2; // should be an angle_t but signed // void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo); void G_DoReborn(INT32 playernum); -void G_PlayerReborn(INT32 player); +void G_PlayerReborn(INT32 player, boolean betweenmaps); void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean skipprecutscene, boolean FLS); char *G_BuildMapTitle(INT32 mapnum); diff --git a/src/g_input.c b/src/g_input.c index 45c517e1a..afefbcc3b 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -709,8 +709,8 @@ void G_DefineDefaultControls(void) for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0) { - gamecontroldefault[i][gc_weaponnext ][0] = 'e'; - gamecontroldefault[i][gc_weaponprev ][0] = 'q'; + gamecontroldefault[i][gc_weaponnext ][0] = KEY_MOUSEWHEELUP+0; + gamecontroldefault[i][gc_weaponprev ][0] = KEY_MOUSEWHEELDOWN+0; gamecontroldefault[i][gc_wepslot1 ][0] = '1'; gamecontroldefault[i][gc_wepslot2 ][0] = '2'; gamecontroldefault[i][gc_wepslot3 ][0] = '3'; diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 483932492..9e454bcd5 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -201,7 +201,7 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, // (do not accept hit with the extensions) num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx; frac = num / den; - if (frac < 0.0 || frac > 1.0) + if (frac < 0.0l || frac > 1.0l) return NULL; // now get the frac along the BSP line diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 77ef26506..02df290b8 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -149,7 +149,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; @@ -159,7 +159,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)); break; @@ -263,7 +263,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; @@ -273,7 +273,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)); break; @@ -694,7 +694,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength); + realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); #endif HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, @@ -724,6 +724,13 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm { INT32 newwidth, newheight; +#ifndef NO_PNG_LUMPS + // 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); +#endif + // don't do it twice (like a cache) if (grMipmap->width == 0) { @@ -926,7 +933,7 @@ static void HWR_LoadPatchFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)patch, lumplength)) - patch = R_PNGToPatch((UINT8 *)patch, lumplength); + patch = R_PNGToPatch((UINT8 *)patch, lumplength, NULL, false); #endif grMipmap->width = (UINT16)SHORT(patch->width); diff --git a/src/hardware/hw_dll.h b/src/hardware/hw_dll.h index 452e9037c..3fa5852d8 100644 --- a/src/hardware/hw_dll.h +++ b/src/hardware/hw_dll.h @@ -61,9 +61,6 @@ typedef void (*I_Error_t) (const char *error, ...) FUNCIERROR; // ========================================================================== // Constants -#ifndef M_PIl -#define M_PIl 3.1415926535897932384626433832795029L -#endif #define DEGREE (0.017453292519943295769236907684883l) // 2*PI/360 void DBG_Printf(const char *lpFmt, ...) /*FUNCPRINTF*/; diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 1de20cad7..fa66536b6 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -162,6 +162,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_TURR &lspr[NOLIGHT], // SPR_SHRP &lspr[NOLIGHT], // SPR_CRAB + &lspr[NOLIGHT], // SPR_CR2B + &lspr[NOLIGHT], // SPR_CSPR &lspr[NOLIGHT], // SPR_JJAW &lspr[NOLIGHT], // SPR_SNLR &lspr[NOLIGHT], // SPR_VLTR @@ -180,6 +182,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_UNID &lspr[NOLIGHT], // SPR_CANA &lspr[NOLIGHT], // SPR_CANG + &lspr[NOLIGHT], // SPR_PYRE + &lspr[NOLIGHT], // SPR_PTER // Generic Boos Items &lspr[JETLIGHT_L], // SPR_JETF // Boss jet fumes @@ -197,6 +201,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_EGGO &lspr[NOLIGHT], // SPR_SEBH &lspr[NOLIGHT], // SPR_FAKE + &lspr[LBLUESHINE_L],// SPR_SHCK // Boss 4 (Castle Eggman) &lspr[NOLIGHT], // SPR_EGGP @@ -204,11 +209,15 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_EGR1 // Boss 5 (Arid Canyon) - &lspr[NOLIGHT], //SPR_FANG // replaces EGGQ - &lspr[NOLIGHT], //SPR_FBOM - &lspr[NOLIGHT], //SPR_FSGN - &lspr[REDBALL_L], //SPR_BARX // bomb explosion (also used by barrel) - &lspr[NOLIGHT], //SPR_BARD // bomb dust (also used by barrel) + &lspr[NOLIGHT], // SPR_FANG // replaces EGGQ + &lspr[NOLIGHT], // SPR_BRKN + &lspr[NOLIGHT], // SPR_WHAT + &lspr[INVINCIBLE_L], // SPR_VWRE + &lspr[INVINCIBLE_L], // SPR_PROJ + &lspr[NOLIGHT], // SPR_FBOM + &lspr[NOLIGHT], // SPR_FSGN + &lspr[REDBALL_L], // SPR_BARX // bomb explosion (also used by barrel) + &lspr[NOLIGHT], // SPR_BARD // bomb dust (also used by barrel) // Boss 6 (Red Volcano) &lspr[NOLIGHT], // SPR_EEGR @@ -255,6 +264,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_WSPB &lspr[NOLIGHT], // SPR_STPT &lspr[NOLIGHT], // SPR_BMNE + &lspr[NOLIGHT], // SPR_PUMI // Monitor Boxes &lspr[NOLIGHT], // SPR_MSTV @@ -372,6 +382,10 @@ light_t *t_lspr[NUMSPRITES] = // Red Volcano Scenery &lspr[REDBALL_L], // SPR_FLME &lspr[REDBALL_L], // SPR_DFLM + &lspr[NOLIGHT], // SPR_LFAL + &lspr[NOLIGHT], // SPR_JPLA + &lspr[NOLIGHT], // SPR_TFLO + &lspr[NOLIGHT], // SPR_WVIN // Dark City Scenery @@ -383,13 +397,20 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_XMS3 &lspr[NOLIGHT], // SPR_XMS4 &lspr[NOLIGHT], // SPR_XMS5 + &lspr[NOLIGHT], // SPR_XMS6 &lspr[NOLIGHT], // SPR_FHZI + &lspr[NOLIGHT], // SPR_ROSY // Halloween Scenery &lspr[RINGLIGHT_L], // SPR_PUMK &lspr[NOLIGHT], // SPR_HHPL &lspr[NOLIGHT], // SPR_SHRM &lspr[NOLIGHT], // SPR_HHZM + + // Azure Temple Scenery + &lspr[NOLIGHT], // SPR_BGAR + &lspr[NOLIGHT], // SPR_RCRY + &lspr[GREENBALL_L], // SPR_CFLM // Botanic Serenity Scenery &lspr[NOLIGHT], // SPR_BSZ1 @@ -410,7 +431,6 @@ light_t *t_lspr[NUMSPRITES] = // Misc Scenery &lspr[NOLIGHT], // SPR_STLG &lspr[NOLIGHT], // SPR_DBAL - &lspr[NOLIGHT], // SPR_RCRY // Powerup Indicators &lspr[NOLIGHT], // SPR_ARMA @@ -464,11 +484,14 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_SSWY &lspr[NOLIGHT], // SPR_SSWR &lspr[NOLIGHT], // SPR_SSWB + &lspr[NOLIGHT], // SPR_BSTY + &lspr[NOLIGHT], // SPR_BSTR // Environmental Effects &lspr[NOLIGHT], // SPR_RAIN &lspr[NOLIGHT], // SPR_SNO1 &lspr[NOLIGHT], // SPR_SPLH + &lspr[NOLIGHT], // SPR_LSPL &lspr[NOLIGHT], // SPR_SPLA &lspr[NOLIGHT], // SPR_SMOK &lspr[NOLIGHT], // SPR_BUBL diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 6d3e6c8ce..f2658707d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5454,7 +5454,7 @@ static void HWR_AddSprites(sector_t *sec) #ifdef HWPRECIP precipmobj_t *precipthing; #endif - fixed_t approx_dist, limit_dist; + fixed_t approx_dist, limit_dist, hoop_limit_dist; // BSP is traversed by subsector. // A sector might have been split into several @@ -5471,7 +5471,9 @@ static void HWR_AddSprites(sector_t *sec) // Handle all things in sector. // If a limit exists, handle things a tiny bit different. - if ((limit_dist = (fixed_t)((maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : cv_drawdist.value) << FRACBITS)) + limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS; + hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; + if (limit_dist || hoop_limit_dist) { for (thing = sec->thinglist; thing; thing = thing->snext) { @@ -5480,8 +5482,16 @@ static void HWR_AddSprites(sector_t *sec) approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - if (approx_dist > limit_dist) - continue; + if (thing->sprite == SPR_HOOP) + { + if (hoop_limit_dist && approx_dist > hoop_limit_dist) + continue; + } + else + { + if (limit_dist && approx_dist > limit_dist) + continue; + } HWR_ProjectSprite(thing); } @@ -5711,6 +5721,13 @@ static void HWR_ProjectSprite(mobj_t *thing) return; } + if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) + { + // bodge support - not nearly as comprehensive as r_things.c, but better than nothing + if (thing->tracer->sprite == SPR_NULL || thing->tracer->flags2 & MF2_DONTDRAW) + return; + } + // store information in a vissprite vis = HWR_NewVisSprite(); vis->x1 = x1; @@ -5724,7 +5741,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->z2 = z2; //Hurdler: 25/04/2000: now support colormap in hardware mode - if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" + if ((vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 7b6367cf3..b847fdbc3 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -26,6 +26,7 @@ #include #include +#include "../d_main.h" #include "../doomdef.h" #include "../doomstat.h" #include "../fastcmp.h" @@ -70,6 +71,10 @@ #endif #endif +#ifndef errno +#include "errno.h" +#endif + #define NUMVERTEXNORMALS 162 float avertexnormals[NUMVERTEXNORMALS][3] = { {-0.525731f, 0.000000f, 0.850651f}, @@ -294,7 +299,8 @@ static md2_model_t *md2_readModel(const char *filename) if (model == NULL) return 0; - file = fopen(filename, "rb"); + //Filename checking fixed ~Monster Iestyn and Golden + file = fopen(va("%s"PATHSEP"%s", srb2home, filename), "rb"); if (!file) { free(model); @@ -523,7 +529,8 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ #endif #endif png_FILE_p png_FILE; - char *pngfilename = va("md2/%s", filename); + //Filename checking fixed ~Monster Iestyn and Golden + char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); FIL_ForceExtension(pngfilename, ".png"); png_FILE = fopen(pngfilename, "rb"); @@ -651,7 +658,8 @@ static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h, size_t pw, ph, size, ptr = 0; INT32 ch, rep; FILE *file; - char *pcxfilename = va("md2/%s", filename); + //Filename checking fixed ~Monster Iestyn and Golden + char *pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); FIL_ForceExtension(pcxfilename, ".pcx"); file = fopen(pcxfilename, "rb"); @@ -845,11 +853,12 @@ void HWR_InitMD2(void) } // read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { - CONS_Printf("%s", M_GetText("Error while loading md2.dat\n")); + CONS_Printf("%s %s\n", M_GetText("Error while loading md2.dat:"), strerror(errno)); nomd2s = true; return; } @@ -911,7 +920,8 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup CONS_Printf("AddPlayerMD2()...\n"); // read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { @@ -956,7 +966,8 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu return; // Read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { @@ -1202,7 +1213,7 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p if (!md2 || !skin) return 0; - if ((unsigned)(spr2 & ~FF_SPR2SUPER) >= free_spr2) + if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2) return 0; while (!(md2->model->spr2frames[spr2*2 + 1]) @@ -1266,6 +1277,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) // MD2 colormap fix // colormap test + if (spr->mobj->subsector) { sector_t *sector = spr->mobj->subsector->sector; UINT8 lightlevel = 255; @@ -1297,6 +1309,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr) else Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); } + else + Surf.FlatColor.rgba = 0xFFFFFFFF; // Look at HWR_ProjectSprite for more { diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 2fe6741e2..ac989613a 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1427,7 +1427,6 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, Clamp2D(GL_TEXTURE_WRAP_T); } -// PRBoom sky dome typedef struct vbo_vertex_s { float x, y, z; @@ -1456,62 +1455,59 @@ typedef struct static int rows, columns; static boolean yflip; static int texw, texh; -static float yMult, yAdd; static boolean foglayer; static float delta = 0.0f; + static int gl_sky_detail = 16; + static INT32 lasttex = -1; -static RGBA_t SkyColor; - #define MAP_COEFF 128.0f -#define MAP_SCALE (MAP_COEFF*(float)FRACUNIT) static void SkyVertex(vbo_vertex_t *vbo, int r, int c) { - static fixed_t scale = 10000 << FRACBITS; - static angle_t maxSideAngle = ANGLE_180 / 3; + const float radians = (M_PIl / 180.0f); + const float scale = 10000.0f; + const float maxSideAngle = 60.0f; - angle_t topAngle = (angle_t)(c / (float)columns * ANGLE_MAX); - angle_t sideAngle = maxSideAngle * (rows - r) / rows; - fixed_t height = FINESINE(sideAngle>>ANGLETOFINESHIFT); - fixed_t realRadius = FixedMul(scale, FINECOSINE(sideAngle>>ANGLETOFINESHIFT)); - fixed_t x = FixedMul(realRadius, FINECOSINE(topAngle>>ANGLETOFINESHIFT)); - fixed_t y = (!yflip) ? FixedMul(scale, height) : FixedMul(scale, height) * -1; - fixed_t z = FixedMul(realRadius, FINESINE(topAngle>>ANGLETOFINESHIFT)); - float timesRepeat; - - timesRepeat = (short)(4 * (256.0f / texw)); - if (timesRepeat == 0.0f) + float topAngle = (c / (float)columns * 360.0f); + float sideAngle = (maxSideAngle * (rows - r) / rows); + float height = sin(sideAngle * radians); + float realRadius = scale * cos(sideAngle * radians); + float x = realRadius * cos(topAngle * radians); + float y = (!yflip) ? scale * height : -scale * height; + float z = realRadius * sin(topAngle * radians); + float timesRepeat = (4 * (256.0f / texw)); + if (fpclassify(timesRepeat) == FP_ZERO) timesRepeat = 1.0f; if (!foglayer) { - boolean flip = yflip; vbo->r = 255; vbo->g = 255; vbo->b = 255; vbo->a = (r == 0 ? 0 : 255); - // Flip Y coordinate anyway for the top part of the hemisphere - if (r <= 1) - flip = !flip; - // And the texture coordinates. vbo->u = (-timesRepeat * c / (float)columns); - if (!flip) // Flipped Y is for the lower hemisphere. - vbo->v = (r / (float)rows) * 1.f * yMult + yAdd; + if (!yflip) // Flipped Y is for the lower hemisphere. + vbo->v = (r / (float)rows) + 0.5f; else - vbo->v = ((rows-r)/(float)rows) * 1.f * yMult + yAdd; + vbo->v = 1.0f + ((rows - r) / (float)rows) + 0.5f; + } + + if (r != 4) + { + y += 300.0f; } // And finally the vertex. - vbo->x = (float)x/(float)MAP_SCALE; - vbo->y = (float)y/(float)MAP_SCALE + delta; - vbo->z = (float)z/(float)MAP_SCALE; + vbo->x = x; + vbo->y = y + delta; + vbo->z = z; } -GLSkyVBO sky_vbo; +static GLSkyVBO sky_vbo; static void gld_BuildSky(int row_count, int col_count) { @@ -1542,10 +1538,7 @@ static void gld_BuildSky(int row_count, int col_count) vertex_p = &vbo->data[0]; vbo->loopcount = 0; - memset(&SkyColor, 0xFF, sizeof(SkyColor)); - - // Why not? - for (yflip = false; yflip <= true; yflip++) + for (yflip = 0; yflip < 2; yflip++) { vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_FAN; vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; @@ -1553,21 +1546,14 @@ static void gld_BuildSky(int row_count, int col_count) vbo->loops[vbo->loopcount].use_texture = false; vbo->loopcount++; - yAdd = 0.5f; - yMult = 1.0f; - /*if (yflip == 0) - SkyColor = &sky->CeilingSkyColor[vbo_idx]; - else - SkyColor = &sky->FloorSkyColor[vbo_idx];*/ - delta = 0.0f; foglayer = true; for (c = 0; c < col_count; c++) { SkyVertex(vertex_p, 1, c); - vertex_p->r = SkyColor.s.red; - vertex_p->g = SkyColor.s.green; - vertex_p->b = SkyColor.s.blue; + vertex_p->r = 255; + vertex_p->g = 255; + vertex_p->b = 255; vertex_p->a = 255; vertex_p++; } @@ -1580,7 +1566,7 @@ static void gld_BuildSky(int row_count, int col_count) vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_STRIP; vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; vbo->loops[vbo->loopcount].vertexcount = 2 * col_count + 2; - vbo->loops[vbo->loopcount].use_texture = true; //(r > 1) ? true : false; + vbo->loops[vbo->loopcount].use_texture = true; vbo->loopcount++; for (c = 0; c <= col_count; c++) @@ -1592,12 +1578,18 @@ static void gld_BuildSky(int row_count, int col_count) } } -static void RenderDomeForReal(INT32 skytexture) +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +static void RenderDome(INT32 skytexture) { int i, j; GLSkyVBO *vbo = &sky_vbo; - pglRotatef(270.f, 0.f, 1.f, 0.f); + pglRotatef(270.0f, 0.0f, 1.0f, 0.0f); rows = 4; columns = 4 * gl_sky_detail; @@ -1636,8 +1628,6 @@ static void RenderDomeForReal(INT32 skytexture) } pglScalef(1.0f, 1.0f, 1.0f); - - // current color is undefined after glDrawArrays pglColor4f(1.0f, 1.0f, 1.0f, 1.0f); } @@ -1645,12 +1635,9 @@ EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture { SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); SetTransform(&transform); - texw = texture_width; texh = texture_height; - RenderDomeForReal(tex); - - // HWR_DrawSkyBackground left no blend flags after rendering the sky + RenderDome(tex); SetBlend(0); } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 3bc643c3c..428656bf2 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -71,6 +71,10 @@ patch_t *lt_font[LT_FONTSIZE]; patch_t *cred_font[CRED_FONTSIZE]; patch_t *ttlnum[20]; // act numbers (0-19) +// Name tag fonts +patch_t *ntb_font[NT_FONTSIZE]; +patch_t *nto_font[NT_FONTSIZE]; + static player_t *plr; boolean chat_on; // entering a chat message? static char w_chat[HU_MAXMSGLEN]; @@ -246,6 +250,32 @@ void HU_LoadGraphics(void) ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); } + // cache the base name tag font for entire game execution + j = NT_FONTSTART; + for (i = 0; i < NT_FONTSIZE; i++) + { + sprintf(buffer, "NTFNT%.3d", j); + j++; + + if (W_CheckNumForName(buffer) == LUMPERROR) + ntb_font[i] = NULL; + else + ntb_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + } + + // cache the outline name tag font for entire game execution + j = NT_FONTSTART; + for (i = 0; i < NT_FONTSIZE; i++) + { + sprintf(buffer, "NTFNO%.3d", j); + j++; + + if (W_CheckNumForName(buffer) == LUMPERROR) + nto_font[i] = NULL; + else + nto_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + } + // cache the crosshairs, don't bother to know which one is being used, // just cache all 3, they're so small anyway. for (i = 0; i < HU_CROSSHAIRS; i++) diff --git a/src/hu_stuff.h b/src/hu_stuff.h index ab77e67b6..55b61d4b7 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -35,6 +35,12 @@ #define CRED_FONTEND 'Z' // the last font character #define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1) +// Name tag font +// Used by base and outline font set +#define NT_FONTSTART '!' // the first font character +#define NT_FONTEND 'Z' // the last font character +#define NT_FONTSIZE (NT_FONTEND - NT_FONTSTART + 1) + #define HU_CROSSHAIRS 3 // maximum of 9 - see HU_Init(); extern char *shiftxform; // english translation shift table @@ -77,6 +83,8 @@ extern patch_t *tallnum[10]; extern patch_t *nightsnum[10]; extern patch_t *lt_font[LT_FONTSIZE]; extern patch_t *cred_font[CRED_FONTSIZE]; +extern patch_t *ntb_font[NT_FONTSIZE]; +extern patch_t *nto_font[NT_FONTSIZE]; extern patch_t *ttlnum[20]; extern patch_t *emeraldpics[3][8]; extern patch_t *rflagico; diff --git a/src/i_tcp.c b/src/i_tcp.c index f2b4336dc..da92f2767 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -776,6 +776,8 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen #endif #endif mysockaddr_t straddr; + struct sockaddr_in sin; + socklen_t len = sizeof(sin); if (s == (SOCKET_TYPE)ERRSOCKET) return (SOCKET_TYPE)ERRSOCKET; @@ -869,12 +871,16 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); } + if (getsockname(s, (struct sockaddr *)&sin, &len) == -1) + CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n")); + else + current_port = (UINT16)ntohs(sin.sin_port); + return s; } static boolean UDP_Socket(void) { - const char *sock_port = NULL; size_t s; struct my_addrinfo *ai, *runp, hints; int gaie; @@ -896,20 +902,11 @@ static boolean UDP_Socket(void) hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; - if (M_CheckParm("-clientport")) - { - if (!M_IsNextParm()) - I_Error("syntax: -clientport "); - sock_port = M_GetNextParm(); - } - else - sock_port = port_name; - if (M_CheckParm("-bindaddr")) { while (M_IsNextParm()) { - gaie = I_getaddrinfo(M_GetNextParm(), sock_port, &hints, &ai); + gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai); if (gaie == 0) { runp = ai; @@ -930,7 +927,7 @@ static boolean UDP_Socket(void) } else { - gaie = I_getaddrinfo("0.0.0.0", sock_port, &hints, &ai); + gaie = I_getaddrinfo("0.0.0.0", port_name, &hints, &ai); if (gaie == 0) { runp = ai; @@ -945,8 +942,8 @@ static boolean UDP_Socket(void) #ifdef HAVE_MINIUPNPC if (UPNP_support) { - I_UPnP_rem(sock_port, "UDP"); - I_UPnP_add(NULL, sock_port, "UDP"); + I_UPnP_rem(port_name, "UDP"); + I_UPnP_add(NULL, port_name, "UDP"); } #endif } @@ -963,7 +960,7 @@ static boolean UDP_Socket(void) { while (M_IsNextParm()) { - gaie = I_getaddrinfo(M_GetNextParm(), sock_port, &hints, &ai); + gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai); if (gaie == 0) { runp = ai; @@ -984,7 +981,7 @@ static boolean UDP_Socket(void) } else { - gaie = I_getaddrinfo("::", sock_port, &hints, &ai); + gaie = I_getaddrinfo("::", port_name, &hints, &ai); if (gaie == 0) { runp = ai; @@ -1260,7 +1257,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) int gaie; if (!port || !port[0]) - port = port_name; + port = DEFAULTPORT; DEBFILE(va("Creating new node: %s@%s\n", address, port)); @@ -1424,14 +1421,15 @@ boolean I_InitTcpNetwork(void) if (!I_InitTcpDriver()) return false; - if (M_CheckParm("-udpport")) + if (M_CheckParm("-port")) + // Combined -udpport and -clientport into -port + // As it was really redundant having two seperate parms that does the same thing { if (M_IsNextParm()) strcpy(port_name, M_GetNextParm()); else strcpy(port_name, "0"); } - current_port = (UINT16)atoi(port_name); // parse network game options, if (M_CheckParm("-server") || dedicated) diff --git a/src/info.c b/src/info.c index 5baf28943..cfaad552d 100644 --- a/src/info.c +++ b/src/info.c @@ -50,6 +50,8 @@ char sprnames[NUMSPRITES + 1][5] = "TURR", // Pop-Up Turret "SHRP", // Sharp "CRAB", // Crushstacean + "CR2B", // Banpyura + "CSPR", // Banpyura spring "JJAW", // Jet Jaw "SNLR", // Snailer "VLTR", // BASH @@ -68,6 +70,8 @@ char sprnames[NUMSPRITES + 1][5] = "UNID", // Unidus "CANA", // Canarivore "CANG", // Canarivore gas + "PYRE", // Pyre Fly + "PTER", // Pterabyte // Generic Boss Items "JETF", // Boss jet fumes @@ -85,6 +89,7 @@ char sprnames[NUMSPRITES + 1][5] = "EGGO", // Boss 3 "SEBH", // Boss 3 Junk "FAKE", // Boss 3 Fakemobile + "SHCK", // Boss 3 Shockwave // Boss 4 (Castle Eggman) "EGGP", @@ -93,6 +98,10 @@ char sprnames[NUMSPRITES + 1][5] = // Boss 5 (Arid Canyon) "FANG", // replaces EGGQ + "BRKN", // broken robot chunk + "WHAT", // alart + "VWRE", + "PROJ", // projector light "FBOM", "FSGN", "BARX", // bomb explosion (also used by barrel) @@ -144,6 +153,7 @@ char sprnames[NUMSPRITES + 1][5] = "WSPB", // Wall spike base "STPT", // Starpost "BMNE", // Big floating mine + "PUMI", // Rollout Rock // Monitor Boxes "MSTV", // MiSc TV sprites @@ -212,11 +222,11 @@ char sprnames[NUMSPRITES + 1][5] = "GARG", // Deep Sea Gargoyle "SEWE", // Deep Sea Seaweed "DRIP", // Dripping water - "CRL1", // Coral 1 - "CRL2", // Coral 2 - "CRL3", // Coral 3 + "CORL", // Coral "BCRY", // Blue Crystal "KELP", // Kelp + "ALGA", // Animated algae top + "ALGB", // Animated algae segment "DSTG", // DSZ Stalagmites "LIBE", // DSZ Light beam @@ -246,7 +256,7 @@ char sprnames[NUMSPRITES + 1][5] = // Arid Canyon Scenery "BTBL", // Big tumbleweed "STBL", // Small tumbleweed - "CACT", // Cacti sprites + "CACT", // Cacti "WWSG", // Caution Sign "WWS2", // Cacti Sign "WWS3", // Sharp Turn Sign @@ -258,7 +268,6 @@ char sprnames[NUMSPRITES + 1][5] = "ADST", // Arid dust "MCRT", // Minecart "MCSP", // Minecart spark - "NON2", // Saloon door thinker "SALD", // Saloon door "TRAE", // Train cameo locomotive "TRAI", // Train cameo wagon @@ -267,6 +276,10 @@ char sprnames[NUMSPRITES + 1][5] = // Red Volcano Scenery "FLME", // Flame jet "DFLM", // Blade's flame + "LFAL", // Lavafall + "JPLA", // Jungle palm + "TFLO", // Torch flower + "WVIN", // Wall vines // Dark City Scenery @@ -278,7 +291,9 @@ char sprnames[NUMSPRITES + 1][5] = "XMS3", // Snowman "XMS4", // Lamppost "XMS5", // Hanging Star + "XMS6", // Mistletoe "FHZI", // FHZ ice + "ROSY", // Halloween Scenery "PUMK", // Pumpkins @@ -286,6 +301,11 @@ char sprnames[NUMSPRITES + 1][5] = "SHRM", // Mushroom "HHZM", // Misc + // Azure Temple Scenery + "BGAR", // ATZ Gargoyles + "RCRY", // ATZ Red Crystal (Target) + "CFLM", // Green torch flame + // Botanic Serenity Scenery "BSZ1", // Tall flowers "BSZ2", // Medium flowers @@ -305,7 +325,6 @@ char sprnames[NUMSPRITES + 1][5] = // Misc Scenery "STLG", // Stalagmites "DBAL", // Disco - "RCRY", // ATZ Red Crystal (Target) // Powerup Indicators "ARMA", // Armageddon Shield Orb @@ -359,11 +378,14 @@ char sprnames[NUMSPRITES + 1][5] = "SSWY", // Yellow Side Spring "SSWR", // Red Side Spring "SSWB", // Blue Side Spring + "BSTY", // Yellow Booster + "BSTR", // Red Booster // Environmental Effects "RAIN", // Rain "SNO1", // Snowflake "SPLH", // Water Splish + "LSPL", // Lava Splish "SPLA", // Water Splash "SMOK", "BUBL", // Bubble @@ -511,6 +533,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "TIRE", "GLID", + "LAND", "CLNG", "CLMB", @@ -518,7 +541,6 @@ char spr2names[NUMPLAYERSPRITES][5] = "FRUN", "BNCE", - "BLND", "FIRE", @@ -576,8 +598,14 @@ char spr2names[NUMPLAYERSPRITES][5] = "TALA", "TALB", + "CNT1", + "CNT2", + "CNT3", + "CNT4", + "SIGN", "LIFE", + "XTRA", }; playersprite_t free_spr2 = SPR2_FIRSTFREESLOT; @@ -608,6 +636,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_TIRE, (conditional, will never be referenced) SPR2_FLY , // SPR2_GLID, + SPR2_ROLL, // SPR2_LAND, SPR2_CLMB, // SPR2_CLNG, SPR2_ROLL, // SPR2_CLMB, @@ -615,7 +644,6 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_RUN , // SPR2_FRUN, SPR2_FALL, // SPR2_BNCE, - SPR2_ROLL, // SPR2_BLND, 0, // SPR2_FIRE, @@ -673,8 +701,14 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_TAL9, // SPR2_TALA, SPR2_TAL0, // SPR2_TALB, + SPR2_WAIT, // SPR2_CNT1, + SPR2_FALL, // SPR2_CNT2, + SPR2_SPNG, // SPR2_CNT3, + SPR2_CNT1, // SPR2_CNT4, + 0, // SPR2_SIGN, 0, // SPR2_LIFE, + 0, // SPR2_XTRA (should never be referenced) }; @@ -727,11 +761,12 @@ state_t states[NUMSTATES] = // CA_FLY/CA_SWIM {SPR_PLAY, SPR2_FLY , 2, {NULL}, 0, 0, S_PLAY_FLY}, // S_PLAY_FLY - {SPR_PLAY, SPR2_SWIM, 2, {NULL}, 0, 0, S_PLAY_SWIM}, // S_PLAY_SWIM + {SPR_PLAY, SPR2_SWIM, 4, {NULL}, 0, 0, S_PLAY_SWIM}, // S_PLAY_SWIM {SPR_PLAY, SPR2_TIRE, 12, {NULL}, 0, 0, S_PLAY_FLY_TIRED}, // S_PLAY_FLY_TIRED // CA_GLIDEANDCLIMB {SPR_PLAY, SPR2_GLID, 2, {NULL}, 0, 0, S_PLAY_GLIDE}, // S_PLAY_GLIDE + {SPR_PLAY, SPR2_LAND, 9, {NULL}, 0, 0, S_PLAY_STND}, // S_PLAY_GLIDE_LANDING {SPR_PLAY, SPR2_CLNG|FF_ANIMATE, -1, {NULL}, 0, 4, S_NULL}, // S_PLAY_CLING {SPR_PLAY, SPR2_CLMB, 5, {NULL}, 0, 0, S_PLAY_CLIMB}, // S_PLAY_CLIMB @@ -741,7 +776,7 @@ state_t states[NUMSTATES] = // CA_BOUNCE {SPR_PLAY, SPR2_BNCE|FF_ANIMATE, -1, {NULL}, 0, 0, S_NULL}, // S_PLAY_BOUNCE - {SPR_PLAY, SPR2_BLND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE, 0, S_PLAY_BOUNCE_LANDING}, // S_PLAY_BOUNCE_LANDING + {SPR_PLAY, SPR2_LAND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE, 0, S_PLAY_BOUNCE_LANDING}, // S_PLAY_BOUNCE_LANDING // CA2_GUNSLINGER {SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_FIRE_FINISH, 0, S_PLAY_FIRE}, // S_PLAY_FIRE @@ -832,6 +867,9 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP {SPR_PLAY, SPR2_TALB , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE + // [: + {SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH + // Blue Crawla {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND {SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2}, // S_POSS_RUN1 @@ -979,6 +1017,22 @@ state_t states[NUMSTATES] = {SPR_CRAB, 3, 37, {NULL}, 0, 0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_WAIT {SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CRUSHCHAIN + // Banpyura + {SPR_CR2B, 0, 3, {A_CrushstaceanWalk}, 0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM2}, // S_BANPYURA_ROAM1 + {SPR_CR2B, 1, 3, {A_CrushstaceanWalk}, 0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM3}, // S_BANPYURA_ROAM2 + {SPR_CR2B, 0, 3, {A_CrushstaceanWalk}, 0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM4}, // S_BANPYURA_ROAM3 + {SPR_CR2B, 2, 3, {A_CrushstaceanWalk}, 0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM1}, // S_BANPYURA_ROAM4 + {SPR_CR2B, 0, 40, {NULL}, 0, 0, S_BANPYURA_ROAM1}, // S_BANPYURA_ROAMPAUSE + + {SPR_CSPR, 0, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1}, // S_CDIAG1 + {SPR_CSPR, 1, 1, {A_Pain}, 0, 0, S_CDIAG3}, // S_CDIAG2 + {SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG4}, // S_CDIAG3 + {SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG5}, // S_CDIAG4 + {SPR_CSPR, 4, 1, {A_CrushclawAim}, 50, 20, S_CDIAG6}, // S_CDIAG5 + {SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG7}, // S_CDIAG6 + {SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG8}, // S_CDIAG7 + {SPR_CSPR, 1, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1}, // S_CDIAG8 + // Jet Jaw {SPR_JJAW, 0, 1, {A_JetJawRoam}, 0, 0, S_JETJAW_ROAM2}, // S_JETJAW_ROAM1 {SPR_JJAW, 0, 1, {A_JetJawRoam}, 0, 0, S_JETJAW_ROAM3}, // S_JETJAW_ROAM2 @@ -1167,6 +1221,22 @@ state_t states[NUMSTATES] = {SPR_CANG, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_CANARIVOREGAS_8}, // S_CANARIVOREGAS_7 {SPR_CANG, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL}, // S_CANARIVOREGAS_8 + // Pyre Fly + {SPR_PYRE, FF_ANIMATE, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_FLY + {SPR_PYRE, 4|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_BURN + {SPR_FLAM, FF_FULLBRIGHT, 10, {NULL}, 0, 0, S_PYREFIRE2}, // S_PYREFIRE1 + {SPR_FLAM, 1|FF_FULLBRIGHT, 10, {A_FireShrink}, 0, 16, S_NULL}, // S_PYREFIRE2 + + // Pterabyte + {SPR_NULL, 0, -1, {A_SpawnPterabytes}, 0, 0, S_PTERABYTESPAWNER}, // S_PTERABYTESPAWNER + {SPR_NULL, 0, 1, {A_PterabyteHover}, 0, 0, S_PTERABYTEWAYPOINT}, // S_PTERABYTEWAYPOINT + {SPR_PTER, 0, 6, {NULL}, 0, 0, S_PTERABYTE_FLY2}, // S_PTERABYTE_FLY1 + {SPR_PTER, 1, 2, {NULL}, 0, 0, S_PTERABYTE_FLY3}, // S_PTERABYTE_FLY2 + {SPR_PTER, 2, 6, {NULL}, 0, 0, S_PTERABYTE_FLY4}, // S_PTERABYTE_FLY3 + {SPR_PTER, 3, 2, {NULL}, 0, 0, S_PTERABYTE_FLY1}, // S_PTERABYTE_FLY4 + {SPR_PTER, 4, 1, {NULL}, 0, 0, S_PTERABYTE_SWOOPDOWN}, // S_PTERABYTE_SWOOPDOWN + {SPR_PTER, 0, 1, {NULL}, 0, 0, S_PTERABYTE_SWOOPUP}, // S_PTERABYTE_SWOOPUP + // Boss Explosion {SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE @@ -1294,6 +1364,11 @@ state_t states[NUMSTATES] = {SPR_SEBH, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH1 {SPR_SEBH, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH2 + // Boss 3 Shockwave + + {SPR_SHCK, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE2}, // S_SHOCKWAVE1 + {SPR_SHCK, 3|FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE1}, // S_SHOCKWAVE2 + // Boss 4 {SPR_EGGP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_STND {SPR_EGGP, 1, 3, {NULL}, 0, 0, S_EGGMOBILE4_LATK2}, // S_EGGMOBILE4_LATK1 @@ -1336,6 +1411,28 @@ state_t states[NUMSTATES] = {SPR_EFIR, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBOJET // Boss 5 + {SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0}, // S_FANG_SETUP + + {SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1}, // S_FANG_INTRO0 + {SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2}, // S_FANG_INTRO1 + {SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3}, // S_FANG_INTRO2 + {SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4}, // S_FANG_INTRO3 + {SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5}, // S_FANG_INTRO4 + {SPR_FANG, 27, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6}, // S_FANG_INTRO5 + {SPR_FANG, 28, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7}, // S_FANG_INTRO6 + {SPR_FANG, 29, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8}, // S_FANG_INTRO7 + {SPR_FANG, 30, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5}, // S_FANG_INTRO8 + {SPR_FANG, 23|FF_ANIMATE, 50, {NULL}, 1, 4, S_FANG_INTRO10}, // S_FANG_INTRO9 + {SPR_FANG, 25, 5, {NULL}, 0, 0, S_FANG_INTRO11}, // S_FANG_INTRO10 + {SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12}, // S_FANG_INTRO11 + {SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1}, // S_FANG_INTRO12 + + {SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2}, // S_FANG_CLONE1 + {SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3}, // S_FANG_INTRO2 + {SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4}, // S_FANG_CLONE3 + {SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4}, // S_FANG_CLONE4 + + {SPR_FANG, 0, 0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1}, // S_FANG_IDLE0 {SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1 {SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3}, // S_FANG_IDLE2 {SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4}, // S_FANG_IDLE3 @@ -1410,8 +1507,8 @@ state_t states[NUMSTATES] = {SPR_FANG, 21, 0, {A_DoNPCPain}, 0, 0, S_FANG_DIE2}, // S_FANG_DIE1 {SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2 - {SPR_FANG, 22, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3 - {SPR_FANG, 22, 104, {NULL}, 0, 0, S_FANG_DIE5}, // S_FANG_DIE4 + {SPR_FANG, 22, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3 + {SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5}, // S_FANG_DIE4 {SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5 {SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6 @@ -1425,6 +1522,26 @@ state_t states[NUMSTATES] = {SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO + {SPR_NULL, 0, -1, {A_RandomStateRange}, S_BROKENROBOTA, S_BROKENROBOTF, S_NULL}, // S_BROKENROBOTRANDOM + {SPR_BRKN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTA + {SPR_BRKN, 4|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTB + {SPR_BRKN, 8|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTC + {SPR_BRKN, 12|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTD + {SPR_BRKN, 16|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTE + {SPR_BRKN, 20|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTF + + {SPR_WHAT, FF_ANIMATE|FF_FULLBRIGHT, 4, {NULL}, 1, 2, S_ALART2}, // S_ALART1 + {SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL}, // S_ALART2 + + {SPR_VWRE, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREF + {SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREB + + {SPR_PROJ, FF_TRANS20|FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_PROJECTORLIGHT2}, // S_PROJECTORLIGHT1 + {SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_PROJECTORLIGHT3}, // S_PROJECTORLIGHT2 + {SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_PROJECTORLIGHT4}, // S_PROJECTORLIGHT3 + {SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT, 2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5}, // S_PROJECTORLIGHT4 + {SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_PROJECTORLIGHT5 + {SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1 {SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2 {SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2}, // S_FBOMB_EXPL1 @@ -1584,7 +1701,7 @@ state_t states[NUMSTATES] = {SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3 {SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE - {SPR_FLAM, FF_FULLBRIGHT, 0, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST + {SPR_FLAM, FF_FULLBRIGHT, 1, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST {SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1 {SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2 @@ -2152,14 +2269,12 @@ state_t states[NUMSTATES] = {SPR_DRIP, FF_TRANS30|4, 1, {NULL}, 0, 0, S_DRIPC2}, // S_DRIPC1 {SPR_DRIP, FF_TRANS30|5, 1, {NULL}, 0, 0, S_NULL}, // S_DRIPC2 - // Coral 1 - {SPR_CRL1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1 - - // Coral 2 - {SPR_CRL2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL2 - - // Coral 3 - {SPR_CRL3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3 + // Coral + {SPR_CORL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1 + {SPR_CORL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL2 + {SPR_CORL, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3 + {SPR_CORL, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL4 + {SPR_CORL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL5 // Blue Crystal {SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1 @@ -2167,6 +2282,11 @@ state_t states[NUMSTATES] = // Kelp {SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KELP + // Animated algae + {SPR_ALGA, 0, 1, {A_ConnectToGround}, MT_ANIMALGAESEG, 0, S_ANIMALGAETOP2}, // S_ANIMALGAETOP1 + {SPR_ALGA, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL}, // S_ANIMALGAETOP2 + {SPR_ALGB, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL}, // S_ANIMALGAESEG + // DSZ Stalagmites {SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DSZSTALAGMITE {SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE @@ -2311,16 +2431,20 @@ state_t states[NUMSTATES] = {SPR_STBL, 6, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL8}, // S_LITTLETUMBLEWEED_ROLL7 {SPR_STBL, 7, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL1}, // S_LITTLETUMBLEWEED_ROLL8 - // Cacti Sprites - {SPR_CACT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI1 - {SPR_CACT, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI2 - {SPR_CACT, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI3 - {SPR_CACT, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI4 + // Cacti + {SPR_CACT, 0, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI1 + {SPR_CACT, 1, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI2 + {SPR_CACT, 2, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI3 + {SPR_CACT, 3, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI4 {SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI5 {SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI6 {SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI7 {SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI8 {SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI9 + {SPR_CACT, 9, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI10 + {SPR_CACT, 10, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI11 + {SPR_CACT, 11, -1, {NULL}, 0, 0, S_NULL}, // S_CACTITINYSEG + {SPR_CACT, 12, -1, {NULL}, 0, 0, S_NULL}, // S_CACTISMALLSEG // Warning Signs {SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CAUTION @@ -2391,8 +2515,8 @@ state_t states[NUMSTATES] = {SPR_MCSP, FF_FULLBRIGHT, 1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK}, // S_MINECARTSPARK // Saloon door - {SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR - {SPR_NON2, 0, -1, {A_SaloonDoorSpawn}, 0, 0, S_NULL}, // S_SALONDOORTHINKER + {SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR + {SPR_NULL, 0, -1, {A_SaloonDoorSpawn}, MT_SALOONDOOR, 48, S_NULL}, // S_SALOONDOORCENTER // Train cameo {SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2}, // S_TRAINCAMEOSPAWNER_1 @@ -2412,6 +2536,12 @@ state_t states[NUMSTATES] = {SPR_FLME, FF_FULLBRIGHT , 4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1 {SPR_FLME, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2 {SPR_FLME, FF_FULLBRIGHT|2, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME3 + {SPR_FLME, FF_FULLBRIGHT|3, 4, {NULL}, 0, 0, S_FLAMEJETFLAME5}, // S_FLAMEJETFLAME4 + {SPR_FLME, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_FLAMEJETFLAME6}, // S_FLAMEJETFLAME5 + {SPR_FLME, FF_FULLBRIGHT|5, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME6 + {SPR_FLME, FF_FULLBRIGHT|6, 4, {NULL}, 0, 0, S_FLAMEJETFLAME8}, // S_FLAMEJETFLAME7 + {SPR_FLME, FF_FULLBRIGHT|7, 5, {NULL}, 0, 0, S_FLAMEJETFLAME9}, // S_FLAMEJETFLAME8 + {SPR_FLME, FF_FULLBRIGHT|8, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME9 // Spinning flame jets // A: Counter-clockwise @@ -2427,32 +2557,54 @@ state_t states[NUMSTATES] = {SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2 {SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL}, // S_FLAMEJETFLAMEB3 + // Lavafall + {SPR_LFAL, 5, 1, {NULL}, 0, 0, S_LAVAFALL_DORMANT}, // S_LAVAFALL_DORMANT + {SPR_LFAL, 6|FF_ANIMATE, 4, {A_LavafallRocks}, 1, 2, S_LAVAFALL_TELL}, // S_LAVAFALL_TELL + {SPR_LFAL, 9|FF_FULLBRIGHT|FF_ANIMATE, 2, {A_LavafallLava}, 1, 1, S_LAVAFALL_SHOOT}, // S_LAVAFALL_SHOOT + {SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA2}, // S_LAVAFALL_LAVA1 + {SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA1}, // S_LAVAFALL_LAVA2 + {SPR_LFAL, 2|FF_FULLBRIGHT|FF_ANIMATE, 9, {NULL}, 2, 3, S_NULL}, // S_LAVAFALL_LAVA3 + {SPR_LFAL, 11|FF_ANIMATE|FF_RANDOMANIM, 12, {NULL}, 3, 3, S_LAVAFALLROCK}, // S_LAVAFALLROCK + + // Rollout Rock + {SPR_NULL, 0, 1, {A_RolloutSpawn}, 256*FRACUNIT, MT_ROLLOUTROCK, S_ROLLOUTSPAWN}, // S_ROLLOUTSPAWN + {SPR_PUMI, 0, 1, {A_RolloutRock}, 63*FRACUNIT/64, 7*FRACUNIT/10, S_ROLLOUTROCK}, // S_ROLLOUTROCK + + // RVZ scenery + {SPR_JPLA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERNLEAF + {SPR_JPLA, 1, 1, {NULL}, 0, 0, S_BIGFERN2}, // S_BIGFERN1 + {SPR_JPLA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERN2 + {SPR_JPLA, 2, -1, {NULL}, 0, 0, S_NULL}, // S_JUNGLEPALM + {SPR_TFLO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_TORCHFLOWER}, // S_TORCHFLOWER + {SPR_WVIN, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_LONG + {SPR_WVIN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_SHORT + // Trapgoyles - {SPR_GARG, 0, 67, {NULL}, 0, 0, S_TRAPGOYLE_CHECK}, // S_TRAPGOYLE - {SPR_GARG, 0, 3, {NULL}, 0, 0, S_TRAPGOYLE_FIRE1}, // S_TRAPGOYLE_CHECK - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLE_FIRE2}, // S_TRAPGOYLE_FIRE1 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLE_FIRE3}, // S_TRAPGOYLE_FIRE2 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLE}, // S_TRAPGOYLE_FIRE3 + {SPR_BGAR, 0, 67, {NULL}, 0, 0, S_TRAPGOYLE_CHECK}, // S_TRAPGOYLE + {SPR_BGAR, 0, 3, {NULL}, 0, 0, S_TRAPGOYLE_FIRE1}, // S_TRAPGOYLE_CHECK + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLE_FIRE2}, // S_TRAPGOYLE_FIRE1 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLE_FIRE3}, // S_TRAPGOYLE_FIRE2 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLE}, // S_TRAPGOYLE_FIRE3 - {SPR_GARG, 0, 67, {NULL}, 0, 0, S_TRAPGOYLEUP_CHECK}, // S_TRAPGOYLEUP - {SPR_GARG, 0, 3, {NULL}, 0, 0, S_TRAPGOYLEUP_FIRE1}, // S_TRAPGOYLEUP_CHECK - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_TRAPGOYLEUP_FIRE2}, // S_TRAPGOYLEUP_FIRE1 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_TRAPGOYLEUP_FIRE3}, // S_TRAPGOYLEUP_FIRE2 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_TRAPGOYLEUP}, // S_TRAPGOYLEUP_FIRE3 + {SPR_BGAR, 0, 67, {NULL}, 0, 0, S_TRAPGOYLEUP_CHECK}, // S_TRAPGOYLEUP + {SPR_BGAR, 0, 3, {NULL}, 0, 0, S_TRAPGOYLEUP_FIRE1}, // S_TRAPGOYLEUP_CHECK + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_TRAPGOYLEUP_FIRE2}, // S_TRAPGOYLEUP_FIRE1 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_TRAPGOYLEUP_FIRE3}, // S_TRAPGOYLEUP_FIRE2 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_TRAPGOYLEUP}, // S_TRAPGOYLEUP_FIRE3 - {SPR_GARG, 0, 67, {NULL}, 0, 0, S_TRAPGOYLEDOWN_CHECK}, // S_TRAPGOYLEDOWN - {SPR_GARG, 0, 3, {NULL}, 0, 0, S_TRAPGOYLEDOWN_FIRE1}, // S_TRAPGOYLEDOWN_CHECK - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_TRAPGOYLEDOWN_FIRE2}, // S_TRAPGOYLEDOWN_FIRE1 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_TRAPGOYLEDOWN_FIRE3}, // S_TRAPGOYLEDOWN_FIRE2 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_TRAPGOYLEDOWN}, // S_TRAPGOYLEDOWN_FIRE3 + {SPR_BGAR, 0, 67, {NULL}, 0, 0, S_TRAPGOYLEDOWN_CHECK}, // S_TRAPGOYLEDOWN + {SPR_BGAR, 0, 3, {NULL}, 0, 0, S_TRAPGOYLEDOWN_FIRE1}, // S_TRAPGOYLEDOWN_CHECK + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_TRAPGOYLEDOWN_FIRE2}, // S_TRAPGOYLEDOWN_FIRE1 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_TRAPGOYLEDOWN_FIRE3}, // S_TRAPGOYLEDOWN_FIRE2 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_TRAPGOYLEDOWN}, // S_TRAPGOYLEDOWN_FIRE3 - {SPR_GARG, 0, 135, {NULL}, 0, 0, S_TRAPGOYLELONG_CHECK}, // S_TRAPGOYLELONG - {SPR_GARG, 0, 3, {NULL}, 0, 0, S_TRAPGOYLELONG_FIRE1}, // S_TRAPGOYLELONG_CHECK - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE2}, // S_TRAPGOYLELONG_FIRE1 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE3}, // S_TRAPGOYLELONG_FIRE2 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE4}, // S_TRAPGOYLELONG_FIRE3 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE5}, // S_TRAPGOYLELONG_FIRE4 - {SPR_GARG, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG}, // S_TRAPGOYLELONG_FIRE5 + {SPR_BGAR, 0, 135, {NULL}, 0, 0, S_TRAPGOYLELONG_CHECK}, // S_TRAPGOYLELONG + {SPR_BGAR, 0, 3, {NULL}, 0, 0, S_TRAPGOYLELONG_FIRE1}, // S_TRAPGOYLELONG_CHECK + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE2}, // S_TRAPGOYLELONG_FIRE1 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE3}, // S_TRAPGOYLELONG_FIRE2 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE4}, // S_TRAPGOYLELONG_FIRE3 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG_FIRE5}, // S_TRAPGOYLELONG_FIRE4 + {SPR_BGAR, 0, 1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_TRAPGOYLELONG}, // S_TRAPGOYLELONG_FIRE5 // Target/Red Crystal {SPR_RCRY, 0, -1, {NULL}, 0, 0, S_TARGET_IDLE}, // S_TARGET_IDLE @@ -2461,6 +2613,9 @@ state_t states[NUMSTATES] = {SPR_RCRY, 1, 0, {A_SpawnObjectRelative}, 0, MT_TARGET, S_NULL}, // S_TARGET_RESPAWN {SPR_RCRY, FF_FULLBRIGHT|1, -1, {A_SetObjectFlags}, MF_PUSHABLE, 1, S_TARGET_ALLDONE}, // S_TARGET_ALLDONE + // Green flame + {SPR_CFLM, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 3, S_GREENFLAME}, // S_GREENFLAME + // Stalagmites {SPR_STLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_STG0 {SPR_STLG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_STG1 @@ -2481,6 +2636,7 @@ state_t states[NUMSTATES] = {SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST1 {SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2 {SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR + {SPR_XMS6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MISTLETOE // Xmas GFZ bushes {SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBLUEBERRYBUSH {SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBERRYBUSH @@ -2488,6 +2644,16 @@ state_t states[NUMSTATES] = // FHZ {SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE1 {SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE2 + {SPR_ROSY, 16, 8, {NULL}, 0, 0, S_ROSY_IDLE2}, // S_ROSY_IDLE1 + {SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE3}, // S_ROSY_IDLE2 + {SPR_ROSY, 18, 8, {NULL}, 0, 0, S_ROSY_IDLE4}, // S_ROSY_IDLE3 + {SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE1}, // S_ROSY_IDLE4 + {SPR_ROSY, 14, -1, {NULL}, 1, 0, S_NULL}, // S_ROSY_JUMP + {SPR_ROSY, 5, -1, {NULL}, 7, 0, S_NULL}, // S_ROSY_WALK + {SPR_ROSY, 19, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_HUG + {SPR_ROSY, 13, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_PAIN + {SPR_ROSY, 1|FF_ANIMATE, -1, {NULL}, 3, 16, S_NULL}, // S_ROSY_STND + {SPR_ROSY, 20|FF_ANIMATE, TICRATE, {NULL}, 3, 4, S_ROSY_WALK}, // S_ROSY_UNHAPPY // Halloween Scenery // Pumpkins @@ -3143,6 +3309,17 @@ state_t states[NUMSTATES] = {SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ8}, // S_BHORIZ7 {SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1}, // S_BHORIZ8 + // Boosters + {SPR_NULL, 0, 1, {A_Pain}, 0, 0, S_INVISIBLE}, // S_BOOSTERSOUND + {SPR_BSTY, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_YELLOWBOOSTERROLLER + {SPR_BSTY, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_YELLOWBOOSTERSEG_LEFT + {SPR_BSTY, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_YELLOWBOOSTERSEG_RIGHT + {SPR_BSTY, 9|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWBOOSTERSEG_FACE + {SPR_BSTR, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_REDBOOSTERROLLER + {SPR_BSTR, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_REDBOOSTERSEG_LEFT + {SPR_BSTR, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_REDBOOSTERSEG_RIGHT + {SPR_BSTR, 9|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_REDBOOSTERSEG_FACE + // Rain {SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1 {SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN @@ -3163,6 +3340,9 @@ state_t states[NUMSTATES] = {SPR_SPLH, FF_TRANS50|7, 2, {NULL}, 0, 0, S_SPLISH9}, // S_SPLISH8 {SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL}, // S_SPLISH9 + // Lava splish + {SPR_LSPL, FF_ANIMATE, 16, {NULL}, 7, 2, S_NULL}, // S_LAVASPLISH + // Water Splash {SPR_SPLA, FF_TRANS50 , 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1 {SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2 @@ -3474,7 +3654,7 @@ state_t states[NUMSTATES] = // Puma (Mario fireball) {SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2}, // S_PUMA_START1 - {SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1, S_PUMA_UP1}, // S_PUMA_START2 + {SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1 + (1<<16), S_PUMA_UP1}, // S_PUMA_START2 {SPR_PUMA, FF_FULLBRIGHT , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2}, // S_PUMA_UP1 {SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3}, // S_PUMA_UP2 {SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1}, // S_PUMA_UP3 @@ -3797,21 +3977,21 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN {SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA - {SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEB - {SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEC - {SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLED - {SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEE - {SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEF - {SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEG - {SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEH - {SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEI - {SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEJ - {SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEK - {SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEL - {SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEM - {SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEN - {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEO - {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEP + {SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEB + {SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEC + {SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLED + {SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEE + {SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEF + {SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEG + {SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEH + {SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEI + {SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEJ + {SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEK + {SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEL + {SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEM + {SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEN + {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEO + {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEP {SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS @@ -3927,7 +4107,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MT_THOK, // damage sfx_None, // activesound MF_SOLID|MF_SHOOTABLE, // flags - MT_NULL // raisestate + (statenum_t)MT_NULL// raisestate }, { // MT_TAILSOVERLAY @@ -3957,6 +4137,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_METALJETFUME + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_JETFUMEFLASH, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 2, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + S_JETFUME1 // raisestate + }, + { // MT_BLUECRAWLA 100, // doomednum S_POSS_STND, // spawnstate @@ -4351,7 +4558,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_XPLD1, // deathstate S_NULL, // xdeathstate sfx_pop, // deathsound - 1, // speed + 600, // speed 22*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset @@ -4359,7 +4566,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // damage sfx_s3kd2l, // activesound MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags - MT_CRUSHCHAIN // raisestate + (statenum_t)MT_CRUSHCHAIN// raisestate }, { // MT_CRUSHCHAIN @@ -4389,6 +4596,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BANPYURA + 138, // doomednum + S_BANPYURA_ROAM1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 32, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_BANPSPRING + -1, // doomednum + S_CDIAG1, // spawnstate + 1, // spawnhealth + S_CDIAG2, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_cdfm08, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD1, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 300, // speed + 22*FRACUNIT, // radius + 22*FRACUNIT, // height + 0, // display offset + 11*FRACUNIT, // mass + 11*FRACUNIT, // damage + sfx_None, // activesound + MF_SPRING|MF_NOGRAVITY, // flags + S_CDIAG2 // raisestate + }, + { // MT_JETJAW 113, // doomednum S_JETJAW_ROAM1, // spawnstate @@ -4709,7 +4970,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_PAIN|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + MF_SCENERY|MF_PAIN|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_SNAPPER_LEGRAISE // raisestate }, @@ -4736,7 +4997,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_PAIN|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + MF_PAIN|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -4956,6 +5217,141 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_PYREFLY + 136, // doomednum + S_PYREFLY_FLY, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_PYREFLY_BURN, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 1, // speed + 24*FRACUNIT, // radius + 34*FRACUNIT, // height + 0, // display offset + DMG_FIRE, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_SLIDEME, // flags + S_NULL // raisestate + }, + + { // MT_PYREFLY_FIRE + -1, // doomednum + S_PYREFIRE1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 34*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_FIRE|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_PTERABYTESPAWNER + 135, // doomednum + S_PTERABYTESPAWNER, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPTHING|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_PTERABYTEWAYPOINT + -1, // doomednum + S_PTERABYTEWAYPOINT, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 4*FRACUNIT, // speed + 24*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPTHING|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_PTERABYTE + -1, // doomednum + S_PTERABYTE_FLY1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_pscree, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 4*FRACUNIT, // speed + 24*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_SLIDEME, // flags + S_NULL // raisestate + }, + { // MT_BOSSEXPLODE -1, // doomednum S_BOSSEXPLODE, // spawnstate @@ -5442,30 +5838,30 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SHOCK + { // MT_SHOCKWAVE -1, // doomednum - S_THUNDERCOIN_SPARK, // spawnstate + S_SHOCKWAVE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_None, // seesound + sfx_s3k5e, // seesound 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance + 8*TICRATE, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_SPRK1, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - 10*FRACUNIT, // speed - 16*FRACUNIT, // radius - 35*FRACUNIT, // height + 12*FRACUNIT, // speed + 48*FRACUNIT, // radius + 8*FRACUNIT, // height 0, // display offset DMG_ELECTRIC|(sfx_buzz2<<8), // mass - 20, // damage + 3, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_MISSILE|MF_PAIN|MF_NOGRAVITY|MF_PAPERCOLLISION, // flags S_NULL // raisestate }, @@ -5606,7 +6002,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FANG 204, // doomednum - S_FANG_IDLE1, // spawnstate + S_FANG_SETUP, // spawnstate 8, // spawnhealth S_FANG_PATHINGSTART1, // seestate sfx_None, // seesound @@ -5627,10 +6023,118 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 3, // damage sfx_boingf, // activesound - MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE, // flags + MF_RUNSPAWNFUNC|MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE|MF_NOCLIPTHING, // flags -- MF_NOCLIPTHING will be removed after intro event ends S_NULL // raisestate }, + { // MT_BROKENROBOT + -1, // doomednum + S_BROKENROBOTRANDOM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_ambint, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 255, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 1000, // mass + 0, // damage + sfx_crumbl, // activesound + MF_RUNSPAWNFUNC|MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_VWREF + -1, // doomednum + S_VWREF, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 42*FRACUNIT, // radius + 12*FRACUNIT, // height + 1, // display offset + 1000, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_VWREB + -1, // doomednum + S_VWREB, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 42*FRACUNIT, // radius + 12*FRACUNIT, // height + -1, // display offset + 1000, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PROJECTORLIGHT + -1, // doomednum + S_PROJECTORLIGHT1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 42*FRACUNIT, // radius + 52*FRACUNIT, // height + -1, // display offset + 1000, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_FBOMB -1, // doomednum S_FBOMB1, // spawnstate @@ -6485,8 +6989,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 16*FRACUNIT, // radius + 32*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage @@ -6566,8 +7070,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_ncitem, // deathsound 1, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 16*FRACUNIT, // radius + 30*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage @@ -7185,12 +7689,120 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // height 0, // display offset 0, // mass - 1*FRACUNIT, // damage + 11*FRACUNIT, // damage sfx_None, // activesound MF_SPRING|MF_NOGRAVITY, // flags S_BHORIZ2 // raisestate }, + { // MT_BOOSTERSEG + -1, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 28*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_BOOSTERROLLER + -1, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 14*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_YELLOWBOOSTER + 544, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_cdfm62, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 28*FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 0, // mass + 36*FRACUNIT, // damage + sfx_None, // activesound + MF_SPRING|MF_NOGRAVITY, // flags + S_BOOSTERSOUND // raisestate + }, + + { // MT_REDBOOSTER + 545, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_cdfm62, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 28*FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 0, // mass + 72*FRACUNIT, // damage + sfx_None, // activesound + MF_SPRING|MF_NOGRAVITY, // flags + S_BOOSTERSOUND // raisestate + }, + { // MT_BUBBLES 500, // doomednum S_BUBBLES1, // spawnstate @@ -10022,7 +10634,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10049,7 +10661,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_SCENERY, // flags + MF_SPECIAL|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10070,13 +10682,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 29*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10097,13 +10709,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 30*FRACUNIT, // radius + 53*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10124,13 +10736,67 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 28*FRACUNIT, // radius + 41*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CORAL4 + 1014, // doomednum + S_CORAL4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 56*FRACUNIT, // radius + 112*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CORAL5 + 1015, // doomednum + S_CORAL5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 56*FRACUNIT, // radius + 112*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10157,13 +10823,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, { // MT_KELP 1007, // doomednum - S_KELP, // spawnstate + S_KELP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10178,19 +10844,73 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 292*FRACUNIT, // height + 16*FRACUNIT, // radius + 292*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOBLOCKMAP, // flags + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_ANIMALGAETOP + 1013, // doomednum + S_ANIMALGAETOP1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 120*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIP|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_ANIMALGAESEG + -1, // doomednum + S_ANIMALGAESEG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 120*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIP|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_DSZSTALAGMITE 1008, // doomednum - S_DSZSTALAGMITE, // spawnstate + S_DSZSTALAGMITE,// spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10206,12 +10926,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 8*FRACUNIT, // radius - 116*FRACUNIT, // height + 116*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_SOLID, // flags + MF_SCENERY|MF_SOLID, // flags S_NULL // raisestate }, @@ -10233,18 +10953,18 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 8*FRACUNIT, // radius - 116*FRACUNIT, // height + 116*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_SOLID, // flags + MF_SCENERY|MF_SOLID, // flags S_NULL // raisestate }, { // MT_LIGHTBEAM 1010, // doomednum - S_LIGHTBEAM1, // spawnstate + S_LIGHTBEAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10259,7 +10979,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius + 16*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset 4, // mass @@ -10325,7 +11045,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FLAMEPARTICLE -1, // doomednum - S_FLAMEPARTICLE, // spawnstate + S_FLAMEPARTICLE,// spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10621,7 +11341,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SMALLMACE - -1, // doomednum + 1130, // doomednum S_SMALLMACE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10648,7 +11368,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGMACE - -1, // doomednum + 1131, // doomednum S_BIGMACE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10703,7 +11423,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_BIGGRABCHAIN -1, // doomednum - S_BIGGRABCHAIN, // spawnstate + S_BIGGRABCHAIN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10729,7 +11449,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_YELLOWSPRINGBALL - -1, // doomednum + 1134, // doomednum S_YELLOWSPRINGBALL, // spawnstate 1000, // spawnhealth S_YELLOWSPRINGBALL2, // seestate @@ -10756,7 +11476,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_REDSPRINGBALL - -1, // doomednum + 1135, // doomednum S_REDSPRINGBALL, // spawnstate 1000, // spawnhealth S_REDSPRINGBALL2, // seestate @@ -10783,7 +11503,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SMALLFIREBAR - -1, // doomednum + 1136, // doomednum S_SMALLFIREBAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10810,7 +11530,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGFIREBAR - -1, // doomednum + 1137, // doomednum S_BIGFIREBAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11346,7 +12066,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // damage sfx_None, // activesound MF_SLIDEME|MF_SOLID|MF_PUSHABLE, // flags - MT_ROCKCRUMBLE3 // raisestate + (statenum_t)MT_ROCKCRUMBLE3// raisestate }, { // MT_BRAMBLES @@ -11447,13 +12167,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 13*FRACUNIT, // radius + 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11474,13 +12194,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 64*FRACUNIT, // height + 15*FRACUNIT, // radius + 52*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11501,13 +12221,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 13*FRACUNIT, // radius + 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11528,13 +12248,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 80*FRACUNIT, // height + 15*FRACUNIT, // radius + 52*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11558,7 +12278,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // radius 96*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11585,7 +12305,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // radius 128*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11610,9 +12330,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 24*FRACUNIT, // radius - 224*FRACUNIT, // height + 224*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11637,9 +12357,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 24*FRACUNIT, // radius - 256*FRACUNIT, // height + 256*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11666,13 +12386,121 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 48*FRACUNIT, // radius 96*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags S_NULL // raisestate }, + { // MT_CACTI10 + 1230, // doomednum + S_CACTI10, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 13*FRACUNIT, // radius + 28*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_CACTI11 + 1231, // doomednum + S_CACTI11, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 15*FRACUNIT, // radius + 60*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_CACTITINYSEG + -1, // doomednum + S_CACTITINYSEG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 13*FRACUNIT, // radius + 28*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_CACTISMALLSEG + -1, // doomednum + S_CACTISMALLSEG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 15*FRACUNIT, // radius + 60*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_ARIDSIGN_CAUTION 1212, // doomednum S_ARIDSIGN_CAUTION, // spawnstate @@ -11804,7 +12632,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SHOOTABLE|MF_ENEMY|MF_PUSHABLE, // flags + MF_SOLID|MF_SHOOTABLE|MF_PUSHABLE, // flags S_NULL // raisestate }, @@ -11940,7 +12768,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // damage sfx_s3k76, // activesound MF_PUSHABLE, // flags - MT_MINECARTSIDEMARK // raisestate + (statenum_t)MT_MINECARTSIDEMARK// raisestate }, { // MT_MINECARTSEG @@ -12132,9 +12960,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SALOONDOORTHINKER + { // MT_SALOONDOORCENTER 1221, // doomednum - S_SALOONDOORTHINKER, // spawnstate + S_SALOONDOORCENTER, // spawnstate 1, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -12155,7 +12983,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + MF_SOLID|MF_NOGRAVITY|MF_RUNSPAWNFUNC|MF_PAPERCOLLISION|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -12456,6 +13284,303 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_LAVAFALL + 1304, // doomednum + S_LAVAFALL_DORMANT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_lvfal1, // seesound + 8, // reactiontime + sfx_s3kd5l, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 30*FRACUNIT, // radius + 32*FRACUNIT, // height + 1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_SPAWNCEILING, // flags + S_NULL // raisestate + }, + + { // MT_LAVAFALL_LAVA + -1, // doomednum + S_LAVAFALL_LAVA1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_LAVAFALL_LAVA3, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 30*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_PAIN|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_LAVAFALLROCK + -1, // doomednum + S_LAVAFALLROCK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_ROLLOUTSPAWN + 1305, // doomednum + S_ROLLOUTSPAWN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SPAWNCEILING, // flags + S_NULL // raisestate + }, + + { // MT_ROLLOUTROCK + -1, // doomednum + S_ROLLOUTROCK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime (sets number of frames the rock cycles through) + sfx_None, // attacksound + S_NULL, // painstate + 12*TICRATE, // painchance (sets how long an unridden rock should last before disappearing - set to 0 to disable) + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 32*FRACUNIT, // speed + 30*FRACUNIT, // radius + 60*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_PUSHABLE|MF_SOLID|MF_SLIDEME, // flags + S_NULL // raisestate + }, + + { // MT_BIGFERNLEAF + -1, // doomednum + S_BIGFERNLEAF, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_BIGFERN + 1306, // doomednum + S_BIGFERN1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_JUNGLEPALM + 1307, // doomednum + S_JUNGLEPALM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_TORCHFLOWER + 1308, // doomednum + S_TORCHFLOWER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 14*FRACUNIT, // radius + 110*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_WALLVINE_LONG + 1309, // doomednum + S_WALLVINE_LONG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 1*FRACUNIT, // radius + 288*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_WALLVINE_SHORT + 1310, // doomednum + S_WALLVINE_SHORT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 1*FRACUNIT, // radius + 288*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP, // flags + S_NULL // raisestate + }, + { // MT_TRAPGOYLE 1500, // doomednum S_TRAPGOYLE, // spawnstate @@ -12591,6 +13716,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GREENFLAME + 1505, // doomednum + S_GREENFLAME, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + MT_NULL, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_PAIN, // flags + S_NULL // raisestate + }, + { // MT_STALAGMITE0 1900, // doomednum S_STG0, // spawnstate @@ -13050,6 +14202,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_MISTLETOE + 2105, // doomednum + S_MISTLETOE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 52*FRACUNIT, // radius + 106*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_XMASBLUEBERRYBUSH 1859, // doomednum S_XMASBLUEBERRYBUSH, // spawnstate @@ -13185,6 +14364,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_ROSY + 2104, // doomednum + S_ROSY_IDLE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_ENEMY|MF_SLIDEME, // flags -- "enemy" may seem weird but it doesn't have any unintended consequences in context because no MF_SHOOTABLE|MF_SPECIAL + S_NULL // raisestate + }, + + { // MT_CDLHRT + -1, // doomednum + S_LHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 4*FRACUNIT, // speed + 4*FRACUNIT, // radius + 4*FRACUNIT, // height + 1, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_JACKO1 2006, // doomednum S_JACKO1, // spawnstate @@ -16240,6 +17473,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_LAVASPLISH + -1, // doomednum + S_LAVASPLISH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 6*FRACUNIT, // radius + 1*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_SMOKE -1, // doomednum S_SMOKE1, // spawnstate diff --git a/src/info.h b/src/info.h index a9d4bdde0..e7f41f585 100644 --- a/src/info.h +++ b/src/info.h @@ -138,6 +138,7 @@ void A_SetReactionTime(); void A_Boss1Spikeballs(); void A_Boss3TakeDamage(); void A_Boss3Path(); +void A_Boss3ShockThink(); void A_LinedefExecute(); void A_PlaySeeSound(); void A_PlayAttackSound(); @@ -252,6 +253,7 @@ void A_Boss5CheckOnGround(); void A_Boss5CheckFalling(); void A_Boss5PinchShot(); void A_Boss5MakeItRain(); +void A_Boss5MakeJunk(); void A_LookForBetter(); void A_Boss5BombExplode(); void A_DustDevilThink(); @@ -266,6 +268,14 @@ void A_SnapperThinker(); void A_SaloonDoorSpawn(); void A_MinecartSparkThink(); void A_ModuloToState(); +void A_LavafallRocks(); +void A_LavafallLava(); +void A_FallingLavaCheck(); +void A_FireShrink(); +void A_SpawnPterabytes(); +void A_PterabyteHover(); +void A_RolloutSpawn(); +void A_RolloutRock(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 512 @@ -296,6 +306,8 @@ typedef enum sprite SPR_TURR, // Pop-Up Turret SPR_SHRP, // Sharp SPR_CRAB, // Crushstacean + SPR_CR2B, // Banpyura + SPR_CSPR, // Banpyura spring SPR_JJAW, // Jet Jaw SPR_SNLR, // Snailer SPR_VLTR, // BASH @@ -314,6 +326,8 @@ typedef enum sprite SPR_UNID, // Unidus SPR_CANA, // Canarivore SPR_CANG, // Canarivore gas + SPR_PYRE, // Pyre Fly + SPR_PTER, // Pterabyte // Generic Boss Items SPR_JETF, // Boss jet fumes @@ -331,6 +345,7 @@ typedef enum sprite SPR_EGGO, // Boss 3 SPR_SEBH, // Boss 3 Junk SPR_FAKE, // Boss 3 Fakemobile + SPR_SHCK, // Boss 3 Shockwave // Boss 4 (Castle Eggman) SPR_EGGP, @@ -339,6 +354,10 @@ typedef enum sprite // Boss 5 (Arid Canyon) SPR_FANG, // replaces EGGQ + SPR_BRKN, + SPR_WHAT, + SPR_VWRE, + SPR_PROJ, // projector light SPR_FBOM, SPR_FSGN, SPR_BARX, // bomb explosion (also used by barrel) @@ -390,6 +409,7 @@ typedef enum sprite SPR_WSPB, // Wall spike base SPR_STPT, // Starpost SPR_BMNE, // Big floating mine + SPR_PUMI, // Rollout Rock // Monitor Boxes SPR_MSTV, // MiSc TV sprites @@ -458,11 +478,11 @@ typedef enum sprite SPR_GARG, // Deep Sea Gargoyle SPR_SEWE, // Deep Sea Seaweed SPR_DRIP, // Dripping water - SPR_CRL1, // Coral 1 - SPR_CRL2, // Coral 2 - SPR_CRL3, // Coral 3 + SPR_CORL, // Coral SPR_BCRY, // Blue Crystal SPR_KELP, // Kelp + SPR_ALGA, // Animated algae top + SPR_ALGB, // Animated algae segment SPR_DSTG, // DSZ Stalagmites SPR_LIBE, // DSZ Light beam @@ -492,7 +512,7 @@ typedef enum sprite // Arid Canyon Scenery SPR_BTBL, // Big tumbleweed SPR_STBL, // Small tumbleweed - SPR_CACT, // Cacti sprites + SPR_CACT, // Cacti SPR_WWSG, // Caution Sign SPR_WWS2, // Cacti Sign SPR_WWS3, // Sharp Turn Sign @@ -504,7 +524,6 @@ typedef enum sprite SPR_ADST, // Arid dust SPR_MCRT, // Minecart SPR_MCSP, // Minecart spark - SPR_NON2, // Saloon door thinker SPR_SALD, // Saloon door SPR_TRAE, // Train cameo locomotive SPR_TRAI, // Train cameo wagon @@ -513,6 +532,10 @@ typedef enum sprite // Red Volcano Scenery SPR_FLME, // Flame jet SPR_DFLM, // Blade's flame + SPR_LFAL, // Lavafall + SPR_JPLA, // Jungle palm + SPR_TFLO, // Torch flower + SPR_WVIN, // Wall vines // Dark City Scenery @@ -524,13 +547,20 @@ typedef enum sprite SPR_XMS3, // Snowman SPR_XMS4, // Lamppost SPR_XMS5, // Hanging Star + SPR_XMS6, // Mistletoe SPR_FHZI, // FHZ Ice + SPR_ROSY, // Halloween Scenery SPR_PUMK, // Pumpkins SPR_HHPL, // Dr Seuss Trees SPR_SHRM, // Mushroom SPR_HHZM, // Misc + + // Azure Temple Scenery + SPR_BGAR, // ATZ Gargoyles + SPR_RCRY, // ATZ Red Crystal (Target) + SPR_CFLM, // Green torch flame // Botanic Serenity Scenery SPR_BSZ1, // Tall flowers @@ -551,7 +581,6 @@ typedef enum sprite // Misc Scenery SPR_STLG, // Stalagmites SPR_DBAL, // Disco - SPR_RCRY, // ATZ Red Crystal (Target) // Powerup Indicators SPR_ARMA, // Armageddon Shield Orb @@ -605,11 +634,14 @@ typedef enum sprite SPR_SSWY, // Yellow Side Spring SPR_SSWR, // Red Side Spring SPR_SSWB, // Blue Side Spring + SPR_BSTY, // Yellow Booster + SPR_BSTR, // Red Booster // Environmental Effects SPR_RAIN, // Rain SPR_SNO1, // Snowflake SPR_SPLH, // Water Splish + SPR_LSPL, // Lava Splish SPR_SPLA, // Water Splash SPR_SMOK, SPR_BUBL, // Bubble @@ -764,6 +796,7 @@ typedef enum playersprite SPR2_TIRE, // tired SPR2_GLID, // glide + SPR2_LAND, // landing after glide/bounce SPR2_CLNG, // cling SPR2_CLMB, // climb @@ -771,7 +804,6 @@ typedef enum playersprite SPR2_FRUN, // float run SPR2_BNCE, // bounce - SPR2_BLND, // bounce landing SPR2_FIRE, // fire @@ -832,15 +864,27 @@ typedef enum playersprite SPR2_TALA, SPR2_TALB, + SPR2_CNT1, // continue disappointment + SPR2_CNT2, // continue lift + SPR2_CNT3, // continue spin + SPR2_CNT4, // continue "soooooooniiic!" tugging + SPR2_SIGN, // end sign head SPR2_LIFE, // life monitor icon - SPR2_XTRA, // stuff that isn't in-game - keep this last in the list + + SPR2_XTRA, // stuff that isn't in-map - "would this ever need an md2 or variable length animation?" SPR2_FIRSTFREESLOT, SPR2_LASTFREESLOT = 0x7f, NUMPLAYERSPRITES } playersprite_t; +// SPR2_XTRA +#define XTRA_LIFEPIC 0 // Life icon patch +#define XTRA_CHARSEL 1 // Character select picture +#define XTRA_CONTINUE 2 // Continue icon +#define XTRA_ENDING 3 // Ending finale patches + typedef enum state { S_NULL, @@ -887,6 +931,7 @@ typedef enum state // CA_GLIDEANDCLIMB S_PLAY_GLIDE, + S_PLAY_GLIDE_LANDING, S_PLAY_CLING, S_PLAY_CLIMB, @@ -986,6 +1031,9 @@ typedef enum state S_TAILSOVERLAY_GASP, S_TAILSOVERLAY_EDGE, + // [: + S_JETFUMEFLASH, + // Blue Crawla S_POSS_STND, S_POSS_RUN1, @@ -1134,6 +1182,21 @@ typedef enum state S_CRUSHCLAW_WAIT, S_CRUSHCHAIN, + // Banpyura + S_BANPYURA_ROAM1, + S_BANPYURA_ROAM2, + S_BANPYURA_ROAM3, + S_BANPYURA_ROAM4, + S_BANPYURA_ROAMPAUSE, + S_CDIAG1, + S_CDIAG2, + S_CDIAG3, + S_CDIAG4, + S_CDIAG5, + S_CDIAG6, + S_CDIAG7, + S_CDIAG8, + // Jet Jaw S_JETJAW_ROAM1, S_JETJAW_ROAM2, @@ -1320,6 +1383,22 @@ typedef enum state S_CANARIVOREGAS_7, S_CANARIVOREGAS_8, + // Pyre Fly + S_PYREFLY_FLY, + S_PYREFLY_BURN, + S_PYREFIRE1, + S_PYREFIRE2, + + // Pterabyte + S_PTERABYTESPAWNER, + S_PTERABYTEWAYPOINT, + S_PTERABYTE_FLY1, + S_PTERABYTE_FLY2, + S_PTERABYTE_FLY3, + S_PTERABYTE_FLY4, + S_PTERABYTE_SWOOPDOWN, + S_PTERABYTE_SWOOPUP, + // Boss Explosion S_BOSSEXPLODE, @@ -1447,6 +1526,10 @@ typedef enum state S_BOSSSEBH1, S_BOSSSEBH2, + // Boss 3 Shockwave + S_SHOCKWAVE1, + S_SHOCKWAVE2, + // Boss 4 S_EGGMOBILE4_STND, S_EGGMOBILE4_LATK1, @@ -1489,6 +1572,25 @@ typedef enum state S_EGGROBOJET, // Boss 5 + S_FANG_SETUP, + S_FANG_INTRO0, + S_FANG_INTRO1, + S_FANG_INTRO2, + S_FANG_INTRO3, + S_FANG_INTRO4, + S_FANG_INTRO5, + S_FANG_INTRO6, + S_FANG_INTRO7, + S_FANG_INTRO8, + S_FANG_INTRO9, + S_FANG_INTRO10, + S_FANG_INTRO11, + S_FANG_INTRO12, + S_FANG_CLONE1, + S_FANG_CLONE2, + S_FANG_CLONE3, + S_FANG_CLONE4, + S_FANG_IDLE0, S_FANG_IDLE1, S_FANG_IDLE2, S_FANG_IDLE3, @@ -1560,6 +1662,26 @@ typedef enum state S_FANG_FLEEBOUNCE2, S_FANG_KO, + S_BROKENROBOTRANDOM, + S_BROKENROBOTA, + S_BROKENROBOTB, + S_BROKENROBOTC, + S_BROKENROBOTD, + S_BROKENROBOTE, + S_BROKENROBOTF, + + S_ALART1, + S_ALART2, + + S_VWREF, + S_VWREB, + + S_PROJECTORLIGHT1, + S_PROJECTORLIGHT2, + S_PROJECTORLIGHT3, + S_PROJECTORLIGHT4, + S_PROJECTORLIGHT5, + S_FBOMB1, S_FBOMB2, S_FBOMB_EXPL1, @@ -2283,14 +2405,12 @@ typedef enum state S_DRIPC1, S_DRIPC2, - // Coral 1 + // Coral S_CORAL1, - - // Coral 2 S_CORAL2, - - // Coral 3 S_CORAL3, + S_CORAL4, + S_CORAL5, // Blue Crystal S_BLUECRYSTAL1, @@ -2298,6 +2418,11 @@ typedef enum state // Kelp, S_KELP, + // Animated algae + S_ANIMALGAETOP1, + S_ANIMALGAETOP2, + S_ANIMALGAESEG, + // DSZ Stalagmites S_DSZSTALAGMITE, S_DSZ2STALAGMITE, @@ -2432,7 +2557,7 @@ typedef enum state S_LITTLETUMBLEWEED_ROLL7, S_LITTLETUMBLEWEED_ROLL8, - // Cacti Sprites + // Cacti S_CACTI1, S_CACTI2, S_CACTI3, @@ -2442,8 +2567,12 @@ typedef enum state S_CACTI7, S_CACTI8, S_CACTI9, + S_CACTI10, + S_CACTI11, + S_CACTITINYSEG, + S_CACTISMALLSEG, - // Warning signs sprites + // Warning signs S_ARIDSIGN_CAUTION, S_ARIDSIGN_CACTI, S_ARIDSIGN_SHARPTURN, @@ -2513,7 +2642,7 @@ typedef enum state // Saloon door S_SALOONDOOR, - S_SALOONDOORTHINKER, + S_SALOONDOORCENTER, // Train cameo S_TRAINCAMEOSPAWNER_1, @@ -2534,6 +2663,12 @@ typedef enum state S_FLAMEJETFLAME1, S_FLAMEJETFLAME2, S_FLAMEJETFLAME3, + S_FLAMEJETFLAME4, + S_FLAMEJETFLAME5, + S_FLAMEJETFLAME6, + S_FLAMEJETFLAME7, + S_FLAMEJETFLAME8, + S_FLAMEJETFLAME9, // Spinning flame jets S_FJSPINAXISA1, // Counter-clockwise @@ -2546,6 +2681,28 @@ typedef enum state S_FLAMEJETFLAMEB2, S_FLAMEJETFLAMEB3, + // Lavafall + S_LAVAFALL_DORMANT, + S_LAVAFALL_TELL, + S_LAVAFALL_SHOOT, + S_LAVAFALL_LAVA1, + S_LAVAFALL_LAVA2, + S_LAVAFALL_LAVA3, + S_LAVAFALLROCK, + + // Rollout Rock + S_ROLLOUTSPAWN, + S_ROLLOUTROCK, + + // RVZ scenery + S_BIGFERNLEAF, + S_BIGFERN1, + S_BIGFERN2, + S_JUNGLEPALM, + S_TORCHFLOWER, + S_WALLVINE_LONG, + S_WALLVINE_SHORT, + // Trapgoyles S_TRAPGOYLE, S_TRAPGOYLE_CHECK, @@ -2577,6 +2734,9 @@ typedef enum state S_TARGET_RESPAWN, S_TARGET_ALLDONE, + // ATZ's green flame + S_GREENFLAME, + // Stalagmites S_STG0, S_STG1, @@ -2597,6 +2757,7 @@ typedef enum state S_LAMPPOST1, // normal S_LAMPPOST2, // with snow S_HANGSTAR, + S_MISTLETOE, // Xmas GFZ bushes S_XMASBLUEBERRYBUSH, S_XMASBERRYBUSH, @@ -2604,6 +2765,16 @@ typedef enum state // FHZ S_FHZICE1, S_FHZICE2, + S_ROSY_IDLE1, + S_ROSY_IDLE2, + S_ROSY_IDLE3, + S_ROSY_IDLE4, + S_ROSY_JUMP, + S_ROSY_WALK, + S_ROSY_HUG, + S_ROSY_PAIN, + S_ROSY_STND, + S_ROSY_UNHAPPY, // Halloween Scenery // Pumpkins @@ -3255,6 +3426,17 @@ typedef enum state S_BHORIZ7, S_BHORIZ8, + // Booster + S_BOOSTERSOUND, + S_YELLOWBOOSTERROLLER, + S_YELLOWBOOSTERSEG_LEFT, + S_YELLOWBOOSTERSEG_RIGHT, + S_YELLOWBOOSTERSEG_FACE, + S_REDBOOSTERROLLER, + S_REDBOOSTERSEG_LEFT, + S_REDBOOSTERSEG_RIGHT, + S_REDBOOSTERSEG_FACE, + // Rain S_RAIN1, S_RAINRETURN, @@ -3275,6 +3457,9 @@ typedef enum state S_SPLISH8, S_SPLISH9, + // Lava Splish + S_LAVASPLISH, + // added water splash S_SPLASH1, S_SPLASH2, @@ -3908,6 +4093,7 @@ typedef enum mobj_type MT_THOK, // Thok! mobj MT_PLAYER, MT_TAILSOVERLAY, // c: + MT_METALJETFUME, // Enemies MT_BLUECRAWLA, // Crawla (Blue) @@ -3926,6 +4112,8 @@ typedef enum mobj_type MT_CRUSHSTACEAN, // Crushstacean MT_CRUSHCLAW, // Big meaty claw MT_CRUSHCHAIN, // Chain + MT_BANPYURA, // Banpyura + MT_BANPSPRING, // Banpyura spring MT_JETJAW, // Jet Jaw MT_SNAILER, // Snailer MT_VULTURE, // BASH @@ -3947,6 +4135,11 @@ typedef enum mobj_type MT_UNIBALL, // Unidus Ball MT_CANARIVORE, // Canarivore MT_CANARIVORE_GAS, // Canarivore gas + MT_PYREFLY, // Pyre Fly + MT_PYREFLY_FIRE, // Pyre Fly fire + MT_PTERABYTESPAWNER, // Pterabyte spawner + MT_PTERABYTEWAYPOINT, // Pterabyte waypoint + MT_PTERABYTE, // Pterabyte // Generic Boss Items MT_BOSSEXPLODE, @@ -3973,7 +4166,7 @@ typedef enum mobj_type // Boss 3 MT_EGGMOBILE3, MT_FAKEMOBILE, - MT_SHOCK, + MT_SHOCKWAVE, // Boss 4 MT_EGGMOBILE4, @@ -3984,6 +4177,10 @@ typedef enum mobj_type // Boss 5 MT_FANG, + MT_BROKENROBOT, + MT_VWREF, + MT_VWREB, + MT_PROJECTORLIGHT, MT_FBOMB, MT_TNTDUST, // also used by barrel MT_FSGNA, @@ -4054,6 +4251,11 @@ typedef enum mobj_type MT_REDHORIZ, MT_BLUEHORIZ, + MT_BOOSTERSEG, + MT_BOOSTERROLLER, + MT_YELLOWBOOSTER, + MT_REDBOOSTER, + // Interactive Objects MT_BUBBLES, // Bubble source MT_SIGN, // Level end sign @@ -4182,11 +4384,15 @@ typedef enum mobj_type MT_SEAWEED, // DSZ Seaweed MT_WATERDRIP, // Dripping Water source MT_WATERDROP, // Water drop from dripping water - MT_CORAL1, // Coral 1 - MT_CORAL2, // Coral 2 - MT_CORAL3, // Coral 3 + MT_CORAL1, // Coral + MT_CORAL2, + MT_CORAL3, + MT_CORAL4, + MT_CORAL5, MT_BLUECRYSTAL, // Blue Crystal MT_KELP, // Kelp + MT_ANIMALGAETOP, // Animated algae top + MT_ANIMALGAESEG, // Animated algae segment MT_DSZSTALAGMITE, // Deep Sea 1 Stalagmite MT_DSZ2STALAGMITE, // Deep Sea 2 Stalagmite MT_LIGHTBEAM, // DSZ Light beam @@ -4237,15 +4443,19 @@ typedef enum mobj_type // Arid Canyon Scenery MT_BIGTUMBLEWEED, MT_LITTLETUMBLEWEED, - MT_CACTI1, - MT_CACTI2, - MT_CACTI3, - MT_CACTI4, - MT_CACTI5, // Harmful Cactus 1 - MT_CACTI6, // Harmful Cactus 2 - MT_CACTI7, // Harmful Cactus 3 - MT_CACTI8, // Harmful Cactus 4 - MT_CACTI9, // Harmful Cactus 5 + MT_CACTI1, // Tiny Red Flower Cactus + MT_CACTI2, // Small Red Flower Cactus + MT_CACTI3, // Tiny Blue Flower Cactus + MT_CACTI4, // Small Blue Flower Cactus + MT_CACTI5, // Prickly Pear + MT_CACTI6, // Barrel Cactus + MT_CACTI7, // Tall Barrel Cactus + MT_CACTI8, // Armed Cactus + MT_CACTI9, // Ball Cactus + MT_CACTI10, // Tiny Cactus + MT_CACTI11, // Small Cactus + MT_CACTITINYSEG, // Tiny Cactus Segment + MT_CACTISMALLSEG, // Small Cactus Segment MT_ARIDSIGN_CAUTION, // Caution Sign MT_ARIDSIGN_CACTI, // Cacti Sign MT_ARIDSIGN_SHARPTURN, // Sharp Turn Sign @@ -4263,7 +4473,7 @@ typedef enum mobj_type MT_MINECARTSIDEMARK, MT_MINECARTSPARK, MT_SALOONDOOR, - MT_SALOONDOORTHINKER, + MT_SALOONDOORCENTER, MT_TRAINCAMEOSPAWNER, MT_TRAINSEG, MT_TRAINDUSTSPAWNER, @@ -4280,6 +4490,20 @@ typedef enum mobj_type MT_FLAMEJETFLAMEB, // Blade's flame + MT_LAVAFALL, + MT_LAVAFALL_LAVA, + MT_LAVAFALLROCK, + + MT_ROLLOUTSPAWN, + MT_ROLLOUTROCK, + + MT_BIGFERNLEAF, + MT_BIGFERN, + MT_JUNGLEPALM, + MT_TORCHFLOWER, + MT_WALLVINE_LONG, + MT_WALLVINE_SHORT, + // Dark City Scenery // Egg Rock Scenery @@ -4290,6 +4514,7 @@ typedef enum mobj_type MT_TRAPGOYLEDOWN, MT_TRAPGOYLELONG, MT_TARGET, // AKA Red Crystal + MT_GREENFLAME, // Stalagmites MT_STALAGMITE0, @@ -4311,6 +4536,7 @@ typedef enum mobj_type MT_LAMPPOST1, // normal MT_LAMPPOST2, // with snow MT_HANGSTAR, + MT_MISTLETOE, // Xmas GFZ bushes MT_XMASBLUEBERRYBUSH, MT_XMASBERRYBUSH, @@ -4318,6 +4544,8 @@ typedef enum mobj_type // FHZ MT_FHZICE1, MT_FHZICE2, + MT_ROSY, + MT_CDLHRT, // Halloween Scenery // Pumpkins @@ -4446,6 +4674,7 @@ typedef enum mobj_type MT_RAIN, // Rain MT_SNOWFLAKE, // Snowflake MT_SPLISH, // Water splish! + MT_LAVASPLISH, // Lava splish! MT_SMOKE, MT_SMALLBUBBLE, // small bubble MT_MEDIUMBUBBLE, // medium bubble diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 3c136a436..8f173e32e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -182,6 +182,8 @@ static const struct { {META_CAMERA, "camera_t"}, {META_ACTION, "action"}, + + {META_LUABANKS, "luabanks[]"}, {NULL, NULL} }; @@ -228,6 +230,18 @@ static int lib_isPlayerAdmin(lua_State *L) return 1; } +static int lib_reserveLuabanks(lua_State *L) +{ + static boolean reserved = false; + if (!lua_lumploading) + return luaL_error(L, "luabanks[] cannot be reserved from within a hook or coroutine!"); + if (reserved) + return luaL_error(L, "luabanks[] has already been reserved! Only one savedata-enabled mod at a time may use this feature."); + reserved = true; + LUA_PushUserdata(L, &luabanks, META_LUABANKS); + return 1; +} + // M_RANDOM ////////////// @@ -802,15 +816,12 @@ static int lib_pCheckDeathPitCollide(lua_State *L) static int lib_pCheckSolidLava(lua_State *L) { - mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); //HUDSAFE INLEVEL - if (!mo) - return LUA_ErrInvalid(L, "mobj_t"); if (!rover) return LUA_ErrInvalid(L, "ffloor_t"); - lua_pushboolean(L, P_CheckSolidLava(mo, rover)); + lua_pushboolean(L, P_CheckSolidLava(rover)); return 1; } @@ -2736,6 +2747,7 @@ static luaL_Reg lib[] = { {"chatprintf", lib_chatprintf}, {"userdataType", lib_userdataType}, {"IsPlayerAdmin", lib_isPlayerAdmin}, + {"reserveLuabanks", lib_reserveLuabanks}, // m_random {"P_RandomFixed",lib_pRandomFixed}, diff --git a/src/lua_hook.h b/src/lua_hook.h index 45e116c34..37b1f3e06 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -50,6 +50,7 @@ enum hook { hook_FollowMobj, hook_PlayerCanDamage, hook_PlayerQuit, + hook_IntermissionThinker, hook_MAX // last hook }; @@ -91,5 +92,6 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnM boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following 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 #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 7f7e8adc6..03c7ce911 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -61,6 +61,7 @@ const char *const hookNames[hook_MAX+1] = { "FollowMobj", "PlayerCanDamage", "PlayerQuit", + "IntermissionThinker", NULL }; @@ -1322,4 +1323,27 @@ void LUAh_PlayerQuit(player_t *plr, int reason) lua_settop(gL, 0); } +// Hook for Y_Ticker +void LUAh_IntermissionThinker(void) +{ + hook_p hookp; + if (!gL || !(hooksAvailable[hook_IntermissionThinker/8] & (1<<(hook_IntermissionThinker%8)))) + return; + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_IntermissionThinker) + 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; + } + } +} + #endif diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 8c1134bca..865b61e8f 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -637,6 +637,68 @@ static int libd_drawString(lua_State *L) return 0; } +static int libd_drawNameTag(lua_State *L) +{ + INT32 x; + INT32 y; + const char *str; + INT32 flags; + UINT8 basecolor; + UINT8 outlinecolor; + UINT8 *basecolormap = NULL; + UINT8 *outlinecolormap = NULL; + + HUDONLY + + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + str = luaL_checkstring(L, 3); + flags = luaL_optinteger(L, 4, 0); + basecolor = luaL_optinteger(L, 5, SKINCOLOR_BLUE); + outlinecolor = luaL_optinteger(L, 6, SKINCOLOR_ORANGE); + if (basecolor != SKINCOLOR_NONE) + basecolormap = R_GetTranslationColormap(TC_DEFAULT, basecolor, GTC_CACHE); + if (outlinecolor != SKINCOLOR_NONE) + outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + V_DrawNameTag(x, y, flags, FRACUNIT, basecolormap, outlinecolormap, str); + return 0; +} + +static int libd_drawScaledNameTag(lua_State *L) +{ + fixed_t x; + fixed_t y; + const char *str; + INT32 flags; + fixed_t scale; + UINT8 basecolor; + UINT8 outlinecolor; + UINT8 *basecolormap = NULL; + UINT8 *outlinecolormap = NULL; + + HUDONLY + + x = luaL_checkfixed(L, 1); + y = luaL_checkfixed(L, 2); + str = luaL_checkstring(L, 3); + flags = luaL_optinteger(L, 4, 0); + scale = luaL_optinteger(L, 5, FRACUNIT); + if (scale < 0) + return luaL_error(L, "negative scale"); + basecolor = luaL_optinteger(L, 6, SKINCOLOR_BLUE); + outlinecolor = luaL_optinteger(L, 7, SKINCOLOR_ORANGE); + if (basecolor != SKINCOLOR_NONE) + basecolormap = R_GetTranslationColormap(TC_DEFAULT, basecolor, GTC_CACHE); + if (outlinecolor != SKINCOLOR_NONE) + outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + V_DrawNameTag(FixedInt(x), FixedInt(y), flags, scale, basecolormap, outlinecolormap, str); + return 0; +} + static int libd_stringWidth(lua_State *L) { const char *str = luaL_checkstring(L, 1); @@ -659,6 +721,13 @@ static int libd_stringWidth(lua_State *L) return 1; } +static int libd_nameTagWidth(lua_State *L) +{ + HUDONLY + lua_pushinteger(L, V_NameTagWidth(luaL_checkstring(L, 1))); + return 1; +} + static int libd_getColormap(lua_State *L) { INT32 skinnum = TC_DEFAULT; @@ -837,9 +906,12 @@ static luaL_Reg lib_draw[] = { {"drawPaddedNum", libd_drawPaddedNum}, {"drawFill", libd_drawFill}, {"drawString", libd_drawString}, + {"drawNameTag", libd_drawNameTag}, + {"drawScaledNameTag", libd_drawScaledNameTag}, {"fadeScreen", libd_fadeScreen}, // misc {"stringWidth", libd_stringWidth}, + {"nameTagWidth", libd_nameTagWidth}, // m_random {"RandomFixed",libd_RandomFixed}, {"RandomByte",libd_RandomByte}, diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 77f37f8ec..8ef0bafcf 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -18,6 +18,7 @@ #include "p_mobj.h" #include "p_local.h" #include "z_zone.h" +#include "doomstat.h" // luabanks[] #include "lua_script.h" #include "lua_libs.h" @@ -146,7 +147,7 @@ static int lib_getSpr2default(lua_State *L) return luaL_error(L, "spr2defaults[] invalid index"); if (i >= free_spr2) - return 0; + return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, 0, free_spr2-1); lua_pushinteger(L, spr2defaults[i]); return 1; @@ -1026,6 +1027,61 @@ static int sfxinfo_num(lua_State *L) return 1; } +////////////// +// LUABANKS // +////////////// + +static int lib_getluabanks(lua_State *L) +{ + UINT8 i; + + lua_remove(L, 1); // don't care about luabanks[] dummy userdata. + + if (lua_isnumber(L, 1)) + i = lua_tonumber(L, 1); + else + return luaL_error(L, "luabanks[] invalid index"); + + if (i >= NUM_LUABANKS) + luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1); + + lua_pushinteger(L, luabanks[i]); + return 1; +} + +static int lib_setluabanks(lua_State *L) +{ + UINT8 i; + INT32 j = 0; + + if (hud_running) + return luaL_error(L, "Do not alter luabanks[] in HUD rendering code!"); + + lua_remove(L, 1); // don't care about luabanks[] dummy userdata. + + if (lua_isnumber(L, 1)) + i = lua_tonumber(L, 1); + else + return luaL_error(L, "luabanks[] invalid index"); + + if (i >= NUM_LUABANKS) + luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1); + + if (lua_isnumber(L, 2)) + j = lua_tonumber(L, 2); + else + return luaL_error(L, "luabanks[] invalid set"); + + luabanks[i] = j; + return 0; +} + +static int lib_luabankslen(lua_State *L) +{ + lua_pushinteger(L, NUM_LUABANKS); + return 1; +} + ////////////////////////////// // // Now push all these functions into the Lua state! @@ -1147,6 +1203,18 @@ int LUA_InfoLib(lua_State *L) lua_pushvalue(L, -1); lua_setglobal(L, "S_sfx"); lua_setglobal(L, "sfxinfo"); + + luaL_newmetatable(L, META_LUABANKS); + lua_pushcfunction(L, lib_getluabanks); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_setluabanks); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, lib_luabankslen); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + return 0; } diff --git a/src/lua_libs.h b/src/lua_libs.h index 827c1d798..7609971ce 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -67,6 +67,8 @@ extern lua_State *gL; #define META_ACTION "ACTIONF_T*" +#define META_LUABANKS "LUABANKS[]*" + boolean luaL_checkboolean(lua_State *L, int narg); int LUA_EnumLib(lua_State *L); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index dbb69b7e2..1da232efa 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -411,37 +411,53 @@ static int sector_iterate(lua_State *L) // sector.lines, i -> sector.lines[i] // sector.lines.valid, for validity checking +// +// 25/9/19 Monster Iestyn +// Modified this and _num to use triple pointers, to allow for a new hack of mine involving offsetof +// this way we don't need to check frontsector or backsector of line #0 in the array +// static int sectorlines_get(lua_State *L) { - line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES)); + line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES)); size_t i; size_t numoflines = 0; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { int field = luaL_checkoption(L, 2, NULL, valid_opt); - if (!seclines) + if (!seclines || !(*seclines)) { if (field == 0) { lua_pushboolean(L, 0); return 1; } - return luaL_error(L, "accessed sector_t doesn't exist anymore."); + return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); } else if (field == 0) { lua_pushboolean(L, 1); return 1; } } +/* a snip from sector_t struct in r_defs.h, for reference + size_t linecount; + struct line_s **lines; // [linecount] size +*/ + // 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)))); + +/* OLD HACK // check first linedef to figure which of its sectors owns this sector->lines pointer // then check that sector's linecount to get a maximum index - //if (!seclines[0]) + //if (!(*seclines)[0]) //return luaL_error(L, "no lines found!"); // no first linedef????? - if (seclines[0]->frontsector->lines == seclines) - numoflines = seclines[0]->frontsector->linecount; - else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first - numoflines = seclines[0]->backsector->linecount; + if ((*seclines)[0]->frontsector->lines == *seclines) + numoflines = (*seclines)[0]->frontsector->linecount; + else if ((*seclines)[0]->backsector && *seclines[0]->backsector->lines == *seclines) // check backsector exists first + numoflines = (*seclines)[0]->backsector->linecount; //if neither sector has it then ??? +*/ if (!numoflines) return luaL_error(L, "no lines found!"); @@ -449,23 +465,21 @@ static int sectorlines_get(lua_State *L) i = (size_t)lua_tointeger(L, 2); if (i >= numoflines) return 0; - LUA_PushUserdata(L, seclines[i], META_LINE); + LUA_PushUserdata(L, (*seclines)[i], META_LINE); return 1; } +// #(sector.lines) -> sector.linecount static int sectorlines_num(lua_State *L) { - line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES)); + line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES)); size_t numoflines = 0; - // check first linedef to figure which of its sectors owns this sector->lines pointer - // then check that sector's linecount to get a maximum index - //if (!seclines[0]) - //return luaL_error(L, "no lines found!"); // no first linedef????? - if (seclines[0]->frontsector->lines == seclines) - numoflines = seclines[0]->frontsector->linecount; - else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first - numoflines = seclines[0]->backsector->linecount; - //if neither sector has it then ??? + + if (!seclines || !(*seclines)) + 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)))); lua_pushinteger(L, numoflines); return 1; } @@ -543,7 +557,7 @@ static int sector_get(lua_State *L) LUA_PushUserdata(L, §ors[sector->camsec], META_SECTOR); return 1; case sector_lines: // lines - LUA_PushUserdata(L, sector->lines, META_SECTORLINES); + LUA_PushUserdata(L, §or->lines, META_SECTORLINES); // push the address of the "lines" member in the struct, to allow our hacks in sectorlines_get/_num to work return 1; case sector_ffloors: // ffloors lua_pushcfunction(L, lib_iterateSectorFFloors); @@ -579,6 +593,7 @@ static int sector_set(lua_State *L) case sector_thinglist: // thinglist case sector_heightsec: // heightsec case sector_camsec: // camsec + case sector_lines: // lines case sector_ffloors: // ffloors #ifdef ESLOPE case sector_fslope: // f_slope diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 063158b26..30026da49 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -164,6 +164,8 @@ static int mobj_get(lua_State *L) enum mobj_e field = Lua_optoption(L, 2, NULL, mobj_opt); lua_settop(L, 2); + INLEVEL + if (!mo) { if (field == mobj_valid) { lua_pushboolean(L, 0); @@ -409,6 +411,8 @@ static int mobj_set(lua_State *L) enum mobj_e field = Lua_optoption(L, 2, mobj_opt[0], mobj_opt); lua_settop(L, 3); + INLEVEL + if (!mo) return LUA_ErrInvalid(L, "mobj_t"); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index dd9959afb..b1222ce67 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -25,7 +25,6 @@ static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; - INLEVEL if (lua_gettop(L) < 2) { //return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do end'."); @@ -52,7 +51,6 @@ static int lib_getPlayer(lua_State *L) { const char *field; // i -> players[i] - INLEVEL if (lua_type(L, 2) == LUA_TNUMBER) { lua_Integer i = luaL_checkinteger(L, 2); diff --git a/src/lua_script.c b/src/lua_script.c index deb644dc0..ec73d7bf7 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -431,7 +431,7 @@ void LUA_InvalidateLevel(void) for (i = 0; i < numsectors; i++) { LUA_InvalidateUserdata(§ors[i]); - LUA_InvalidateUserdata(sectors[i].lines); + LUA_InvalidateUserdata(§ors[i].lines); if (sectors[i].ffloors) { for (rover = sectors[i].ffloors; rover; rover = rover->next) @@ -1121,7 +1121,7 @@ void LUA_Archive(void) for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i]) + if (!playeringame[i] && i > 0) // dedicated servers... continue; // all players in game will be archived, even if they just add a 0. ArchiveExtVars(&players[i], "player"); @@ -1157,7 +1157,7 @@ void LUA_UnArchive(void) for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i]) + if (!playeringame[i] && i > 0) // dedicated servers... continue; UnArchiveExtVars(&players[i]); } diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index a28f6a359..7f68905aa 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -52,6 +52,8 @@ enum skin { skin_supercolor, skin_prefoppositecolor, skin_highresscale, + skin_contspeed, + skin_contangle, skin_soundsid, skin_availability }; @@ -88,6 +90,8 @@ static const char *const skin_opt[] = { "supercolor", "prefoppositecolor", "highresscale", + "contspeed", + "contangle", "soundsid", "availability", NULL}; @@ -199,6 +203,12 @@ static int skin_get(lua_State *L) case skin_highresscale: lua_pushinteger(L, skin->highresscale); break; + case skin_contspeed: + lua_pushinteger(L, skin->contspeed); + break; + case skin_contangle: + lua_pushinteger(L, skin->contangle); + break; case skin_soundsid: LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID); break; diff --git a/src/m_cond.c b/src/m_cond.c index 539c6d1f6..b7520aba7 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -528,12 +528,22 @@ skincolors_t M_GetEmblemColor(emblem_t *em) return em->color; } -const char *M_GetEmblemPatch(emblem_t *em) +const char *M_GetEmblemPatch(emblem_t *em, boolean big) { - static char pnamebuf[7] = "GOTITn"; + static char pnamebuf[7]; + + if (!big) + strcpy(pnamebuf, "GOTITn"); + else + strcpy(pnamebuf, "EMBMn0"); I_Assert(em->sprite >= 'A' && em->sprite <= 'Z'); - pnamebuf[5] = em->sprite; + + if (!big) + pnamebuf[5] = em->sprite; + else + pnamebuf[4] = em->sprite; + return pnamebuf; } @@ -544,11 +554,21 @@ skincolors_t M_GetExtraEmblemColor(extraemblem_t *em) return em->color; } -const char *M_GetExtraEmblemPatch(extraemblem_t *em) +const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big) { - static char pnamebuf[7] = "GOTITn"; + static char pnamebuf[7]; + + if (!big) + strcpy(pnamebuf, "GOTITn"); + else + strcpy(pnamebuf, "EMBMn0"); I_Assert(em->sprite >= 'A' && em->sprite <= 'Z'); - pnamebuf[5] = em->sprite; + + if (!big) + pnamebuf[5] = em->sprite; + else + pnamebuf[4] = em->sprite; + return pnamebuf; } diff --git a/src/m_cond.h b/src/m_cond.h index f82e49372..e9859cf11 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -171,9 +171,9 @@ INT32 M_CountEmblems(void); // Emblem shit emblem_t *M_GetLevelEmblems(INT32 mapnum); skincolors_t M_GetEmblemColor(emblem_t *em); -const char *M_GetEmblemPatch(emblem_t *em); +const char *M_GetEmblemPatch(emblem_t *em, boolean big); skincolors_t M_GetExtraEmblemColor(extraemblem_t *em); -const char *M_GetExtraEmblemPatch(extraemblem_t *em); +const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big); // If you're looking to compare stats for unlocks or what not, use these // They stop checking upon reaching the target number so they diff --git a/src/m_menu.c b/src/m_menu.c index b32c0a65d..54c0b6c87 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -66,6 +66,13 @@ // And just some randomness for the exits. #include "m_random.h" +#if defined(HAVE_SDL) +#include "SDL.h" +#if SDL_VERSION_ATLEAST(2,0,0) +#include "sdl/sdlmain.h" // JOYSTICK_HOTPLUG +#endif +#endif + #ifdef PC_DOS #include // for snprintf int snprintf(char *str, size_t n, const char *fmt, ...); @@ -118,9 +125,8 @@ const char *quitmsg[NUM_QUITMESSAGES]; // Stuff for customizing the player select screen Tails 09-22-2003 description_t description[MAXSKINS]; -INT16 char_on = -1, startchar = 1; +INT16 char_on = -1, startchar = 0; static char *char_notes = NULL; -static fixed_t char_scroll = 0; boolean menuactive = false; boolean fromlevelselect = false; @@ -136,7 +142,7 @@ typedef enum levellist_mode_t levellistmode = LLM_CREATESERVER; UINT8 maplistoption = 0; -static char joystickInfo[8][29]; +static char joystickInfo[MAX_JOYSTICKS+1][29]; #ifndef NONET static UINT32 serverlistpage; #endif @@ -160,6 +166,16 @@ static INT32 vidm_selected = 0; static INT32 vidm_nummodes; static INT32 vidm_column_size; +// new menus +static tic_t recatkdrawtimer = 0; +static tic_t ntsatkdrawtimer = 0; + +static tic_t charseltimer = 0; +static fixed_t char_scroll = 0; +#define charscrollamt 128*FRACUNIT + +static tic_t keydown = 0; + // // PROTOTYPES // @@ -240,6 +256,7 @@ menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; // Single Player static void M_StartTutorial(INT32 choice); static void M_LoadGame(INT32 choice); +static void M_HandleTimeAttackLevelSelect(INT32 choice); static void M_TimeAttackLevelSelect(INT32 choice); static void M_TimeAttack(INT32 choice); static void M_NightsAttackLevelSelect(INT32 choice); @@ -276,9 +293,10 @@ menu_t MP_MainDef; // Split into multiple parts due to size // Controls menu_t OP_ChangeControlsDef; -menu_t OP_MPControlsDef, OP_CameraControlsDef, OP_MiscControlsDef; +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; static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(INT32 choice); static void M_Setup2PControlsMenu(INT32 choice); @@ -308,7 +326,8 @@ static void M_Addons(INT32 choice); static void M_AddonsOptions(INT32 choice); static patch_t *addonsp[NUM_EXT+5]; -#define numaddonsshown 4 +#define addonmenusize 9 // number of items actually displayed in the addons menu view, formerly (2*numaddonsshown + 1) +#define numaddonsshown 4 // number of items to each side of the currently selected item, unless at top/bottom ends of directory static void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlight, boolean allowlowercase); @@ -377,6 +396,8 @@ static void Dummymares_OnChange(void); // CONSOLE VARIABLES AND THEIR POSSIBLE VALUES GO HERE. // ========================================================================== +consvar_t cv_showfocuslost = {"showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL }; + static CV_PossibleValue_t map_cons_t[] = { {1,"MIN"}, {NUMMAPS, "MAX"} @@ -397,7 +418,7 @@ static CV_PossibleValue_t serversort_cons_t[] = { {1,"Modified State"}, {2,"Most Players"}, {3,"Least Players"}, - {4,"Max Players"}, + {4,"Max Player Slots"}, {5,"Gametype"}, {0,NULL} }; @@ -424,7 +445,8 @@ consvar_t cv_ghost_guest = {"ghost_guest", "Show", CV_SAVE, ghost2_cons_ static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t liveslimit_cons_t[] = {{-1, "MIN"}, {99, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t liveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {-1, "Infinite"}, {0, NULL}}; +static CV_PossibleValue_t contlimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NULL}}; static CV_PossibleValue_t dummymares_cons_t[] = { {-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL} }; @@ -433,7 +455,7 @@ static consvar_t cv_dummyteam = {"dummyteam", "Spectator", CV_HIDEN, dummyteam_c static consvar_t cv_dummyscramble = {"dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyrings = {"dummyrings", "0", CV_HIDEN, ringlimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummylives = {"dummylives", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummycontinues = {"dummycontinues", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static consvar_t cv_dummycontinues = {"dummycontinues", "0", CV_HIDEN, contlimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dummymares_cons_t, Dummymares_OnChange, 0, NULL, NULL, 0, 0, NULL}; // ========================================================================== @@ -734,8 +756,8 @@ static menuitem_t SP_TimeAttackLevelSelectMenu[] = // Single Player Time Attack static menuitem_t SP_TimeAttackMenu[] = { - {IT_STRING|IT_CALL, NULL, "Level Select...", &M_TimeAttackLevelSelect, 52}, - {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 62}, + {IT_STRING|IT_KEYHANDLER, NULL, "Level Select...", M_HandleTimeAttackLevelSelect, 62}, + {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 72}, {IT_DISABLED, NULL, "Guest Option...", &SP_GuestReplayDef, 100}, {IT_DISABLED, NULL, "Replay...", &SP_ReplayDef, 110}, @@ -1003,13 +1025,11 @@ static menuitem_t OP_P1ControlsMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Mouse Options...", &OP_MouseOptionsDef, 20}, {IT_SUBMENU | IT_STRING, NULL, "Gamepad Options...", &OP_Joystick1Def , 30}, - {IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam , 50}, - {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 60}, - {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 70}, + {IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_CameraOptionsDef, 50}, - //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog, 90}, - {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar, 90}, - {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake, 100}, + //{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}, }; static menuitem_t OP_P2ControlsMenu[] = @@ -1018,13 +1038,11 @@ static menuitem_t OP_P2ControlsMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Second Mouse Options...", &OP_Mouse2OptionsDef, 20}, {IT_SUBMENU | IT_STRING, NULL, "Second Gamepad Options...", &OP_Joystick2Def , 30}, - {IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam2 , 50}, - {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 60}, - {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 70}, + {IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_Camera2OptionsDef, 50}, - //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog2, 90}, - {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar2, 90}, - {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake2, 100}, + //{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}, }; static menuitem_t OP_ChangeControlsMenu[] = @@ -1114,14 +1132,7 @@ static menuitem_t OP_Joystick2Menu[] = {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, }; -static menuitem_t OP_JoystickSetMenu[] = -{ - {IT_CALL | IT_NOTHING, "None", NULL, M_AssignJoystick, '0'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '1'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '2'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '3'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '4'}, -}; +static menuitem_t OP_JoystickSetMenu[1+MAX_JOYSTICKS]; static menuitem_t OP_MouseOptionsMenu[] = { @@ -1153,6 +1164,34 @@ static menuitem_t OP_Mouse2OptionsMenu[] = NULL, "Mouse Y Sensitivity", &cv_mouseysens2, 80}, }; +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_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 Speed", &cv_cam_speed, 80}, + + {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 100}, +}; + +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_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 Speed", &cv_cam2_speed, 80}, + + {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 100}, +}; + static menuitem_t OP_VideoOptionsMenu[] = { {IT_HEADER, NULL, "Screen", NULL, 0}, @@ -1198,11 +1237,12 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_HEADER, NULL, "Level", NULL, 155}, {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 161}, {IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 166}, - {IT_STRING | IT_CVAR, NULL, "NiGHTS mode Draw Dist.", &cv_drawdist_nights, 171}, + {IT_STRING | IT_CVAR, NULL, "NiGHTS Hoop Draw Dist.", &cv_drawdist_nights, 171}, {IT_HEADER, NULL, "Diagnostic", NULL, 180}, {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 186}, {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 191}, + {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 196}, }; static menuitem_t OP_VideoModeMenu[] = @@ -1296,22 +1336,25 @@ static menuitem_t OP_OpenGLColorMenu[] = static menuitem_t OP_SoundOptionsMenu[] = { - {IT_HEADER, NULL, "Game Audio", NULL, 0}, // 0 // ScrollMenu offsets - {IT_STRING | IT_CVAR, NULL, "Sound Effects", &cv_gamesounds, 13}, // 6 - {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Sound Volume", &cv_soundvolume, 23}, // 11 + {IT_HEADER, NULL, "Game Audio", NULL, 0}, + {IT_STRING | IT_CVAR, NULL, "Sound Effects", &cv_gamesounds, 6}, + {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Sound Volume", &cv_soundvolume, 11}, - {IT_STRING | IT_CVAR, NULL, "Digital Music", &cv_gamedigimusic, 43}, // 21 - {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Digital Music Volume", &cv_digmusicvolume, 53}, // 26 + {IT_STRING | IT_CVAR, NULL, "Digital Music", &cv_gamedigimusic, 21}, + {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Digital Music Volume", &cv_digmusicvolume, 26}, - {IT_STRING | IT_CVAR, NULL, "MIDI Music", &cv_gamemidimusic, 73}, // 36 - {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "MIDI Music Volume", &cv_midimusicvolume, 83}, // 41 + {IT_STRING | IT_CVAR, NULL, "MIDI Music", &cv_gamemidimusic, 36}, + {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "MIDI Music Volume", &cv_midimusicvolume, 41}, - {IT_HEADER, NULL, "Accessibility", NULL, 103}, // 50 - {IT_STRING | IT_CVAR, NULL, "Closed Captioning", &cv_closedcaptioning, 115}, // 56 - {IT_STRING | IT_CVAR, NULL, "Reset Music Upon Dying", &cv_resetmusic, 125}, // 62 + {IT_HEADER, NULL, "Accessibility", NULL, 50}, + {IT_STRING | IT_CVAR, NULL, "Closed Captioning", &cv_closedcaptioning, 56}, + {IT_STRING | IT_CVAR, NULL, "Reset Music Upon Dying", &cv_resetmusic, 61}, + + {IT_STRING | IT_CVAR, NULL, "Play Sound Effects if Unfocused", &cv_playsoundsifunfocused, 71}, + {IT_STRING | IT_CVAR, NULL, "Play Music if Unfocused", &cv_playmusicifunfocused, 76}, #ifdef HAVE_MIXERX - {IT_STRING | IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 143}, + {IT_STRING | IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 94}, #endif }; @@ -1363,36 +1406,39 @@ static menuitem_t OP_ScreenshotOptionsMenu[] = { {IT_HEADER, NULL, "General", NULL, 0}, {IT_STRING|IT_CVAR, NULL, "Use color profile", &cv_screenshot_colorprofile, 6}, - {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_screenshot_option, 11}, - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_screenshot_folder, 16}, - {IT_HEADER, NULL, "Screenshots (F8)", NULL, 30}, - {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memory, 36}, - {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_level, 41}, - {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategy, 46}, - {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bits, 51}, + {IT_HEADER, NULL, "Screenshots (F8)", NULL, 16}, + {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_screenshot_option, 22}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_screenshot_folder, 27}, + {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memory, 42}, + {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_level, 47}, + {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategy, 52}, + {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bits, 57}, - {IT_HEADER, NULL, "Movie Mode (F9)", NULL, 60}, - {IT_STRING|IT_CVAR, NULL, "Capture Mode", &cv_moviemode, 66}, + {IT_HEADER, NULL, "Movie Mode (F9)", NULL, 64}, + {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_movie_option, 70}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_movie_folder, 75}, + {IT_STRING|IT_CVAR, NULL, "Capture Mode", &cv_moviemode, 90}, - {IT_STRING|IT_CVAR, NULL, "Region Optimizing", &cv_gif_optimize, 71}, - {IT_STRING|IT_CVAR, NULL, "Downscaling", &cv_gif_downscale, 76}, + {IT_STRING|IT_CVAR, NULL, "Region Optimizing", &cv_gif_optimize, 95}, + {IT_STRING|IT_CVAR, NULL, "Downscaling", &cv_gif_downscale, 100}, - {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memorya, 71}, - {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_levela, 76}, - {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategya, 81}, - {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bitsa, 86}, + {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memorya, 95}, + {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_levela, 100}, + {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategya, 105}, + {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bitsa, 110}, }; enum { op_screenshot_colorprofile = 1, - op_screenshot_folder = 3, - op_screenshot_capture = 10, - op_screenshot_gif_start = 11, - op_screenshot_gif_end = 12, - op_screenshot_apng_start = 13, - op_screenshot_apng_end = 16, + op_screenshot_folder = 4, + op_movie_folder = 11, + op_screenshot_capture = 12, + op_screenshot_gif_start = 13, + op_screenshot_gif_end = 14, + op_screenshot_apng_start = 15, + op_screenshot_apng_end = 18, }; static menuitem_t OP_EraseDataMenu[] = @@ -1887,6 +1933,13 @@ menu_t OP_JoystickSetDef = 0, NULL }; +menu_t OP_CameraOptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1CAMERA << 12), + "M_CONTRO", OP_CameraOptionsMenu, &OP_P1ControlsDef, 35, 30); +menu_t OP_Camera2OptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2CAMERA << 12), + "M_CONTRO", OP_Camera2OptionsMenu, &OP_P2ControlsDef, 35, 30); + menu_t OP_VideoOptionsDef = { @@ -1924,18 +1977,9 @@ menu_t OP_ColorOptionsDef = 0, NULL }; -menu_t OP_SoundOptionsDef = -{ +menu_t OP_SoundOptionsDef = DEFAULTSCROLLMENUSTYLE( MN_OP_MAIN + (MN_OP_SOUND << 6), - "M_SOUND", - sizeof (OP_SoundOptionsMenu)/sizeof (menuitem_t), - &OP_MainDef, - OP_SoundOptionsMenu, - M_DrawGenericMenu, - 30, 30, - 0, - NULL -}; + "M_SOUND", OP_SoundOptionsMenu, &OP_MainDef, 30, 30); #ifdef HAVE_MIXERX menu_t OP_SoundAdvancedDef = DEFAULTMENUSTYLE(MN_OP_MAIN + (MN_OP_SOUND << 6), "M_SOUND", OP_SoundAdvancedMenu, &OP_SoundOptionsDef, 30, 30); #endif @@ -2210,6 +2254,12 @@ void Addons_option_Onchange(void) (cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); } +void Moviemode_option_Onchange(void) +{ + OP_ScreenshotOptionsMenu[op_movie_folder].status = + (cv_movie_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); +} + // ========================================================================== // END ORGANIZATION STUFF. // ========================================================================== @@ -2252,8 +2302,10 @@ void M_InitMenuPresTables(void) { menupres[i].muslooping = true; } - if (i == MN_SP_TIMEATTACK || i == MN_SP_NIGHTSATTACK) - strncpy(menupres[i].musname, "_inter", 7); + if (i == MN_SP_TIMEATTACK) + strncpy(menupres[i].musname, "_recat", 7); + else if (i == MN_SP_NIGHTSATTACK) + strncpy(menupres[i].musname, "_nitat", 7); else if (i == MN_SP_PLAYER) strncpy(menupres[i].musname, "_chsel", 7); } @@ -2346,7 +2398,7 @@ static boolean MIT_SetCurBackground(UINT32 menutype, INT32 level, INT32 *retval, } else if (menupres[menutype].bgname[0]) { - strncpy(curbgname, menupres[menutype].bgname, 9); + strncpy(curbgname, menupres[menutype].bgname, 8); curbgxspeed = menupres[menutype].titlescrollxspeed != INT32_MAX ? menupres[menutype].titlescrollxspeed : titlescrollxspeed; curbgyspeed = menupres[menutype].titlescrollyspeed != INT32_MAX ? menupres[menutype].titlescrollyspeed : titlescrollyspeed; return true; @@ -2464,7 +2516,7 @@ void M_ChangeMenuMusic(const char *defaultmusname, boolean defaultmuslooping) void M_SetMenuCurBackground(const char *defaultname) { - char name[8]; + char name[9]; strncpy(name, defaultname, 8); M_IterateMenuTree(MIT_SetCurBackground, &name); } @@ -2530,8 +2582,6 @@ static void M_HandleMenuPresState(menu_t *newMenu) if (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) return; - // Find current presentation values - M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "SRB2BACK" : "TITLESKY"); M_SetMenuCurFadeValue(16); M_SetMenuCurHideTitlePics(); @@ -2744,17 +2794,19 @@ static void M_ChangeCvar(INT32 choice) choice = (choice<<1) - 1; - if (((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_SLIDER) - ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) - ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_NOMOD)) + if (cv->flags & CV_FLOAT) { - CV_SetValue(cv,cv->value+(choice)); - } - else if (cv->flags & CV_FLOAT) - { - char s[20]; - sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); - CV_Set(cv,s); + if (((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_SLIDER) + ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) + ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_NOMOD) + || !(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) + { + char s[20]; + sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); + CV_Set(cv,s); + } + else + CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice)); } else CV_AddValue(cv,choice); @@ -2839,6 +2891,15 @@ static void M_PrevOpt(void) // (in other words -- stop bullshit happening by mashing buttons in fades) static boolean noFurtherInput = false; +static void Command_Manual_f(void) +{ + if (modeattacking) + return; + M_StartControlPanel(); + currentMenu = &MISC_HelpDef; + itemOn = 0; +} + // // M_Responder // @@ -2867,6 +2928,7 @@ boolean M_Responder(event_t *ev) { if (ev->type == ev_keydown) { + keydown++; ch = ev->data1; // added 5-2-98 remap virtual keys (mouse & joystick buttons) @@ -2973,6 +3035,8 @@ boolean M_Responder(event_t *ev) pmousex = lastx += 30; } } + else if (ev->type == ev_keyup) // Preserve event for other responders + keydown = 0; } else if (ev->type == ev_keydown) // Preserve event for other responders ch = ev->data1; @@ -2989,11 +3053,7 @@ boolean M_Responder(event_t *ev) switch (ch) { case KEY_F1: // Help key - if (modeattacking) - return true; - M_StartControlPanel(); - currentMenu = &MISC_HelpDef; - itemOn = 0; + Command_Manual_f(); return true; case KEY_F2: // Empty @@ -3265,7 +3325,7 @@ void M_Drawer(void) } // focus lost notification goes on top of everything, even the former everything - if (window_notinfocus) + if (window_notinfocus && cv_showfocuslost.value) { M_DrawTextBox((BASEVIDWIDTH/2) - (60), (BASEVIDHEIGHT/2) - (16), 13, 2); if (gamestate == GS_LEVEL && (P_AutoPause() || paused)) @@ -3420,6 +3480,7 @@ void M_ClearMenus(boolean callexitmenufunc) if (currentMenu == &MessageDef) // Oh sod off! currentMenu = &MainDef; // Not like it matters menuactive = false; + hidetitlemap = false; } // @@ -3458,6 +3519,8 @@ void M_SetupNextMenu(menu_t *menudef) } } } + + hidetitlemap = false; } // @@ -3488,6 +3551,10 @@ void M_Ticker(void) // void M_Init(void) { + int i; + + COM_AddCommand("manual", Command_Manual_f); + CV_RegisterVar(&cv_nextmap); CV_RegisterVar(&cv_newgametype); CV_RegisterVar(&cv_chooseskin); @@ -3537,6 +3604,17 @@ void M_Init(void) OP_ScreenshotOptionsMenu[op_screenshot_colorprofile].status = IT_GRAYEDOUT; #endif + /* + Well the menu sucks for forcing us to have an item set + at all if every item just calls the same function, and + nothing more. Now just automate the definition. + */ + for (i = 0; i <= MAX_JOYSTICKS; ++i) + { + OP_JoystickSetMenu[i].status = ( IT_NOTHING|IT_CALL ); + OP_JoystickSetMenu[i].itemaction = M_AssignJoystick; + } + #ifndef NONET CV_RegisterVar(&cv_serversort); #endif @@ -3552,9 +3630,13 @@ void M_InitCharacterTables(void) description[i].used = false; strcpy(description[i].notes, "???"); strcpy(description[i].picname, ""); + strcpy(description[i].nametag, ""); strcpy(description[i].skinname, ""); + strcpy(description[i].displayname, ""); description[i].prev = description[i].next = 0; - description[i].pic = NULL; + description[i].charpic = NULL; + description[i].namepic = NULL; + description[i].oppositecolor = description[i].tagtextcolor = description[i].tagoutlinecolor = 0; } } @@ -3644,7 +3726,12 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) for (i = 0; cv->PossibleValue[i+1].strvalue; i++); - if ((range = atoi(cv->defaultvalue)) != cv->value) + if (cv->flags & CV_FLOAT) + range = (INT32)(atof(cv->defaultvalue)*FRACUNIT); + else + range = atoi(cv->defaultvalue); + + if (range != cv->value) { range = ((range - cv->PossibleValue[0].value) * 100 / (cv->PossibleValue[i].value - cv->PossibleValue[0].value)); @@ -3812,7 +3899,7 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y) lasttype = curtype; if (emblem->collected) - V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), + V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -4251,7 +4338,7 @@ static void M_DrawPauseMenu(void) continue; if (emblem->collected) - V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), + V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else V_DrawSmallScaledPatch(40, 44 + (i*8), 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -4471,10 +4558,12 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum) if (!(mapheaderinfo[mapnum]->typeoflevel & TOL_COOP)) return true; - if (mapvisited[mapnum]) // MV_MP + if (mapnum+1 == spstage_start) return true; - if (mapnum+1 == spstage_start) +#ifndef DEVELOP + if (mapvisited[mapnum]) // MV_MP +#endif return true; /* FALLTHRU */ @@ -4520,6 +4609,9 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt) if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) return false; + if (G_IsSpecialStage(mapnum+1)) + return false; + if (gt == GT_COOP && (mapheaderinfo[mapnum]->typeoflevel & TOL_COOP)) return true; @@ -4817,13 +4909,25 @@ static void M_HandleLevelPlatter(INT32 choice) { boolean exitmenu = false; // exit to previous menu INT32 selectval; + UINT8 iter; switch (choice) { case KEY_DOWNARROW: + if (lsrow == levelselect.numrows-1) + { + if (levelselect.numrows < 3) + { + if (!lsoffs[0]) // prevent sound spam + { + lsoffs[0] = -8; + S_StartSound(NULL,sfx_s3kb7); + } + return; + } + lsrow = UINT8_MAX; + } lsrow++; - if (lsrow == levelselect.numrows) - lsrow = 0; lsoffs[0] = lsvseperation(lsrow); @@ -4837,17 +4941,29 @@ static void M_HandleLevelPlatter(INT32 choice) break; case KEY_UPARROW: - lsoffs[0] = -lsvseperation(lsrow); - + iter = lsrow; + if (!lsrow) + { + if (levelselect.numrows < 3) + { + if (!lsoffs[0]) // prevent sound spam + { + lsoffs[0] = 8; + S_StartSound(NULL,sfx_s3kb7); + } + return; + } + lsrow = levelselect.numrows; + } lsrow--; - if (lsrow == UINT8_MAX) - lsrow = levelselect.numrows-1; + + lsoffs[0] = -lsvseperation(iter); if (levelselect.rows[lsrow].header[0]) lshli = lsrow; else { - UINT8 iter = lsrow; + iter = lsrow; do iter = ((iter == 0) ? levelselect.numrows-1 : iter-1); while ((iter != lsrow) && !(levelselect.rows[iter].header[0])); @@ -4880,7 +4996,7 @@ static void M_HandleLevelPlatter(INT32 choice) M_LevelSelectWarp(0); Nextmap_OnChange(); } - else if (!lsoffs[0]) // prevent sound spam + else if (!lsoffs[0]) // prevent sound spam { lsoffs[0] = -8; S_StartSound(NULL,sfx_s3kb2); @@ -4910,7 +5026,7 @@ static void M_HandleLevelPlatter(INT32 choice) ifselectvalnextmap(lscol) else ifselectvalnextmap(0) } - else if (!lsoffs[1]) // prevent sound spam + else if (!lsoffs[1]) // prevent sound spam { lsoffs[1] = 8; S_StartSound(NULL,sfx_s3kb7); @@ -4939,7 +5055,7 @@ static void M_HandleLevelPlatter(INT32 choice) ifselectvalnextmap(lscol) else ifselectvalnextmap(0) } - else if (!lsoffs[1]) // prevent sound spam + else if (!lsoffs[1]) // prevent sound spam { lsoffs[1] = -8; S_StartSound(NULL,sfx_s3kb7); @@ -5091,18 +5207,187 @@ static void M_DrawLevelPlatterRow(UINT8 row, INT32 y) } } +// new menus +static void M_DrawRecordAttackForeground(void) +{ + patch_t *fg = W_CachePatchName("RECATKFG", PU_CACHE); + patch_t *clock = W_CachePatchName("RECCLOCK", PU_CACHE); + angle_t fa; + + INT32 i; + INT32 height = (SHORT(fg->height)/2); + INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + + for (i = -12; i < (BASEVIDHEIGHT/height) + 12; i++) + { + INT32 y = ((i*height) - (height - ((recatkdrawtimer*2)%height))); + // don't draw above the screen + { + INT32 sy = FixedMul(y, dupz<> FRACBITS; + if (vid.height != BASEVIDHEIGHT * dupz) + sy += (vid.height - (BASEVIDHEIGHT * dupz)) / 2; + if ((sy+height) < 0) + continue; + } + V_DrawFixedPatch(0, y< vid.height) + break; + } + + // draw clock + fa = (FixedAngle(((recatkdrawtimer * 4) % 360)<>ANGLETOFINESHIFT) & FINEMASK; + V_DrawSciencePatch(160<width); + INT32 y = BASEVIDHEIGHT - SHORT(background->height)*2; + + if (vid.height != BASEVIDHEIGHT * dupz) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); + V_DrawFill(0, y+50, vid.width, BASEVIDHEIGHT, V_SNAPTOLEFT|31); + + V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); + x += SHORT(background->width); + if (x < BASEVIDWIDTH) + V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); + + bgscrollx -= (FRACUNIT/2); +} + +// NiGHTS Attack foreground. +static void M_DrawNightsAttackBackground(void) +{ + INT32 x, y = 0; + INT32 i; + + // top + patch_t *backtopfg = W_CachePatchName("NTSATKT1", PU_CACHE); + patch_t *fronttopfg = W_CachePatchName("NTSATKT2", PU_CACHE); + INT32 backtopwidth = SHORT(backtopfg->width); + //INT32 backtopheight = SHORT(backtopfg->height); + INT32 fronttopwidth = SHORT(fronttopfg->width); + //INT32 fronttopheight = SHORT(fronttopfg->height); + + // bottom + patch_t *backbottomfg = W_CachePatchName("NTSATKB1", PU_CACHE); + patch_t *frontbottomfg = W_CachePatchName("NTSATKB2", PU_CACHE); + INT32 backbottomwidth = SHORT(backbottomfg->width); + INT32 backbottomheight = SHORT(backbottomfg->height); + INT32 frontbottomwidth = SHORT(frontbottomfg->width); + INT32 frontbottomheight = SHORT(frontbottomfg->height); + + // background + M_DrawNightsAttackMountains(); + + // back top foreground patch + x = -(ntsatkdrawtimer%backtopwidth); + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, backtopfg); + for (i = 0; i < 3; i++) + { + x += (backtopwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, backtopfg); + } + + // front top foreground patch + x = -((ntsatkdrawtimer*2)%fronttopwidth); + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, fronttopfg); + for (i = 0; i < 3; i++) + { + x += (fronttopwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, fronttopfg); + } + + // back bottom foreground patch + x = -(ntsatkdrawtimer%backbottomwidth); + y = BASEVIDHEIGHT - backbottomheight; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, backbottomfg); + for (i = 0; i < 3; i++) + { + x += (backbottomwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, backbottomfg); + } + + // front bottom foreground patch + x = -((ntsatkdrawtimer*2)%frontbottomwidth); + y = BASEVIDHEIGHT - frontbottomheight; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, frontbottomfg); + for (i = 0; i < 3; i++) + { + x += (frontbottomwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, frontbottomfg); + } + + // Increment timer. + ntsatkdrawtimer++; +} + +// NiGHTS Attack floating Super Sonic. +static patch_t *ntssupersonic[2]; +static void M_DrawNightsAttackSuperSonic(void) +{ + const UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_YELLOW, GTC_CACHE); + INT32 timer = (ntsatkdrawtimer/4) % 2; + angle_t fa = (FixedAngle(((ntsatkdrawtimer * 4) % 360)<>ANGLETOFINESHIFT) & FINEMASK; + V_DrawFixedPatch(235<prevMenu == &SP_TimeAttackDef) { + M_SetMenuCurBackground("RECATKBG"); + + curbgxspeed = 0; + curbgyspeed = 18; + if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) + { F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + // Draw and animate foreground + if (!strncmp("RECATKBG", curbgname, 8)) + M_DrawRecordAttackForeground(); + } + + if (curfadevalue) + V_DrawFadeScreen(0xFF00, curfadevalue); + } + + if (currentMenu->prevMenu == &SP_NightsAttackDef) + { + M_SetMenuCurBackground("NTSATKBG"); + + if (curbgcolor >= 0) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); + else if (!curbghide || !titlemapinaction) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); + M_DrawNightsAttackMountains(); + } if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); } @@ -5110,7 +5395,13 @@ static void M_DrawLevelPlatterMenu(void) // finds row at top of the screen while (y > -8) { - iter = ((iter == 0) ? levelselect.numrows-1 : iter-1); + if (iter == 0) + { + if (levelselect.numrows < 3) + break; + iter = levelselect.numrows; + } + iter--; y -= lsvseperation(iter); } @@ -5119,7 +5410,13 @@ static void M_DrawLevelPlatterMenu(void) { M_DrawLevelPlatterRow(iter, y); y += lsvseperation(iter); - iter = ((iter == levelselect.numrows-1) ? 0 : iter+1); + if (iter == levelselect.numrows-1) + { + if (levelselect.numrows < 3) + break; + iter = UINT8_MAX; + } + iter++; } // draw cursor box @@ -5311,7 +5608,19 @@ static void M_DrawMessageMenu(void) if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + { + if (levellistmode == LLM_NIGHTSATTACK) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); + M_DrawNightsAttackMountains(); + } + else + { + F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + if (!strncmp("RECATKBG", curbgname, 8)) + M_DrawRecordAttackForeground(); + } + } if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); } @@ -5639,7 +5948,8 @@ static boolean M_AddonsRefresh(void) static void M_DrawAddons(void) { INT32 x, y; - ssize_t i, m; + size_t i, m; + size_t t, b; // top and bottom item #s to draw in directory const UINT8 *flashcol = NULL; UINT8 hilicol; @@ -5678,52 +5988,63 @@ static void M_DrawAddons(void) hilicol = 0; // white +#define boxwidth (MAXSTRINGLENGTH*8+6) + + // draw the file path and the top white + black lines of the box V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath()); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), MAXSTRINGLENGTH*8+6, 1, hilicol); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), boxwidth, 1, hilicol); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), boxwidth, 1, 30); m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1); // addons menu back color - V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 159); + V_DrawFill(x-21, y - 1, boxwidth, m, 159); - // scrollbar! - if (sizedirmenu <= (2*numaddonsshown + 1)) - i = 0; + // The directory is too small for a scrollbar, so just draw a tall white line + if (sizedirmenu <= addonmenusize) + { + t = 0; // first item + b = sizedirmenu - 1; // last item + i = 0; // "scrollbar" at "top" position + } else { - ssize_t q = m; - m = ((2*numaddonsshown + 1) * m)/sizedirmenu; + size_t q = m; + m = (addonmenusize * m)/sizedirmenu; // height of scroll bar if (dir_on[menudepthleft] <= numaddonsshown) // all the way up - i = 0; - else if (sizedirmenu <= (dir_on[menudepthleft] + numaddonsshown + 1)) // all the way down - i = q-m; - else - i = ((dir_on[menudepthleft] - numaddonsshown) * (q-m))/(sizedirmenu - (2*numaddonsshown + 1)); + { + t = 0; // first item + b = addonmenusize - 1; //9th item + i = 0; // scrollbar at top position + } + else if (dir_on[menudepthleft] >= sizedirmenu - (numaddonsshown + 1)) // all the way down + { + t = sizedirmenu - addonmenusize; // # 9th last + b = sizedirmenu - 1; // last item + i = q-m; // scrollbar at bottom position + } + else // somewhere in the middle + { + t = dir_on[menudepthleft] - numaddonsshown; // 4 items above + b = dir_on[menudepthleft] + numaddonsshown; // 4 items below + i = (t * (q-m))/(sizedirmenu - addonmenusize); // calculate position of scrollbar + } } - V_DrawFill(x + MAXSTRINGLENGTH*8+5 - 21, (y - 1) + i, 1, m, hilicol); + // draw the scrollbar! + V_DrawFill((x-21) + boxwidth-1, (y - 1) + i, 1, m, hilicol); - // get bottom... - m = dir_on[menudepthleft] + numaddonsshown + 1; - if (m > (ssize_t)sizedirmenu) - m = sizedirmenu; +#undef boxwidth - // then compute top and adjust bottom if needed! - if (m < (2*numaddonsshown + 1)) - { - m = min(sizedirmenu, 2*numaddonsshown + 1); - i = 0; - } - else - i = m - (2*numaddonsshown + 1); - - if (i != 0) + // draw up arrow that bobs up and down + if (t != 0) V_DrawString(19, y+4 - (skullAnimCounter/5), highlightflags, "\x1A"); + // make the selection box flash yellow if (skullAnimCounter < 4) flashcol = V_GetStringColormap(highlightflags); - for (; i < m; i++) + // draw icons and item names + for (i = t; i <= b; i++) { UINT32 flags = V_ALLOWLOWERCASE; if (y > BASEVIDHEIGHT) break; @@ -5739,12 +6060,14 @@ static void M_DrawAddons(void) else V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[(type & ~EXT_LOADED)]); + // draw selection box for the item currently selected if ((size_t)i == dir_on[menudepthleft]) { V_DrawFixedPatch((x-(16+4))< (charsonside*2 + 3)) V_DrawString(x, y+4, flags, va("%.*s...%s", charsonside, dirmenu[i]+DIR_STRING, dirmenu[i]+DIR_STRING+dirmenu[i][DIR_LEN]-(charsonside+1))); @@ -5756,9 +6079,11 @@ static void M_DrawAddons(void) y += 16; } - if (m != (ssize_t)sizedirmenu) + // draw down arrow that bobs down and up + if (b != sizedirmenu) V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B"); + // draw search box y = BASEVIDHEIGHT - currentMenu->y + 1; M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1); @@ -5770,9 +6095,11 @@ static void M_DrawAddons(void) V_DrawCharacter(x - 18 + V_StringWidth(menusearch+1, 0), y + 8, '_' | 0x80, false); + // draw search icon x -= (21 + 5 + 16); V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); + // draw save icon x = BASEVIDWIDTH - x - 16; V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); @@ -5985,9 +6312,9 @@ static void M_PandorasBox(INT32 choice) else CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0)); if (players[consoleplayer].lives == INFLIVES) - CV_StealthSetValue(&cv_dummylives, -1); + CV_StealthSet(&cv_dummylives, "Infinite"); else - CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives); + CV_StealthSetValue(&cv_dummylives, max(players[consoleplayer].lives, 1)); CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues); SR_PandorasBox[6].status = ((players[consoleplayer].charflags & SF_SUPER) #ifndef DEVELOP @@ -6569,7 +6896,7 @@ static void M_DrawEmblemHints(void) if (emblem->collected) { collected = V_GREENMAP; - V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), + V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); } else @@ -6895,6 +7222,7 @@ static void M_StartTutorial(INT32 choice) tutorialmode = true; // turn on tutorial mode emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); gamecomplete = false; cursaveslot = 0; @@ -7061,7 +7389,7 @@ static void M_DrawLoadGameData(void) } } - y -= 13; + y -= 4; // character heads, lives, and continues { @@ -7070,7 +7398,7 @@ static void M_DrawLoadGameData(void) patch_t *patch; UINT8 *colormap = NULL; - INT32 tempx = (x+40)<highresscale, 0, patch, colormap); Z_Free(colormap); - tempx -= (15<spriteframes[0]; patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); - if ((calc = SHORT(patch->topoffset) - 42) > 0) - tempy += ((4+calc)<highresscale, flip, patch, colormap); skipsign: - y += 25; + y += 16; tempx = x + 10; if (savegameinfo[savetodraw].lives != INFLIVES @@ -7303,7 +7629,29 @@ static void M_ReadSavegameInfo(UINT32 slot) // File end marker check CHECKPOS - if (READUINT8(save_p) != 0x1d) BADSAVE; + switch (READUINT8(save_p)) + { + case 0xb7: + { + UINT8 i, banksinuse; + CHECKPOS + banksinuse = READUINT8(save_p); + CHECKPOS + if (banksinuse > NUM_LUABANKS) + BADSAVE + for (i = 0; i < banksinuse; i++) + { + (void)READINT32(save_p); + CHECKPOS + } + if (READUINT8(save_p) != 0x1d) + BADSAVE + } + case 0x1d: + break; + default: + BADSAVE + } // done Z_Free(savebuffer); @@ -7499,6 +7847,8 @@ static void M_HandleLoadSave(INT32 choice) } if (exitmenu) { + // Is this a hack? + charseltimer = 0; if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7575,7 +7925,7 @@ static void M_SetupChoosePlayer(INT32 choice) UINT8 firstvalid = 255; UINT8 lastvalid = 0; boolean allowed = false; - char *name; + char *and; (void)choice; SP_PlayerMenu[0].status &= ~IT_DYBIGSPACE; // Correcting a hack that may be made below. @@ -7584,8 +7934,21 @@ static void M_SetupChoosePlayer(INT32 choice) { if (description[i].used) // If the character's disabled through SOC, there's nothing we can do for it. { - name = strtok(Z_StrDup(description[i].skinname), "&"); - skinnum = R_SkinAvailable(name); + and = strchr(description[i].skinname, '&'); + if (and) + { + char firstskin[SKINNAMESIZE+1]; + strncpy(firstskin, description[i].skinname, (and - description[i].skinname)); + firstskin[(and - description[i].skinname)] = '\0'; + description[i].skinnum[0] = R_SkinAvailable(firstskin); + description[i].skinnum[1] = R_SkinAvailable(and+1); + } + else + { + description[i].skinnum[0] = R_SkinAvailable(description[i].skinname); + description[i].skinnum[1] = -1; + } + skinnum = description[i].skinnum[0]; if ((skinnum != -1) && (R_SkinUsable(-1, skinnum))) { // Handling order. @@ -7603,20 +7966,27 @@ static void M_SetupChoosePlayer(INT32 choice) if (!(description[i].picname[0])) { - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 2) + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[1]; - description[i].pic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; + description[i].charpic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); } else - description[i].pic = W_CachePatchName("MISSING", PU_CACHE); + description[i].charpic = W_CachePatchName("MISSING", PU_CACHE); } else - description[i].pic = W_CachePatchName(description[i].picname, PU_CACHE); + description[i].charpic = W_CachePatchName(description[i].picname, PU_CACHE); + + if (description[i].nametag[0]) + { + const char *nametag = description[i].nametag; + description[i].namepic = NULL; + if (W_LumpExists(nametag)) + description[i].namepic = W_CachePatchName(nametag, PU_CACHE); + } } // else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them. - Z_Free(name); } } @@ -7636,8 +8006,22 @@ static void M_SetupChoosePlayer(INT32 choice) return; } - if (Playing() == false) - M_ChangeMenuMusic("_chsel", true); + M_ChangeMenuMusic("_chsel", true); + + /* the menus suck -James */ + if (currentMenu == &SP_LoadDef)/* from save states */ + { + SP_PlayerDef.menuid = + MN_SP_MAIN + + ( MN_SP_LOAD << 6 ) + + ( MN_SP_PLAYER << 12 ); + } + else/* from Secret level select */ + { + SP_PlayerDef.menuid = + MN_SR_MAIN + + ( MN_SR_PLAYER << 6 ); + } SP_PlayerDef.prevMenu = currentMenu; M_SetupNextMenu(&SP_PlayerDef); @@ -7651,7 +8035,11 @@ static void M_SetupChoosePlayer(INT32 choice) char_on = description[char_on].next; } } - char_scroll = 0; // finish scrolling the menu + + // finish scrolling the menu + char_scroll = 0; + charseltimer = 0; + Z_Free(char_notes); char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes); } @@ -7666,6 +8054,9 @@ static void M_HandleChoosePlayerMenu(INT32 choice) boolean exitmenu = false; // exit to previous menu INT32 selectval; + if (keydown > 1) + return; + switch (choice) { case KEY_DOWNARROW: @@ -7673,7 +8064,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice) { S_StartSound(NULL,sfx_s3kb7); char_on = selectval; - char_scroll = -128*FRACUNIT; + char_scroll = -charscrollamt; Z_Free(char_notes); char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes); } @@ -7689,7 +8080,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice) { S_StartSound(NULL,sfx_s3kb7); char_on = selectval; - char_scroll = 128*FRACUNIT; + char_scroll = charscrollamt; Z_Free(char_notes); char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes); } @@ -7715,6 +8106,8 @@ static void M_HandleChoosePlayerMenu(INT32 choice) if (exitmenu) { + // Is this a hack? + charseltimer = 0; if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7723,100 +8116,218 @@ static void M_HandleChoosePlayerMenu(INT32 choice) } // Draw the choose player setup menu, had some fun with player anim +//define CHOOSEPLAYER_DRAWHEADER + static void M_DrawSetupChoosePlayerMenu(void) { - const INT32 my = 24; - patch_t *patch; - INT32 i, o; - UINT8 prev, next; + const INT32 my = 16; - // Black BG - if (curbgcolor >= 0) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); - else if (!curbghide || !titlemapinaction) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); - if (curfadevalue) - V_DrawFadeScreen(0xFF00, curfadevalue); + skin_t *charskin = &skins[0]; + INT32 skinnum = 0; + UINT8 col; + UINT8 *colormap = NULL; + INT32 prev = -1, next = -1; - // Character select profile images!1 - M_DrawTextBox(0, my, 16, 20); + patch_t *charbg = W_CachePatchName("CHARBG", PU_CACHE); + patch_t *charfg = W_CachePatchName("CHARFG", PU_CACHE); + INT16 bgheight = SHORT(charbg->height); + INT16 fgheight = SHORT(charfg->height); + INT16 bgwidth = SHORT(charbg->width); + INT16 fgwidth = SHORT(charfg->width); + INT32 x, y; + INT32 w = (vid.width/vid.dupx); if (abs(char_scroll) > FRACUNIT) char_scroll -= (char_scroll>>2); else // close enough. char_scroll = 0; // just be exact now. - o = (char_scroll >> FRACBITS) + 16; - - if (o < 0) // A little hacky... - { - i = description[char_on].prev; - o += 128; - } - else - i = char_on; - // Get prev character... - prev = description[i].prev; - - if (prev != i) // If there's more than one character available... - { + prev = description[char_on].prev; + // If there's more than one character available... + if (prev != char_on) // Let's get the next character now. - next = description[i].next; - - // Draw prev character if it's visible and its number isn't greater than the current one or there's more than two - if (o < 32) - { - patch = description[prev].pic; - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<height) + 2*(o-32), SHORT(patch->width), 64 - 2*o); - else - V_DrawCroppedPatch(8<height) + o - 32, SHORT(patch->width), 32 - o); - W_UnlockCachedPatch(patch); - } - - // Draw next character if it's visible and its number isn't less than the current one or there's more than two - if (o < 128) // (next != i) was previously a part of this, but it's implicitly true if (prev != i) is true. - { - patch = description[next].pic; - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), 2*o); - else - V_DrawCroppedPatch(8<width), o); - W_UnlockCachedPatch(patch); - } - } - - patch = description[i].pic; - if (o >= 0 && o <= 32) - { - if (SHORT(patch->width) >= 256) - V_DrawSmallScaledPatch(8, my + 40 - o, 0, patch); - else - V_DrawScaledPatch(8, my + 40 - o, 0, patch); - } + next = description[char_on].next; else - { - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), SHORT(patch->height) - 2*(o-32)); - else - V_DrawCroppedPatch(8<width), SHORT(patch->height) - (o-32)); - } - W_UnlockCachedPatch(patch); + // No there isn't. + prev = -1; - // draw title (or big pic) - M_DrawMenuTitle(); + // Find skin number from description[] + skinnum = description[char_on].skinnum[0]; + charskin = &skins[skinnum]; + + // Use the opposite of the character's skincolor + col = description[char_on].oppositecolor; + if (!col) + col = Color_Opposite[charskin->prefcolor - 1][0]; + + // Make the translation colormap + colormap = R_GetTranslationColormap(TC_DEFAULT, col, 0); + + // Don't render the title map + hidetitlemap = true; + charseltimer++; + + // Background and borders + V_DrawFill(0, 0, bgwidth, vid.height, V_SNAPTOTOP|colormap[101]); + { + INT32 sw = (BASEVIDWIDTH * vid.dupx); + INT32 bw = (vid.width - sw) / 2; + col = colormap[106]; + if (bw) + V_DrawFill(0, 0, bw, vid.height, V_NOSCALESTART|col); + } + + y = (charseltimer%32); + V_DrawMappedPatch(0, y-bgheight, V_SNAPTOTOP, charbg, colormap); + V_DrawMappedPatch(0, y, V_SNAPTOTOP, charbg, colormap); + V_DrawMappedPatch(0, y+bgheight, V_SNAPTOTOP, charbg, colormap); + V_DrawMappedPatch(0, -y, V_SNAPTOTOP, charfg, colormap); + V_DrawMappedPatch(0, -y+fgheight, V_SNAPTOTOP, charfg, colormap); + V_DrawFill(fgwidth, 0, vid.width, vid.height, V_SNAPTOTOP|colormap[106]); + + // Character pictures + { + x = 8; + y = (my+16) - FixedInt(char_scroll); + V_DrawScaledPatch(x, y, 0, description[char_on].charpic); + if (prev != -1) + V_DrawScaledPatch(x, y - 144, 0, description[prev].charpic); + if (next != -1) + V_DrawScaledPatch(x, y + 144, 0, description[next].charpic); + } // Character description - M_DrawTextBox(136, my, 21, 20); - V_DrawString(146, my + 9, V_RETURN8|V_ALLOWLOWERCASE, char_notes); + { + INT32 flags = V_ALLOWLOWERCASE|V_RETURN8; + x = 146; + y = my + 9; + V_DrawString(x, y, flags, char_notes); + } + + // Name tags + { + INT32 ox, oxsh = FixedInt(FixedMul(BASEVIDWIDTH*FRACUNIT, FixedDiv(char_scroll, 128*FRACUNIT))), txsh; + patch_t *curpatch = NULL, *prevpatch = NULL, *nextpatch = NULL; + const char *curtext = NULL, *prevtext = NULL, *nexttext = NULL; + UINT8 curtextcolor = 0, prevtextcolor = 0, nexttextcolor = 0; + UINT8 curoutlinecolor = 0, prevoutlinecolor = 0, nextoutlinecolor = 0; + + // Name tag + curtext = description[char_on].displayname; + curtextcolor = description[char_on].tagtextcolor; + curoutlinecolor = description[char_on].tagoutlinecolor; + if (curtext[0] == '\0') + curpatch = description[char_on].namepic; + if (!curtextcolor) + curtextcolor = charskin->prefcolor; + if (!curoutlinecolor) + curoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + + txsh = oxsh; + ox = 8 + SHORT((description[char_on].charpic)->width)/2; + y = my + 144; + + // cur + { + x = ox - txsh; + if (curpatch) + x -= (SHORT(curpatch->width)/2); + + if (curtext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(TC_DEFAULT, curtextcolor, 0), + R_GetTranslationColormap(TC_DEFAULT, curoutlinecolor, 0), + curtext + ); + } + else if (curpatch) + V_DrawScaledPatch(x, y, 0, curpatch); + } + + if (char_scroll) + { + // prev + if ((prev != -1) && char_scroll < 0) + { + prevtext = description[prev].displayname; + prevtextcolor = description[prev].tagtextcolor; + prevoutlinecolor = description[prev].tagoutlinecolor; + if (prevtext[0] == '\0') + prevpatch = description[prev].namepic; + charskin = &skins[description[prev].skinnum[0]]; + if (!prevtextcolor) + prevtextcolor = charskin->prefcolor; + if (!prevoutlinecolor) + prevoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + + x = (ox - txsh) - w; + if (prevpatch) + x -= (SHORT(prevpatch->width)/2); + + if (prevtext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(TC_DEFAULT, prevtextcolor, 0), + R_GetTranslationColormap(TC_DEFAULT, prevoutlinecolor, 0), + prevtext + ); + } + else if (prevpatch) + V_DrawScaledPatch(x, y, 0, prevpatch); + } + // next + else if ((next != -1) && char_scroll > 0) + { + nexttext = description[next].displayname; + nexttextcolor = description[next].tagtextcolor; + nextoutlinecolor = description[next].tagoutlinecolor; + if (nexttext[0] == '\0') + nextpatch = description[next].namepic; + charskin = &skins[description[next].skinnum[0]]; + if (!nexttextcolor) + nexttextcolor = charskin->prefcolor; + if (!nextoutlinecolor) + nextoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + + x = (ox - txsh) + w; + if (nextpatch) + x -= (SHORT(nextpatch->width)/2); + + if (nexttext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(TC_DEFAULT, nexttextcolor, 0), + R_GetTranslationColormap(TC_DEFAULT, nextoutlinecolor, 0), + nexttext + ); + } + else if (nextpatch) + V_DrawScaledPatch(x, y, 0, nextpatch); + } + } + } + + // Alternative menu header +#ifdef CHOOSEPLAYER_DRAWHEADER + { + patch_t *header = W_CachePatchName("M_PICKP", PU_CACHE); + INT32 xtitle = 146; + INT32 ytitle = (35 - SHORT(header->height))/2; + V_DrawFixedPatch(xtitle<collected) - V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem), PU_CACHE), + V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE)); else V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -8120,16 +8626,27 @@ static void M_HandleLevelStats(INT32 choice) // Drawing function for Time Attack void M_DrawTimeAttackMenu(void) { - INT32 i, x, y, cursory = 0; + INT32 i, x, y, empatx, empaty, cursory = 0; UINT16 dispstatus; - patch_t *PictureOfUrFace; + patch_t *PictureOfUrFace; // my WHAT + patch_t *empatch; - M_ChangeMenuMusic("_inter", true); // Eww, but needed for when user hits escape during demo playback + M_SetMenuCurBackground("RECATKBG"); + + curbgxspeed = 0; + curbgyspeed = 18; + + M_ChangeMenuMusic("_recat", true); // Eww, but needed for when user hits escape during demo playback if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) + { F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + // Draw and animate foreground + if (!strncmp("RECATKBG", curbgname, 8)) + M_DrawRecordAttackForeground(); + } if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); @@ -8180,10 +8697,10 @@ void M_DrawTimeAttackMenu(void) // Character face! { - if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= 2) + if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1) { spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[1]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); } else @@ -8203,6 +8720,7 @@ void M_DrawTimeAttackMenu(void) patch_t *PictureOfLevel; lumpnum_t lumpnum; char beststr[40]; + char reqscore[40], reqtime[40], reqrings[40]; M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false); @@ -8214,17 +8732,72 @@ void M_DrawTimeAttackMenu(void) else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); - V_DrawSmallScaledPatch(208, 32+lsheadingheight, 0, PictureOfLevel); + y = 32+lsheadingheight; + V_DrawSmallScaledPatch(216, y, 0, PictureOfLevel); - V_DrawString(104 - 72, 32+lsheadingheight/2, 0, "* LEVEL RECORDS *"); + + if (currentMenu == &SP_TimeAttackDef) + { + if (itemOn == talevel) + { + /* Draw arrows !! */ + y = y + 25 - 4; + V_DrawCharacter(216 - 10 - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(216 + 80 + 2 + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + } + // Draw press ESC to exit string on main record attack menu + V_DrawString(104-72, 180, V_TRANSLUCENT, M_GetText("Press ESC to exit")); + } + + em = M_GetLevelEmblems(cv_nextmap.value); + // Draw record emblems. + while (em) + { + switch (em->type) + { + case ET_SCORE: + yHeight = 33; + sprintf(reqscore, "(%u)", em->var); + break; + case ET_TIME: + yHeight = 53; + sprintf(reqtime, "(%i:%02i.%02i)", G_TicsToMinutes((tic_t)em->var, true), + G_TicsToSeconds((tic_t)em->var), + G_TicsToCentiseconds((tic_t)em->var)); + break; + case ET_RINGS: + yHeight = 73; + sprintf(reqrings, "(%u)", em->var); + break; + default: + goto skipThisOne; + } + + empatch = W_CachePatchName(M_GetEmblemPatch(em, true), PU_CACHE); + + empatx = SHORT(empatch->leftoffset)/2; + empaty = SHORT(empatch->topoffset)/2; + + if (em->collected) + V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch, + R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); + else + V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDITL", PU_CACHE)); + + skipThisOne: + em = M_GetLevelEmblems(-1); + } if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->score) sprintf(beststr, "(none)"); else sprintf(beststr, "%u", mainrecords[cv_nextmap.value-1]->score); - V_DrawString(104-72, 48+lsheadingheight/2, V_YELLOWMAP, "SCORE:"); - V_DrawRightAlignedString(104+72, 48+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawString(104-72, 33+lsheadingheight/2, V_YELLOWMAP, "SCORE:"); + V_DrawRightAlignedString(104+64, 33+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawRightAlignedString(104+72, 43+lsheadingheight/2, V_ALLOWLOWERCASE, reqscore); if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time) sprintf(beststr, "(none)"); @@ -8233,39 +8806,23 @@ void M_DrawTimeAttackMenu(void) G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time), G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time)); - V_DrawString(104-72, 58+lsheadingheight/2, V_YELLOWMAP, "TIME:"); - V_DrawRightAlignedString(104+72, 58+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawString(104-72, 53+lsheadingheight/2, V_YELLOWMAP, "TIME:"); + V_DrawRightAlignedString(104+64, 53+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawRightAlignedString(104+72, 63+lsheadingheight/2, V_ALLOWLOWERCASE, reqtime); if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->rings) sprintf(beststr, "(none)"); else sprintf(beststr, "%hu", mainrecords[cv_nextmap.value-1]->rings); - V_DrawString(104-72, 68+lsheadingheight/2, V_YELLOWMAP, "RINGS:"); - V_DrawRightAlignedString(104+72, 68+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawString(104-72, 73+lsheadingheight/2, V_YELLOWMAP, "RINGS:"); - // Draw record emblems. - em = M_GetLevelEmblems(cv_nextmap.value); - while (em) - { - switch (em->type) - { - case ET_SCORE: yHeight = 48; break; - case ET_TIME: yHeight = 58; break; - case ET_RINGS: yHeight = 68; break; - default: - goto skipThisOne; - } + if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->gotperfect) + V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + else + V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|V_YELLOWMAP, beststr); - if (em->collected) - V_DrawSmallMappedPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); - else - V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - skipThisOne: - em = M_GetLevelEmblems(-1); - } + V_DrawRightAlignedString(104+72, 83+lsheadingheight/2, V_ALLOWLOWERCASE, reqrings); } // ALWAYS DRAW level and skin even when not on this menu! @@ -8284,6 +8841,39 @@ void M_DrawTimeAttackMenu(void) } } +static void M_HandleTimeAttackLevelSelect(INT32 choice) +{ + switch (choice) + { + case KEY_DOWNARROW: + M_NextOpt(); + break; + case KEY_UPARROW: + M_PrevOpt(); + break; + + case KEY_LEFTARROW: + CV_AddValue(&cv_nextmap, -1); + break; + case KEY_RIGHTARROW: + CV_AddValue(&cv_nextmap, 1); + break; + + case KEY_ENTER: + M_TimeAttackLevelSelect(0); + break; + + case KEY_ESCAPE: + noFurtherInput = true; + M_GoBack(0); + return; + + default: + return; + } + S_StartSound(NULL, sfx_menu1); +} + static void M_TimeAttackLevelSelect(INT32 choice) { (void)choice; @@ -8324,12 +8914,11 @@ void M_DrawNightsAttackMenu(void) INT32 i, x, y, cursory = 0; UINT16 dispstatus; - M_ChangeMenuMusic("_inter", true); // Eww, but needed for when user hits escape during demo playback + M_SetMenuCurBackground("NTSATKBG"); - if (curbgcolor >= 0) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); - else if (!curbghide || !titlemapinaction) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + M_ChangeMenuMusic("_nitat", true); // Eww, but needed for when user hits escape during demo playback + + M_DrawNightsAttackBackground(); if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); @@ -8387,7 +8976,7 @@ void M_DrawNightsAttackMenu(void) lumpnum_t lumpnum; char beststr[40]; - UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0); + //UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0); UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value); UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value); tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value); @@ -8404,10 +8993,10 @@ void M_DrawNightsAttackMenu(void) V_DrawSmallScaledPatch(208, 32+lsheadingheight, 0, PictureOfLevel); - V_DrawString(104 - 72, 32+lsheadingheight/2, 0, "* LEVEL RECORDS *"); - - if (P_HasGrades(cv_nextmap.value, 0)) - V_DrawScaledPatch(235, 135, 0, ngradeletters[bestoverall]); + // Super Sonic + M_DrawNightsAttackSuperSonic(); + //if (P_HasGrades(cv_nextmap.value, 0)) + // V_DrawScaledPatch(235 - (SHORT((ngradeletters[bestoverall])->width)*3)/2, 135, 0, ngradeletters[bestoverall]); if (P_HasGrades(cv_nextmap.value, cv_dummymares.value)) {//make bigger again @@ -8449,10 +9038,10 @@ void M_DrawNightsAttackMenu(void) } if (em->collected) - V_DrawSmallMappedPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), + V_DrawSmallMappedPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else - V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); skipThisOne: em = M_GetLevelEmblems(-1); @@ -8460,6 +9049,10 @@ void M_DrawNightsAttackMenu(void) } } + // Draw press ESC to exit string on main nights attack menu + if (currentMenu == &SP_NightsAttackDef) + V_DrawString(104-72, 180, V_TRANSLUCENT, M_GetText("Press ESC to exit")); + // ALWAYS DRAW level even when not on this menu! if (currentMenu != &SP_NightsAttackDef) V_DrawString(SP_NightsAttackDef.x, SP_NightsAttackDef.y + SP_TimeAttackMenu[nalevel].alphaKey, V_TRANSLUCENT, SP_NightsAttackMenu[nalevel].text); @@ -8488,6 +9081,9 @@ static void M_NightsAttack(INT32 choice) // This is really just to make sure Sonic is the played character, just in case M_PatchSkinNameTable(); + ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_CACHE); + ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_CACHE); + G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please M_SetupNextMenu(&SP_NightsAttackDef); @@ -8505,6 +9101,7 @@ static void M_ChooseNightsAttack(INT32 choice) char nameofdemo[256]; (void)choice; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); modeattacking = ATTACKING_NIGHTS; @@ -8529,6 +9126,7 @@ static void M_ChooseTimeAttack(INT32 choice) char nameofdemo[256]; (void)choice; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); modeattacking = ATTACKING_RECORD; @@ -9268,6 +9866,12 @@ static void M_ServerOptions(INT32 choice) } #endif + /* Disable fading because of different menu head. */ + if (currentMenu == &OP_MainDef)/* from Options menu */ + OP_ServerOptionsDef.menuid = MN_OP_MAIN + ( MN_OP_SERVER << 6 ); + else/* from Multiplayer menu */ + OP_ServerOptionsDef.menuid = MN_MP_MAIN + ( MN_MP_SERVER_OPTIONS << 6 ); + OP_ServerOptionsDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_ServerOptionsDef); } @@ -9332,6 +9936,8 @@ static void M_ConnectIP(INT32 choice) return; } + M_ClearMenus(true); + COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); // A little "please wait" message. @@ -9363,7 +9969,6 @@ static void M_HandleConnectIP(INT32 choice) case KEY_ENTER: S_StartSound(NULL,sfx_menu1); // Tails - M_ClearMenus(true); M_ConnectIP(1); break; @@ -9413,6 +10018,7 @@ static void M_HandleConnectIP(INT32 choice) if (exitmenu) { + currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) M_SetupNextMenu (currentMenu->prevMenu); else @@ -9895,18 +10501,33 @@ static void M_ScreenshotOptions(INT32 choice) static void M_DrawJoystick(void) { - INT32 i; + INT32 i, compareval2, compareval; // draw title (or big pic) M_DrawMenuTitle(); - for (i = 0; i <= 4; i++) // See MAX_JOYSTICKS + for (i = 0; i <= MAX_JOYSTICKS; i++) // See MAX_JOYSTICKS { M_DrawTextBox(OP_JoystickSetDef.x-8, OP_JoystickSetDef.y+LINEHEIGHT*i-12, 28, 1); //M_DrawSaveLoadBorder(OP_JoystickSetDef.x+4, OP_JoystickSetDef.y+1+LINEHEIGHT*i); - if ((setupcontrols_secondaryplayer && (i == cv_usejoystick2.value)) - || (!setupcontrols_secondaryplayer && (i == cv_usejoystick.value))) +#ifdef JOYSTICK_HOTPLUG + if (atoi(cv_usejoystick2.string) > I_NumJoys()) + compareval2 = atoi(cv_usejoystick2.string); + else + compareval2 = cv_usejoystick2.value; + + if (atoi(cv_usejoystick.string) > I_NumJoys()) + compareval = atoi(cv_usejoystick.string); + else + compareval = cv_usejoystick.value; +#else + compareval2 = cv_usejoystick2.value; + compareval = cv_usejoystick.value; +#endif + + if ((setupcontrols_secondaryplayer && (i == compareval2)) + || (!setupcontrols_secondaryplayer && (i == compareval))) V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,V_GREENMAP,joystickInfo[i]); else V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,0,joystickInfo[i]); @@ -9919,7 +10540,7 @@ static void M_DrawJoystick(void) } } -static void M_SetupJoystickMenu(INT32 choice) +void M_SetupJoystickMenu(INT32 choice) { INT32 i = 0; const char *joyNA = "Unavailable"; @@ -9928,12 +10549,27 @@ static void M_SetupJoystickMenu(INT32 choice) strcpy(joystickInfo[i], "None"); - for (i = 1; i < 8; i++) + for (i = 1; i <= MAX_JOYSTICKS; i++) { if (i <= n && (I_GetJoyName(i)) != NULL) strncpy(joystickInfo[i], I_GetJoyName(i), 28); else strcpy(joystickInfo[i], joyNA); + +#ifdef JOYSTICK_HOTPLUG + // We use cv_usejoystick.string as the USER-SET var + // and cv_usejoystick.value as the INTERNAL var + // + // In practice, if cv_usejoystick.string == 0, this overrides + // cv_usejoystick.value and always disables + // + // Update cv_usejoystick.string here so that the user can + // properly change this value. + if (i == cv_usejoystick.value) + CV_SetValue(&cv_usejoystick, i); + if (i == cv_usejoystick2.value) + CV_SetValue(&cv_usejoystick2, i); +#endif } M_SetupNextMenu(&OP_JoystickSetDef); @@ -9963,10 +10599,76 @@ static void M_Setup2PJoystickMenu(INT32 choice) static void M_AssignJoystick(INT32 choice) { +#ifdef JOYSTICK_HOTPLUG + INT32 oldchoice, oldstringchoice; + INT32 numjoys = I_NumJoys(); + + if (setupcontrols_secondaryplayer) + { + oldchoice = oldstringchoice = atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value; + CV_SetValue(&cv_usejoystick2, choice); + + // Just in case last-minute changes were made to cv_usejoystick.value, + // update the string too + // But don't do this if we're intentionally setting higher than numjoys + if (choice <= numjoys) + { + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + // reset this so the comparison is valid + if (oldchoice > numjoys) + oldchoice = cv_usejoystick2.value; + + if (oldchoice != choice) + { + if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device + CV_SetValue(&cv_usejoystick2, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); + + if (oldstringchoice == + (atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value)) + M_StartMessage("This gamepad is used by another\n" + "player. Reset the gamepad\n" + "for that player first.\n\n" + "(Press a key)\n", NULL, MM_NOTHING); + } + } + } + else + { + oldchoice = oldstringchoice = atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value; + CV_SetValue(&cv_usejoystick, choice); + + // Just in case last-minute changes were made to cv_usejoystick.value, + // update the string too + // But don't do this if we're intentionally setting higher than numjoys + if (choice <= numjoys) + { + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + // reset this so the comparison is valid + if (oldchoice > numjoys) + oldchoice = cv_usejoystick.value; + + if (oldchoice != choice) + { + if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device + CV_SetValue(&cv_usejoystick, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); + + if (oldstringchoice == + (atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value)) + M_StartMessage("This gamepad is used by another\n" + "player. Reset the gamepad\n" + "for that player first.\n\n" + "(Press a key)\n", NULL, MM_NOTHING); + } + } + } +#else if (setupcontrols_secondaryplayer) CV_SetValue(&cv_usejoystick2, choice); else CV_SetValue(&cv_usejoystick, choice); +#endif } // ============= diff --git a/src/m_menu.h b/src/m_menu.h index 347725e10..3bfa48597 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -63,6 +63,7 @@ typedef enum MN_MP_CONNECT, MN_MP_ROOM, MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + MN_MP_SERVER_OPTIONS, // Options MN_OP_MAIN, @@ -72,10 +73,12 @@ typedef enum MN_OP_P1MOUSE, MN_OP_P1JOYSTICK, MN_OP_JOYSTICKSET, // OP_JoystickSetDef shared with P2 + MN_OP_P1CAMERA, MN_OP_P2CONTROLS, MN_OP_P2MOUSE, MN_OP_P2JOYSTICK, + MN_OP_P2CAMERA, MN_OP_VIDEO, MN_OP_VIDEOMODE, @@ -101,6 +104,7 @@ typedef enum MN_SR_LEVELSELECT, MN_SR_UNLOCKCHECKLIST, MN_SR_EMBLEMHINT, + MN_SR_PLAYER, // Addons (Part of MISC, but let's make it our own) MN_AD_MAIN, @@ -206,7 +210,6 @@ void M_QuitResponse(INT32 ch); // Determines whether to show a level in the list (platter version does not need to be exposed) boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); - // flags for items in the menu // menu handle (what we do when key is pressed #define IT_TYPE 14 // (2+4+8) @@ -242,6 +245,8 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_CV_NOPRINT 1536 #define IT_CV_NOMOD 2048 #define IT_CV_INVISSLIDER 2560 +#define IT_CV_INTEGERSTEP 4096 // if IT_CV_NORMAL and cvar is CV_FLOAT, modify it by 1 instead of 0.0625 +#define IT_CV_FLOATSLIDER 4608 // IT_CV_SLIDER, value modified by 0.0625 instead of 1 (for CV_FLOAT cvars) //call/submenu specific // There used to be a lot more here but ... @@ -309,6 +314,10 @@ extern menu_t *currentMenu; extern menu_t MainDef; extern menu_t SP_LoadDef; +// Call upon joystick hotplug +void M_SetupJoystickMenu(INT32 choice); +extern menu_t OP_JoystickSetDef; + // Stuff for customizing the player select screen typedef struct { @@ -316,9 +325,18 @@ typedef struct char notes[441]; char picname[8]; char skinname[SKINNAMESIZE*2+2]; // skin&skin\0 - patch_t *pic; + patch_t *charpic; UINT8 prev; UINT8 next; + + // new character select + char displayname[SKINNAMESIZE+1]; + SINT8 skinnum[2]; + UINT8 oppositecolor; + char nametag[8]; + patch_t *namepic; + UINT8 tagtextcolor; + UINT8 tagoutlinecolor; } description_t; // level select platter @@ -367,6 +385,7 @@ typedef struct extern description_t description[MAXSKINS]; +extern consvar_t cv_showfocuslost; extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort; extern CV_PossibleValue_t gametype_cons_t[]; @@ -397,6 +416,9 @@ void Screenshot_option_Onchange(void); // Addons menu updating void Addons_option_Onchange(void); +// Moviemode menu updating +void Moviemode_option_Onchange(void); + // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(id, header, source, prev, x, y)\ {\ diff --git a/src/m_misc.c b/src/m_misc.c index 22e19df73..f7d5cf961 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -108,6 +108,9 @@ consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAV static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}}; consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_movie_option = {"movie_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Moviemode_option_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_movie_folder = {"movie_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; + static CV_PossibleValue_t zlib_mem_level_t[] = { {1, "(Min Memory) 1"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5"}, {6, "6"}, {7, "7"}, @@ -194,7 +197,7 @@ INT32 M_MapNumber(char first, char second) // ========================================================================== // some libcs has no access function, make our own -#if defined (_WIN32_WCE) +#if 0 int access(const char *path, int amode) { int accesshandle = -1; @@ -1124,19 +1127,25 @@ static inline moviemode_t M_StartMovieGIF(const char *pathname) void M_StartMovie(void) { #if NUMSCREENS > 2 - const char *pathname = "."; + char pathname[MAX_WADPATH]; if (moviemode) return; - if (cv_screenshot_option.value == 0) - pathname = usehome ? srb2home : srb2path; - else if (cv_screenshot_option.value == 1) - pathname = srb2home; - else if (cv_screenshot_option.value == 2) - pathname = srb2path; - else if (cv_screenshot_option.value == 3 && *cv_screenshot_folder.string != '\0') - pathname = cv_screenshot_folder.string; + if (cv_movie_option.value == 0) + strcpy(pathname, usehome ? srb2home : srb2path); + else if (cv_movie_option.value == 1) + strcpy(pathname, srb2home); + else if (cv_movie_option.value == 2) + strcpy(pathname, srb2path); + else if (cv_movie_option.value == 3 && *cv_movie_folder.string != '\0') + strcpy(pathname, cv_movie_folder.string); + + if (cv_movie_option.value != 3) + { + strcat(pathname, PATHSEP"movies"PATHSEP); + I_mkdir(pathname, 0755); + } if (rendermode == render_none) I_Error("Can't make a movie without a render system\n"); @@ -1474,7 +1483,8 @@ void M_ScreenShot(void) void M_DoScreenShot(void) { #if NUMSCREENS > 2 - const char *freename = NULL, *pathname = "."; + const char *freename = NULL; + char pathname[MAX_WADPATH]; boolean ret = false; UINT8 *linear = NULL; @@ -1486,13 +1496,19 @@ void M_DoScreenShot(void) return; if (cv_screenshot_option.value == 0) - pathname = usehome ? srb2home : srb2path; + strcpy(pathname, usehome ? srb2home : srb2path); else if (cv_screenshot_option.value == 1) - pathname = srb2home; + strcpy(pathname, srb2home); else if (cv_screenshot_option.value == 2) - pathname = srb2path; + strcpy(pathname, srb2path); else if (cv_screenshot_option.value == 3 && *cv_screenshot_folder.string != '\0') - pathname = cv_screenshot_folder.string; + strcpy(pathname, cv_screenshot_folder.string); + + if (cv_screenshot_option.value != 3) + { + strcat(pathname, PATHSEP"screenshots"PATHSEP); + I_mkdir(pathname, 0755); + } #ifdef USE_PNG freename = Newsnapshotfile(pathname,"png"); diff --git a/src/m_misc.h b/src/m_misc.h index 6ac92dbcc..7038e3e48 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -30,7 +30,7 @@ typedef enum { extern moviemode_t moviemode; extern consvar_t cv_screenshot_option, cv_screenshot_folder, cv_screenshot_colorprofile; -extern consvar_t cv_moviemode; +extern consvar_t cv_moviemode, cv_movie_folder, cv_movie_option; extern consvar_t cv_zlib_memory, cv_zlib_level, cv_zlib_strategy, cv_zlib_window_bits; extern consvar_t cv_zlib_memorya, cv_zlib_levela, cv_zlib_strategya, cv_zlib_window_bitsa; extern consvar_t cv_apng_delay; diff --git a/src/m_swap.h b/src/m_swap.h index 2d42f6138..3b50dc623 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -14,29 +14,39 @@ #ifndef __M_SWAP__ #define __M_SWAP__ -#include "endian.h" - // Endianess handling. // WAD files are stored little endian. +#include "endian.h" + +// Little to big endian #ifdef SRB2_BIG_ENDIAN -#define SHORT(x) ((INT16)(\ -(((UINT16)(x) & (UINT16)0x00ffU) << 8) \ -| \ -(((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ + #define SHORT(x) ((INT16)(\ + (((UINT16)(x) & (UINT16)0x00ffU) << 8) \ + | \ + (((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ -#define LONG(x) ((INT32)(\ -(((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ -| \ -(((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ -| \ -(((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ -| \ -(((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) + #define LONG(x) ((INT32)(\ + (((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ + | \ + (((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ + | \ + (((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ + | \ + (((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) #else -#define SHORT(x) ((INT16)(x)) -#define LONG(x) ((INT32)(x)) + #define SHORT(x) ((INT16)(x)) + #define LONG(x) ((INT32)(x)) +#endif + +// Big to little endian +#ifdef SRB2_LITTLE_ENDIAN + #define BIGENDIAN_LONG(x) ((INT32)(((x)>>24)&0xff)|(((x)<<8)&0xff0000)|(((x)>>8)&0xff00)|(((x)<<24)&0xff000000)) + #define BIGENDIAN_SHORT(x) ((INT16)(((x)>>8)|((x)<<8))) +#else + #define BIGENDIAN_LONG(x) ((INT32)(x)) + #define BIGENDIAN_SHORT(x) ((INT16)(x)) #endif #endif diff --git a/src/p_enemy.c b/src/p_enemy.c index bc3665237..cc2d64e8b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -170,6 +170,7 @@ void A_SetReactionTime(mobj_t *actor); void A_Boss1Spikeballs(mobj_t *actor); void A_Boss3TakeDamage(mobj_t *actor); void A_Boss3Path(mobj_t *actor); +void A_Boss3ShockThink(mobj_t *actor); void A_LinedefExecute(mobj_t *actor); void A_PlaySeeSound(mobj_t *actor); void A_PlayAttackSound(mobj_t *actor); @@ -282,6 +283,7 @@ void A_Boss5CheckOnGround(mobj_t *actor); void A_Boss5CheckFalling(mobj_t *actor); void A_Boss5PinchShot(mobj_t *actor); void A_Boss5MakeItRain(mobj_t *actor); +void A_Boss5MakeJunk(mobj_t *actor); void A_LookForBetter(mobj_t *actor); void A_Boss5BombExplode(mobj_t *actor); void A_DustDevilThink(mobj_t *actor); @@ -296,6 +298,14 @@ void A_SnapperThinker(mobj_t *actor); void A_SaloonDoorSpawn(mobj_t *actor); void A_MinecartSparkThink(mobj_t *actor); void A_ModuloToState(mobj_t *actor); +void A_LavafallRocks(mobj_t *actor); +void A_LavafallLava(mobj_t *actor); +void A_FallingLavaCheck(mobj_t *actor); +void A_FireShrink(mobj_t *actor); +void A_SpawnPterabytes(mobj_t *actor); +void A_PterabyteHover(mobj_t *actor); +void A_RolloutSpawn(mobj_t *actor); +void A_RolloutRock(mobj_t *actor); //for p_enemy.c @@ -2017,6 +2027,7 @@ void A_CrushstaceanWalk(mobj_t *actor) || (actor->reactiontime-- <= 0)) { actor->flags2 ^= MF2_AMBUSH; + P_SetTarget(&actor->target, NULL); P_SetMobjState(actor, locvar2); actor->reactiontime = actor->info->reactiontime; } @@ -2077,7 +2088,7 @@ void A_CrushclawAim(mobj_t *actor) return; // there is only one step and it is crab } - if (crab->target || P_LookForPlayers(crab, true, false, 600*crab->scale)) + if (crab->target || P_LookForPlayers(crab, true, false, actor->info->speed*crab->scale)) ang = R_PointToAngle2(crab->x, crab->y, crab->target->x, crab->target->y); else ang = crab->angle + ((crab->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); @@ -2160,7 +2171,7 @@ void A_CrushclawLaunch(mobj_t *actor) UINT8 i = 0; for (i = 0; (i < CSEGS); i++) { - mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate); + mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, (mobjtype_t)actor->info->raisestate); P_SetTarget(&prevchain->target, newchain); prevchain = newchain; } @@ -3027,10 +3038,15 @@ void A_Boss1Laser(mobj_t *actor) if (!actor->target) return; - if ((upperend & 1) && (actor->extravalue2 > 1)) - actor->extravalue2--; + if (actor->state->tics > 1) + dur = actor->tics; + else + { + if ((upperend & 1) && (actor->extravalue2 > 1)) + actor->extravalue2--; - dur = actor->extravalue2; + dur = actor->extravalue2; + } switch (locvar2) { @@ -3076,23 +3092,15 @@ void A_Boss1Laser(mobj_t *actor) actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); if (mobjinfo[locvar1].seesound) S_StartSound(actor, mobjinfo[locvar1].seesound); - if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - { - point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); - point->angle = actor->angle; - point->fuse = dur+1; - P_SetTarget(&point->target, actor->target); - P_SetTarget(&actor->target, point); - } - } - /* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path - else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/ - /*if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) - angle = FixedAngle(FixedDiv(dur*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); - else*/ - angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); + point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); + point->angle = actor->angle; + point->fuse = dur+1; + P_SetTarget(&point->target, actor->target); + P_SetTarget(&actor->target, point); + } + + angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); point = P_SpawnMobj(x, y, z, locvar1); P_SetTarget(&point->target, actor); @@ -4028,13 +4036,17 @@ bossjustdie: } case MT_FANG: { + if (mo->flags2 & MF2_SLIDEPUSH) + { + P_RemoveMobj(mo); + return; + } if (mo->tracer) { var1 = var2 = 0; A_Boss5Jump(mo); mo->momx = ((16 - 1)*mo->momx)/16; mo->momy = ((16 - 1)*mo->momy)/16; - if (!(mo->flags2 & MF2_AMBUSH)) { const fixed_t time = FixedHypot(mo->tracer->x - mo->x, mo->tracer->y - mo->y)/FixedHypot(mo->momx, mo->momy); const fixed_t speed = 64*FRACUNIT; @@ -5340,20 +5352,22 @@ static mobj_t *minus; static boolean PIT_MinusCarry(mobj_t *thing) { + if (minus->tracer) + return true; + if (minus->type == thing->type) return true; - if (!(thing->flags & MF_SHOOTABLE) || !(thing->flags & MF_ENEMY)) + if (!(thing->flags & (MF_PUSHABLE|MF_ENEMY))) return true; - if (P_AproxDistance(minus->x - thing->x, minus->y - thing->y) >= minus->radius * 3) + if (P_AproxDistance(minus->x - thing->x, minus->y - thing->y) >= minus->radius*3) return true; if (abs(thing->z - minus->z) > minus->height) return true; P_SetTarget(&minus->tracer, thing); - minus->tracer->flags &= ~MF_PUSHABLE; return true; } @@ -5417,6 +5431,9 @@ void A_MinusDigging(mobj_t *actor) A_Chase(actor); // Carry over shit, maybe + if (P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) + P_SetTarget(&actor->tracer, NULL); + if (!actor->tracer) { fixed_t radius = 3*actor->radius; @@ -5466,7 +5483,6 @@ void A_MinusPopup(mobj_t *actor) else actor->momz = 10*FRACUNIT; - actor->flags |= MF_SPECIAL|MF_SHOOTABLE; S_StartSound(actor, sfx_s3k82); for (i = 1; i <= num; i++) { @@ -5479,6 +5495,7 @@ void A_MinusPopup(mobj_t *actor) if (actor->tracer) P_DamageMobj(actor->tracer, actor, actor, 1, 0); + actor->flags = (actor->flags & ~MF_NOCLIPTHING)|MF_SPECIAL|MF_SHOOTABLE; } // Function: A_MinusCheck @@ -8079,6 +8096,57 @@ void A_Boss3Path(mobj_t *actor) } } +// Function: A_Boss3ShockThink +// +// Description: Inserts new interstitial shockwave objects when the space between others spreads too much. +// +// var1 = unused +// var2 = unused +// +void A_Boss3ShockThink(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss3ShockThink", actor)) + return; +#endif + + if (actor->momx || actor->momy) + actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy) + ANGLE_90; + + if (actor->hnext && !P_MobjWasRemoved(actor->hnext)) + { + mobj_t *snext = actor->hnext; + mobj_t *snew; + fixed_t x0, y0, x1, y1; + + // Break the link if movements are too different + if (FixedHypot(snext->momx - actor->momx, snext->momy - actor->momy) > 12*actor->scale) + { + P_SetTarget(&actor->hnext, NULL); + return; + } + + // Check distance between shockwave objects to determine whether interstitial ones should be spawned + x0 = actor->x; + y0 = actor->y; + x1 = snext->x; + y1 = snext->y; + if (FixedHypot(x1 - x0, y1 - y0) > 2*actor->radius) + { + snew = P_SpawnMobj((x0 + x1) >> 1, (y0 + y1) >> 1, (actor->z + snext->z) >> 1, actor->type); + snew->momx = (actor->momx + snext->momx) >> 1; + snew->momy = (actor->momy + snext->momy) >> 1; + snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? + snew->angle = (actor->angle + snext->angle) >> 1; + P_SetTarget(&snew->target, actor->target); + snew->fuse = actor->fuse; + + P_SetTarget(&actor->hnext, snew); + P_SetTarget(&snew->hnext, snext); + } + } +} + // Function: A_LinedefExecute // // Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well. @@ -8354,8 +8422,8 @@ void A_ChangeAngleAbsolute(mobj_t *actor) // // var1 = sound # to play // var2: -// 0 = Play sound without an origin -// 1 = Play sound using calling object as origin +// lower 16 bits = If 1, play sound using calling object as origin. If 0, play sound without an origin +// upper 16 bits = If 1, do not play sound during preticker. // void A_PlaySound(mobj_t *actor) { @@ -8366,7 +8434,10 @@ void A_PlaySound(mobj_t *actor) return; #endif - S_StartSound(locvar2 ? actor : NULL, locvar1); + if (leveltime < 2 && (locvar2 >> 16)) + return; + + S_StartSound((locvar2 & 65535) ? actor : NULL, locvar1); } // Function: A_FindTarget @@ -12143,7 +12214,7 @@ void A_MineExplode(mobj_t *actor) #undef dist if (actor->watertop != INT32_MAX) - P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH); + P_SpawnMobj(actor->x, actor->y, actor->watertop, (actor->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH); } } @@ -12183,7 +12254,6 @@ void A_ConnectToGround(mobj_t *actor) mobj_t *work; fixed_t workz; fixed_t workh; - SINT8 dir; angle_t ang; INT32 locvar1 = var1; INT32 locvar2 = var2; @@ -12197,23 +12267,17 @@ void A_ConnectToGround(mobj_t *actor) P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); if (actor->flags2 & MF2_OBJECTFLIP) - { - workz = actor->ceilingz - (actor->z + actor->height); - dir = -1; - } + workz = (actor->z + actor->height) - actor->ceilingz; else - { workz = actor->floorz - actor->z; - dir = 1; - } if (locvar2) { workh = FixedMul(mobjinfo[locvar2].height, actor->scale); if (actor->flags2 & MF2_OBJECTFLIP) - workz -= workh; + workz += workh; work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2); - workz += dir*workh; + workz += workh; } if (!locvar1) @@ -12222,21 +12286,18 @@ void A_ConnectToGround(mobj_t *actor) if (!(workh = FixedMul(mobjinfo[locvar1].height, actor->scale))) return; - if (actor->flags2 & MF2_OBJECTFLIP) - workz -= workh; - ang = actor->angle + ANGLE_45; - while (dir*workz < 0) + while (workz < 0) { work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); if (work) work->angle = ang; ang += ANGLE_90; - workz += dir*workh; + workz += workh; } if (workz != 0) - actor->z += workz; + actor->z += P_MobjFlip(actor)*workz; } // Function: A_SpawnParticleRelative @@ -12978,6 +13039,100 @@ void A_Boss5MakeItRain(mobj_t *actor) actor->extravalue2 = 0; } +// Function: A_Boss5MakeJunk +// +// Description: Make a mess. +// +// var1 = state # to set on MT_BROKENROBOT (if 0 do nothing, if -1 go to if colorized) +// var2 = mode (-1 = spin, 0 = make 1, & 1 make 8, & 2 alart mode) +// +void A_Boss5MakeJunk(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *broked; + angle_t ang; + INT32 i = ((locvar2 & 1) ? 8 : 1); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5MakeJunk", actor)) + return; +#endif + + if (locvar1 < 0 && (actor->flags2 & MF2_SLIDEPUSH)) // this entire action is a hack, don't judge me + { + INT32 curextravalue2 = actor->extravalue2; + P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_PROJECTORLIGHT); + actor->z += P_MobjFlip(actor)*actor->height; + actor->flags |= MF_NOGRAVITY; + S_StartSound(actor, sfx_vwre); + actor->extravalue2 = 49; + P_SetMobjState(actor, -locvar1); + actor->extravalue2 = curextravalue2; + actor->angle -= FixedAngle((49*45)<extravalue2)/50; + if (trans > 9) + trans = 9; + if (trans < 0) + trans = 0; + if (!(actor->extravalue2 & 1)) + { + if (actor->extravalue2 > 10) + { + mobj_t *front = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_VWREF); + broked = P_SpawnMobjFromMobj(front, 0, 0, 0, MT_VWREB); + front->z = broked->z = front->z - broked->height; + P_SetObjectMomZ(front, (4<momz = front->momz; + broked->fuse = front->fuse = (actor->height+(2*front->height))/front->momz; + } + if (!(actor->colorized = !actor->colorized)) + actor->frame |= FF_FULLBRIGHT; + } + actor->angle += ANGLE_45; + actor->frame = (actor->frame & ~FF_TRANSMASK)|(trans<fuse = TICRATE; + else + broked->fuse = (((locvar2 & 1) ? 4 : 2)*TICRATE)/3; + broked->angle = ang; + P_InstaThrust(broked, ang, ((locvar2 & 2) ? 8 : 5)*actor->scale); + P_SetObjectMomZ(broked, (((locvar2) ? 4 : 0) + P_RandomRange(2, 5))< 0) + P_SetMobjState(broked, locvar1); + if (!P_MobjWasRemoved(broked)) + P_TeleportMove(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z); + ang += ANGLE_45; + } + + if (locvar2 & 2) + { + broked = P_SpawnMobjFromMobj(actor, 0, 0, 64<fuse = states[S_FANG_INTRO12].tics+10; + P_SetMobjState(broked, S_ALART1); + } + else if (locvar2 & 1) + { + broked->z += broked->momz; + S_StartSound(actor, sfx_s3kccs); + actor->flags &= ~MF_NOCLIPTHING; + } + else + S_StartSound(actor, sfx_s3kd3s); +} + // Function: A_LookForBetter // // Description: A_Look, except it finds a better target in multiplayer, and doesn't lose the target in singleplayer. @@ -13104,11 +13259,14 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) if (dustdevil->height - pos > thresh) { fixed_t dist = FixedHypot(thing->x - dustdevil->x, thing->y - dustdevil->y); - fixed_t dragamount = 6 * FRACUNIT; + fixed_t dragamount = player->speed; fixed_t x, y; if (player->powers[pw_nocontrol] == 0) + { + P_ResetPlayer(player); A_PlayActiveSound(dustdevil); + } player->powers[pw_nocontrol] = 2; player->drawangle += ANG20; P_SetPlayerMobjState(thing, S_PLAY_PAIN); @@ -13304,6 +13462,13 @@ void A_TNTExplode(mobj_t *actor) if (LUA_CallAction("A_TNTExplode", actor)) return; #endif + + if (actor->tracer) + { + P_SetTarget(&actor->tracer->tracer, NULL); + P_SetTarget(&actor->tracer, NULL); + } + P_UnsetThingPosition(actor); if (sector_list) { @@ -13517,8 +13682,6 @@ void A_KillSegments(mobj_t *actor) static void P_SnapperLegPlace(mobj_t *mo) { mobj_t *seg = mo->tracer; - fixed_t x0 = mo->x; - fixed_t y0 = mo->y; angle_t a = mo->angle; angle_t fa = (a >> ANGLETOFINESHIFT) & FINEMASK; fixed_t c = FINECOSINE(fa); @@ -13533,7 +13696,8 @@ static void P_SnapperLegPlace(mobj_t *mo) fixed_t rad = mo->radius; INT32 necklen = (32*(mo->info->reactiontime - mo->reactiontime))/mo->info->reactiontime; // Not in FU - P_TeleportMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, mo->z + mo->height/3); + seg->z = mo->z + ((mo->eflags & MFE_VERTICALFLIP) ? (((mo->height<<1)/3) - seg->height) : mo->height/3); + P_TryMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, true); seg->angle = a; // Move as many legs as available. @@ -13553,13 +13717,14 @@ static void P_SnapperLegPlace(mobj_t *mo) { x = c*o2 + s*o1; y = s*o2 - c*o1; - P_TryMove(seg, x0 + x, y0 + y, true); + seg->z = mo->z + (((mo->eflags & MFE_VERTICALFLIP) ? (mo->height - seg->height) : 0)); + P_TryMove(seg, mo->x + x, mo->y + y, true); P_SetMobjState(seg, seg->info->raisestate); } else P_SetMobjState(seg, seg->info->spawnstate); - seg->angle = R_PointToAngle2(x0, y0, seg->x, seg->y); + seg->angle = R_PointToAngle2(mo->x, mo->y, seg->x, seg->y); seg = seg->tracer; } while (seg); @@ -13587,14 +13752,14 @@ void A_SnapperSpawn(mobj_t *actor) #endif // It spawns 1 head. - seg = P_SpawnMobj(actor->x, actor->y, actor->z, headtype); + seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, headtype); P_SetTarget(&ptr->tracer, seg); ptr = seg; // It spawns 4 legs which will be handled in the thinker function. for (i = 1; i <= 4; i++) { - seg = P_SpawnMobj(actor->x, actor->y, actor->z, legtype); + seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, legtype); P_SetTarget(&ptr->tracer, seg); ptr = seg; @@ -13742,51 +13907,43 @@ void A_SnapperThinker(mobj_t *actor) // // Description: Spawns a saloon door. // -// var1 = unused -// var2 = unused +// var1 = mobjtype for sides +// var2 = distance sides should be placed apart // void A_SaloonDoorSpawn(mobj_t *actor) { + INT32 locvar1 = var1; + INT32 locvar2 = var2; angle_t ang = actor->angle; angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK; - fixed_t c = FINECOSINE(fa); - fixed_t s = FINESINE(fa); - INT32 d = 48; - fixed_t x = actor->x; - fixed_t y = actor->y; - fixed_t z = actor->z; + fixed_t c = FINECOSINE(fa)*locvar2; + fixed_t s = FINESINE(fa)*locvar2; mobj_t *door; + mobjflag2_t ambush = (actor->flags & MF2_AMBUSH); #ifdef HAVE_BLUA if (LUA_CallAction("A_SaloonDoorSpawn", actor)) return; #endif - //Front - door = P_SpawnMobj(x + c*d, y + s*d, z, MT_SALOONDOOR); + if (!locvar1) + return; + + // One door... + if (!(door = P_SpawnMobjFromMobj(actor, c, s, 0, locvar1))) return; door->angle = ang + ANGLE_180; + door->extravalue1 = AngleFixed(door->angle); // Origin angle + door->extravalue2 = 0; // Angular speed + P_SetTarget(&door->tracer, actor); // Origin door + door->flags2 |= ambush; // Can be opened by normal players? - // Origin angle - door->extravalue1 = AngleFixed(door->angle); - - // Angular speed - door->extravalue2 = 0; - - // Origin door - P_SetTarget(&door->tracer, actor); - - //Back - door = P_SpawnMobj(x - c*d, y - s*d, z, MT_SALOONDOOR); + // ...two door! + if (!(door = P_SpawnMobjFromMobj(actor, -c, -s, 0, locvar1))) return; door->angle = ang; - - // Origin angle - door->extravalue1 = AngleFixed(door->angle); - - // Angular speed - door->extravalue2 = 0; - - // Origin door - P_SetTarget(&door->tracer, actor); + door->extravalue1 = AngleFixed(door->angle); // Origin angle + door->extravalue2 = 0; // Angular speed + P_SetTarget(&door->tracer, actor); // Origin door + door->flags2 |= ambush; // Can be opened by normal players? } // Function: A_MinecartSparkThink @@ -13847,3 +14004,289 @@ void A_ModuloToState(mobj_t *actor) P_SetMobjState(actor, (locvar2)); modulothing++; } + +// Function: A_LavafallRocks +// +// Description: Spawn random rock particles. +// +// var1 = unused +// var2 = unused +// +void A_LavafallRocks(mobj_t *actor) +{ + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LavafallRocks", actor)) + return; +#endif + + // Don't spawn rocks unless a player is relatively close by. + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].mo + && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600 << FRACBITS)) + break; // Stop looking. + + if (i < MAXPLAYERS) + { + angle_t fa = (FixedAngle(P_RandomKey(360) << FRACBITS) >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t offset = P_RandomRange(4, 12) << FRACBITS; + fixed_t xoffs = FixedMul(FINECOSINE(fa), actor->radius + offset); + fixed_t yoffs = FixedMul(FINESINE(fa), actor->radius + offset); + P_SpawnMobjFromMobj(actor, xoffs, yoffs, 0, MT_LAVAFALLROCK); + } +} + +// Function: A_LavafallLava +// +// Description: Spawn lava from lavafall. +// +// var1 = unused +// var2 = unused +// +void A_LavafallLava(mobj_t *actor) +{ + mobj_t *lavafall; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LavafallLava", actor)) + return; +#endif + + if ((40 - actor->fuse) % (2*(actor->scale >> FRACBITS))) + return; + + lavafall = P_SpawnMobjFromMobj(actor, 0, 0, -8*FRACUNIT, MT_LAVAFALL_LAVA); + lavafall->momz = -P_MobjFlip(actor)*25*FRACUNIT; +} + +// Function: A_FallingLavaCheck +// +// Description: If actor hits the ground or a water surface, enter the death animation. +// +// var1 = unused +// var2 = unused +// +void A_FallingLavaCheck(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FallingLavaCheck", actor)) + return; +#endif + + if (actor->eflags & MFE_TOUCHWATER || P_IsObjectOnGround(actor)) + { + actor->flags = MF_NOGRAVITY|MF_NOCLIPTHING; + actor->momz = 0; + if (actor->eflags & MFE_TOUCHWATER) + actor->z = (actor->eflags & MFE_VERTICALFLIP) ? actor->waterbottom : actor->watertop; + P_SetMobjState(actor, actor->info->deathstate); + } +} + +// Function: A_FireShrink +// +// Description: Shrink the actor down to the specified scale at the specified speed. +// +// var1 = Scale to shrink to +// var2 = Shrinking speed +// +void A_FireShrink(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FireShrink", actor)) + return; +#endif + + actor->destscale = locvar1; + actor->scalespeed = FRACUNIT/locvar2; +} + +// Function: A_SpawnPterabytes +// +// Description: Spawn Pterabytes around the actor in a circle. +// +// var1 = unused +// var2 = unused +// +void A_SpawnPterabytes(mobj_t *actor) +{ + mobj_t *waypoint, *ptera; + fixed_t c, s; + fixed_t rad = 280*FRACUNIT; + angle_t ang = 0; + angle_t interval, fa; + UINT8 amount = 1; + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnPterabytes", actor)) + return; +#endif + + if (actor->spawnpoint) + amount = actor->spawnpoint->extrainfo + 1; + + interval = FixedAngle(FRACUNIT*360/amount); + + for (i = 0; i < amount; i++) + { + fa = (ang >> ANGLETOFINESHIFT) & FINEMASK; + c = FINECOSINE(fa); + s = FINESINE(fa); + waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT); + waypoint->angle = ang + ANGLE_90; + P_SetTarget(&waypoint->tracer, actor); + ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE); + ptera->angle = waypoint->angle; + P_SetTarget(&ptera->tracer, waypoint); + ptera->extravalue1 = 0; + ang += interval; + } +} + +// Function: A_PterabyteHover +// +// Description: Hover in a circular fashion, bobbing up and down slightly. +// +// var1 = unused +// var2 = unused +// +void A_PterabyteHover(mobj_t *actor) +{ + angle_t ang, fa; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PterabyteHover", actor)) + return; +#endif + + P_InstaThrust(actor, actor->angle, actor->info->speed); + actor->angle += ANG1; + actor->extravalue1 = (actor->extravalue1 + 3) % 360; + ang = actor->extravalue1*ANG1; + fa = (ang >> ANGLETOFINESHIFT) & FINEMASK; + actor->z += FINESINE(fa); +} +// Function: A_RolloutSpawn +// +// Description: Spawns a new Rollout Rock when the currently spawned rock is destroyed or moves far enough away. +// +// var1 = Distance currently spawned rock should travel before spawning a new one +// var2 = Object type to spawn +// +void A_RolloutSpawn(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RolloutSpawn", actor)) + return; +#endif + + if (!(actor->target) + || P_MobjWasRemoved(actor->target) + || P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) > locvar1) + { + actor->target = P_SpawnMobj(actor->x, actor->y, actor->z, locvar2); + actor->target->flags2 |= (actor->flags2 & (MF2_AMBUSH | MF2_OBJECTFLIP)) | MF2_SLIDEPUSH; + actor->target->eflags |= (actor->eflags & MFE_VERTICALFLIP); + + if (actor->target->flags2 & MF2_AMBUSH) + { + actor->target->color = SKINCOLOR_SUPERRUST3; + actor->target->colorized = true; + } + } +} + +// Function: A_RolloutRock +// +// Description: Thinker for Rollout Rock. +// +// var1 = Drag +// var2 = Vertical bobbing speed factor +// +void A_RolloutRock(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + UINT8 maxframes = actor->info->reactiontime; // number of frames the mobj cycles through + fixed_t pi = (22*FRACUNIT/7); + fixed_t circumference = FixedMul(2 * pi, actor->radius); // used to calculate when to change frame + fixed_t speed = P_AproxDistance(actor->momx, actor->momy), topspeed = FixedMul(actor->info->speed, actor->scale); + boolean inwater = actor->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER); + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RolloutRock", actor)) + return; +#endif + + actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves + + if (actor->threshold) + actor->threshold--; + + if (inwater && !(actor->flags2 & MF2_AMBUSH)) // buoyancy in water (or lava) + { + UINT8 flip = P_MobjFlip(actor); + fixed_t prevmomz = actor->momz; + actor->momz = FixedMul(actor->momz, locvar2); + actor->momz += flip * FixedMul(locvar2, actor->scale); + if (flip*prevmomz < 0 && flip*actor->momz >= 0 && !actor->threshold) + { + if (actor->eflags & MFE_UNDERWATER) + S_StartSound(actor, sfx_splash); + else if (!actor->threshold) + S_StartSound(actor, sfx_splish); + actor->threshold = max((topspeed - speed) >> FRACBITS, 8); + } + } + + if (speed > topspeed) // cap speed + { + actor->momx = FixedMul(FixedDiv(actor->momx, speed), topspeed); + actor->momy = FixedMul(FixedDiv(actor->momy, speed), topspeed); + } + + if (P_IsObjectOnGround(actor) || inwater) // apply drag to speed (compensates for lack of friction but also works in liquids) + { + actor->momx = FixedMul(actor->momx, locvar1); + actor->momy = FixedMul(actor->momy, locvar1); + } + + speed = P_AproxDistance(actor->momx, actor->momy); // recalculate speed for visual rolling + + if (speed < actor->scale >> 1) // stop moving if speed is insignificant + { + actor->momx = 0; + actor->momy = 0; + } + else if (speed > actor->scale) + { + actor->movecount = 1; // rock has moved; fuse should be set so we don't have a trillion rocks lying around + actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); // set rock's angle to movement direction + actor->movefactor += speed; + if (actor->movefactor > circumference / maxframes) // if distance moved is enough to change frame, change it! + { + actor->reactiontime++; + actor->reactiontime %= maxframes; + actor->movefactor = 0; + } + } + + actor->frame = actor->reactiontime % maxframes; // set frame + + 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 + actor->fuse = actor->info->painchance; + + if (actor->fuse && actor->fuse < 2*TICRATE) + actor->flags2 ^= MF2_DONTDRAW; + +} diff --git a/src/p_floor.c b/src/p_floor.c index 7887dc530..1360375a7 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1778,6 +1778,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node) case MT_RAIN: case MT_SNOWFLAKE: case MT_SPLISH: + case MT_LAVASPLISH: case MT_SMOKE: case MT_SMALLBUBBLE: case MT_MEDIUMBUBBLE: @@ -2424,7 +2425,7 @@ void T_RaiseSector(levelspecthink_t *raise) mobj_t *thing; sector_t *sector; INT32 i; - boolean playeronme = false; + boolean playeronme = false, active = false; fixed_t ceilingdestination, floordestination; result_e res = 0; @@ -2458,8 +2459,53 @@ void T_RaiseSector(levelspecthink_t *raise) break; } } + + if (raise->vars[9]) // Dynamically Sinking Platform^tm + { +#define shaketime 10 + if (raise->vars[11] > shaketime) // State: moving + { + if (playeronme) // If player is standing on the platform, accelerate + { + raise->vars[10] += (FRACUNIT >> 5); + } + else // otherwise, decelerate until inflection + { + raise->vars[10] -= FRACUNIT >> 3; + if (raise->vars[10] <= 0) // inflection! + { + raise->vars[10] = 0; + raise->vars[11] = 0; // allow the shake to occur again (fucks over players attempting to jump-cheese) + } + } + active = raise->vars[10] > 0; + } + else // State: shaking + { + if (playeronme || raise->vars[11]) + { + active = true; + if (++raise->vars[11] > shaketime) + { + if (playeronme) + raise->vars[10] = FRACUNIT >> 5; + else + raise->vars[10] = FRACUNIT << 1; + } + else + { + raise->vars[10] = ((shaketime/2) - raise->vars[11]) << FRACBITS; + if (raise->vars[10] < -raise->vars[2]/2) + raise->vars[10] = -raise->vars[2]/2; + } + } + } +#undef shaketime + } + else // Air bobbing platform (not a Dynamically Sinking Platform^tm) + active = playeronme; - if (playeronme) + if (active) { raise->vars[3] = raise->vars[2]; @@ -2553,6 +2599,8 @@ void T_RaiseSector(levelspecthink_t *raise) raise->vars[3] = origspeed; } + raise->vars[3] += raise->vars[10]; + res = T_MovePlane ( raise->sector, // sector diff --git a/src/p_inter.c b/src/p_inter.c index ae5fce6ff..9017f795d 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -428,7 +428,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) || special->state == &states[S_FANG_BOUNCE4] || special->state == &states[S_FANG_PINCHBOUNCE3] || special->state == &states[S_FANG_PINCHBOUNCE4]) - && P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > -(special->height/4)) + && P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > (special->height/4)) { P_DamageMobj(toucher, special, special, 1, 0); P_SetTarget(&special->tracer, toucher); @@ -450,12 +450,18 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } } break; + case MT_PYREFLY: + if (special->extravalue2 == 2 && P_DamageMobj(player->mo, special, special, 1, DMG_FIRE)) + return; default: break; } if (P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object? { + if (special->type == MT_PTERABYTE && special->target == player->mo && special->extravalue1 == 1) + return; // Can't hurt a Pterabyte if it's trying to pick you up + if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) { if (elementalpierce == 2) @@ -471,13 +477,29 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->momy = -toucher->momy; if (player->charability == CA_FLY && player->panim == PA_ABILITY) toucher->momz = -toucher->momz/2; + else if (player->pflags & PF_GLIDING && !P_IsObjectOnGround(toucher)) + { + player->pflags &= ~(PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE); + P_SetPlayerMobjState(toucher, S_PLAY_FALL); + toucher->momz += P_MobjFlip(toucher) * (player->speed >> 3); + toucher->momx = 7*toucher->momx>>3; + toucher->momy = 7*toucher->momy>>3; + } + else if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) + && player->panim == PA_DASH) + P_DoPlayerPain(player, special, special); } P_DamageMobj(special, toucher, toucher, 1, 0); if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) P_TwinSpinRejuvenate(player, player->thokitem); } else + { + if (special->type == MT_PTERABYTE && special->target == player->mo) + return; // Don't hurt the player you're trying to grab + P_DamageMobj(toucher, special, special, 1, 0); + } return; } @@ -1074,7 +1096,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->exiting) return; - if (player->bumpertime < TICRATE/4) + if (player->bumpertime <= (TICRATE/2)-5) { S_StartSound(toucher, special->info->seesound); if (player->powers[pw_carry] == CR_NIGHTSMODE) @@ -1482,8 +1504,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetMobjState(mo2, mo2->info->painstate); } } - - S_StartSound(toucher, special->info->painsound); return; case MT_FAKEMOBILE: @@ -1509,10 +1529,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->momx = P_ReturnThrustX(special, angle, touchspeed); toucher->momy = P_ReturnThrustY(special, angle, touchspeed); toucher->momz = -toucher->momz; - if (player->pflags & PF_GLIDING) + if (player->pflags & PF_GLIDING && !P_IsObjectOnGround(toucher)) { player->pflags &= ~(PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE); P_SetPlayerMobjState(toucher, S_PLAY_FALL); + toucher->momz += P_MobjFlip(toucher) * (player->speed >> 3); + toucher->momx = 7*toucher->momx>>3; + toucher->momy = 7*toucher->momy>>3; } player->homing = 0; @@ -1557,10 +1580,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->momx = P_ReturnThrustX(special, special->angle, touchspeed); toucher->momy = P_ReturnThrustY(special, special->angle, touchspeed); toucher->momz = -toucher->momz; - if (player->pflags & PF_GLIDING) + if (player->pflags & PF_GLIDING && !P_IsObjectOnGround(toucher)) { player->pflags &= ~(PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE); P_SetPlayerMobjState(toucher, S_PLAY_FALL); + toucher->momz += P_MobjFlip(toucher) * (player->speed >> 3); + toucher->momx = 7*toucher->momx>>3; + toucher->momy = 7*toucher->momy>>3; } player->homing = 0; @@ -1595,6 +1621,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Buenos Dias Mandy P_SetPlayerMobjState(toucher, S_PLAY_STUN); player->pflags &= ~PF_APPLYAUTOBRAKE; + P_ResetPlayer(player); player->drawangle = special->angle + ANGLE_180; P_InstaThrust(toucher, special->angle, FixedMul(3*special->info->speed, special->scale/2)); toucher->z += P_MobjFlip(toucher); @@ -1700,13 +1727,15 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; if (mariomode) return; + if (special->state-states != S_EXTRALARGEBUBBLE) + return; // Don't grab the bubble during its spawn animation else if (toucher->eflags & MFE_VERTICALFLIP) { - if (special->z+special->height < toucher->z + toucher->height / 3 - || special->z+special->height > toucher->z + (toucher->height*2/3)) + if (special->z+special->height < toucher->z + || special->z+special->height > toucher->z + (toucher->height*2/3)) return; // Only go in the mouth } - else if (special->z < toucher->z + toucher->height / 3 + else if (special->z < toucher->z || special->z > toucher->z + (toucher->height*2/3)) return; // Only go in the mouth @@ -1762,7 +1791,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_MINECARTSPAWNER: - if (!special->fuse || 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); @@ -1772,7 +1801,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_ResetPlayer(player); player->pflags |= PF_JUMPDOWN; player->powers[pw_carry] = CR_MINECART; - toucher->player->pflags &= ~PF_APPLYAUTOBRAKE; + player->pflags &= ~PF_APPLYAUTOBRAKE; P_SetTarget(&toucher->tracer, mcart); toucher->momx = toucher->momy = toucher->momz = 0; @@ -2454,6 +2483,28 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->flags |= MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; P_SetThingPosition(target); + if (target->player->powers[pw_super]) + { + target->player->powers[pw_super] = 0; + if (P_IsLocalPlayer(target->player)) + { + music_stack_noposition = true; // HACK: Do not reposition next music + music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music + } + P_RestoreMusic(target->player); + + if (gametype != GT_COOP) + { + HU_SetCEchoFlags(0); + HU_SetCEchoDuration(5); + HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[target->player-players])); + } + } + + target->color = target->player->skincolor; + target->colorized = false; + G_GhostAddColor(GHC_NORMAL); + if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0)) ; else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != INFLIVES) @@ -2481,8 +2532,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget else if (P_IsLocalPlayer(target->player)) gameovermus = true; - if (gameovermus) - P_PlayJingle(target->player, JT_GOVER); // Yousa dead now, Okieday? Tails 03-14-2000 + if (gameovermus) // Yousa dead now, Okieday? Tails 03-14-2000 + S_ChangeMusicEx("_gover", 0, 0, 0, (2*MUSICRATE) - (MUSICRATE/25), 0); // 1.96 seconds + //P_PlayJingle(target->player, JT_GOVER); // can't be used because incompatible with track fadeout if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers) { @@ -2598,6 +2650,14 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } break; + case MT_BANPYURA: + if (target->tracer) + { + S_StopSound(target->tracer); + P_KillMobj(target->tracer, inflictor, source, damagetype); + } + break; + case MT_EGGSHIELD: P_SetObjectMomZ(target, 4*target->scale, false); P_InstaThrust(target, target->angle, 3*target->scale); @@ -3404,7 +3464,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Spectator handling - if (netgame) + if (multiplayer) { if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator) return false; @@ -3436,7 +3496,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Make sure that boxes cannot be popped by enemies, red rings, etc. - if (target->flags & MF_MONITOR && ((!source || !source->player || source->player->bot) || (inflictor && !inflictor->player))) + if (target->flags & MF_MONITOR && ((!source || !source->player || source->player->bot) + || (inflictor && inflictor->type >= MT_REDRING && inflictor->type <= MT_GRENADERING))) return false; } @@ -3518,7 +3579,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } - if (G_IsSpecialStage(gamemap)) + if (G_IsSpecialStage(gamemap) && !(damagetype & DMG_DEATHMASK)) { P_SpecialStageDamage(player, inflictor, source); return true; @@ -3542,10 +3603,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Instant-Death if (damagetype & DMG_DEATHMASK) - { P_KillPlayer(player, source, damage); - player->rings = player->spheres = 0; - } else if (metalrecording) { if (!inflictor) @@ -3580,7 +3638,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) return true; #endif - else if (player->powers[pw_shield] || player->bot) //If One-Hit Shield + else if (player->powers[pw_shield] || (player->bot && !ultimatemode)) //If One-Hit Shield { P_ShieldDamage(player, inflictor, source, damage, damagetype); damage = 0; diff --git a/src/p_local.h b/src/p_local.h index 662eb691a..02f497850 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -115,10 +115,10 @@ typedef struct camera_s extern camera_t camera, camera2; extern consvar_t cv_cam_dist, cv_cam_still, cv_cam_height; -extern consvar_t cv_cam_speed, cv_cam_rotate, cv_cam_rotspeed; +extern consvar_t cv_cam_speed, cv_cam_rotate, cv_cam_rotspeed, cv_cam_orbit, cv_cam_adjust; extern consvar_t cv_cam2_dist, cv_cam2_still, cv_cam2_height; -extern consvar_t cv_cam2_speed, cv_cam2_rotate, cv_cam2_rotspeed; +extern consvar_t cv_cam2_speed, cv_cam2_rotate, cv_cam2_rotspeed, cv_cam2_orbit, cv_cam2_adjust; extern fixed_t t_cam_dist, t_cam_height, t_cam_rotate; extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; @@ -303,7 +303,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); -boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover); +boolean P_CheckSolidLava(ffloor_t *rover); void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype); mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type); diff --git a/src/p_map.c b/src/p_map.c index 15fa97c8f..159489f70 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -124,6 +124,7 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) // Positive spring modes are minor variants of vanilla spring behaviour. // 1 = launch players in jump // 2 = don't modify player at all, just add momentum +// 3 = speed-booster mode (force onto ground, MF_AMBUSH causes auto-spin) // Negative spring modes are mildly-related gimmicks with customisation. // -1 = pinball bumper // Any other spring mode defaults to standard vanilla spring behaviour, @@ -151,7 +152,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (object->player) { - if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) + if (spring->info->painchance == 3) + ; + else if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) strong = 1; else if (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2) strong = 2; @@ -208,7 +211,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { angle_t nightsangle = 0; - if (object->player->bumpertime >= TICRATE/4) + if (object->player->bumpertime > (TICRATE/2)-5) return false; if ((object->player->pflags & PF_TRANSFERTOCLOSEST) && object->player->axis1 && object->player->axis2) @@ -286,7 +289,27 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (spring->info->painchance != 2) { if (object->player) + { object->player->pflags &= ~PF_APPLYAUTOBRAKE; +#ifndef SPRINGSPIN + object->player->powers[pw_justsprung] = 5; + if (horizspeed) + object->player->powers[pw_noautobrake] = ((horizspeed*TICRATE)>>(FRACBITS+3))/9; // TICRATE at 72*FRACUNIT + else if (P_MobjFlip(object) == P_MobjFlip(spring)) + object->player->powers[pw_justsprung] |= (1<<15); +#else + object->player->powers[pw_justsprung] = 15; + if (horizspeed) + object->player->powers[pw_noautobrake] = ((horizspeed*TICRATE)>>(FRACBITS+3))/9; // TICRATE at 72*FRACUNIT + else + { + if (abs(object->player->rmomx) > object->scale || abs(object->player->rmomy) > object->scale) + object->player->drawangle = R_PointToAngle2(0, 0, object->player->rmomx, object->player->rmomy); + if (P_MobjFlip(object) == P_MobjFlip(spring)) + object->player->powers[pw_justsprung] |= (1<<15); + } +#endif + } if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA { @@ -321,6 +344,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) // Set position! P_TryMove(object, spring->x + offx, spring->y + offy, true); + + if ((spring->info->painchance == 3)) + { + object->z = spring->z; + if (spring->eflags & MFE_VERTICALFLIP) + object->z -= object->height; + object->momz = 0; + } } } @@ -344,26 +375,36 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (horizspeed) { - object->player->drawangle = spring->angle; - if (vertispeed || (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0)) - { - object->angle = spring->angle; + object->angle = object->player->drawangle = spring->angle; - if (!demoplayback || P_AnalogMove(object->player)) - { - if (object->player == &players[consoleplayer]) - localangle = spring->angle; - else if (object->player == &players[secondarydisplayplayer]) - localangle2 = spring->angle; - } + if (!demoplayback || P_AnalogMove(object->player)) + { + if (object->player == &players[consoleplayer]) + localangle = spring->angle; + else if (object->player == &players[secondarydisplayplayer]) + localangle2 = spring->angle; } } - pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // I still need these. - secondjump = object->player->secondjump; - washoming = object->player->homing; if (object->player->pflags & PF_GLIDING) P_SetPlayerMobjState(object, S_PLAY_FALL); + if ((spring->info->painchance == 3)) + { + if (!(pflags = (object->player->pflags & PF_SPINNING)) && + (((object->player->charability2 == CA2_SPINDASH) && (object->player->cmd.buttons & BT_USE)) + || (spring->flags2 & MF2_AMBUSH))) + { + pflags = PF_SPINNING; + P_SetPlayerMobjState(object, S_PLAY_ROLL); + S_StartSound(object, sfx_spin); + } + else + P_SetPlayerMobjState(object, S_PLAY_ROLL); + } + else + pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // I still need these. + secondjump = object->player->secondjump; + washoming = object->player->homing; P_ResetPlayer(object->player); if (spring->info->painchance == 1) // For all those ancient, SOC'd abilities. @@ -371,7 +412,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->player->pflags |= P_GetJumpFlags(object->player); P_SetPlayerMobjState(object, S_PLAY_JUMP); } - else if ((spring->info->painchance == 2) || (pflags & PF_BOUNCING)) // Adding momentum only. + else if ((spring->info->painchance == 2) || ((spring->info->painchance != 3) && (pflags & PF_BOUNCING))) // Adding momentum only. { object->player->pflags |= (pflags &~ PF_STARTJUMP); object->player->secondjump = secondjump; @@ -385,6 +426,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->player->pflags |= pflags; object->player->secondjump = secondjump; } + else if (object->player->dashmode >= 3*TICRATE) + P_SetPlayerMobjState(object, S_PLAY_DASH); + else if (P_IsObjectOnGround(object) && horizspeed >= FixedMul(object->player->runspeed, object->scale)) + P_SetPlayerMobjState(object, S_PLAY_RUN); else P_SetPlayerMobjState(object, S_PLAY_WALK); } @@ -493,6 +538,42 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) } } +static void P_DoPterabyteCarry(player_t *player, mobj_t *ptera) +{ + if (player->powers[pw_carry] && players->powers[pw_carry] != CR_ROLLOUT) + return; + if (ptera->extravalue1 != 1) + return; // Not swooping + if (ptera->target != player->mo) + return; // Not swooping for you! + + if (player->spectator) + return; + + if ((player->mo->eflags & MFE_VERTICALFLIP) != (ptera->eflags & MFE_VERTICALFLIP)) + return; // Both should be in same gravity + + if (ptera->eflags & MFE_VERTICALFLIP) + { + if (ptera->ceilingz - (ptera->z + ptera->height) < player->mo->height - FixedMul(2*FRACUNIT, player->mo->scale)) + return; + } + else if (ptera->z - ptera->floorz < player->mo->height - FixedMul(2*FRACUNIT, player->mo->scale)) + return; // No room to pick up this guy! + + P_ResetPlayer(player); + P_SetTarget(&player->mo->tracer, ptera); + player->pflags &= ~PF_APPLYAUTOBRAKE; + player->powers[pw_carry] = CR_PTERABYTE; + S_StartSound(player->mo, sfx_s3k4a); + P_UnsetThingPosition(player->mo); + player->mo->x = ptera->x; + player->mo->y = ptera->y; + P_SetThingPosition(player->mo); + ptera->movefactor = 3*TICRATE; + ptera->watertop = ptera->waterbottom = ptera->cusval = 0; +} + static void P_DoTailsCarry(player_t *sonic, player_t *tails) { INT32 p; @@ -607,6 +688,34 @@ static void P_SlapStick(mobj_t *fang, mobj_t *pole) P_SetTarget(&pole->tracer, NULL); } +static void P_PlayerBarrelCollide(mobj_t *toucher, mobj_t *barrel) +{ + if (toucher->momz < 0) + { + if (toucher->z + toucher->momz > barrel->z + barrel->height) + return; + } + else + { + if (toucher->z > barrel->z + barrel->height) + return; + } + + if (toucher->momz > 0) + { + if (toucher->z + toucher->height + toucher->momz < barrel->z) + return; + } + else + { + if (toucher->z + toucher->height < barrel->z) + return; + } + + if (P_PlayerCanDamage(toucher->player, barrel)) + P_DamageMobj(barrel, toucher, toucher, 1, 0); +} + // // PIT_CheckThing // @@ -749,7 +858,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) + if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return true; // Don't collide with your buddies while NiGHTS-flying. @@ -857,6 +966,15 @@ static boolean PIT_CheckThing(mobj_t *thing) } #endif + if (tmthing->type == MT_LAVAFALL_LAVA && (thing->type == MT_RING || thing->type == MT_REDTEAMRING || thing->type == MT_BLUETEAMRING || thing->type == MT_FLINGRING)) + { + //height check + if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !(thing->health)) + return true; + + P_KillMobj(thing, tmthing, tmthing, DMG_FIRE); + } + if (tmthing->type == MT_MINECART) { //height check @@ -875,12 +993,11 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_SALOONDOOR && tmthing->player) { - if (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer) && tmthing->tracer->health) + 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) { - fixed_t dx = tmthing->tracer->momx; - fixed_t dy = tmthing->tracer->momy; - fixed_t dm = min(FixedHypot(dx, dy), 16*FRACUNIT); - angle_t ang = R_PointToAngle2(0, 0, dx, dy) - thing->angle; + fixed_t dm = min(FixedHypot(ref->momx, ref->momy), 16*FRACUNIT); + angle_t ang = R_PointToAngle2(0, 0, ref->momx, ref->momy) - thing->angle; fixed_t s = FINESINE((ang >> ANGLETOFINESHIFT) & FINEMASK); S_StartSound(tmthing, thing->info->activesound); thing->extravalue2 += 2*FixedMul(s, dm)/3; @@ -888,41 +1005,73 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - if (thing->type == MT_TNTBARREL && tmthing->player) + if (thing->type == MT_SALOONDOORCENTER && tmthing->player) { - if (tmthing->momz < 0) - { - if (tmthing->z + tmthing->momz > thing->z + thing->height) - return true; - } - else - { - if (tmthing->z > thing->z + thing->height) - return true; - } - - if (tmthing->momz > 0) - { - if (tmthing->z + tmthing->height + tmthing->momz < thing->z) - return true; - } - else - { - if (tmthing->z + tmthing->height < thing->z) - return true; - } - - if ((tmthing->player->pflags & (PF_SPINNING | PF_GLIDING)) - || ((tmthing->player->pflags & PF_JUMPED) - && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) - || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) - || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) - || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) - && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height / 2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) - || (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY))) - P_DamageMobj(thing, tmthing, tmthing, 1, 0); + if ((thing->flags & MF2_AMBUSH) || (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer))) + return true; } + if (thing->type == MT_ROLLOUTROCK && tmthing->player && tmthing->health) + { + if (tmthing->player->powers[pw_carry] == CR_ROLLOUT) + { + return true; + } + if ((thing->flags & MF_PUSHABLE) // not carrying a player + && (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something + && ((tmthing->eflags & MFE_VERTICALFLIP) == (thing->eflags & MFE_VERTICALFLIP)) + && (P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < (thing->radius)) + && (P_MobjFlip(tmthing)*tmthing->momz <= 0) + && ((!(tmthing->eflags & MFE_VERTICALFLIP) && abs(thing->z + thing->height - tmthing->z) < (thing->height>>2)) + || (tmthing->eflags & MFE_VERTICALFLIP && abs(tmthing->z + tmthing->height - thing->z) < (thing->height>>2)))) + { + thing->flags &= ~MF_PUSHABLE; // prevent riding player from applying pushable movement logic + thing->flags2 &= ~MF2_DONTDRAW; // don't leave the rock invisible if it was flashing prior to boarding + P_SetTarget(&thing->tracer, tmthing); + P_ResetPlayer(tmthing->player); + P_SetPlayerMobjState(tmthing, S_PLAY_WALK); + tmthing->player->powers[pw_carry] = CR_ROLLOUT; + P_SetTarget(&tmthing->tracer, thing); + P_SetObjectMomZ(thing, tmthing->momz, true); + return true; + } + } + else if (tmthing->type == MT_ROLLOUTROCK) + { + if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !thing->health) + return true; + + if (thing == tmthing->tracer) // don't collide with rider + return true; + + if (thing->flags & MF_SPRING) // bounce on springs + { + P_DoSpring(thing, tmthing); + return true; + } + else if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) == (MF_MONITOR|MF_SHOOTABLE) && !(tmthing->flags & MF_PUSHABLE)) // pop monitors while carrying a player + { + P_KillMobj(thing, tmthing, tmthing->tracer, 0); + return true; + } + + if (thing->type == tmthing->type // bounce against other rollout rocks + && (tmthing->momx || tmthing->momy || thing->momx || thing->momy)) + { + fixed_t tempmomx = thing->momx, tempmomy = thing->momy; + thing->momx = tmthing->momx; + thing->momy = tmthing->momy; + tmthing->momx = tempmomx; + tmthing->momy = tempmomy; + } + } + + if (thing->type == MT_PTERABYTE && tmthing->player) + P_DoPterabyteCarry(tmthing->player, thing); + + if (thing->type == MT_TNTBARREL && tmthing->player) + P_PlayerBarrelCollide(tmthing, thing); + if (thing->type == MT_VULTURE && tmthing->type == MT_VULTURE) { fixed_t dx = thing->x - tmthing->x; @@ -1022,7 +1171,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (tmthing->flags & MF_SHOOTABLE && thing->health > 0) { - UINT8 damagetype = (thing->info->mass & 0xFF); + UINT32 damagetype = (thing->info->mass & 0xFF); if (!damagetype && thing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8))) @@ -1039,7 +1188,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (thing->flags & MF_SHOOTABLE && tmthing->health > 0) { - UINT8 damagetype = (tmthing->info->mass & 0xFF); + UINT32 damagetype = (tmthing->info->mass & 0xFF); if (!damagetype && tmthing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8))) @@ -1563,8 +1712,8 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - if ((!tmthing->player) && (thing->player)) - ; // no solid thing should ever be able to step up onto a player + if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM) && (thing->player)) + ; // springs and gas jets should never be able to step up onto a player // z checking at last // Treat noclip things as non-solid! else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID @@ -1967,7 +2116,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) continue; } - if (thing->player && (P_CheckSolidLava(thing, rover) || P_CanRunOnWater(thing->player, rover))) + if (thing->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(thing->player, rover))) ; else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) ; @@ -2632,8 +2781,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->eflags |= MFE_JUSTSTEPPEDDOWN; } #ifdef ESLOPE - // HACK TO FIX DSZ2: apply only if slopes are involved - else if (tmceilingslope && tmceilingz < thingtop && thingtop - tmceilingz <= maxstep) + else if (tmceilingz < thingtop && thingtop - tmceilingz <= maxstep) { thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height; thing->ceilingrover = tmceilingrover; @@ -2648,8 +2796,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->eflags |= MFE_JUSTSTEPPEDDOWN; } #ifdef ESLOPE - // HACK TO FIX DSZ2: apply only if slopes are involved - else if (tmfloorslope && tmfloorz > thing->z && tmfloorz - thing->z <= maxstep) + else if (tmfloorz > thing->z && tmfloorz - thing->z <= maxstep) { thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; @@ -2884,11 +3031,8 @@ static boolean P_ThingHeightClip(mobj_t *thing) thing->z = thing->ceilingz - thing->height; } - if (thing->z != oldz) - { - if (thing->player) - P_PlayerHitFloor(thing->player, !onfloor); - } + if (P_MobjFlip(thing)*(thing->z - oldz) > 0 && thing->player) + P_PlayerHitFloor(thing->player, !onfloor); // debug: be sure it falls to the floor thing->eflags &= ~MFE_ONGROUND; @@ -3202,7 +3346,7 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) && glidesector->sector->ceilingpic == skyflatnum) return false; - if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < ceilingz) + if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < floorz) || (player->mo->z >= ceilingz)) floorclimb = true; } @@ -3340,13 +3484,13 @@ isblocking: && canclimb) { slidemo->angle = climbangle; - if (!demoplayback || P_AnalogMove(slidemo->player)) + /*if (!demoplayback || P_AnalogMove(slidemo->player)) { if (slidemo->player == &players[consoleplayer]) localangle = slidemo->angle; else if (slidemo->player == &players[secondarydisplayplayer]) localangle2 = slidemo->angle; - } + }*/ if (!slidemo->player->climbing) { @@ -3485,6 +3629,64 @@ stairstep: goto retry; } +static void P_CheckLavaWall(mobj_t *mo, sector_t *sec) +{ + ffloor_t *rover; + fixed_t topheight, bottomheight; + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!(rover->flags & FF_SWIMMABLE)) + continue; + + if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 3) + continue; + + if (rover->master->flags & ML_BLOCKMONSTERS) + continue; + + topheight = +#ifdef ESLOPE + *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : +#endif + *rover->topheight; + + if (mo->eflags & MFE_VERTICALFLIP) + { + if (topheight < mo->z - mo->height) + continue; + } + else + { + if (topheight < mo->z) + continue; + } + + bottomheight = +#ifdef ESLOPE + *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : +#endif + *rover->bottomheight; + + if (mo->eflags & MFE_VERTICALFLIP) + { + if (bottomheight > mo->z) + continue; + } + else + { + if (bottomheight > mo->z + mo->height) + continue; + } + + P_DamageMobj(mo, NULL, NULL, 1, DMG_FIRE); + return; + } +} + // // P_SlideMove // The momx / momy move is bad, so try to slide @@ -3645,6 +3847,12 @@ retry: P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy, PT_ADDLINES, PTR_SlideTraverse); + if (bestslideline && mo->player && bestslideline->sidenum[1] != 0xffff) + { + sector_t *sec = P_PointOnLineSide(mo->x, mo->y, bestslideline) ? bestslideline->frontsector : bestslideline->backsector; + P_CheckLavaWall(mo, sec); + } + // Some walls are bouncy even if you're not if (bestslideline && bestslideline->flags & ML_BOUNCY) { diff --git a/src/p_maputl.c b/src/p_maputl.c index 45fc82fbf..111103294 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -662,7 +662,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover))) + if (mobj->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(mobj->player, rover))) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) @@ -674,7 +674,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF + if (delta1 >= delta2 && (rover->flags & FF_INTANGABLEFLATS) != FF_PLATFORM) // thing is below FOF { if (bottomheight < opentop) { opentop = bottomheight; @@ -687,7 +687,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) highceiling = bottomheight; } - if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF + if (delta1 < delta2 && (rover->flags & FF_INTANGABLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF { if (topheight > openbottom) { openbottom = topheight; @@ -708,7 +708,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover))) + if (mobj->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(mobj->player, rover))) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) @@ -720,7 +720,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF + if (delta1 >= delta2 && (rover->flags & FF_INTANGABLEFLATS) != FF_PLATFORM) // thing is below FOF { if (bottomheight < opentop) { opentop = bottomheight; @@ -733,7 +733,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) highceiling = bottomheight; } - if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF + if (delta1 < delta2 && (rover->flags & FF_INTANGABLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF { if (topheight > openbottom) { openbottom = topheight; diff --git a/src/p_mobj.c b/src/p_mobj.c index 5a70932de..5735dc27b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1578,7 +1578,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) // Goop has slower, reversed gravity if (goopgravity) - gravityadd = -gravityadd/5; + gravityadd = -((gravityadd/5) + (gravityadd/8)); gravityadd = FixedMul(gravityadd, mo->scale); @@ -1990,6 +1990,8 @@ void P_XYMovement(mobj_t *mo) { mo->momz = transfermomz; mo->standingslope = NULL; + if (player->pflags & PF_SPINNING) + player->pflags = (player->pflags & ~PF_SPINNING) | (PF_JUMPED | PF_THOKKED); } } #endif @@ -2222,7 +2224,7 @@ void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype) topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); - if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should stand on lava or run on water + if (mo->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(mo->player, rover))) // only the player should stand on lava or run on water ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only continue; @@ -2369,9 +2371,9 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) return false; if (((mo->z <= mo->subsector->sector->floorheight - && !(mo->eflags & MFE_VERTICALFLIP) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR)) + && ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR)) || (mo->z + mo->height >= mo->subsector->sector->ceilingheight - && (mo->eflags & MFE_VERTICALFLIP) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING))) + && ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING))) && (GETSECSPECIAL(mo->subsector->sector->special, 1) == 6 || GETSECSPECIAL(mo->subsector->sector->special, 1) == 7)) return true; @@ -2379,23 +2381,11 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) return false; } -boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover) +boolean P_CheckSolidLava(ffloor_t *rover) { - I_Assert(mo != NULL); - I_Assert(!P_MobjWasRemoved(mo)); - - { - fixed_t topheight = - #ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : - #endif - *rover->topheight; - - if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 - && !(rover->master->flags & ML_BLOCKMONSTERS) - && ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale))) - return true; - } + if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 + && !(rover->master->flags & ML_BLOCKMONSTERS)) + return true; return false; } @@ -2954,7 +2944,7 @@ static void P_PlayerZMovement(mobj_t *mo) } // Get up if you fell. if (mo->player->panim == PA_PAIN) - P_SetPlayerMobjState(mo, S_PLAY_STND); + P_SetPlayerMobjState(mo, S_PLAY_WALK); #ifdef ESLOPE if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) { @@ -3330,7 +3320,7 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT; // Reset water state. - mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER); + mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER|MFE_TOUCHLAVA); for (rover = sector->ffloors; rover; rover = rover->next) { @@ -3371,16 +3361,18 @@ void P_MobjCheckWater(mobj_t *mobj) // Just touching the water? if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - height < bottomheight) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + height > topheight)) - { mobj->eflags |= MFE_TOUCHWATER; - if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY)) - mobj->eflags |= MFE_GOOWATER; - } + // Actually in the water? if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - (height>>1) > bottomheight) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + (height>>1) < topheight)) - { mobj->eflags |= MFE_UNDERWATER; + + if (mobj->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) + { + if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 3) + mobj->eflags |= MFE_TOUCHLAVA; + if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY)) mobj->eflags |= MFE_GOOWATER; } @@ -3444,9 +3436,18 @@ void P_MobjCheckWater(mobj_t *mobj) || ((mobj->eflags & MFE_VERTICALFLIP) && mobj->ceilingz-mobj->waterbottom <= height>>1)) return; - if (!wasgroundpounding && (mobj->eflags & MFE_GOOWATER || wasingoo)) { // Decide what happens to your momentum when you enter/leave goopy water. - if (P_MobjFlip(mobj)*mobj->momz < 0) // You are entering the goo? - mobj->momz = FixedMul(mobj->momz, FixedDiv(2*FRACUNIT, 5*FRACUNIT)); // kill momentum significantly, to make the goo feel thick. + if (mobj->eflags & MFE_GOOWATER || wasingoo) { // Decide what happens to your momentum when you enter/leave goopy water. + if (P_MobjFlip(mobj)*mobj->momz > 0) + { + mobj->momz -= (mobj->momz/8); // cut momentum a little bit to prevent multiple bobs + //CONS_Printf("leaving\n"); + } + else + { + if (!wasgroundpounding) + mobj->momz >>= 1; // kill momentum significantly, to make the goo feel thick. + //CONS_Printf("entering\n"); + } } else if (wasinwater && P_MobjFlip(mobj)*mobj->momz > 0) mobj->momz = FixedMul(mobj->momz, FixedDiv(780*FRACUNIT, 457*FRACUNIT)); // Give the mobj a little out-of-water boost. @@ -3458,14 +3459,15 @@ void P_MobjCheckWater(mobj_t *mobj) { // Spawn a splash mobj_t *splish; + mobjtype_t splishtype = (mobj->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH; if (mobj->eflags & MFE_VERTICALFLIP) { - splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[MT_SPLISH].height, mobj->scale), MT_SPLISH); + splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[splishtype].height, mobj->scale), splishtype); splish->flags2 |= MF2_OBJECTFLIP; splish->eflags |= MFE_VERTICALFLIP; } else - splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, MT_SPLISH); + splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype); splish->destscale = mobj->scale; P_SetScale(splish, mobj->scale); } @@ -3493,14 +3495,15 @@ void P_MobjCheckWater(mobj_t *mobj) { // Spawn a splash mobj_t *splish; + mobjtype_t splishtype = (mobj->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH; if (mobj->eflags & MFE_VERTICALFLIP) { - splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[MT_SPLISH].height, mobj->scale), MT_SPLISH); + splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[splishtype].height, mobj->scale), splishtype); splish->flags2 |= MF2_OBJECTFLIP; splish->eflags |= MFE_VERTICALFLIP; } else - splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, MT_SPLISH); + splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype); splish->destscale = mobj->scale; P_SetScale(splish, mobj->scale); } @@ -3516,6 +3519,8 @@ void P_MobjCheckWater(mobj_t *mobj) if (mobj->eflags & MFE_GOOWATER || wasingoo) S_StartSound(mobj, sfx_ghit); + else if (mobj->eflags & MFE_TOUCHLAVA) + S_StartSound(mobj, sfx_splash); else S_StartSound(mobj, sfx_splish); // And make a sound! @@ -3760,7 +3765,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled if (thiscam->momx || thiscam->momy) { - if (!P_TryCameraMove(thiscam->x + thiscam->momx, thiscam->y + thiscam->momy, thiscam)) + if (!P_TryCameraMove(thiscam->x + thiscam->momx, thiscam->y + thiscam->momy, thiscam)) // Thanks for the greatly improved camera, Lach -- Sev { // Never fails for 2D mode. mobj_t dummy; dummy.thinker.function.acp1 = (actionf_p1)P_MobjThinker; @@ -3770,9 +3775,22 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled dummy.z = thiscam->z; dummy.height = thiscam->height; if (!resetcalled && !(player->pflags & PF_NOCLIP) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. + { P_ResetCamera(player, thiscam); + resetcalled = true; + } else + { + fixed_t camspeed = P_AproxDistance(thiscam->momx, thiscam->momy); + P_SlideCameraMove(thiscam); + + if (!resetcalled && P_AproxDistance(thiscam->momx, thiscam->momy) == camspeed) + { + P_ResetCamera(player, thiscam); + resetcalled = true; + } + } if (resetcalled) // Okay this means the camera is fully reset. return true; } @@ -3981,6 +3999,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) } else { +#if 0 // i don't know why this is here, it's causing a few undesired state glitches, and disabling it doesn't appear to negatively affect the game, but i don't want it gone permanently just in case some obscure bug crops up if (!(mobj->player->powers[pw_carry] == CR_NIGHTSMODE)) // used for drilling mobj->player->pflags &= ~PF_STARTJUMP; mobj->player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); @@ -3990,6 +4009,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) mobj->player->powers[pw_tailsfly] = 0; P_SetPlayerMobjState(mobj, S_PLAY_WALK); } +#endif mobj->eflags &= ~MFE_JUSTHITFLOOR; } @@ -4111,6 +4131,45 @@ void P_RainThinker(precipmobj_t *mobj) P_SetPrecipMobjState(mobj, S_SPLASH1); } +static void P_KillRingsInLava(mobj_t *mo) +{ + msecnode_t *node; + I_Assert(mo != NULL); + I_Assert(!P_MobjWasRemoved(mo)); + + // go through all sectors being touched by the ring + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + if (!node->m_sector) + break; + + if (node->m_sector->ffloors) + { + ffloor_t *rover; + fixed_t topheight, bottomheight; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) // go through all fofs in the sector + { + if (!(rover->flags & FF_EXISTS)) continue; // fof must be real + + if (!(rover->flags & FF_SWIMMABLE // fof must be water + && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3)) // fof must be lava water + continue; + + // find heights of FOF + topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); + bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); + + if (mo->z <= topheight && mo->z + mo->height >= bottomheight) // if ring touches it, KILL IT + { + P_KillMobj(mo, NULL, NULL, DMG_FIRE); + return; + } + } + } + } +} + static void P_RingThinker(mobj_t *mobj) { if (mobj->momx || mobj->momy) @@ -4570,22 +4629,37 @@ static void P_Boss3Thinker(mobj_t *mobj) if (!mobj->movefactor) // to firing mode { - UINT8 i; - angle_t ang = 0; + UINT8 i, numtospawn = 24; + angle_t ang = 0, interval = FixedAngle((360 << FRACBITS) / numtospawn); + mobj_t *shock, *sfirst, *sprev = NULL; mobj->movecount = mobj->health+1; mobj->movefactor = -512*FRACUNIT; // shock the water! - for (i = 0; i < 64; i++) + for (i = 0; i < numtospawn; i++) { - mobj_t *shock = P_SpawnMobjFromMobj(mobj, 0, 0, 4*FRACUNIT, MT_SHOCK); + shock = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SHOCKWAVE); P_SetTarget(&shock->target, mobj); - P_InstaThrust(shock, ang, shock->info->speed); - P_CheckMissileSpawn(shock); - ang += (ANGLE_MAX/64); + shock->fuse = shock->info->painchance; + + if (i % 2 == 0) + P_SetMobjState(shock, shock->state->nextstate); + + if (!sprev) + sfirst = shock; + else + { + if (i == numtospawn - 1) + P_SetTarget(&shock->hnext, sfirst); + P_SetTarget(&sprev->hnext, shock); + } + + P_Thrust(shock, ang, shock->info->speed); + ang += interval; + sprev = shock; } - S_StartSound(mobj, sfx_fizzle); + S_StartSound(mobj, shock->info->seesound); // look for a new target P_BossTargetPlayer(mobj, false); @@ -4644,13 +4718,17 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz) } } +#define CEZ3TILT + // Pull them closer. static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) { INT32 s; mobj_t *base = mobj, *seg; - fixed_t originx, originy, workx, worky, dx, dy, bz = mobj->watertop+(8<watertop+(8<spawnpoint) { originx = mobj->spawnpoint->x << FRACBITS; @@ -4661,13 +4739,25 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) originx = mobj->x; originy = mobj->y; } +#else + if (mobj->spawnpoint) + { + rad -= R_PointToDist2(mobj->x, mobj->y, + (mobj->spawnpoint->x<spawnpoint->y<tracer)) // there are 10 per spoke, remember that { - dx = (originx + P_ReturnThrustX(mobj, angle, (9*132)<x)/9; - dy = (originy + P_ReturnThrustY(mobj, angle, (9*132)<y)/9; +#ifdef CEZ3TILT + dx = (originx + P_ReturnThrustX(mobj, angle, rad) - mobj->x)/9; + dy = (originy + P_ReturnThrustY(mobj, angle, rad) - mobj->y)/9; +#else + dx = P_ReturnThrustX(mobj, angle, rad)/9; + dy = P_ReturnThrustY(mobj, angle, rad)/9; +#endif workx = mobj->x + P_ReturnThrustX(mobj, angle, (112)<y + P_ReturnThrustY(mobj, angle, (112)<hnext, --s) @@ -4857,6 +4947,7 @@ static void P_Boss4Thinker(mobj_t *mobj) mobj->movecount += mobj->threshold; if (mobj->movecount <= 0) { + mobj->flags2 &= ~MF2_INVERTAIMABLE; mobj->movecount = 0; mobj->movedir++; // Initialization complete, next phase! } @@ -5028,6 +5119,24 @@ static void P_Boss5Thinker(mobj_t *mobj) { if (!mobj->health) { + if (mobj->fuse) + { + if (mobj->flags2 & MF2_SLIDEPUSH) + { + INT32 trans = 10-((10*mobj->fuse)/70); + if (trans > 9) + trans = 9; + if (trans < 0) + trans = 0; + mobj->frame = (mobj->frame & ~FF_TRANSMASK)|(trans<fuse & 1)) + { + mobj->colorized = !mobj->colorized; + mobj->frame ^= FF_FULLBRIGHT; + } + } + return; + } if (mobj->state == &states[mobj->info->xdeathstate]) mobj->momz -= (2*FRACUNIT)/3; else if (mobj->tracer && P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y) < 2*mobj->radius) @@ -6986,6 +7095,16 @@ void P_HandleMinecartSegments(mobj_t *mobj) P_UpdateMinecartSegments(mobj); } +static void P_PyreFlyBurn(mobj_t *mobj, fixed_t hoffs, INT16 vrange, mobjtype_t mobjtype, fixed_t momz) +{ + angle_t fa = (FixedAngle(P_RandomKey(360)*FRACUNIT) >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t xoffs = FixedMul(FINECOSINE(fa), mobj->radius + hoffs); + fixed_t yoffs = FixedMul(FINESINE(fa), mobj->radius + hoffs); + fixed_t zoffs = P_RandomRange(-vrange, vrange)*FRACUNIT; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, zoffs, mobjtype); + particle->momz = momz; +} + // // P_MobjThinker // @@ -7276,7 +7395,8 @@ void P_MobjThinker(mobj_t *mobj) case MT_FLAMEAURA_ORB: if (!(mobj->flags2 & MF2_SHIELD)) return; - mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield + if ((statenum_t)(mobj->state-states) < mobj->info->painstate) + mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield if (mobj->tracer /* && mobj->target -- the following is implicit by P_AddShield && mobj->target->player @@ -7451,6 +7571,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->fuse -= 2; flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); + P_SetMobjState(flame, S_FLAMEJETFLAME4); flame->angle = mobj->angle; @@ -7495,7 +7616,10 @@ void P_MobjThinker(mobj_t *mobj) flame->momz = -strength; } else + { flame->momz = strength; + P_SetMobjState(flame, S_FLAMEJETFLAME7); + } P_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT,3*FRACUNIT)); S_StartSound(flame, sfx_fire); } @@ -7550,6 +7674,7 @@ void P_MobjThinker(mobj_t *mobj) case MT_ROCKCRUMBLE16: case MT_WOODDEBRIS: case MT_BRICKDEBRIS: + case MT_BROKENROBOT: if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) && mobj->state != &states[mobj->info->deathstate]) { @@ -7614,6 +7739,248 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->movedir) mobj->angle += mobj->movedir; break; + case MT_ROSY: + { + UINT8 i; + fixed_t pdist = 1700*mobj->scale, work, actualwork; + player_t *player = NULL; + statenum_t stat = (mobj->state-states); + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (!players[i].mo) + continue; + if (players[i].bot) + continue; + if (!players[i].mo->health) + continue; + actualwork = work = FixedHypot(mobj->x-players[i].mo->x, mobj->y-players[i].mo->y); + if (player) + { + if (players[i].skin == 0 || players[i].skin == 5) + work = (2*work)/3; + if (work >= pdist) + continue; + } + pdist = actualwork; + player = &players[i]; + } + + if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN) + { + if (P_IsObjectOnGround(mobj)) + { + mobj->momx = mobj->momy = 0; + if (player && mobj->cvmem < (-2*TICRATE)) + stat = S_ROSY_UNHAPPY; + else + stat = S_ROSY_WALK; + P_SetMobjState(mobj, stat); + } + else if (P_MobjFlip(mobj)*mobj->momz < 0) + mobj->frame = mobj->state->frame+mobj->state->var1; + } + + if (!player) + { + if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP) + { + mobj->momx = mobj->momy = 0; + P_SetMobjState(mobj, S_ROSY_IDLE1); + } + } + else + { + boolean dojump = false, targonground, love, makeheart = false; + if (mobj->target != player->mo) + P_SetTarget(&mobj->target, player->mo); + targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN)); + love = (player->skin == 0 || player->skin == 5); + + switch (stat) + { + case S_ROSY_IDLE1: + case S_ROSY_IDLE2: + case S_ROSY_IDLE3: + case S_ROSY_IDLE4: + dojump = true; + break; + case S_ROSY_JUMP: + case S_ROSY_PAIN: + // handled above + break; + case S_ROSY_WALK: + { + fixed_t x = mobj->x, y = mobj->y, z = mobj->z; + angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y); + boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false); + + P_UnsetThingPosition(mobj); + mobj->x = x; + mobj->y = y; + mobj->z = z; + P_SetThingPosition(mobj); + + if (allowed) + { + fixed_t mom, max; + P_Thrust(mobj, angletoplayer, (3*FRACUNIT)>>1); + mom = FixedHypot(mobj->momx, mobj->momy); + max = pdist; + if ((--mobj->extravalue1) <= 0) + { + if (++mobj->frame > mobj->state->frame+mobj->state->var1) + mobj->frame = mobj->state->frame; + if (mom > 12*mobj->scale) + mobj->extravalue1 = 2; + else if (mom > 6*mobj->scale) + mobj->extravalue1 = 3; + else + mobj->extravalue1 = 4; + } + if (max < (mobj->radius + mobj->target->radius)) + { + mobj->momx = mobj->target->player->cmomx; + mobj->momy = mobj->target->player->cmomy; + if ((mobj->cvmem > TICRATE && !player->exiting) || !targonground) + P_SetMobjState(mobj, (stat = S_ROSY_STND)); + else + { + mobj->target->momx = mobj->momx; + mobj->target->momy = mobj->momy; + P_SetMobjState(mobj, (stat = S_ROSY_HUG)); + S_StartSound(mobj, sfx_cdpcm6); + mobj->angle = angletoplayer; + } + } + else + { + max /= 3; + if (max > 30*mobj->scale) + max = 30*mobj->scale; + if (mom > max && max > mobj->scale) + { + max = FixedDiv(max, mom); + mobj->momx = FixedMul(mobj->momx, max); + mobj->momy = FixedMul(mobj->momy, max); + } + if (abs(mobj->momx) > mobj->scale || abs(mobj->momy) > mobj->scale) + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + } + } + else + dojump = true; + } + break; + case S_ROSY_HUG: + if (targonground) + { + player->pflags |= PF_STASIS; + if (mobj->cvmem < 5*TICRATE) + mobj->cvmem++; + if (love && !(leveltime & 7)) + makeheart = true; + } + else + { + if (mobj->cvmem < (love ? 5*TICRATE : 0)) + { + P_SetMobjState(mobj, (stat = S_ROSY_PAIN)); + S_StartSound(mobj, sfx_cdpcm7); + } + else + P_SetMobjState(mobj, (stat = S_ROSY_JUMP)); + var1 = var2 = 0; + A_DoNPCPain(mobj); + mobj->cvmem -= TICRATE; + } + break; + case S_ROSY_STND: + if ((pdist > (mobj->radius + mobj->target->radius + 3*(mobj->scale + mobj->target->scale)))) + P_SetMobjState(mobj, (stat = S_ROSY_WALK)); + else if (!targonground) + ; + else + { + if (love && !(leveltime & 15)) + makeheart = true; + if (player->exiting || --mobj->cvmem < TICRATE) + { + P_SetMobjState(mobj, (stat = S_ROSY_HUG)); + S_StartSound(mobj, sfx_cdpcm6); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + mobj->target->momx = mobj->momx; + mobj->target->momy = mobj->momy; + } + } + break; + case S_ROSY_UNHAPPY: + default: + break; + } + + if (stat == S_ROSY_HUG) + { + if (player->panim != PA_IDLE) + P_SetPlayerMobjState(mobj->target, S_PLAY_STND); + player->pflags |= PF_STASIS; + } + + if (dojump) + { + P_SetMobjState(mobj, S_ROSY_JUMP); + mobj->z += P_MobjFlip(mobj); + mobj->momx = mobj->momy = 0; + P_SetObjectMomZ(mobj, 6<height, MT_CDLHRT); + cdlhrt->destscale = (5*mobj->scale)>>4; + P_SetScale(cdlhrt, cdlhrt->destscale); + cdlhrt->fuse = (5*TICRATE)>>1; + cdlhrt->momz = mobj->scale; + P_SetTarget(&cdlhrt->target, mobj); + cdlhrt->extravalue1 = mobj->x; + cdlhrt->extravalue2 = mobj->y; + } + } + } + break; + case MT_CDLHRT: + { + if (mobj->cvmem < 24) + mobj->cvmem++; + mobj->movedir += ANG10; + P_UnsetThingPosition(mobj); + mobj->x = mobj->extravalue1 + P_ReturnThrustX(mobj, mobj->movedir, mobj->cvmem*mobj->scale); + mobj->y = mobj->extravalue2 + P_ReturnThrustY(mobj, mobj->movedir, mobj->cvmem*mobj->scale); + P_SetThingPosition(mobj); + if ((--mobj->fuse) < 6) + { + if (!mobj->fuse) + { + P_RemoveMobj(mobj); + return; + } + mobj->frame = (mobj->frame & ~FF_TRANSMASK)|((10-(mobj->fuse*2))<<(FF_TRANSSHIFT)); + } + } + break; + case MT_VWREF: + case MT_VWREB: + { + INT32 strength; + ++mobj->movedir; + mobj->frame &= ~FF_TRANSMASK; + strength = min(mobj->fuse, (INT32)mobj->movedir)*3; + if (strength < 10) + mobj->frame |= ((10-strength)<<(FF_TRANSSHIFT)); + } + /* FALLTHRU */ default: if (mobj->fuse) { // Scenery object fuse! Very basic! @@ -8816,13 +9183,17 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_RING: + case MT_REDTEAMRING: + case MT_BLUETEAMRING: + P_KillRingsInLava(mobj); + if (P_MobjWasRemoved(mobj)) + return; + /* FALLTHRU */ case MT_COIN: case MT_BLUESPHERE: case MT_BOMBSPHERE: case MT_NIGHTSCHIP: case MT_NIGHTSSTAR: - case MT_REDTEAMRING: - case MT_BLUETEAMRING: // No need to check water. Who cares? P_RingThinker(mobj); if (mobj->flags2 & MF2_NIGHTSPULL) @@ -8832,6 +9203,10 @@ void P_MobjThinker(mobj_t *mobj) return; // Flung items case MT_FLINGRING: + P_KillRingsInLava(mobj); + if (P_MobjWasRemoved(mobj)) + return; + /* FALLTHRU */ case MT_FLINGCOIN: case MT_FLINGBLUESPHERE: case MT_FLINGNIGHTSCHIP: @@ -9033,6 +9408,159 @@ void P_MobjThinker(mobj_t *mobj) } mobj->flags2 ^= MF2_DONTDRAW; break; + case MT_LAVAFALLROCK: + if (P_IsObjectOnGround(mobj)) + P_RemoveMobj(mobj); + break; + case MT_PYREFLY: + { + fixed_t hdist; + + mobj->extravalue1 = (mobj->extravalue1 + 3) % 360; + mobj->z += FINESINE(((mobj->extravalue1*ANG1) >> ANGLETOFINESHIFT) & FINEMASK); + + if (!(mobj->flags2 & MF2_BOSSNOTRAP)) + P_LookForPlayers(mobj, true, false, 1500*FRACUNIT); + + if (!mobj->target) + break; + + if (mobj->extravalue2 == 1) + P_PyreFlyBurn(mobj, 0, 20, MT_SMOKE, 4*FRACUNIT); + else if (mobj->extravalue2 == 2) + { + INT32 fireradius = min(100 - mobj->fuse, 52); + P_PyreFlyBurn(mobj, P_RandomRange(0, fireradius)*FRACUNIT, 20, MT_FLAMEPARTICLE, 4*FRACUNIT); + P_PyreFlyBurn(mobj, fireradius*FRACUNIT, 40, MT_PYREFLY_FIRE, 0); + } + + hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + + if (!(mobj->flags2 & MF2_BOSSNOTRAP) && hdist <= 450*FRACUNIT) + mobj->flags2 |= MF2_BOSSNOTRAP; + + if (!(mobj->flags2 & MF2_BOSSNOTRAP)) + break; + + if (hdist < 1000*FRACUNIT) + { + //Aim for player z position. If too close to floor/ceiling, aim just above/below them. + fixed_t destz = min(max(mobj->target->z, mobj->target->floorz + 70*FRACUNIT), mobj->target->ceilingz - 80*FRACUNIT - mobj->height); + fixed_t dist = P_AproxDistance(hdist, destz - mobj->z); + P_InstaThrust(mobj, R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y), 2*FRACUNIT); + mobj->momz = FixedMul(FixedDiv(destz - mobj->z, dist), 2*FRACUNIT); + } + else + { + mobj->momx = 0; + mobj->momy = 0; + mobj->momz = 0; + if (hdist >= 1500*FRACUNIT) + { + mobj->flags2 &= ~MF2_BOSSNOTRAP; + P_SetTarget(&mobj->target, NULL); + } + } + break; + } + case MT_PTERABYTE: + { + if (mobj->extravalue1 & 4) // Cooldown after grabbing + { + if (mobj->movefactor) + mobj->movefactor--; + else + { + P_SetTarget(&mobj->target, NULL); + mobj->extravalue1 &= 3; + } + } + + if ((mobj->extravalue1 & 3) == 0) // Hovering + { + fixed_t vdist, hdist, time; + fixed_t hspeed = 3*mobj->info->speed; + angle_t fa; + + var1 = 1; + var2 = 0; + A_CapeChase(mobj); + + if (mobj->target) + break; // Still carrying a player or in cooldown + + P_LookForPlayers(mobj, true, false, 256*FRACUNIT); + + if (!mobj->target) + break; + + if (mobj->target->player->powers[pw_flashing]) + { + P_SetTarget(&mobj->target, NULL); + break; + } + + vdist = mobj->z - mobj->target->z - mobj->target->height; + if (P_MobjFlip(mobj)*vdist <= 0) + { + P_SetTarget(&mobj->target, NULL); + break; + } + + hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + if (hdist > 450*FRACUNIT) + { + P_SetTarget(&mobj->target, NULL); + break; + } + + P_SetMobjState(mobj, S_PTERABYTE_SWOOPDOWN); + mobj->extravalue1++; + S_StartSound(mobj, mobj->info->attacksound); + time = FixedDiv(hdist, hspeed); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + fa = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; + mobj->momx = FixedMul(FINECOSINE(fa), hspeed); + mobj->momy = FixedMul(FINESINE(fa), hspeed); + mobj->momz = -2*FixedDiv(vdist, time); + mobj->extravalue2 = -FixedDiv(mobj->momz, time); //Z accel + mobj->movecount = time >> FRACBITS; + mobj->reactiontime = mobj->movecount; + } + else if ((mobj->extravalue1 & 3) == 1) // Swooping + { + mobj->reactiontime--; + mobj->momz += mobj->extravalue2; + if (mobj->reactiontime) + break; + + if (mobj->state - states == S_PTERABYTE_SWOOPDOWN) + { + P_SetMobjState(mobj, S_PTERABYTE_SWOOPUP); + mobj->reactiontime = mobj->movecount; + } + else if (mobj->state - states == S_PTERABYTE_SWOOPUP) + { + P_SetMobjState(mobj, S_PTERABYTE_FLY1); + mobj->extravalue1++; + if (mobj->target && mobj->target->tracer != mobj) + P_SetTarget(&mobj->target, NULL); // Failed to grab the target + mobj->momx = mobj->momy = mobj->momz = 0; + } + } + else // Returning + { + var1 = 2*mobj->info->speed; + var2 = 1; + A_HomingChase(mobj); + if (P_AproxDistance(mobj->x - mobj->tracer->x, mobj->y - mobj->tracer->y) <= mobj->info->speed) + { + mobj->extravalue1 -= 2; + mobj->momx = mobj->momy = mobj->momz = 0; + } + } + break; + } case MT_SPINFIRE: if (mobj->flags & MF_NOGRAVITY) { @@ -9063,9 +9591,12 @@ void P_MobjThinker(mobj_t *mobj) { if (mobj->state->action.acp1 == (actionf_p1)A_Boss1Laser) { - /*var1 = mobj->state->var1; - var2 = mobj->state->var2 & 65535; - mobj->state->action.acp1(mobj);*/ + if (mobj->state->tics > 1) + { + var1 = mobj->state->var1; + var2 = mobj->state->var2 & 65535; + mobj->state->action.acp1(mobj); + } } else if (leveltime & 1) // Fire mode { @@ -9231,6 +9762,18 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s } P_RemoveMobj(mobj); return; + case MT_FANG: + if (mobj->flags2 & MF2_SLIDEPUSH) + { + var1 = 0; + var2 = 0; + A_BossDeath(mobj); + return; + } + P_SetMobjState(mobj, mobj->state->nextstate); + if (P_MobjWasRemoved(mobj)) + return; + break; case MT_METALSONIC_BATTLE: break; // don't remove case MT_SPIKE: @@ -9248,6 +9791,52 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s case MT_NIGHTSCORE: P_RemoveMobj(mobj); return; + case MT_LAVAFALL: + if (mobj->state - states == S_LAVAFALL_DORMANT) + { + mobj->fuse = 30; + P_SetMobjState(mobj, S_LAVAFALL_TELL); + S_StartSound(mobj, mobj->info->seesound); + } + else if (mobj->state - states == S_LAVAFALL_TELL) + { + mobj->fuse = 40; + P_SetMobjState(mobj, S_LAVAFALL_SHOOT); + S_StopSound(mobj); + S_StartSound(mobj, mobj->info->attacksound); + } + else + { + mobj->fuse = 30; + P_SetMobjState(mobj, S_LAVAFALL_DORMANT); + S_StopSound(mobj); + } + return; + case MT_PYREFLY: + if (mobj->health <= 0) + break; + + mobj->extravalue2 = (mobj->extravalue2 + 1) % 3; + if (mobj->extravalue2 == 0) + { + P_SetMobjState(mobj, mobj->info->spawnstate); + mobj->fuse = 100; + S_StopSound(mobj); + S_StartSound(mobj, sfx_s3k8c); + } + else if (mobj->extravalue2 == 1) + { + mobj->fuse = 50; + S_StartSound(mobj, sfx_s3ka3); + } + else + { + P_SetMobjState(mobj, mobj->info->meleestate); + mobj->fuse = 100; + S_StopSound(mobj); + S_StartSound(mobj, sfx_s3kc2l); + } + return; case MT_PLAYER: break; // don't remove default: @@ -9717,6 +10306,15 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->reactiontime >>= 1; } break; + case MT_BANPYURA: + { + mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BANPSPRING); + bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; + P_SetTarget(&mobj->tracer, bigmeatyclaw); + P_SetTarget(&bigmeatyclaw->tracer, mobj); + mobj->reactiontime >>= 1; + } + break; case MT_BIGMINE: mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; break; @@ -9742,6 +10340,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->movefactor = -512*FRACUNIT; mobj->flags2 |= MF2_CLASSICPUSH; break; + case MT_EGGMOBILE4: + mobj->flags2 |= MF2_INVERTAIMABLE; + break; case MT_FLICKY_08: mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUA); break; @@ -9800,11 +10401,14 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_METALSONIC_BATTLE: case MT_METALSONIC_RACE: - sc = 3; + sc = 5; break; case MT_FANG: sc = 4; break; + case MT_ROSY: + sc = 3; + break; case MT_CORK: mobj->flags2 |= MF2_SUPERFIRE; break; @@ -9820,16 +10424,28 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } case MT_TNTBARREL: mobj->momx = 1; //stack hack + mobj->flags2 |= MF2_INVERTAIMABLE; break; case MT_MINECARTEND: P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID)); mobj->tracer->angle = mobj->angle + ANGLE_90; break; + case MT_TORCHFLOWER: + { + mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME); + P_SetTarget(&mobj->target, fire); + break; + } + case MT_PYREFLY: + mobj->extravalue1 = (FixedHypot(mobj->x, mobj->y)/FRACUNIT) % 360; + mobj->extravalue2 = 0; + mobj->fuse = 100; + break; default: break; } - if (sc != -1) + if (sc != -1 && !(mobj->flags2 & MF2_SLIDEPUSH)) { UINT8 i; for (i = 0; i < MAXPLAYERS; i++) @@ -9841,6 +10457,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj->color = SKINCOLOR_SILVER; mobj->colorized = true; + mobj->flags2 |= MF2_SLIDEPUSH; break; } } @@ -10141,7 +10758,7 @@ void P_SpawnPrecipitation(void) if (curWeather == PRECIP_SNOW) { // Not in a sector with visible sky -- exception for NiGHTS. - if (!(maptol & TOL_NIGHTS) && precipsector->sector->ceilingpic != skyflatnum) + if ((!(maptol & TOL_NIGHTS) && (precipsector->sector->ceilingpic != skyflatnum)) == !(precipsector->sector->flags & SF_INVERTPRECIP)) continue; rainmo = P_SpawnSnowMobj(x, y, height, MT_SNOWFLAKE); @@ -10154,7 +10771,7 @@ void P_SpawnPrecipitation(void) else // everything else. { // Not in a sector with visible sky. - if (precipsector->sector->ceilingpic != skyflatnum) + if ((precipsector->sector->ceilingpic != skyflatnum) == !(precipsector->sector->flags & SF_INVERTPRECIP)) continue; rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN); @@ -10412,7 +11029,7 @@ void P_SpawnPlayer(INT32 playernum) mobj_t *mobj; if (p->playerstate == PST_REBORN) - G_PlayerReborn(playernum); + G_PlayerReborn(playernum, false); // spawn as spectator determination if (!G_GametypeHasSpectators()) @@ -10420,9 +11037,9 @@ void P_SpawnPlayer(INT32 playernum) p->spectator = p->outofcoop = (((multiplayer || netgame) && gametype == GT_COOP) // only question status in coop && ((leveltime > 0 - && ((G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) // late join special stage + && ((G_IsSpecialStage(gamemap)) // late join special stage || (cv_coopstarposts.value == 2 && (p->jointime < 1 || p->outofcoop)))) // late join or die in new coop - || (((cv_cooplives.value == 1) || !P_GetLives(p)) && p->lives <= 0))); // game over and can't redistribute lives + || (!P_GetLives(p) && p->lives <= 0))); // game over and can't redistribute lives } else { @@ -10489,7 +11106,6 @@ void P_SpawnPlayer(INT32 playernum) P_SetupStateAnimation(mobj, mobj->state); mobj->health = 1; - p->rings = p->spheres = 0; p->playerstate = PST_LIVE; p->bonustime = false; @@ -10975,6 +11591,16 @@ You should think about modifying the deathmatch starts to take full advantage of // They're likely facets of the level's design and therefore required to progress. } + if (i == MT_ROSY) + { + if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA))) + return; // she doesn't hang out here + else if (mariomode) + i = MT_TOAD; // don't remove on penalty of death + else if (!(netgame || multiplayer) && players[consoleplayer].skin == 3) + return; // no doubles + } + if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++))) return; // you already got this token, or there are too many, or the gametype's not right @@ -11188,6 +11814,17 @@ You should think about modifying the deathmatch starts to take full advantage of else mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; break; + case MT_METALSONIC_RACE: + case MT_METALSONIC_BATTLE: + case MT_FANG: + case MT_ROSY: + if (mthing->options & MTF_EXTRA) + { + mobj->color = SKINCOLOR_SILVER; + mobj->colorized = true; + mobj->flags2 |= MF2_SLIDEPUSH; + } + break; case MT_BALLOON: if (mthing->angle > 0) mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1; @@ -11852,6 +12489,108 @@ ML_EFFECT5 : Don't stop thinking when too far away if (mthing->angle > 0) mobj->tics += mthing->angle; break; + case MT_LAVAFALL: + mobj->fuse = 30 + mthing->angle; + if (mthing->options & MTF_AMBUSH) + { + P_SetScale(mobj, 2*mobj->scale); + mobj->destscale = mobj->scale; + } + break; + case MT_PYREFLY: + //start on fire if Ambush flag is set, otherwise behave normally + if (mthing->options & MTF_AMBUSH) + { + P_SetMobjState(mobj, mobj->info->meleestate); + mobj->extravalue2 = 2; + S_StartSound(mobj, sfx_s3kc2l); + } + break; + case MT_BIGFERN: + { + angle_t angle = FixedAngle(mthing->angle << FRACBITS); + UINT8 j; + for (j = 0; j < 8; j++) + { + angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t xoffs = FINECOSINE(fa); + fixed_t yoffs = FINESINE(fa); + mobj_t *leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); + leaf->angle = angle; + angle += ANGLE_45; + } + break; + } + case MT_REDBOOSTER: + { + angle_t angle = FixedAngle(mthing->angle << FRACBITS); + fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t x2 = FINECOSINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t y2 = FINESINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); + + mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); + seg->angle = angle-ANGLE_90; + P_SetMobjState(seg, S_REDBOOSTERSEG_FACE); + seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); + seg->angle = angle+ANGLE_90; + P_SetMobjState(seg, S_REDBOOSTERSEG_FACE); + seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); + seg->angle = angle; + P_SetMobjState(seg, S_REDBOOSTERSEG_LEFT); + seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); + seg->angle = angle; + P_SetMobjState(seg, S_REDBOOSTERSEG_RIGHT); + + seg = P_SpawnMobjFromMobj(mobj, 13*(x1+x2), 13*(y1+y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_REDBOOSTERROLLER); + seg = P_SpawnMobjFromMobj(mobj, 13*(x1-x2), 13*(y1-y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_REDBOOSTERROLLER); + seg = P_SpawnMobjFromMobj(mobj, -13*(x1+x2), -13*(y1+y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_REDBOOSTERROLLER); + seg = P_SpawnMobjFromMobj(mobj, -13*(x1-x2), -13*(y1-y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_REDBOOSTERROLLER); + break; + } + case MT_YELLOWBOOSTER: + { + angle_t angle = FixedAngle(mthing->angle << FRACBITS); + fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t x2 = FINECOSINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t y2 = FINESINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); + + mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); + seg->angle = angle-ANGLE_90; + P_SetMobjState(seg, S_YELLOWBOOSTERSEG_FACE); + seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); + seg->angle = angle+ANGLE_90; + P_SetMobjState(seg, S_YELLOWBOOSTERSEG_FACE); + seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); + seg->angle = angle; + P_SetMobjState(seg, S_YELLOWBOOSTERSEG_LEFT); + seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); + seg->angle = angle; + P_SetMobjState(seg, S_YELLOWBOOSTERSEG_RIGHT); + + seg = P_SpawnMobjFromMobj(mobj, 13*(x1+x2), 13*(y1+y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); + seg = P_SpawnMobjFromMobj(mobj, 13*(x1-x2), 13*(y1-y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); + seg = P_SpawnMobjFromMobj(mobj, -13*(x1+x2), -13*(y1+y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); + seg = P_SpawnMobjFromMobj(mobj, -13*(x1-x2), -13*(y1-y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); + break; + } default: break; } @@ -12050,7 +12789,7 @@ ML_EFFECT5 : Don't stop thinking when too far away { if (mthing->options & MTF_AMBUSH) { - if (i == MT_YELLOWDIAG || i == MT_REDDIAG) + if (i == MT_YELLOWDIAG || i == MT_REDDIAG || i == MT_BLUEDIAG) mobj->angle += ANGLE_22h; if (i == MT_YELLOWHORIZ || i == MT_REDHORIZ || i == MT_BLUEHORIZ) @@ -12089,7 +12828,7 @@ ML_EFFECT5 : Don't stop thinking when too far away if (mthing->options & MTF_OBJECTSPECIAL) { - if (i == MT_YELLOWDIAG || i == MT_REDDIAG) + if (i == MT_YELLOWDIAG || i == MT_REDDIAG || i == MT_BLUEDIAG) mobj->flags |= MF_NOGRAVITY; if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) diff --git a/src/p_mobj.h b/src/p_mobj.h index a9d5244b0..94fcc2987 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -233,15 +233,17 @@ typedef enum MFE_VERTICALFLIP = 1<<5, // Goo water MFE_GOOWATER = 1<<6, + // The mobj is touching a lava block + MFE_TOUCHLAVA = 1<<7, // Mobj was already pushed this tic - MFE_PUSHED = 1<<7, + MFE_PUSHED = 1<<8, // Mobj was already sprung this tic - MFE_SPRUNG = 1<<8, + MFE_SPRUNG = 1<<9, // Platform movement - MFE_APPLYPMOMZ = 1<<9, + MFE_APPLYPMOMZ = 1<<10, // Compute and trigger on mobj angle relative to tracer // See Linedef Exec 457 (Track mobj angle to point) - MFE_TRACERANGLE = 1<<10, + MFE_TRACERANGLE = 1<<11, // free: to and including 1<<15 } mobjeflag_t; diff --git a/src/p_saveg.c b/src/p_saveg.c index 12f14e99d..fb2365bf0 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3618,7 +3618,7 @@ static void P_NetUnArchiveThinkers(void) { executor_t *delay = NULL; UINT32 mobjnum; - for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; + for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next) { if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay) @@ -4119,12 +4119,54 @@ static inline boolean P_NetUnArchiveMisc(void) return true; } +static inline void P_ArchiveLuabanksAndConsistency(void) +{ + UINT8 i, banksinuse = NUM_LUABANKS; + + while (banksinuse && !luabanks[banksinuse-1]) + banksinuse--; // get the last used bank + + if (banksinuse) + { + WRITEUINT8(save_p, 0xb7); // luabanks marker + WRITEUINT8(save_p, banksinuse); + for (i = 0; i < banksinuse; i++) + WRITEINT32(save_p, luabanks[i]); + } + + WRITEUINT8(save_p, 0x1d); // consistency marker +} + +static inline boolean P_UnArchiveLuabanksAndConsistency(void) +{ + switch (READUINT8(save_p)) + { + case 0xb7: + { + UINT8 i, banksinuse = READUINT8(save_p); + if (banksinuse > NUM_LUABANKS) + return false; + for (i = 0; i < banksinuse; i++) + luabanks[i] = READINT32(save_p); + if (READUINT8(save_p) != 0x1d) + return false; + } + case 0x1d: + break; + default: + return false; + } + + return true; +} + void P_SaveGame(void) { P_ArchiveMisc(); P_ArchivePlayer(); - WRITEUINT8(save_p, 0x1d); // consistency marker + // yes, even in non HAVE_BLUA + P_ArchiveLuabanksAndConsistency(); } void P_SaveNetGame(void) @@ -4163,7 +4205,7 @@ void P_SaveNetGame(void) LUA_Archive(); #endif - WRITEUINT8(save_p, 0x1d); // consistency marker + P_ArchiveLuabanksAndConsistency(); } boolean P_LoadGame(INT16 mapoverride) @@ -4175,8 +4217,7 @@ boolean P_LoadGame(INT16 mapoverride) P_UnArchiveSPGame(mapoverride); P_UnArchivePlayer(); - // Savegame end marker - if (READUINT8(save_p) != 0x1d) + if (!P_UnArchiveLuabanksAndConsistency()) return false; // Only do this after confirming savegame is ok @@ -4217,5 +4258,5 @@ boolean P_LoadNetGame(void) // precipitation when loading a netgame save. Instead, precip has to be spawned here. // This is done in P_NetUnArchiveSpecials now. - return READUINT8(save_p) == 0x1d; + return P_UnArchiveLuabanksAndConsistency(); } diff --git a/src/p_setup.c b/src/p_setup.c index 793735082..cef176636 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2246,6 +2246,8 @@ static void P_LevelInitStuff(void) for (i = 0; i < MAXPLAYERS; i++) { + G_PlayerReborn(i, true); + if (canresetlives && (netgame || multiplayer) && playeringame[i] && (gametype == GT_COMPETITION || players[i].lives <= 0)) { // In Co-Op, replenish a user's lives if they are depleted. @@ -2253,41 +2255,18 @@ static void P_LevelInitStuff(void) } // obliteration station... - players[i].rings = players[i].spheres =\ - players[i].xtralife = players[i].deadtimer =\ - players[i].numboxes = players[i].totalring =\ - players[i].laps = players[i].aiming =\ - players[i].losstime = players[i].timeshit =\ - players[i].marescore = players[i].lastmarescore =\ - players[i].maxlink = players[i].startedtime =\ - players[i].finishedtime = players[i].finishedspheres =\ - players[i].finishedrings = players[i].lastmare =\ - players[i].lastmarelap = players[i].lastmarebonuslap =\ - players[i].totalmarelap = players[i].totalmarebonuslap =\ - players[i].marebegunat = players[i].textvar =\ - players[i].texttimer = players[i].linkcount =\ - players[i].linktimer = players[i].flyangle =\ - players[i].anotherflyangle = players[i].nightstime =\ - players[i].oldscale = players[i].mare = players[i].marelap =\ - players[i].marebonuslap = players[i].lapbegunat =\ - players[i].lapstartedtime = players[i].totalmarescore =\ - players[i].realtime = players[i].exiting = 0; + players[i].numboxes = players[i].totalring =\ + players[i].laps = players[i].marescore = players[i].lastmarescore =\ + players[i].mare = players[i].exiting = 0; - // i guess this could be part of the above but i feel mildly uncomfortable implicitly casting - players[i].gotcontinue = false; - - // aha, the first evidence this shouldn't be a memset! players[i].drillmeter = 40*20; - P_ResetPlayer(&players[i]); // hit these too - players[i].pflags &= ~(PF_GAMETYPEOVER|PF_TRANSFERTOCLOSEST); - - // unset ALL the pointers. P_SetTarget isn't needed here because if this - // function is being called we're just going to clobber the data anyways - players[i].mo = players[i].followmobj = players[i].awayviewmobj =\ - players[i].capsule = players[i].axis1 = players[i].axis2 = players[i].drone = NULL; + players[i].pflags &= ~(PF_GAMETYPEOVER); } + + if (botingame) + CV_SetValue(&cv_analog2, true); } // @@ -2627,7 +2606,6 @@ boolean P_SetupLevel(boolean skipprecip) boolean loadedbm = false; sector_t *ss; boolean chase; - levelloading = true; // This is needed. Don't touch. @@ -3068,8 +3046,11 @@ boolean P_SetupLevel(boolean skipprecip) CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n")); } - else if (gametype == GT_RACE && server && cv_usemapnumlaps.value) - CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps); + else if (gametype == GT_RACE && server) + CV_StealthSetValue(&cv_numlaps, + (cv_basenumlaps.value) + ? cv_basenumlaps.value + : mapheaderinfo[gamemap - 1]->numlaps); // =========== // landing point for netgames. diff --git a/src/p_spec.c b/src/p_spec.c index 256ca3453..50939ae5b 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2718,6 +2718,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) CONS_Debug(DBG_GAMELOGIC, "Line type 414 Executor: sfx number %d is invalid!\n", sfxnum); return; } + if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set { if (line->flags & ML_EFFECT5) // Repeat Midtexture @@ -2758,30 +2759,32 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) return; } } - - if (line->flags & ML_NOCLIMB) + else { - // play the sound from nowhere, but only if display player triggered it - if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer])) + if (line->flags & ML_NOCLIMB) + { + // play the sound from nowhere, but only if display player triggered it + if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer])) + S_StartSound(NULL, sfxnum); + } + else if (line->flags & ML_EFFECT4) + { + // play the sound from nowhere S_StartSound(NULL, sfxnum); - } - else if (line->flags & ML_EFFECT4) - { - // play the sound from nowhere - S_StartSound(NULL, sfxnum); - } - else if (line->flags & ML_BLOCKMONSTERS) - { - // play the sound from calling sector's soundorg - if (callsec) - S_StartSound(&callsec->soundorg, sfxnum); + } + else if (line->flags & ML_BLOCKMONSTERS) + { + // play the sound from calling sector's soundorg + if (callsec) + S_StartSound(&callsec->soundorg, sfxnum); + else if (mo) + S_StartSound(&mo->subsector->sector->soundorg, sfxnum); + } else if (mo) - S_StartSound(&mo->subsector->sector->soundorg, sfxnum); - } - else if (mo) - { - // play the sound from mobj that triggered it - S_StartSound(mo, sfxnum); + { + // play the sound from mobj that triggered it + S_StartSound(mo, sfxnum); + } } } break; @@ -4174,26 +4177,11 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n // Check the 3D floor's type... if (rover->flags & FF_BLOCKPLAYER) { + boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight)); + boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight)); // Thing must be on top of the floor to be affected... - if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) - { - if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight) - continue; - } - else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) - { - if (!(player->mo->eflags & MFE_VERTICALFLIP) - || player->mo->z + player->mo->height != bottomheight) - continue; - } - else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) - { - if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight) - || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight))) - continue; - } + if (!(floorallowed || ceilingallowed)) + continue; } else { @@ -4234,26 +4222,11 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n // Check the 3D floor's type... if (rover->flags & FF_BLOCKPLAYER) { + boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight)); + boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight)); // Thing must be on top of the floor to be affected... - if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) - { - if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight) - continue; - } - else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) - { - if (!(player->mo->eflags & MFE_VERTICALFLIP) - || player->mo->z + player->mo->height != bottomheight) - continue; - } - else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) - { - if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight) - || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight))) - continue; - } + if (!(floorallowed || ceilingallowed)) + continue; } else { @@ -4304,26 +4277,11 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar // Check the 3D floor's type... if (rover->flags & FF_BLOCKPLAYER) { + boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == top)); + boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == bottom)); // Thing must be on top of the floor to be affected... - if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) - { - if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != top) - return false; - } - else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) - { - if (!(mo->eflags & MFE_VERTICALFLIP) - || mo->z + mo->height != bottom) - return false; - } - else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) - { - if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottom) - || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == top))) - return false; - } + if (!(floorallowed || ceilingallowed)) + continue; } else { @@ -4345,10 +4303,10 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar // static boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) { - if (mo->eflags & MFE_VERTICALFLIP) - return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING); - else - return (mo->z == P_GetSpecialBottomZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_FLOOR); + boolean floorallowed = ((sec->flags & SF_FLIPSPECIAL_FLOOR) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == P_GetSpecialBottomZ(mo, sec, sec))); + boolean ceilingallowed = ((sec->flags & SF_FLIPSPECIAL_CEILING) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == P_GetSpecialTopZ(mo, sec, sec))); + // Thing must be on top of the floor to be affected... + return (floorallowed || ceilingallowed); } /** Applies a sector special to a player. @@ -5312,26 +5270,11 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo) if (((rover->flags & FF_BLOCKPLAYER) && mo->player) || ((rover->flags & FF_BLOCKOTHERS) && !mo->player)) { + boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == topheight)); + boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == bottomheight)); // Thing must be on top of the floor to be affected... - if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) - { - if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight) - continue; - } - else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) - { - if (!(mo->eflags & MFE_VERTICALFLIP) - || mo->z + mo->height != bottomheight) - continue; - } - else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) - { - if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight) - || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight))) - continue; - } + if (!(floorallowed || ceilingallowed)) + continue; } else { @@ -5374,26 +5317,11 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) // Check the 3D floor's type... if (rover->flags & FF_BLOCKPLAYER) { + boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight)); + boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight)); // Thing must be on top of the floor to be affected... - if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)) - { - if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight) - continue; - } - else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) - && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) - { - if (!(player->mo->eflags & MFE_VERTICALFLIP) - || player->mo->z + player->mo->height != bottomheight) - continue; - } - else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) - { - if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight) - || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight))) - continue; - } + if (!(floorallowed || ceilingallowed)) + continue; } else { @@ -5450,38 +5378,16 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) } if (!(po->flags & POF_TESTHEIGHT)) // Don't do height checking - { - } + ; else if (po->flags & POF_SOLID) { + boolean floorallowed = ((polysec->flags & SF_FLIPSPECIAL_FLOOR) && ((polysec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == polysec->ceilingheight)); + boolean ceilingallowed = ((polysec->flags & SF_FLIPSPECIAL_CEILING) && ((polysec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == polysec->floorheight)); // Thing must be on top of the floor to be affected... - if ((polysec->flags & SF_FLIPSPECIAL_FLOOR) - && !(polysec->flags & SF_FLIPSPECIAL_CEILING)) + if (!(floorallowed || ceilingallowed)) { - if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != polysec->ceilingheight) - { - po = (polyobj_t *)(po->link.next); - continue; - } - } - else if ((polysec->flags & SF_FLIPSPECIAL_CEILING) - && !(polysec->flags & SF_FLIPSPECIAL_FLOOR)) - { - if (!(player->mo->eflags & MFE_VERTICALFLIP) - || player->mo->z + player->mo->height != polysec->floorheight) - { - po = (polyobj_t *)(po->link.next); - continue; - } - } - else if (polysec->flags & SF_FLIPSPECIAL_BOTH) - { - if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == polysec->floorheight) - || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == polysec->ceilingheight))) - { - po = (polyobj_t *)(po->link.next); - continue; - } + po = (polyobj_t *)(po->link.next); + continue; } } else @@ -5580,17 +5486,13 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) f_affectpoint = P_GetSpecialBottomZ(player->mo, sector, sector); c_affectpoint = P_GetSpecialTopZ(player->mo, sector, sector); - // Only go further if on the ground - if ((sector->flags & SF_FLIPSPECIAL_FLOOR) && !(sector->flags & SF_FLIPSPECIAL_CEILING) && player->mo->z != f_affectpoint) - return; - - if ((sector->flags & SF_FLIPSPECIAL_CEILING) && !(sector->flags & SF_FLIPSPECIAL_FLOOR) && player->mo->z + player->mo->height != c_affectpoint) - return; - - if ((sector->flags & SF_FLIPSPECIAL_BOTH) - && player->mo->z != f_affectpoint - && player->mo->z + player->mo->height != c_affectpoint) - return; + { + boolean floorallowed = ((sector->flags & SF_FLIPSPECIAL_FLOOR) && ((sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == f_affectpoint)); + boolean ceilingallowed = ((sector->flags & SF_FLIPSPECIAL_CEILING) && ((sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == c_affectpoint)); + // Thing must be on top of the floor to be affected... + if (!(floorallowed || ceilingallowed)) + return; + } P_ProcessSpecialSector(player, sector, NULL); } @@ -6085,8 +5987,6 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline) * to the lowest nearby height if not * there already. * - * Replaces the old "AirBob". - * * \param sec Control sector. * \param actionsector Target sector. * \param sourceline Control linedef. @@ -6131,8 +6031,7 @@ static void P_AddRaiseThinker(sector_t *sec, line_t *sourceline) raise->sourceline = sourceline; } -// Function to maintain backwards compatibility -static void P_AddOldAirbob(sector_t *sec, line_t *sourceline, boolean noadjust) +static void P_AddAirbob(sector_t *sec, line_t *sourceline, boolean noadjust, boolean dynamic) { levelspecthink_t *airbob; @@ -6169,6 +6068,8 @@ static void P_AddOldAirbob(sector_t *sec, line_t *sourceline, boolean noadjust) airbob->vars[5] = sec->ceilingheight; airbob->vars[4] = airbob->vars[5] - (sec->ceilingheight - sec->floorheight); + + airbob->vars[9] = dynamic ? 1 : 0; airbob->sourceline = sourceline; } @@ -6683,6 +6584,11 @@ void P_SpawnSpecials(INT32 fromnetsave) if (lines[i].flags & ML_EFFECT3) sectors[s].flags |= SF_TRIGGERSPECIAL_TOUCH; + if (lines[i].flags & ML_EFFECT2) + sectors[s].flags |= SF_TRIGGERSPECIAL_HEADBUMP; + + if (lines[i].flags & ML_EFFECT1) + sectors[s].flags |= SF_INVERTPRECIP; if (lines[i].frontsector && GETSECSPECIAL(lines[i].frontsector->special, 4) == 12) sectors[s].camsec = sides[*lines[i].sidenum].sector-sectors; @@ -6987,11 +6893,16 @@ void P_SpawnSpecials(INT32 fromnetsave) case 151: // Adjustable air bobbing platform P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); lines[i].flags |= ML_BLOCKMONSTERS; - P_AddOldAirbob(lines[i].frontsector, lines + i, (lines[i].special != 151)); + P_AddAirbob(lines[i].frontsector, lines + i, (lines[i].special != 151), false); break; case 152: // Adjustable air bobbing platform in reverse P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddOldAirbob(lines[i].frontsector, lines + i, true); + P_AddAirbob(lines[i].frontsector, lines + i, true, false); + break; + case 153: // Dynamic Sinking Platform + P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); + lines[i].flags |= ML_BLOCKMONSTERS; + P_AddAirbob(lines[i].frontsector, lines + i, false, true); break; case 160: // Float/bob platform @@ -7042,14 +6953,14 @@ void P_SpawnSpecials(INT32 fromnetsave) case 176: // Air bobbing platform that will crumble and bob on the water when it falls and hits P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers); lines[i].flags |= ML_BLOCKMONSTERS; - P_AddOldAirbob(lines[i].frontsector, lines + i, true); + P_AddAirbob(lines[i].frontsector, lines + i, true, false); break; case 177: // Air bobbing platform that will crumble and bob on // the water when it falls and hits, then never return P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_CRUMBLE|FF_NORETURN, secthinkers); lines[i].flags |= ML_BLOCKMONSTERS; - P_AddOldAirbob(lines[i].frontsector, lines + i, true); + P_AddAirbob(lines[i].frontsector, lines + i, true, false); break; case 178: // Crumbling platform that will float when it hits water @@ -7063,7 +6974,7 @@ void P_SpawnSpecials(INT32 fromnetsave) case 180: // Air bobbing platform that will crumble P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE, secthinkers); lines[i].flags |= ML_BLOCKMONSTERS; - P_AddOldAirbob(lines[i].frontsector, lines + i, true); + P_AddAirbob(lines[i].frontsector, lines + i, true, false); break; case 190: // Rising Platform FOF (solid, opaque, shadows) @@ -7171,21 +7082,21 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 252: // Shatter block (breaks when touched) - ffloorflags = FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER; + ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER; if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_SOLID|FF_SHATTERBOTTOM; + ffloorflags |= FF_BLOCKPLAYER|FF_SHATTERBOTTOM; P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); break; case 253: // Translucent shatter block (see 76) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_TRANSLUCENT, secthinkers); + P_AddFakeFloorsByLine(i, FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_TRANSLUCENT, secthinkers); break; case 254: // Bustable block ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP; if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_ONLYKNUX; + ffloorflags |= FF_STRONGBUST; P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); break; diff --git a/src/p_tick.c b/src/p_tick.c index 7606510fe..6b5c7980c 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -482,7 +482,7 @@ static inline void P_DoSpecialStageStuff(void) countspheres += players[i].spheres; // If in water, deplete timer 6x as fast. - if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) + if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER)) players[i].nightstime -= 5; if (--players[i].nightstime > 6) { diff --git a/src/p_user.c b/src/p_user.c index 58ba00fc9..dde1dc1dc 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -191,7 +191,7 @@ boolean P_AutoPause(void) if (netgame || modeattacking || gamestate == GS_TITLESCREEN) return false; - return (menuactive || window_notinfocus); + return (menuactive || ( window_notinfocus && cv_pauseifunfocused.value )); } // @@ -898,7 +898,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) if (player->mo->target) { player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); - player->drawangle = player->mo->angle = player->angle_pos + player->drawangle = player->angle_pos + ((player->mo->target->flags2 & MF2_AMBUSH) ? // if axis is invert, take the opposite right angle -ANGLE_90 : ANGLE_90); // flyangle is always 0 here, below is kept for posterity /*(player->flyangle > 90 && player->flyangle < 270 ? ANGLE_90 : -ANGLE_90) @@ -1031,6 +1031,17 @@ void P_ResetPlayer(player_t *player) { player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_THOKKED|PF_CANCARRY|PF_SHIELDABILITY|PF_BOUNCING); + if (player->powers[pw_carry] == CR_ROLLOUT) + { + if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer)) + { + player->mo->tracer->flags |= MF_PUSHABLE; + P_SetTarget(&player->mo->tracer->tracer, NULL); + } + P_SetTarget(&player->mo->tracer, NULL); + player->powers[pw_carry] = CR_NONE; + } + if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_NIGHTSFALL || player->powers[pw_carry] == CR_BRAKGOOP || player->powers[pw_carry] == CR_MINECART)) player->powers[pw_carry] = CR_NONE; @@ -1085,6 +1096,9 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) // Spinning. if (player->pflags & PF_SPINNING) return true; + + if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) + return true; // From the front. if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) @@ -1109,7 +1123,7 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) } else if (P_MobjFlip(player->mo)*(topheight - (thing->z + thing->height/2)) < 0) { - if (player->charability == CA_FLY && player->panim == PA_ABILITY && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0)) + if (player->charability == CA_FLY && player->panim == PA_ABILITY && !(player->mo->eflags & MFE_UNDERWATER) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0)) return true; } @@ -1979,7 +1993,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) mobj_t *ghost2 = P_SpawnGhostMobj(mobj->player->followmobj); P_SetTarget(&ghost2->tracer, ghost); P_SetTarget(&ghost->tracer, ghost2); - ghost2->flags2 |= MF2_LINKDRAW; + ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW); } return ghost; @@ -2217,148 +2231,166 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) player->pflags &= ~PF_SPINNING; } - if (player->pflags & PF_SPINNING) - { - if (player->mo->state-states != S_PLAY_ROLL && !(player->pflags & PF_STARTDASH)) - { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_spin); - } - } - else if (player->pflags & PF_GLIDING) // ground gliding - { - if (dorollstuff) - { - player->skidtime = TICRATE; - player->mo->tics = -1; - } - else if (!player->skidtime) - player->pflags &= ~PF_GLIDING; - } - else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) - { - if (player->mo->state-states != S_PLAY_MELEE_LANDING) - { - mobjtype_t type = player->revitem; - P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); - player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; - S_StartSound(player->mo, sfx_s3k8b); - player->pflags |= PF_FULLSTASIS; - - // hearticles - if (type) - { - UINT8 i = 0; - angle_t throwang = -(2*ANG30); - fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t zo = 6*player->mo->scale; - fixed_t mu = FixedMul(player->maxdash, player->mo->scale); - fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); - fixed_t ev; - mobj_t *missile = NULL; - if (mu2 < mu) - mu2 = mu; - ev = (50*FRACUNIT - (mu/25))/50; - while (i < 5) - { - missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); - P_SetTarget(&missile->target, player->mo); - missile->angle = throwang + player->drawangle; - P_Thrust(missile, player->drawangle + ANGLE_90, - P_ReturnThrustY(missile, throwang, mu)); // side to side component - P_Thrust(missile, player->drawangle, mu2); // forward component - P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); - missile->momz += player->mo->pmomz; - missile->fuse = TICRATE/2; - missile->extravalue2 = ev; - - i++; - throwang += ANG30; - } - if (mobjinfo[type].seesound && missile) - S_StartSound(missile, missile->info->seesound); - } - } - } - else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) - ; - else if (player->panim != PA_IDLE && player->panim != PA_WALK && player->panim != PA_RUN && player->panim != PA_DASH) - { - if (player->cmomx || player->cmomy) - { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) - P_SetPlayerMobjState(player->mo, S_PLAY_DASH); - else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) - && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) - P_SetPlayerMobjState(player->mo, S_PLAY_RUN); - else if ((player->rmomx || player->rmomy) - && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) - P_SetPlayerMobjState(player->mo, S_PLAY_WALK); - else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE) - P_SetPlayerMobjState(player->mo, S_PLAY_STND); - } - else - { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) - P_SetPlayerMobjState(player->mo, S_PLAY_DASH); - else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) - && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) - P_SetPlayerMobjState(player->mo, S_PLAY_RUN); - else if ((player->mo->momx || player->mo->momy) - && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) - P_SetPlayerMobjState(player->mo, S_PLAY_WALK); - else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE) - P_SetPlayerMobjState(player->mo, S_PLAY_STND); - } - } - - if (!(player->pflags & PF_GLIDING)) - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); - player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); - player->secondjump = 0; - player->glidetime = 0; - player->climbing = 0; - player->powers[pw_tailsfly] = 0; - - if (player->pflags & PF_SHIELDABILITY) - { - player->pflags &= ~PF_SHIELDABILITY; - - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack. - { - if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound - S_StartSound(player->mo, sfx_s3k4c); - else // create a fire pattern on the ground - { - S_StartSound(player->mo, sfx_s3k47); - P_ElementalFire(player, true); - } - P_SetObjectMomZ(player->mo, - (player->mo->eflags & MFE_UNDERWATER) - ? 6*FRACUNIT/5 - : 5*FRACUNIT/2, - false); - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); - player->mo->momx = player->mo->momy = 0; - clipmomz = false; - } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack. - { - P_DoBubbleBounce(player); - clipmomz = false; - } - } - if (player->pflags & PF_BOUNCING) { - P_MobjCheckWater(player->mo); - player->mo->momz *= -1; - P_DoAbilityBounce(player, true); - if (player->scoreadd) - player->scoreadd--; + if (dorollstuff && player->mo->state-states != S_PLAY_BOUNCE_LANDING) + { + P_MobjCheckWater(player->mo); + player->mo->momz *= -1; + P_DoAbilityBounce(player, true); + if (player->scoreadd) + player->scoreadd--; + } clipmomz = false; } + else + { + if (player->pflags & PF_SPINNING) + { + if (player->mo->state-states != S_PLAY_ROLL && !(player->pflags & PF_STARTDASH)) + { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_spin); + } + } + else if (player->pflags & PF_GLIDING) // ground gliding + { + if (dorollstuff) + { + player->skidtime = TICRATE; + player->mo->tics = -1; + } + else if (!player->skidtime) + player->pflags &= ~PF_GLIDING; + } + else if (player->charability == CA_GLIDEANDCLIMB && player->pflags & PF_THOKKED && (~player->pflags) & PF_SHIELDABILITY) + { + if (player->mo->state-states != S_PLAY_GLIDE_LANDING) + { + P_ResetPlayer(player); + P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE_LANDING); + S_StartSound(player->mo, sfx_s3k4c); + player->pflags |= PF_STASIS; + player->mo->momx = ((player->mo->momx - player->cmomx)/3) + player->cmomx; + player->mo->momy = ((player->mo->momy - player->cmomy)/3) + player->cmomy; + } + } + else if (player->charability2 == CA2_MELEE + && ((player->panim == PA_ABILITY2) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY && player->cmd.buttons & (BT_JUMP|BT_USE)))) + { + if (player->mo->state-states != S_PLAY_MELEE_LANDING) + { + mobjtype_t type = player->revitem; + P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); + player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; + S_StartSound(player->mo, sfx_s3k8b); + player->pflags |= PF_FULLSTASIS; + + // hearticles + if (type) + { + UINT8 i = 0; + angle_t throwang = -(2*ANG30); + fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t zo = 6*player->mo->scale; + fixed_t mu = FixedMul(player->maxdash, player->mo->scale); + fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t ev; + mobj_t *missile = NULL; + if (mu2 < mu) + mu2 = mu; + ev = (50*FRACUNIT - (mu/25))/50; + while (i < 5) + { + missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); + P_SetTarget(&missile->target, player->mo); + missile->angle = throwang + player->drawangle; + P_Thrust(missile, player->drawangle + ANGLE_90, + P_ReturnThrustY(missile, throwang, mu)); // side to side component + P_Thrust(missile, player->drawangle, mu2); // forward component + P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->momz += player->mo->pmomz; + missile->fuse = TICRATE/2; + missile->extravalue2 = ev; + + i++; + throwang += ANG30; + } + if (mobjinfo[type].seesound && missile) + S_StartSound(missile, missile->info->seesound); + } + } + } + else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) + ; + else if (player->panim != PA_IDLE && player->panim != PA_WALK && player->panim != PA_RUN && player->panim != PA_DASH) + { + if (player->cmomx || player->cmomy) + { + if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) + && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + else if ((player->rmomx || player->rmomy) + && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE) + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + } + else + { + if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) + && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + else if ((player->mo->momx || player->mo->momy) + && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE) + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + } + } + + if (!(player->pflags & PF_GLIDING)) + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); + player->secondjump = 0; + player->glidetime = 0; + player->climbing = 0; + player->powers[pw_tailsfly] = 0; + + if (player->pflags & PF_SHIELDABILITY) + { + player->pflags &= ~PF_SHIELDABILITY; + + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack. + { + if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound + S_StartSound(player->mo, sfx_s3k4c); + else // create a fire pattern on the ground + { + S_StartSound(player->mo, sfx_s3k47); + P_ElementalFire(player, true); + } + P_SetObjectMomZ(player->mo, + (player->mo->eflags & MFE_UNDERWATER) + ? 6*FRACUNIT/5 + : 5*FRACUNIT/2, + false); + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + player->mo->momx = player->mo->momy = 0; + clipmomz = false; + } + else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack. + { + P_DoBubbleBounce(player); + clipmomz = false; + } + } + } } return clipmomz; @@ -2440,39 +2472,42 @@ static void P_CheckBustableBlocks(player_t *player) if ((rover->flags & FF_BUSTUP)/* && !rover->master->frontsector->crumblestate*/) { - // If it's an FF_SPINBUST, you have to either be jumping, or coming down - // onto the top from a spin. - if (rover->flags & FF_SPINBUST && ((!(player->pflags & PF_JUMPED) && !(player->pflags & PF_SPINNING) && !(player->pflags & PF_BOUNCING)) || (player->pflags & PF_STARTDASH))) + // If it's an FF_SHATTER, you can break it just by touching it. + if (rover->flags & FF_SHATTER) + goto bust; + + // If it's an FF_SPINBUST, you can break it if you are in your spinning frames + // (either from jumping or spindashing). + if (rover->flags & FF_SPINBUST + && (((player->pflags & PF_SPINNING) && !(player->pflags & PF_STARTDASH)) + || (player->pflags & PF_JUMPED && !(player->pflags & PF_NOJUMPDAMAGE)))) + goto bust; + + // You can always break it if you have CA_GLIDEANDCLIMB + // or if you are bouncing on it + // or you are using CA_TWINSPIN/CA2_MELEE. + if (player->charability == CA_GLIDEANDCLIMB + || (player->pflags & PF_BOUNCING) + || ((player->charability == CA_TWINSPIN) && (player->panim == PA_ABILITY)) + || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + goto bust; + + if (rover->flags & FF_STRONGBUST) continue; - // if it's not an FF_SHATTER, you must be spinning (and not jumping) - // or be super - // or have CA_GLIDEANDCLIMB - // or be in dashmode with SF_DASHMODE - // or be using CA_TWINSPIN - // or be using CA2_MELEE - // or are drilling in NiGHTS - // or are recording for Metal Sonic - if (!(rover->flags & FF_SHATTER) && !(rover->flags & FF_SPINBUST) - && !((player->pflags & PF_SPINNING) && !(player->pflags & PF_JUMPED)) + // If it's not an FF_STRONGBUST, you can break if you are spinning (and not jumping) + // or you are super + // or you are in dashmode with SF_DASHMODE + // or you are drilling in NiGHTS + // or you are recording for Metal Sonic + if (!((player->pflags & PF_SPINNING) && !(player->pflags & PF_JUMPED)) && !(player->powers[pw_super]) - && !(player->charability == CA_GLIDEANDCLIMB) - && !(player->pflags & PF_BOUNCING) - && !((player->charflags & SF_DASHMODE) && (player->dashmode >= 3*TICRATE)) - && !((player->charability == CA_TWINSPIN) && (player->panim == PA_ABILITY)) - && !(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + && !(((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) && (player->dashmode >= DASHMODE_THRESHOLD)) && !(player->pflags & PF_DRILLING) && !metalrecording) continue; - // Only players with CA_GLIDEANDCLIMB, or CA_TWINSPIN/CA2_MELEE users can break this rock... - if (!(rover->flags & FF_SHATTER) && (rover->flags & FF_ONLYKNUX) - && !(player->charability == CA_GLIDEANDCLIMB - || (player->pflags & PF_BOUNCING) - || ((player->charability == CA_TWINSPIN) && (player->panim == PA_ABILITY)) - || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))) - continue; - + bust: topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); @@ -2964,22 +2999,19 @@ static void P_DoBubbleBreath(player_t *player) P_SetScale(bubble, bubble->destscale); } - if (player->powers[pw_carry] == CR_NIGHTSMODE) // NiGHTS Super doesn't spawn flight bubbles - return; - // Tails stirs up the water while flying in it if (player->powers[pw_tailsfly] && (leveltime & 1) && player->charability != CA_SWIM) { - fixed_t radius = (3*player->mo->radius)>>1; + fixed_t radius = player->mo->radius; angle_t fa = ((leveltime%45)*FINEANGLES/8) & FINEMASK; fixed_t stirwaterx = FixedMul(FINECOSINE(fa),radius); fixed_t stirwatery = FixedMul(FINESINE(fa),radius); fixed_t stirwaterz; if (player->mo->eflags & MFE_VERTICALFLIP) - stirwaterz = player->mo->z + player->mo->height - FixedDiv(player->mo->height,3*FRACUNIT/2); + stirwaterz = player->mo->z + player->mo->height - (4<mo->z + FixedDiv(player->mo->height,3*FRACUNIT/2); + stirwaterz = player->mo->z + (4<mo->x + stirwaterx, @@ -3060,7 +3092,6 @@ static void P_DoClimbing(player_t *player) glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy); - if (!glidesector || glidesector->sector != player->mo->subsector->sector) { boolean floorclimb = false; boolean thrust = false; @@ -3444,9 +3475,13 @@ static void P_DoClimbing(player_t *player) if (!floorclimb) { if (boostup) + { P_SetObjectMomZ(player->mo, 2*FRACUNIT, true); + if (cmd->forwardmove) + P_SetObjectMomZ(player->mo, 2*player->mo->momz/3, false); + } if (thrust) - P_InstaThrust(player->mo, player->mo->angle, FixedMul(4*FRACUNIT, player->mo->scale)); // Lil' boost up. + P_Thrust(player->mo, player->mo->angle, FixedMul(4*FRACUNIT, player->mo->scale)); // Lil' boost up. player->climbing = 0; player->pflags |= P_GetJumpFlags(player); @@ -3460,12 +3495,6 @@ static void P_DoClimbing(player_t *player) P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); } } - else - { - player->climbing = 0; - player->pflags |= P_GetJumpFlags(player); - P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); - } if (cmd->sidemove != 0 || cmd->forwardmove != 0) climb = true; @@ -3484,15 +3513,28 @@ static void P_DoClimbing(player_t *player) player->pflags |= P_GetJumpFlags(player); P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); P_SetObjectMomZ(player->mo, 4*FRACUNIT, false); - P_InstaThrust(player->mo, player->mo->angle, FixedMul(-4*FRACUNIT, player->mo->scale)); + P_Thrust(player->mo, player->mo->angle, FixedMul(-4*FRACUNIT, player->mo->scale)); } +#define CLIMBCONEMAX FixedAngle(90*FRACUNIT) if (!demoplayback || P_AnalogMove(player)) { if (player == &players[consoleplayer]) - localangle = player->mo->angle; + { + angle_t angdiff = localangle - player->mo->angle; + if (angdiff < ANGLE_180 && angdiff > CLIMBCONEMAX) + localangle = player->mo->angle + CLIMBCONEMAX; + else if (angdiff > ANGLE_180 && angdiff < InvAngle(CLIMBCONEMAX)) + localangle = player->mo->angle - CLIMBCONEMAX; + } else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + { + angle_t angdiff = localangle2 - player->mo->angle; + if (angdiff < ANGLE_180 && angdiff > CLIMBCONEMAX) + localangle2 = player->mo->angle + CLIMBCONEMAX; + else if (angdiff > ANGLE_180 && angdiff < InvAngle(CLIMBCONEMAX)) + localangle2 = player->mo->angle - CLIMBCONEMAX; + } } if (player->climbing == 0) @@ -3687,7 +3729,7 @@ static void P_DoTeeter(player_t *player) bottomheight = *rover->bottomheight; #endif - if (P_CheckSolidLava(player->mo, rover)) + if (P_CheckSolidLava(rover)) ; else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND)) continue; // intangible 3d floor @@ -4140,8 +4182,11 @@ static void P_DoSuperStuff(player_t *player) { player->powers[pw_super] = 0; P_SetPlayerMobjState(player->mo, S_PLAY_STND); - music_stack_noposition = true; // HACK: Do not reposition next music - music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music + if (P_IsLocalPlayer(player)) + { + music_stack_noposition = true; // HACK: Do not reposition next music + music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music + } P_RestoreMusic(player); P_SpawnShieldOrb(player); @@ -4210,7 +4255,7 @@ static void P_DoSuperStuff(player_t *player) if (gametype != GT_COOP) player->powers[pw_flashing] = flashingtics-1; - if ((player->mo->health > 0) && (player->mo->sprite2 & FF_SPR2SUPER)) + if (player->mo->sprite2 & FF_SPR2SUPER) P_SetPlayerMobjState(player->mo, player->mo->state-states); // Inform the netgame that the champion has fallen in the heat of battle. @@ -4223,8 +4268,11 @@ static void P_DoSuperStuff(player_t *player) } // Resume normal music if you're the console player - music_stack_noposition = true; // HACK: Do not reposition next music - music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music + if (P_IsLocalPlayer(player)) + { + music_stack_noposition = true; // HACK: Do not reposition next music + music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music + } P_RestoreMusic(player); // If you had a shield, restore its visual significance. @@ -4309,6 +4357,16 @@ void P_DoJump(player_t *player, boolean soundandstate) if (player->mo->ceilingz-player->mo->floorz <= player->mo->height-1) return; + if (player->powers[pw_carry] == CR_PTERABYTE) + { + S_StartSound(player->mo, sfx_s3kd7s); + player->mo->tracer->cusval += 10; + player->mo->tracer->watertop = P_RandomRange(-player->mo->tracer->cusval, player->mo->tracer->cusval) << (FRACBITS - 1); + player->mo->tracer->waterbottom = P_RandomRange(-player->mo->tracer->cusval, player->mo->tracer->cusval) << (FRACBITS - 1); + player->mo->tracer->cvmem = P_RandomRange(-player->mo->tracer->cusval, player->mo->tracer->cusval) << (FRACBITS - 1); + return; + } + // Jump this high. if (player->powers[pw_carry] == CR_PLAYER) { @@ -4322,6 +4380,7 @@ void P_DoJump(player_t *player, boolean soundandstate) { player->mo->momz = 9*FRACUNIT; player->powers[pw_carry] = CR_NONE; + P_SetTarget(&player->mo->tracer->target, NULL); P_SetTarget(&player->mo->tracer, NULL); } else if (player->powers[pw_carry] == CR_ROPEHANG) @@ -4330,6 +4389,14 @@ void P_DoJump(player_t *player, boolean soundandstate) player->powers[pw_carry] = CR_NONE; P_SetTarget(&player->mo->tracer, NULL); } + else if (player->powers[pw_carry] == CR_ROLLOUT) + { + player->mo->momz = 9*FRACUNIT + player->mo->tracer->momz; + player->powers[pw_carry] = CR_NONE; + player->mo->tracer->flags |= MF_PUSHABLE; + P_SetTarget(&player->mo->tracer->tracer, NULL); + P_SetTarget(&player->mo->tracer, NULL); + } else if (player->mo->eflags & MFE_GOOWATER) { player->mo->momz = 7*FRACUNIT; @@ -4455,7 +4522,8 @@ static void P_DoSpinDashDust(player_t *player) static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) { boolean canstand = true; // can we stand on the ground? (mostly relevant for slopes) - if (player->pflags & PF_STASIS) + if (player->pflags & PF_STASIS + && (player->pflags & PF_JUMPSTASIS || player->mo->state-states != S_PLAY_GLIDE_LANDING)) return; #ifdef HAVE_BLUA @@ -4479,7 +4547,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) { case CA2_SPINDASH: // Spinning and Spindashing // Start revving - if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<mo->scale) + if ((cmd->buttons & BT_USE) && (player->speed < FixedMul(5<mo->scale) || player->mo->state - states == S_PLAY_GLIDE_LANDING) && !player->mo->momz && onground && !(player->pflags & (PF_USEDOWN|PF_SPINNING)) && canstand) { @@ -4641,8 +4709,9 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) if (player->speed < FixedMul(player->maxdash, player->mo->scale)) #endif { - player->drawangle = player->mo->angle; - P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale)); + if (player->panim == PA_IDLE) + player->drawangle = player->mo->angle; + P_InstaThrust(player->mo, player->drawangle, FixedMul(player->maxdash, player->mo->scale)); } player->mo->momx += player->cmomx; player->mo->momy += player->cmomy; @@ -4886,56 +4955,185 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range) // static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { - mobj_t *lockon = NULL; + mobj_t *lockonthok = NULL, *lockonshield = NULL, *visual = NULL; if (player->pflags & PF_JUMPSTASIS) return; - if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockon = P_LookForEnemies(player, true, false))) + if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockonthok = P_LookForEnemies(player, true, false))) { if (P_IsLocalPlayer(player)) // Only display it on your own view. { - mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockon); + visual = P_SpawnMobj(lockonthok->x, lockonthok->y, lockonthok->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker + P_SetTarget(&visual->target, lockonthok); } } - if (cmd->buttons & BT_USE && !(player->pflags & PF_JUMPDOWN) && !player->exiting && !P_PlayerInPain(player)) + ////////////////// + //SHIELD ACTIVES// + //& SUPER FLOAT!// + ////////////////// + + if ((player->pflags & PF_JUMPED) && !player->exiting && !P_PlayerInPain(player)) { - if (player->mo->tracer && player->powers[pw_carry] == CR_MACESPIN) - {} - else if (onground || player->climbing || (player->mo->tracer && player->powers[pw_carry])) - {} - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND - && !(player->pflags & PF_JUMPED) - && !(player->pflags & PF_USEDOWN)) - P_DoJumpShield(player); - else if (!(player->pflags & PF_SLIDING) && ((gametype != GT_CTF) || (!player->gotflag))) + if (onground || player->climbing || player->powers[pw_carry]) + ; + else if (gametype == GT_CTF && player->gotflag) + ; + else if (player->pflags & (PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player has used an ability previously + ; + else if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_USEDOWN) + && ((!(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX)))) // thokked is optional if you're bubblewrapped { + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) + { + if ((lockonshield = P_LookForEnemies(player, false, false))) + { + if (P_IsLocalPlayer(player)) // Only display it on your own view. + { + boolean dovis = true; + if (lockonshield == lockonthok) + { + if (leveltime & 2) + dovis = false; + else if (visual) + P_RemoveMobj(visual); + } + if (dovis) + { + visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker + P_SetTarget(&visual->target, lockonshield); + P_SetMobjStateNF(visual, visual->info->spawnstate+1); + } + } + } + } + if (cmd->buttons & BT_USE // Spin button effects + #ifdef HAVE_BLUA + && !LUAh_ShieldSpecial(player) + #endif + ) + { + // Force stop + if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) + { + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->mo->momx = player->mo->momy = player->mo->momz = 0; + S_StartSound(player->mo, sfx_ngskid); + } + else + { + switch (player->powers[pw_shield] & SH_NOSTACK) + { + // Whirlwind jump/Thunder jump + case SH_WHIRLWIND: + case SH_THUNDERCOIN: + P_DoJumpShield(player); + break; + // Armageddon pow + case SH_ARMAGEDDON: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + P_BlackOw(player); + break; + // Attraction blast + case SH_ATTRACT: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->homing = 2; + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonshield)); + if (lockonshield) + { + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonshield->x, lockonshield->y); + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_s3k40); + player->homing = 3*TICRATE; + } + else + S_StartSound(player->mo, sfx_s3ka6); + break; + // Elemental stomp/Bubble bounce + case SH_ELEMENTAL: + case SH_BUBBLEWRAP: + { + boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + if (elem) + { + player->pflags |= PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + S_StartSound(player->mo, sfx_s3k43); + } + else + { + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_s3k44); + } + player->secondjump = 0; + player->mo->momx = player->mo->momy = 0; + P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); + break; + } + // Flame burst + case SH_FLAMEAURA: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); + player->drawangle = player->mo->angle; + S_StartSound(player->mo, sfx_s3k43); + default: + break; + } + } + } + } + else if ((cmd->buttons & BT_USE)) + { + if (!(player->pflags & PF_USEDOWN) && P_SuperReady(player)) + { + // If you can turn super and aren't already, + // and you don't have a shield, do it! + P_DoSuperTransformation(player, false); + } + else #ifdef HAVE_BLUA if (!LUAh_JumpSpinSpecial(player)) #endif switch (player->charability) { - case CA_TELEKINESIS: - if (player->pflags & PF_JUMPED) + case CA_THOK: + if (player->powers[pw_super]) // Super Sonic float { - if (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) + if ((player->speed > 5*player->mo->scale) // FixedMul(5<mo->scale), but scale is FRACUNIT-based + && (P_MobjFlip(player->mo)*player->mo->momz <= 0)) { - P_Telekinesis(player, - -FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player) - FixedMul(384*FRACUNIT, player->mo->scale)); + if (player->panim != PA_RUN && player->panim != PA_WALK) + { + if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); + else + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); + } + + player->mo->momz = 0; + player->pflags &= ~(PF_STARTJUMP|PF_SPINNING); } } break; - case CA_AIRDRILL: - if (player->pflags & PF_JUMPED) + case CA_TELEKINESIS: + if (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || (player->charflags & SF_MULTIABILITY)) { - if (player->pflags & PF_THOKKED) // speed up falling down - { - if (player->secondjump < 42) - player->secondjump ++; - } + P_Telekinesis(player, + -FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player) + FixedMul(384*FRACUNIT, player->mo->scale)); + } + break; + case CA_TWINSPIN: + if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || player->charflags & SF_MULTIABILITY)) + { + player->pflags |= PF_THOKKED; + S_StartSound(player->mo, sfx_s3k42); + player->mo->frame = 0; + P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); } break; default: @@ -4948,6 +5146,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { if (player->pflags & PF_JUMPED) { + if (cmd->buttons & BT_USE && player->secondjump < 42) // speed up falling down + player->secondjump++; + if (player->flyangle > 0 && player->pflags & PF_THOKKED) { player->flyangle--; @@ -4966,6 +5167,11 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } } + /////////////// + // CHARACTER // + // ABILITIES!// + /////////////// + if (cmd->buttons & BT_JUMP && !player->exiting && !P_PlayerInPain(player)) { #ifdef HAVE_BLUA @@ -5035,7 +5241,6 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); - player->drawangle = player->mo->angle; if (maptol & TOL_2D) { @@ -5050,11 +5255,11 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (player->charability == CA_HOMINGTHOK) { - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockon)); - if (lockon) + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonthok)); + if (lockonthok) { P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonthok->x, lockonthok->y); player->homing = 3*TICRATE; } else @@ -5066,6 +5271,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_NOJUMPDAMAGE; } + player->drawangle = player->mo->angle; + if (player->mo->info->attacksound && !player->spectator) S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound @@ -5102,7 +5309,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->glidetime = 0; P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); - P_InstaThrust(player->mo, player->mo->angle, FixedMul(glidespeed, player->mo->scale)); + if (player->speed < glidespeed) + P_Thrust(player->mo, player->mo->angle, glidespeed - player->speed); player->pflags &= ~(PF_SPINNING|PF_STARTDASH); } break; @@ -5119,7 +5327,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) case CA_SLOWFALL: // Slow descent hover if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE) + if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD) P_SetPlayerMobjState(player->mo, S_PLAY_DASH); else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); @@ -5212,6 +5420,60 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_DoJumpShield(player); } + // HOMING option. + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT // Sonic 3D Blast. + && player->pflags & PF_SHIELDABILITY) + { + if (player->homing && player->mo->tracer) + { + if (!P_HomingAttack(player->mo, player->mo->tracer)) + { + P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); + if (player->mo->eflags & MFE_UNDERWATER) + player->mo->momz = FixedMul(player->mo->momz, FRACUNIT/3); + player->homing = 0; + } + } + + // If you're not jumping, then you obviously wouldn't be homing. + if (!(player->pflags & PF_JUMPED)) + player->homing = 0; + } + else if (player->charability == CA_HOMINGTHOK) // Sonic Adventure. + { + // If you've got a target, chase after it! + if (player->homing && player->mo->tracer) + { + P_SpawnThokMobj(player); + + // But if you don't, then stop homing. + if (!P_HomingAttack(player->mo, player->mo->tracer)) + { + if (player->mo->eflags & MFE_UNDERWATER) + P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); + else + P_SetObjectMomZ(player->mo, 10*FRACUNIT, false); + + player->mo->momx = player->mo->momy = player->homing = 0; + + if (player->mo->tracer->flags2 & MF2_FRET) + P_InstaThrust(player->mo, player->mo->angle, -(player->speed>>3)); + + if (!(player->mo->tracer->flags & MF_BOSS)) + player->pflags &= ~PF_THOKKED; + + P_SetPlayerMobjState(player->mo, S_PLAY_SPRING); + player->pflags |= PF_NOJUMPDAMAGE; + } + } + + // If you're not jumping, then you obviously wouldn't be homing. + if (!(player->pflags & PF_JUMPED)) + player->homing = 0; + } + else + player->homing = 0; + if (cmd->buttons & BT_JUMP) { player->pflags |= PF_JUMPDOWN; @@ -5238,7 +5500,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_JUMPDOWN; // Repeat abilities, but not double jump! - if (player->secondjump == 1 && player->charability != CA_DOUBLEJUMP) + if (player->secondjump == 1 && player->charability != CA_DOUBLEJUMP && player->charability != CA_AIRDRILL) { if (player->charflags & SF_MULTIABILITY) { @@ -5491,7 +5753,7 @@ static void P_2dMovement(player_t *player) if (player->climbing) { if (cmd->forwardmove != 0) - P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT,10*FRACUNIT), false); + P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT, 15*FRACUNIT>>1), false); player->mo->momx = 0; } @@ -5648,35 +5910,28 @@ static void P_3dMovement(player_t *player) else topspeed = normalspd; } - else if (player->powers[pw_super] || player->powers[pw_sneakers]) - { - thrustfactor = player->thrustfactor*2; - acceleration = player->accelstart/2 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration/2; - - if (player->powers[pw_tailsfly]) - topspeed = normalspd; - else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) - { - topspeed = normalspd; - acceleration = 2*acceleration/3; - } - else - topspeed = normalspd * 2; - } else { - thrustfactor = player->thrustfactor; - acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration; - - if (player->powers[pw_tailsfly]) - topspeed = normalspd/2; - else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) + if (player->powers[pw_super] || player->powers[pw_sneakers]) { - topspeed = normalspd/2; - acceleration = 2*acceleration/3; + topspeed = 5 * normalspd / 3; // 1.67x + thrustfactor = player->thrustfactor*2; + acceleration = player->accelstart/2 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration/2; } else + { topspeed = normalspd; + thrustfactor = player->thrustfactor; + acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration; + } + + if (player->powers[pw_tailsfly]) + topspeed >>= 1; + else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) + { + topspeed >>= 1; + acceleration = 2*acceleration/3; + } } if (spin) // Prevent gaining speed whilst rolling! @@ -5715,7 +5970,7 @@ static void P_3dMovement(player_t *player) if (player->climbing) { if (cmd->forwardmove) - P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT, 10*FRACUNIT), false); + P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT, 15*FRACUNIT>>1), false); } else if (!analogmove && cmd->forwardmove != 0 && !(player->pflags & PF_GLIDING || player->exiting @@ -5749,7 +6004,7 @@ static void P_3dMovement(player_t *player) } // Sideways movement if (player->climbing) - P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FixedMul(FixedDiv(cmd->sidemove*FRACUNIT, 10*FRACUNIT), player->mo->scale)); + P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FixedDiv(cmd->sidemove*player->mo->scale, 15*FRACUNIT>>1)); // Analog movement control else if (analogmove) { @@ -7156,10 +7411,13 @@ static void P_NiGHTSMovement(player_t *player) && player->mo->z + player->mo->height - P_GetPlayerHeight(player) <= player->mo->waterbottom && player->mo->z + player->mo->height >= player->mo->waterbottom)) && player->speed > 9000 && leveltime % (TICRATE/7) == 0 && !player->spectator) { + mobjtype_t splishtype = (player->mo->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH; mobj_t *water = P_SpawnMobj(player->mo->x, player->mo->y, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_SPLISH].height, player->mo->scale) : player->mo->watertop), MT_SPLISH); + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[splishtype].height, player->mo->scale) : player->mo->watertop), splishtype); if (player->mo->eflags & MFE_GOOWATER) S_StartSound(water, sfx_ghit); + else if (player->mo->eflags & MFE_TOUCHLAVA) + S_StartSound(water, sfx_splash); else S_StartSound(water, sfx_wslap); if (player->mo->eflags & MFE_VERTICALFLIP) @@ -7445,15 +7703,17 @@ static void P_SkidStuff(player_t *player) { player->skidtime = 0; player->pflags &= ~(PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags |= PF_THOKKED; // nice try, speedrunners (but for real this is just behavior from S3K) P_SetPlayerMobjState(player->mo, S_PLAY_FALL); } // Get up and brush yourself off, idiot. - else if (player->glidetime > 15) + else if (player->glidetime > 15 || !(player->cmd.buttons & BT_JUMP)) { P_ResetPlayer(player); - P_SetPlayerMobjState(player->mo, S_PLAY_STND); - player->mo->momx = player->cmomx; - player->mo->momy = player->cmomy; + P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE_LANDING); + player->pflags |= PF_STASIS; + player->mo->momx = ((player->mo->momx - player->cmomx)/3) + player->cmomx; + player->mo->momy = ((player->mo->momy - player->cmomy)/3) + player->cmomy; } // Didn't stop yet? Skid FOREVER! else if (player->skidtime == 1) @@ -7461,7 +7721,8 @@ static void P_SkidStuff(player_t *player) // Spawn a particle every 3 tics. else if (!(player->skidtime % 3)) { - mobj_t *particle = P_SpawnMobjFromMobj(player->mo, P_RandomRange(-player->mo->radius, player->mo->radius), P_RandomRange(-player->mo->radius, player->mo->radius), 0, MT_SPINDUST); + fixed_t radius = player->mo->radius >> FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(player->mo, P_RandomRange(-radius, radius) << FRACBITS, P_RandomRange(-radius, radius) << FRACBITS, 0, MT_SPINDUST); particle->tics = 10; particle->destscale = (2*player->mo->scale)/3; @@ -7559,6 +7820,12 @@ static void P_MovePlayer(player_t *player) if (!(player->powers[pw_nocontrol] & (1<<15))) player->pflags |= PF_JUMPSTASIS; } + + if (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING) + { + player->pflags |= PF_STASIS; + } + // note: don't unset stasis here if (!player->spectator && G_TagGametype()) @@ -7714,7 +7981,7 @@ static void P_MovePlayer(player_t *player) if ((cmd->forwardmove != 0 || cmd->sidemove != 0) || (player->powers[pw_super] && !onground)) { // If the player is in dashmode, here's their peelout. - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim == PA_RUN && !player->skidtime && (onground || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super])) + if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim == PA_RUN && !player->skidtime && (onground || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super])) P_SetPlayerMobjState (player->mo, S_PLAY_DASH); // If the player is moving fast enough, // break into a run! @@ -7738,7 +8005,7 @@ static void P_MovePlayer(player_t *player) // If your peelout animation is playing, and you're // going too slow, switch back to the run. - if (player->charflags & SF_DASHMODE && player->panim == PA_DASH && player->dashmode < 3*TICRATE) + if (player->charflags & SF_DASHMODE && player->panim == PA_DASH && player->dashmode < DASHMODE_THRESHOLD) P_SetPlayerMobjState(player->mo, S_PLAY_RUN); // If your running animation is playing, and you're @@ -7818,10 +8085,13 @@ static void P_MovePlayer(player_t *player) // AKA my own gravity. =) if (player->pflags & PF_GLIDING) { + mobj_t *mo = player->mo; // seriously why isn't this at the top of the function hngngngng fixed_t leeway; fixed_t glidespeed = player->actionspd; + fixed_t momx = mo->momx - player->cmomx, momy = mo->momy - player->cmomy; + angle_t angle, moveangle = R_PointToAngle2(0, 0, momx, momy); - if (player->powers[pw_super]) + if (player->powers[pw_super] || player->powers[pw_sneakers]) glidespeed *= 2; if (player->mo->eflags & MFE_VERTICALFLIP) @@ -7836,22 +8106,46 @@ static void P_MovePlayer(player_t *player) } // Strafing while gliding. - leeway = FixedAngle(cmd->sidemove*(FRACUNIT/2)); + leeway = FixedAngle(cmd->sidemove*(FRACUNIT)); + angle = mo->angle - leeway; - if (player->skidtime) // ground gliding + if (!player->skidtime) // TODO: make sure this works in 2D! { - fixed_t speed = FixedMul(glidespeed, FRACUNIT - (FRACUNIT>>2)); - if (player->mo->eflags & MFE_UNDERWATER) - speed >>= 1; - speed = FixedMul(speed - player->glidetime*FRACUNIT, player->mo->scale); - if (speed < 0) - speed = 0; - P_InstaThrust(player->mo, player->mo->angle-leeway, speed); + fixed_t speed, scale = mo->scale; + fixed_t newMagnitude, oldMagnitude = R_PointToDist2(momx, momy, 0, 0); + fixed_t accelfactor = 4*FRACUNIT - 3*FINECOSINE(((angle-moveangle) >> ANGLETOFINESHIFT) & FINEMASK); // mamgic number BAD but this feels right + + if (mo->eflags & MFE_UNDERWATER) + speed = FixedMul((glidespeed>>1) + player->glidetime*750, scale); + else + speed = FixedMul(glidespeed + player->glidetime*1500, scale); + + P_Thrust(mo, angle, FixedMul(accelfactor, scale)); + + newMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); + if (newMagnitude > speed) + { + fixed_t tempmomx, tempmomy; + if (oldMagnitude > speed) + { + if (newMagnitude > oldMagnitude) + { + tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), oldMagnitude); + tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), oldMagnitude); + player->mo->momx = tempmomx + player->cmomx; + player->mo->momy = tempmomy + player->cmomy; + } + // else do nothing + } + else + { + tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), speed); + tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), speed); + player->mo->momx = tempmomx + player->cmomx; + player->mo->momy = tempmomy + player->cmomy; + } + } } - else if (player->mo->eflags & MFE_UNDERWATER) - P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul((glidespeed>>1) + player->glidetime*750, player->mo->scale)); - else - P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul(glidespeed + player->glidetime*1500, player->mo->scale)); player->glidetime++; @@ -7876,22 +8170,13 @@ static void P_MovePlayer(player_t *player) } else if (player->climbing) // 'Deceleration' for climbing on walls. { - if (player->mo->momz > 0) - { - player->mo->momz -= FixedMul(FRACUNIT/2, player->mo->scale); - if (player->mo->momz < 0) - player->mo->momz = 0; - } - else if (player->mo->momz < 0) - { - player->mo->momz += FixedMul(FRACUNIT/2, player->mo->scale); - if (player->mo->momz > 0) - player->mo->momz = 0; - } + + if (!player->cmd.forwardmove) + player->mo->momz = 0; } else if (player->pflags & PF_BOUNCING) { - if (!(player->pflags & PF_JUMPDOWN) || (onground && P_MobjFlip(player->mo)*player->mo->momz <= 0)) // If not holding the jump button OR on flat ground + if (!(player->pflags & PF_JUMPDOWN)) // If not holding the jump button { P_ResetPlayer(player); // down, stop bouncing. player->pflags |= PF_THOKKED; @@ -7921,10 +8206,13 @@ static void P_MovePlayer(player_t *player) && (player->speed > runspd || (player->pflags & PF_STARTDASH)) && leveltime % (TICRATE/7) == 0 && player->mo->momz == 0 && !(player->pflags & PF_SLIDING) && !player->spectator) { + mobjtype_t splishtype = (player->mo->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH; mobj_t *water = P_SpawnMobj(player->mo->x - P_ReturnThrustX(NULL, player->mo->angle, player->mo->radius), player->mo->y - P_ReturnThrustY(NULL, player->mo->angle, player->mo->radius), - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_SPLISH].height, player->mo->scale) : player->mo->watertop), MT_SPLISH); + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[splishtype].height, player->mo->scale) : player->mo->watertop), splishtype); if (player->mo->eflags & MFE_GOOWATER) S_StartSound(water, sfx_ghit); + else if (player->mo->eflags & MFE_TOUCHLAVA) + S_StartSound(water, sfx_splash); else S_StartSound(water, sfx_wslap); if (player->mo->eflags & MFE_VERTICALFLIP) @@ -7991,16 +8279,22 @@ static void P_MovePlayer(player_t *player) if (P_MobjFlip(player->mo)*player->mo->momz < FixedMul(5*actionspd, player->mo->scale)) P_SetObjectMomZ(player->mo, actionspd/2, true); + P_SetPlayerMobjState(player->mo, player->mo->state->nextstate); + player->fly1--; } } // Tails Put-Put noise - if (player->charability == CA_FLY && player->bot != 1 && leveltime % 10 == 0 && !player->spectator) + if (player->charability == CA_FLY + && player->bot != 1 + && !(player->mo->eflags & MFE_UNDERWATER) + && leveltime % 10 == 0 + && !player->spectator) S_StartSound(player->mo, sfx_putput); // Descend - if (cmd->buttons & BT_USE && !(player->pflags & PF_STASIS) && !player->exiting) + if (cmd->buttons & BT_USE && !(player->pflags & PF_STASIS) && !player->exiting && !(player->mo->eflags & MFE_GOOWATER)) if (P_MobjFlip(player->mo)*player->mo->momz > -FixedMul(5*actionspd, player->mo->scale)) P_SetObjectMomZ(player->mo, -actionspd/2, true); @@ -8008,11 +8302,12 @@ static void P_MovePlayer(player_t *player) else { // Tails-gets-tired Stuff - if (player->panim == PA_ABILITY) + if (player->panim == PA_ABILITY && player->mo->state-states != S_PLAY_FLY_TIRED) P_SetPlayerMobjState(player->mo, S_PLAY_FLY_TIRED); if (player->charability == CA_FLY && (leveltime % 10 == 0) && player->mo->state-states == S_PLAY_FLY_TIRED + && !(player->mo->eflags & MFE_UNDERWATER) && !player->spectator) S_StartSound(player->mo, sfx_pudpud); } @@ -8117,178 +8412,6 @@ static void P_MovePlayer(player_t *player) localangle2 = player->mo->angle; } - ////////////////// - //SHIELD ACTIVES// - //& SUPER FLOAT!// - ////////////////// - - if (player->pflags & PF_JUMPED && !player->exiting && player->mo->health) - { - mobj_t *lockon = NULL; - if (!player->powers[pw_super] && player->powers[pw_shield] == SH_ATTRACT && !(player->pflags & PF_THOKKED)) - { - if ((lockon = P_LookForEnemies(player, false, false))) - { - if (P_IsLocalPlayer(player)) // Only display it on your own view. - { - mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockon); - P_SetMobjStateNF(visual, visual->info->spawnstate+1); - } - } - } - if (cmd->buttons & BT_USE) // Spin button effects - { - if (player->powers[pw_super]) // Super can't use shield actives, only passives - { - if ((player->charability == CA_THOK) // Super Sonic float - && (player->speed > 5*player->mo->scale) // FixedMul(5<mo->scale), but scale is FRACUNIT-based - && (P_MobjFlip(player->mo)*player->mo->momz <= 0)) - { - if (player->panim != PA_RUN && player->panim != PA_WALK) - { - if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); - else - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); - } - - player->mo->momz = 0; - player->pflags &= ~(PF_STARTJUMP|PF_SPINNING); - } - } - else -#ifdef HAVE_BLUA - if (!LUAh_ShieldSpecial(player)) -#endif - { - if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously - && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super - { - // Force stop - if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) - { - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - S_StartSound(player->mo, sfx_ngskid); - } - else - { - switch (player->powers[pw_shield] & SH_NOSTACK) - { - // Super! - case SH_NONE: - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - break; - // Whirlwind jump/Thunder jump - case SH_WHIRLWIND: - case SH_THUNDERCOIN: - P_DoJumpShield(player); - break; - // Armageddon pow - case SH_ARMAGEDDON: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - P_BlackOw(player); - break; - // Attraction blast - case SH_ATTRACT: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->homing = 2; - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockon)); - if (lockon) - { - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); - player->pflags &= ~PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_s3k40); - player->homing = 3*TICRATE; - } - else - S_StartSound(player->mo, sfx_s3ka6); - break; - // Elemental stomp/Bubble bounce - case SH_ELEMENTAL: - case SH_BUBBLEWRAP: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->pflags &= ~PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - player->secondjump = 0; - player->mo->momx = player->mo->momy = 0; - P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); - S_StartSound(player->mo, - ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) - ? sfx_s3k43 - : sfx_s3k44); - break; - // Flame burst - case SH_FLAMEAURA: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); - player->drawangle = player->mo->angle; - S_StartSound(player->mo, sfx_s3k43); - default: - break; - } - } - } - } - } - } - - // HOMING option. - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT // Sonic 3D Blast. - && player->pflags & PF_SHIELDABILITY) - { - if (player->homing && player->mo->tracer) - { - if (!P_HomingAttack(player->mo, player->mo->tracer)) - { - P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); - if (player->mo->eflags & MFE_UNDERWATER) - player->mo->momz = FixedMul(player->mo->momz, FRACUNIT/3); - player->homing = 0; - } - } - - // If you're not jumping, then you obviously wouldn't be homing. - if (!(player->pflags & PF_JUMPED)) - player->homing = 0; - } - else if (player->charability == CA_HOMINGTHOK) // Sonic Adventure. - { - // If you've got a target, chase after it! - if (player->homing && player->mo->tracer) - { - P_SpawnThokMobj(player); - - // But if you don't, then stop homing. - if (!P_HomingAttack(player->mo, player->mo->tracer)) - { - if (player->mo->eflags & MFE_UNDERWATER) - P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); - else - P_SetObjectMomZ(player->mo, 10*FRACUNIT, false); - - player->mo->momx = player->mo->momy = player->homing = 0; - - if (player->mo->tracer->flags2 & MF2_FRET) - P_InstaThrust(player->mo, player->mo->angle, -(player->speed>>3)); - - if (!(player->mo->tracer->flags & MF_BOSS)) - player->pflags &= ~PF_THOKKED; - - // P_SetPlayerMobjState(player->mo, S_PLAY_SPRING); -- Speed didn't like it, RIP - } - } - - // If you're not jumping, then you obviously wouldn't be homing. - if (!(player->pflags & PF_JUMPED)) - player->homing = 0; - } - else - player->homing = 0; - if (player->climbing == 1) P_DoClimbing(player); @@ -8332,7 +8455,7 @@ static void P_MovePlayer(player_t *player) // Less height while spinning. Good for spinning under things...? if ((player->mo->state == &states[player->mo->info->painstate]) - || ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE && player->charflags & SF_NOJUMPSPIN)) + || ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE)) || (player->pflags & PF_SPINNING) || player->powers[pw_tailsfly] || player->pflags & PF_GLIDING || (player->charability == CA_FLY && player->mo->state-states == S_PLAY_FLY_TIRED)) @@ -8633,7 +8756,7 @@ static void P_DoRopeHang(player_t *player) if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope { - player->pflags |= P_GetJumpFlags(player); + player->pflags |= (P_GetJumpFlags(player)|PF_USEDOWN); P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); P_SetTarget(&player->mo->tracer, NULL); @@ -8826,7 +8949,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) continue; if (mo->type == MT_MINUS && !(mo->flags & (MF_SPECIAL|MF_SHOOTABLE))) - mo->flags |= MF_SPECIAL|MF_SHOOTABLE; + mo->flags = (mo->flags & ~MF_NOCLIPTHING)|MF_SPECIAL|MF_SHOOTABLE; if (mo->type == MT_EGGGUARD && mo->tracer) //nuke Egg Guard's shield! P_KillMobj(mo->tracer, inflictor, source, DMG_NUKE); @@ -8843,7 +8966,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) // Looks for something you can hit - Used for homing attack // If nonenemies is true, includes monitors and springs! // If bullet is true, you can look up and the distance is further, -// but your total angle span you can look is limited to compensate. +// but your total angle span you can look is limited to compensate. (Also, allows monitors.) // mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) { @@ -8853,6 +8976,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) const fixed_t maxdist = FixedMul((bullet ? RING_DIST*2 : RING_DIST), player->mo->scale); const angle_t span = (bullet ? ANG30 : ANGLE_90); fixed_t dist, closestdist = 0; + const mobjflag_t nonenemiesdisregard = (bullet ? 0 : MF_MONITOR)|MF_SPRING; for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next) { @@ -8860,19 +8984,23 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; mo = (mobj_t *)think; - if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag - continue; // not a valid target + + if (mo->flags & MF_NOCLIPTHING) + continue; if (mo->health <= 0) // dead continue; + if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + continue; // not a valid target + if (mo == player->mo) continue; if (mo->flags2 & MF2_FRET) continue; - if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING)) + if (!nonenemies && mo->flags & nonenemiesdisregard) continue; if (!bullet && mo->type == MT_DETON) // Don't be STUPID, Sonic! @@ -9027,19 +9155,22 @@ boolean P_GetLives(player_t *player) INT32 i, maxlivesplayer = -1, livescheck = 1; if (!(netgame || multiplayer) || (gametype != GT_COOP) - || (cv_cooplives.value == 1) || (player->lives == INFLIVES)) return true; - if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0) - return true; - if (cv_cooplives.value == 0) // infinite lives { - player->lives++; + if (player->lives < 1) + player->lives = 1; return true; } + if ((cv_cooplives.value == 2 || cv_cooplives.value == 1) && player->lives > 0) + return true; + + if (cv_cooplives.value == 1) + return false; + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -9146,7 +9277,7 @@ static void P_DeathThink(player_t *player) // continue logic if (!(netgame || multiplayer) && player->lives <= 0) { - if (player->deadtimer > TICRATE && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) + if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) G_UseContinue(); else if (player->deadtimer >= gameovertics) G_UseContinue(); // Even if we don't have one this handles ending the game @@ -9170,12 +9301,12 @@ static void P_DeathThink(player_t *player) // Force respawn if idle for more than 30 seconds in shooter modes. if (player->deadtimer > 30*TICRATE && !G_PlatformGametype()) player->playerstate = PST_REBORN; - else if ((player->lives > 0 || j != MAXPLAYERS) && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages! + else if ((player->lives > 0 || j != MAXPLAYERS) && !(!(netgame || multiplayer) && G_IsSpecialStage(gamemap))) // Don't allow "click to respawn" in special stages! { if (gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) { P_ConsiderAllGone(); - if ((player->deadtimer > 5*TICRATE) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) + if ((player->deadtimer > TICRATE<<1) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) { //player->spectator = true; player->outofcoop = true; @@ -9191,16 +9322,11 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; else switch(gametype) { case GT_COOP: - if (player->deadtimer > TICRATE) - player->playerstate = PST_REBORN; - break; case GT_COMPETITION: + case GT_RACE: if (player->deadtimer > TICRATE) player->playerstate = PST_REBORN; break; - case GT_RACE: - player->playerstate = PST_REBORN; - break; default: if (player->deadtimer > cv_respawntime.value*TICRATE) player->playerstate = PST_REBORN; @@ -9209,7 +9335,7 @@ static void P_DeathThink(player_t *player) } // Single player auto respawn - if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE) + if (!(netgame || multiplayer) && player->deadtimer > TICRATE<<1) player->playerstate = PST_REBORN; } } @@ -9309,12 +9435,16 @@ consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, consvar_t cv_cam_speed = {"cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_orbit = {"cam_orbit", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_adjust = {"cam_adjust", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_dist = {"cam2_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_height = {"cam2_height", "25", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_speed = {"cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_orbit = {"cam2_orbit", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_adjust = {"cam2_adjust", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; fixed_t t_cam_dist = -42; fixed_t t_cam_height = -42; @@ -9368,9 +9498,9 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled) { angle_t angle = 0, focusangle = 0, focusaiming = 0; - fixed_t x, y, z, dist, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; + fixed_t x, y, z, dist, distxy, distz, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight, slopez = 0; INT32 camrotate; - boolean camstill, cameranoclip; + boolean camstill, cameranoclip, camorbit; mobj_t *mo; subsector_t *newsubsec; fixed_t f1, f2; @@ -9451,6 +9581,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // force defaults because we have a camera look section camspeed = (INT32)(atof(cv_cam_speed.defaultvalue) * FRACUNIT); camstill = (!stricmp(cv_cam_still.defaultvalue, "off")) ? false : true; + camorbit = (!stricmp(cv_cam_orbit.defaultvalue, "off")) ? false : true; camrotate = atoi(cv_cam_rotate.defaultvalue); camdist = FixedMul((INT32)(atof(cv_cam_dist.defaultvalue) * FRACUNIT), mo->scale); camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), FixedMul(player->camerascale, mo->scale)); @@ -9459,6 +9590,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { camspeed = cv_cam_speed.value; camstill = cv_cam_still.value; + camorbit = cv_cam_orbit.value; camrotate = cv_cam_rotate.value; camdist = FixedMul(cv_cam_dist.value, mo->scale); camheight = FixedMul(cv_cam_height.value, FixedMul(player->camerascale, mo->scale)); @@ -9467,6 +9599,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { camspeed = cv_cam2_speed.value; camstill = cv_cam2_still.value; + camorbit = cv_cam2_orbit.value; camrotate = cv_cam2_rotate.value; camdist = FixedMul(cv_cam2_dist.value, mo->scale); camheight = FixedMul(cv_cam2_height.value, FixedMul(player->camerascale, mo->scale)); @@ -9576,13 +9709,50 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall dist <<= 1; } + + checkdist = (dist = FixedMul(dist, player->camerascale)); if (checkdist < 128*FRACUNIT) checkdist = 128*FRACUNIT; - x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); - y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); + if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE)) // This block here is like 90% Lach's work, thanks bud + { + if (!resetcalled && ((thiscam == &camera && cv_cam_adjust.value) || (thiscam == &camera2 && cv_cam2_adjust.value))) + { + if (!(mo->eflags & MFE_JUSTHITFLOOR) && (P_IsObjectOnGround(mo)) // Check that player is grounded + && thiscam->ceilingz - thiscam->floorz >= P_GetPlayerHeight(player)) // Check that camera's sector is large enough for the player to fit into, at least + { + if (mo->eflags & MFE_VERTICALFLIP) // if player is upside-down + { + //z = min(z, thiscam->ceilingz); // solution 1: change new z coordinate to be at LEAST its ground height + slopez += min(thiscam->ceilingz - mo->z, 0); // solution 2: change new z coordinate by the difference between camera's ground and top of player + } + else // player is not upside-down + { + //z = max(z, thiscam->floorz); // solution 1: change new z coordinate to be at LEAST its ground height + slopez += max(thiscam->floorz - mo->z - mo->height, 0); // solution 2: change new z coordinate by the difference between camera's ground and top of player + } + } + } + } + + if (camorbit) //Sev here, I'm guessing this is where orbital cam lives + { + if (rendermode == render_opengl) + distxy = FixedMul(dist, FINECOSINE((focusaiming>>ANGLETOFINESHIFT) & FINEMASK)); + else + distxy = dist; + distz = -FixedMul(dist, FINESINE((focusaiming>>ANGLETOFINESHIFT) & FINEMASK)) + slopez; + } + else + { + distxy = dist; + distz = slopez; + } + + x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); + y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); #if 0 if (twodlevel || (mo->flags2 & MF2_TWOD)) @@ -9619,9 +9789,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall pviewheight = FixedMul(41*player->height/48, mo->scale); if (mo->eflags & MFE_VERTICALFLIP) - z = mo->z + mo->height - pviewheight - camheight; + z = mo->z + mo->height - pviewheight - camheight + distz; else - z = mo->z + pviewheight + camheight; + z = mo->z + pviewheight + camheight + distz; // move camera down to move under lower ceilings newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); @@ -9934,6 +10104,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); + } boolean P_SpectatorJoinGame(player_t *player) @@ -10177,7 +10348,7 @@ static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *n ffloor_t *rover; for (rover = sec->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS)) + if (!(rover->flags & (FF_EXISTS|FF_BLOCKOTHERS))) continue; *nz = *rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight; @@ -10349,7 +10520,7 @@ static mobj_t *P_LookForRails(mobj_t* mobj, fixed_t c, fixed_t s, angle_t target //Axes must be directly parallel or antiparallel, give or take 5 degrees. if (angdiff < ANG10) { - mark = P_SpawnMobj(nx, ny, nz, mobj->info->raisestate); + mark = P_SpawnMobj(nx, ny, nz, (mobjtype_t)mobj->info->raisestate); return mark; } } @@ -10564,7 +10735,11 @@ static void P_MinecartThink(player_t *player) } } - P_SetPlayerMobjState(player->mo, S_PLAY_STND); + if (player->mo->state-states != S_PLAY_STND) + { + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + player->mo->tics = -1; + } // Move player to minecart. P_TeleportMove(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT); @@ -10585,7 +10760,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) angle_t horizangle = player->drawangle; fixed_t zoffs = 0; fixed_t backwards = -1*FRACUNIT; - boolean doroll = (player->panim == PA_ROLL || player->panim == PA_JUMP); + boolean doswim = (player->panim == PA_ABILITY && (player->mo->eflags & MFE_UNDERWATER)); + boolean doroll = (player->panim == PA_ROLL || (player->panim == PA_JUMP && !(player->charflags & SF_NOJUMPSPIN)) || doswim); angle_t rollangle; boolean panimchange; INT32 ticnum = 0; @@ -10612,17 +10788,25 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) if (testval < FRACUNIT) testval = FRACUNIT; } - if (smilesonground && !player->mo->reactiontime) + + if (doswim) + zdist = player->mo->momz<<1; + else if (smilesonground && !player->mo->reactiontime) zdist = (player->mo->z - tails->threshold); else zdist = player->mo->momz; + rollangle = R_PointToAngle2(0, 0, testval, -P_MobjFlip(player->mo)*zdist); - zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT); - backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT); + + if (!doswim) + { + zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT); + backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT); + } } else if (player->panim == PA_RUN) backwards = -5*FRACUNIT; - else if (player->panim == PA_SPRING) + else if (player->panim == PA_SPRING || player->panim == PA_JUMP) { zoffs += 4*FRACUNIT; backwards /= 2; @@ -10644,7 +10828,7 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) zoffs = -7*FRACUNIT; backwards = -9*FRACUNIT; } - else if (player->mo->sprite2 == SPR2_FLY || player->mo->sprite2 == SPR2_TIRE) + else if (player->panim == PA_ABILITY) backwards = -5*FRACUNIT; // sprite... @@ -10661,7 +10845,7 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) else chosenstate = S_TAILSOVERLAY_0DEGREES; } - else if (player->panim == PA_SPRING) + else if (player->panim == PA_SPRING || player->panim == PA_JUMP) chosenstate = S_TAILSOVERLAY_MINUS60DEGREES; else if (player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE) chosenstate = S_TAILSOVERLAY_PLUS60DEGREES; @@ -10684,6 +10868,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) } else if (player->mo->sprite2 == SPR2_FLY) chosenstate = S_TAILSOVERLAY_FLY; + else if (player->mo->sprite2 == SPR2_SWIM) + chosenstate = S_TAILSOVERLAY_FLY; else if (player->mo->sprite2 == SPR2_TIRE) chosenstate = S_TAILSOVERLAY_TIRE; else if (player->panim == PA_ABILITY2) @@ -10709,8 +10895,10 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) } } +#if 0 if (player->fly1 != 0 && player->powers[pw_tailsfly] != 0 && !smilesonground) P_SetMobjState(tails, chosenstate); +#endif // animation... if (player->panim == PA_SPRING || player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE) @@ -10725,7 +10913,7 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) else if (player->mo->state-states == S_PLAY_GASP) tails->tics = -1; else if (player->mo->sprite2 == SPR2_TIRE) - ticnum = 4; + ticnum = (doswim ? 2 : 4); else if (player->panim != PA_IDLE) ticnum = player->mo->tics; @@ -10762,6 +10950,123 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) P_SetThingPosition(tails); } +// Metal Sonic's jet fume +static void P_DoMetalJetFume(player_t *player, mobj_t *fume) +{ + static const UINT8 FUME_SKINCOLORS[] = + { + SKINCOLOR_ICY, + SKINCOLOR_SKY, + SKINCOLOR_CYAN, + SKINCOLOR_WAVE, + SKINCOLOR_TEAL, + SKINCOLOR_AQUA, + SKINCOLOR_SEAFOAM, + SKINCOLOR_MINT, + SKINCOLOR_PERIDOT, + SKINCOLOR_LIME, + SKINCOLOR_YELLOW, + SKINCOLOR_SANDY, + SKINCOLOR_GOLD, + SKINCOLOR_APRICOT, + SKINCOLOR_SUNSET + }; + mobj_t *mo = player->mo; + angle_t angle = player->drawangle; + fixed_t dist; + panim_t panim = player->panim; + tic_t dashmode = player->dashmode; + boolean underwater = mo->eflags & MFE_UNDERWATER; + statenum_t stat = fume->state-states; + + if (panim != PA_WALK && panim != PA_RUN && panim != PA_DASH) // turn invisible when not in a coherent movement state + { + if (stat != fume->info->spawnstate) + P_SetMobjState(fume, fume->info->spawnstate); + return; + } + + if (underwater) // No fume underwater; spawn bubbles instead! + { + fume->movedir += FixedAngle(FixedDiv(2 * player->speed, 3 * mo->scale)); + fume->movefactor += player->speed; + + if (fume->movefactor > FixedDiv(2 * player->normalspeed, 3 * mo->scale)) + { + INT16 i; + fixed_t radiusV = 4*FRACUNIT; + fixed_t radiusX = P_ReturnThrustX(mo, angle, -mo->radius >> (panim == PA_WALK ? 1 : 0)); + fixed_t radiusY = P_ReturnThrustY(mo, angle, -mo->radius >> (panim == PA_WALK ? 1 : 0)); + fixed_t factorX = P_ReturnThrustX(mo, angle + ANGLE_90, mo->scale); + fixed_t factorY = P_ReturnThrustY(mo, angle + ANGLE_90, mo->scale); + fixed_t offsetH, offsetV, x, y, z; + + for (i = -1; i < 2; i += 2) + { + offsetH = i*P_ReturnThrustX(fume, fume->movedir, radiusV); + offsetV = i*P_ReturnThrustY(fume, fume->movedir, radiusV); + x = mo->x + radiusX + FixedMul(offsetH, factorX); + y = mo->y + radiusY + FixedMul(offsetH, factorY); + z = mo->z + (mo->height >> 1) + offsetV; + P_SpawnMobj(x, y, z, MT_SMALLBUBBLE)->scale = mo->scale >> 1; + } + + fume->movefactor = 0; + } + + if (panim == PA_WALK) + { + if (stat != fume->info->spawnstate) + P_SetMobjState(fume, fume->info->spawnstate); + return; + } + } + + if (stat == fume->info->spawnstate) // If currently inivisble, activate! + { + P_SetMobjState(fume, (stat = fume->info->seestate)); + P_SetScale(fume, mo->scale); + } + + if (dashmode > DASHMODE_THRESHOLD && stat != fume->info->seestate) // If in dashmode, grow really big and flash + { + fume->destscale = mo->scale; + fume->flags2 ^= MF2_DONTDRAW; + fume->flags2 |= mo->flags2 & MF2_DONTDRAW; + } + else // Otherwise, pick a size and color depending on speed and proximity to dashmode + { + if (dashmode == DASHMODE_THRESHOLD && dashmode > (tic_t)fume->movecount) // If just about to enter dashmode, play the startup animation again + { + P_SetMobjState(fume, (stat = fume->info->seestate)); + P_SetScale(fume, mo->scale << 1); + } + fume->flags2 = (fume->flags2 & ~MF2_DONTDRAW) | (mo->flags2 & MF2_DONTDRAW); + fume->destscale = (mo->scale + FixedDiv(player->speed, player->normalspeed)) / (underwater ? 6 : 3); + fume->color = FUME_SKINCOLORS[(dashmode * sizeof(FUME_SKINCOLORS)) / (DASHMODE_MAX + 1)]; + + if (underwater) + { + fume->frame = (fume->frame & FF_FRAMEMASK) | FF_ANIMATE | (P_RandomRange(0, 9) * FF_TRANS10); + } + } + + fume->movecount = dashmode; // keeps track of previous dashmode value so we know whether Metal is entering or leaving it + fume->eflags = (fume->eflags & ~MFE_VERTICALFLIP) | (mo->eflags & MFE_VERTICALFLIP); // Make sure to flip in reverse gravity! + + // Finally, set its position + dist = -mo->radius - FixedMul(fume->info->radius, fume->destscale - mo->scale/3); + + P_UnsetThingPosition(fume); + fume->x = mo->x + P_ReturnThrustX(fume, angle, dist); + fume->y = mo->y + P_ReturnThrustY(fume, angle, dist); + if (fume->eflags & MFE_VERTICALFLIP) + fume->z = mo->z + ((mo->height + fume->height) >> 1); + else + fume->z = mo->z + ((mo->height - fume->height) >> 1); + P_SetThingPosition(fume); +} + // // P_PlayerThink // @@ -10948,7 +11253,8 @@ void P_PlayerThink(player_t *player) if (player->exiting == 2 || countdown2 == 2) { - if (cv_playersforexit.value) // Count to be sure everyone's exited + UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); + if (numneeded) // Count to be sure everyone's exited { INT32 i, total = 0, exiting = 0; @@ -10964,7 +11270,7 @@ void P_PlayerThink(player_t *player) exiting++; } - if (!total || ((4*exiting)/total) >= cv_playersforexit.value) + if (!total || ((4*exiting)/total) >= numneeded) { if (server) SendNetXCmd(XD_EXITLEVEL, NULL, 0); @@ -11011,8 +11317,6 @@ void P_PlayerThink(player_t *player) { if (gametype != GT_COOP) player->score = 0; - player->mo->health = 1; - player->rings = player->spheres = 0; } else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP) { @@ -11151,14 +11455,15 @@ void P_PlayerThink(player_t *player) // deez New User eXperiences. { + angle_t diff = 0; + UINT8 factor; // Directionchar! // Camera angle stuff. if (player->exiting // no control, no modification || player->powers[pw_carry] == CR_NIGHTSMODE) ; else if (!(player->pflags & PF_DIRECTIONCHAR) - || (player->climbing // stuff where the direction is forced at all times - || (player->pflags & PF_GLIDING)) + || (player->climbing) // stuff where the direction is forced at all times || (P_AnalogMove(player) || twodlevel || player->mo->flags2 & MF2_TWOD) // keep things synchronised up there, since the camera IS seperate from player motion when that happens || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming player->drawangle = player->mo->angle; @@ -11177,8 +11482,16 @@ void P_PlayerThink(player_t *player) /* FALLTHRU */ case CR_MINECART: case CR_GENERIC: + case CR_PTERABYTE: player->drawangle = player->mo->tracer->angle; break; + case CR_ROLLOUT: + if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys + { // inverse direction! + diff = ((player->mo->angle + R_PointToAngle2(0, 0, -cmd->forwardmove<sidemove<drawangle); + factor = 4; + } + break; /* -- in case we wanted to have the camera freely movable during zoom tubes case CR_ZOOMTUBE:*/ case CR_ROPEHANG: @@ -11193,22 +11506,34 @@ void P_PlayerThink(player_t *player) break; } } + else if (player->powers[pw_justsprung]) + { +#ifdef SPRINGSPIN + if (player->powers[pw_justsprung] & (1<<15)) + player->drawangle += (player->powers[pw_justsprung] & ~(1<<15))*(ANG2+ANG1); +#endif + } else if ((player->skidtime > (TICRATE/2 - 2) || ((player->pflags & (PF_SPINNING|PF_STARTDASH)) == PF_SPINNING)) && (abs(player->rmomx) > 5*player->mo->scale || abs(player->rmomy) > 5*player->mo->scale)) // spin/skid force player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); else if (((player->charability2 == CA2_GUNSLINGER || player->charability2 == CA2_MELEE) && player->panim == PA_ABILITY2) || player->pflags & PF_STASIS || player->skidtime) ; else { - angle_t diff; - UINT8 factor; - - if (player->pflags & PF_SLIDING) + if (player->pflags & PF_GLIDING) + { + if (player->speed < player->mo->scale) + diff = player->mo->angle - player->drawangle; + else + diff = (R_PointToAngle2(0, 0, player->rmomx, player->rmomy) - player->drawangle); + factor = 4; + } + else if (player->pflags & PF_SLIDING) { #if 0 // fun hydrocity style horizontal spin if (player->mo->eflags & MFE_TOUCHWATER || player->powers[pw_flashing] > (flashingtics/4)*3) { diff = (player->mo->angle - player->drawangle); - factor = 4; + factor = 16; } else { @@ -11217,7 +11542,7 @@ void P_PlayerThink(player_t *player) } #else diff = (player->mo->angle - player->drawangle); - factor = 4; + factor = 16; #endif } else if (player->pflags & PF_STARTDASH) @@ -11237,23 +11562,25 @@ void P_PlayerThink(player_t *player) diff = (player->mo->angle - player->drawangle); factor = 8; } + } - if (diff) - { - if (diff > ANGLE_180) - diff = InvAngle(InvAngle(diff)/factor); - else - diff /= factor; - player->drawangle += diff; - } + if (diff) + { + if (diff > ANGLE_180) + diff = InvAngle(InvAngle(diff)/factor); + else + diff /= factor; + player->drawangle += diff; } // Autobrake! check ST_drawInput if you modify this { boolean currentlyonground = P_IsObjectOnGround(player->mo); - if (!player->powers[pw_carry] - && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) + if (player->powers[pw_noautobrake]) + ; + else if (!player->powers[pw_carry] && !player->powers[pw_nocontrol] + && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE|PF_STASIS)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) && !(cmd->forwardmove || cmd->sidemove) && (player->rmomx || player->rmomy) && (!player->capsule || (player->capsule->reactiontime != (player-players)+1))) @@ -11264,7 +11591,7 @@ void P_PlayerThink(player_t *player) if (!currentlyonground) acceleration /= 2; // fake skidding! see P_SkidStuff for reference on conditionals - else if (!player->skidtime && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID) && P_AproxDistance(player->mo->momx, player->mo->momy) >= FixedMul(player->runspeed/2, player->mo->scale)) + else if (!player->skidtime && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID) && P_AproxDistance(player->mo->momx, player->mo->momy) >= FixedMul(player->runspeed, player->mo->scale)) // modified from player->runspeed/2 'cuz the skid was just TOO frequent ngl { if (player->mo->state-states != S_PLAY_SKID) P_SetPlayerMobjState(player->mo, S_PLAY_SKID); @@ -11294,9 +11621,6 @@ void P_PlayerThink(player_t *player) } } - if (player->powers[pw_pushing]) - player->powers[pw_pushing]--; - player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. // Unset statis flags after moving. @@ -11376,6 +11700,17 @@ void P_PlayerThink(player_t *player) if (player->powers[pw_tailsfly] && player->powers[pw_tailsfly] < UINT16_MAX && player->charability != CA_SWIM) // tails fly counter player->powers[pw_tailsfly]--; + if (player->powers[pw_pushing] && player->powers[pw_pushing] < UINT16_MAX) + player->powers[pw_pushing]--; + + if (player->powers[pw_justsprung] & ((1<<15)-1) && player->powers[pw_justsprung] < UINT16_MAX) + player->powers[pw_justsprung]--; + else + player->powers[pw_justsprung] = 0; + + if (player->powers[pw_pushing] && player->powers[pw_pushing] < UINT16_MAX) + player->powers[pw_pushing]--; + if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER))) { if (player->powers[pw_underwater] <= 12*TICRATE+1) @@ -11484,9 +11819,9 @@ void P_PlayerThink(player_t *player) if ((totallyradical && !floating) || (player->pflags & PF_STARTDASH)) { - if (dashmode < 3*TICRATE + 3) + if (dashmode < DASHMODE_MAX) dashmode++; // Counter. Adds 1 to dash mode per tic in top speed. - if (dashmode == 3*TICRATE) // This isn't in the ">=" equation because it'd cause the sound to play infinitely. + if (dashmode == DASHMODE_THRESHOLD) // This isn't in the ">=" equation because it'd cause the sound to play infinitely. S_StartSound(player->mo, sfx_s3ka2); // If the player enters dashmode, play this sound on the the tic it starts. } else if ((!totallyradical || !floating) && !(player->pflags & PF_SPINNING)) @@ -11497,7 +11832,7 @@ void P_PlayerThink(player_t *player) dashmode = 0; } - if (dashmode < 3*TICRATE) // Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair. + if (dashmode < DASHMODE_THRESHOLD) // Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair. { player->normalspeed = skins[player->skin].normalspeed; // Reset to default if not capable of entering dash mode. player->jumpfactor = skins[player->skin].jumpfactor; @@ -11519,7 +11854,7 @@ void P_PlayerThink(player_t *player) } else if (dashmode) { - if (dashmode >= 3*TICRATE) // catch getting the flag! + if (dashmode >= DASHMODE_THRESHOLD) // catch getting the flag! { player->normalspeed = skins[player->skin].normalspeed; player->jumpfactor = skins[player->skin].jumpfactor; @@ -11564,6 +11899,36 @@ void P_PlayerThink(player_t *player) }*/ } +// Checks if the mobj is above lava. Used by Pterabyte. +static boolean P_MobjAboveLava(mobj_t *mobj) +{ + sector_t *sector = mobj->subsector->sector; + + if (sector->ffloors) + { + ffloor_t *rover; + + for (rover = sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || GETSECSPECIAL(rover->master->frontsector->special, 1) != 3) + continue; + + if (mobj->eflags & MFE_VERTICALFLIP) + { + if (*rover->bottomheight <= mobj->ceilingz && *rover->bottomheight >= mobj->z) + return true; + } + else + { + if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z) + return true; + } + } + } + + return false; +} + // // P_PlayerAfterThink // @@ -11752,7 +12117,7 @@ void P_PlayerAfterThink(player_t *player) { if ((tails->z + tails->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= tails->ceilingz && (tails->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame - player->mo->z = tails->z + tails->height + FixedMul(FRACUNIT, player->mo->scale); + player->mo->z = tails->z + tails->height + 12*player->mo->scale; else player->powers[pw_carry] = CR_NONE; } @@ -11760,7 +12125,7 @@ void P_PlayerAfterThink(player_t *player) { if ((tails->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= tails->floorz && !(tails->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame - player->mo->z = tails->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale); + player->mo->z = tails->z - player->mo->height - 12*player->mo->scale; else player->powers[pw_carry] = CR_NONE; } @@ -11769,7 +12134,7 @@ void P_PlayerAfterThink(player_t *player) player->powers[pw_carry] = CR_NONE; else { - P_TryMove(player->mo, tails->x, tails->y, true); + P_TryMove(player->mo, tails->x + P_ReturnThrustX(tails, tails->player->drawangle, 4*FRACUNIT), tails->y + P_ReturnThrustY(tails, tails->player->drawangle, 4*FRACUNIT), true); player->mo->momx = tails->momx; player->mo->momy = tails->momy; player->mo->momz = tails->momz; @@ -11795,6 +12160,8 @@ void P_PlayerAfterThink(player_t *player) { if (player->mo->state-states != S_PLAY_RIDE) P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); + if ((tails->skin && ((skin_t *)(tails->skin))->sprites[SPR2_SWIM].numframes) && (tails->eflags & MFE_UNDERWATER)) + tails->player->powers[pw_tailsfly] = 0; } else P_SetTarget(&player->mo->tracer, NULL); @@ -11877,6 +12244,114 @@ void P_PlayerAfterThink(player_t *player) } break; } + case CR_ROLLOUT: + { + mobj_t *mo = player->mo, *rock = player->mo->tracer; + UINT8 walktics = mo->state->tics - P_GetPlayerControlDirection(player); + + if (!rock || P_MobjWasRemoved(rock)) + { + P_SetTarget(&player->mo->tracer, NULL); + player->powers[pw_carry] = CR_NONE; + break; + } + + if (player->cmd.forwardmove || player->cmd.sidemove) + { + rock->movedir = (player->cmd.angleturn << FRACBITS) + R_PointToAngle2(0, 0, player->cmd.forwardmove << FRACBITS, -player->cmd.sidemove << FRACBITS); + P_Thrust(rock, rock->movedir, rock->scale >> 1); + } + + mo->momx = rock->momx; + mo->momy = rock->momy; + mo->momz = 0; + + if (player->panim == PA_IDLE && (mo->momx || mo->momy)) + { + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + } + + if (player->panim == PA_WALK && mo->tics > walktics) + { + mo->tics = walktics; + } + + P_TeleportMove(player->mo, rock->x, rock->y, rock->z + rock->height); + break; + } + case CR_PTERABYTE: // being carried by a Pterabyte + { + mobj_t *ptera = player->mo->tracer; + mobj_t *spawnpoint = ptera->tracer->tracer; + player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14 * FRACUNIT, 10 * FRACUNIT)); + + if (ptera->health <= 0) + goto dropoff; + + if (P_MobjAboveLava(ptera) && ptera->movefactor <= 3*TICRATE - 10) + goto dropoff; + + if (player->mo->eflags & MFE_VERTICALFLIP) + { + if ((ptera->z + ptera->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= ptera->ceilingz + && (ptera->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame + player->mo->z = ptera->z + ptera->height + FixedMul(FRACUNIT, player->mo->scale); + + if (ptera->ceilingz - ptera->z > spawnpoint->ceilingz - spawnpoint->z + 512*FRACUNIT && ptera->movefactor <= 3 * TICRATE - 10) + goto dropoff; + } + else + { + if ((ptera->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= ptera->floorz + && !(ptera->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame + player->mo->z = ptera->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale); + + if (ptera->z - ptera->floorz > spawnpoint->z - spawnpoint->floorz + 512 * FRACUNIT && ptera->movefactor <= 3 * TICRATE - 10) + goto dropoff; + } + + ptera->movefactor--; + if (!ptera->movefactor) + goto dropoff; + + if (ptera->cusval >= 50) + { + player->powers[pw_carry] = CR_NONE; + P_SetTarget(&player->mo->tracer, NULL); + P_KillMobj(ptera, player->mo, player->mo, 0); + player->mo->momz = 9*FRACUNIT; + player->pflags |= PF_APPLYAUTOBRAKE|PF_JUMPED|PF_THOKKED; + P_SetMobjState(player->mo, S_PLAY_ROLL); + break; + } + + if (ptera->cusval) + ptera->cusval--; + + P_TryMove(player->mo, ptera->x + ptera->watertop, ptera->y + ptera->waterbottom, true); + player->mo->z += ptera->cvmem; + player->mo->momx = ptera->momx; + player->mo->momy = ptera->momy; + player->mo->momz = ptera->momz; + + if (P_AproxDistance(player->mo->x - ptera->x - ptera->watertop, player->mo->y - ptera->y - ptera->waterbottom) > player->mo->radius) + goto dropoff; + + ptera->watertop >>= 1; + ptera->waterbottom >>= 1; + ptera->cvmem >>= 1; + + if (player->mo->state-states != S_PLAY_FALL) + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + break; + + dropoff: + player->powers[pw_carry] = CR_NONE; + P_SetTarget(&player->mo->tracer, NULL); + ptera->movefactor = TICRATE; + ptera->extravalue1 |= 4; + break; + } default: break; } @@ -11925,7 +12400,15 @@ void P_PlayerAfterThink(player_t *player) { P_SetTarget(&player->followmobj, P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem)); P_SetTarget(&player->followmobj->tracer, player->mo); - player->followmobj->flags2 |= MF2_LINKDRAW; + switch (player->followmobj->type) + { + case MT_METALJETFUME: + player->followmobj->colorized = true; + break; + default: + player->followmobj->flags2 |= MF2_LINKDRAW; + break; + } } if (player->followmobj) @@ -11941,6 +12424,9 @@ void P_PlayerAfterThink(player_t *player) case MT_TAILSOVERLAY: // c: P_DoTailsOverlay(player, player->followmobj); break; + case MT_METALJETFUME: + P_DoMetalJetFume(player, player->followmobj); + break; default: var1 = 1; var2 = 0; diff --git a/src/r_data.c b/src/r_data.c index 38dc28980..524baad15 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -23,6 +23,7 @@ #include "z_zone.h" #include "p_setup.h" // levelflats #include "v_video.h" // pMasterPalette +#include "byteptr.h" #include "dehacked.h" #ifdef _WIN32 @@ -34,7 +35,7 @@ #endif // Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog -#ifdef _WIN32_WCE +#if 0 #define AVOID_ERRNO #else #include @@ -241,7 +242,7 @@ static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, tex } } -RGBA_t ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) +UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) { RGBA_t output; if (style == AST_TRANSLUCENT) @@ -261,6 +262,9 @@ RGBA_t ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alph // if there's no pixel in here if (!background.rgba) output.s.alpha = foreground.s.alpha; + else + output.s.alpha = 0xFF; + return output.rgba; } #define clamp(c) max(min(c, 0xFF), 0x00); else @@ -298,30 +302,38 @@ RGBA_t ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alph } // just copy the pixel else if (style == AST_COPY) - return background; + output.rgba = foreground.rgba; + + output.s.alpha = 0xFF; + return output.rgba; } #undef clamp - // unimplemented blend modes return the background pixel - output = background; - output.s.alpha = 0xFF; - return output; + return 0; } UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha) { - if ((style == AST_TRANSLUCENT) && (alpha <= (10*255/11))) // Alpha style set to translucent? Is the alpha small enough for translucency? + // Alpha style set to translucent? + if (style == AST_TRANSLUCENT) { - UINT8 *mytransmap; - if (alpha < 255/11) // Is the patch way too translucent? Don't render then. - return background; - // The equation's not exact but it works as intended. I'll call it a day for now. - mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); - if (background != 0xFF) - return *(mytransmap + (background<<8) + foreground); + // Is the alpha small enough for translucency? + if (alpha <= (10*255/11)) + { + UINT8 *mytransmap; + // Is the patch way too translucent? Don't blend then. + if (alpha < 255/11) + return background; + // The equation's not exact but it works as intended. I'll call it a day for now. + mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); + if (background != 0xFF) + return *(mytransmap + (background<<8) + foreground); + } + else // just copy the pixel + return foreground; } // just copy the pixel else if (style == AST_COPY) - return background; + return foreground; // use ASTBlendPixel for all other blend modes // and find the nearest colour in the palette else if (style != AST_TRANSLUCENT) @@ -329,7 +341,7 @@ UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 al RGBA_t texel; RGBA_t bg = V_GetColor(background); RGBA_t fg = V_GetColor(foreground); - texel = ASTBlendPixel(bg, fg, style, alpha); + texel.rgba = ASTBlendPixel(bg, fg, style, alpha); return NearestColor(texel.s.red, texel.s.green, texel.s.blue); } // fallback if all above fails, somehow @@ -374,7 +386,7 @@ static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpa if (count > 0) { for (; dest < cache + position + count; source++, dest++) - if (*dest != 0xFF) + if (*source != 0xFF) *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); } @@ -383,7 +395,7 @@ static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpa } // -// R_DrawTransColumnInCache +// R_DrawBlendFlippedColumnInCache // Similar to the one above except that the column is inverted. // static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) @@ -418,7 +430,7 @@ static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache if (count > 0) { for (; dest < cache + position + count; --source, dest++) - if (*dest != 0xFF) + if (*source != 0xFF) *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); } @@ -471,12 +483,12 @@ static UINT8 *R_GenerateTexture(size_t texnum) wadnum = patch->wad; lumpnum = patch->lump; lumplength = W_LumpLengthPwad(wadnum, lumpnum); - realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); // can't use W_CachePatchNumPwad because OpenGL #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) { - realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength); + realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); goto multipatch; } #endif @@ -545,7 +557,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) texturememory += blocksize; block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); - memset(block, 0xFF, blocksize+1); // Transparency hack + memset(block, TRANSPARENTPIXEL, blocksize+1); // Transparency hack // columns lookup table colofs = (UINT32 *)(void *)block; @@ -569,7 +581,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength); + realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); #endif x1 = patch->originx; @@ -2508,7 +2520,11 @@ void R_PrecacheLevel(void) "spritememory: %s k\n", sizeu1(flatmemory>>10), sizeu2(texturememory>>10), sizeu3(spritememory>>10)); } -// https://github.com/coelckers/prboom-plus/blob/master/prboom2/src/r_patch.c#L350 +// +// R_CheckIfPatch +// +// Returns true if the lump is a valid patch. +// boolean R_CheckIfPatch(lumpnum_t lump) { size_t size; @@ -2553,6 +2569,71 @@ boolean R_CheckIfPatch(lumpnum_t lump) return result; } +// +// R_TextureToFlat +// +// Convert a texture to a flat. +// +void R_TextureToFlat(size_t tex, UINT8 *flat) +{ + texture_t *texture = textures[tex]; + + fixed_t col, ofs; + column_t *column; + UINT8 *desttop, *dest, *deststop; + UINT8 *source; + + // yea + R_CheckTextureCache(tex); + + desttop = flat; + deststop = desttop + (texture->width * texture->height); + + for (col = 0; col < texture->width; col++, desttop++) + { + // no post_t info + if (!texture->holes) + { + column = (column_t *)(R_GetColumn(tex, col)); + source = (UINT8 *)(column); + dest = desttop; + for (ofs = 0; dest < deststop && ofs < texture->height; ofs++) + { + if (source[ofs] != TRANSPARENTPIXEL) + *dest = source[ofs]; + dest += texture->width; + } + } + else + { + INT32 topdelta, prevdelta = -1; + column = (column_t *)((UINT8 *)R_GetColumn(tex, col) - 3); + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + + dest = desttop + (topdelta * texture->width); + source = (UINT8 *)column + 3; + for (ofs = 0; dest < deststop && ofs < column->length; ofs++) + { + if (source[ofs] != TRANSPARENTPIXEL) + *dest = source[ofs]; + dest += texture->width; + } + column = (column_t *)((UINT8 *)column + column->length + 4); + } + } + } +} + +// +// R_PatchToFlat +// +// Convert a patch to a flat. +// void R_PatchToFlat(patch_t *patch, UINT8 *flat) { fixed_t col, ofs; @@ -2587,8 +2668,125 @@ void R_PatchToFlat(patch_t *patch, UINT8 *flat) } } +// +// R_FlatToPatch +// +// Convert a flat to a patch. +// +static unsigned char imgbuf[1<<26]; +patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency) +{ + UINT32 x, y; + UINT8 *img; + UINT8 *imgptr = imgbuf; + UINT8 *colpointers, *startofspan; + size_t size = 0; + + // Write image size and offset + WRITEINT16(imgptr, width); + WRITEINT16(imgptr, height); + WRITEINT16(imgptr, leftoffset); + WRITEINT16(imgptr, topoffset); + + // Leave placeholder to column pointers + colpointers = imgptr; + imgptr += width*4; + + // Write columns + for (x = 0; x < width; x++) + { + int lastStartY = 0; + int spanSize = 0; + startofspan = NULL; + + // Write column pointer + WRITEINT32(colpointers, imgptr - imgbuf); + + // Write pixels + for (y = 0; y < height; y++) + { + UINT8 paletteIndex = raw[((y * width) + x)]; + boolean opaque = transparency ? (paletteIndex != TRANSPARENTPIXEL) : true; + + // End span if we have a transparent pixel + if (!opaque) + { + if (startofspan) + WRITEUINT8(imgptr, 0); + startofspan = NULL; + continue; + } + + // Start new column if we need to + if (!startofspan || spanSize == 255) + { + int writeY = y; + + // If we reached the span size limit, finish the previous span + if (startofspan) + WRITEUINT8(imgptr, 0); + + if (y > 254) + { + // Make sure we're aligned to 254 + if (lastStartY < 254) + { + WRITEUINT8(imgptr, 254); + WRITEUINT8(imgptr, 0); + imgptr += 2; + lastStartY = 254; + } + + // Write stopgap empty spans if needed + writeY = y - lastStartY; + + while (writeY > 254) + { + WRITEUINT8(imgptr, 254); + WRITEUINT8(imgptr, 0); + imgptr += 2; + writeY -= 254; + } + } + + startofspan = imgptr; + WRITEUINT8(imgptr, writeY); + imgptr += 2; + spanSize = 0; + + lastStartY = y; + } + + // Write the pixel + WRITEUINT8(imgptr, paletteIndex); + spanSize++; + startofspan[1] = spanSize; + } + + if (startofspan) + WRITEUINT8(imgptr, 0); + + WRITEUINT8(imgptr, 0xFF); + } + + size = imgptr-imgbuf; + img = Z_Malloc(size, PU_STATIC, NULL); + memcpy(img, imgbuf, size); + + Z_Free(raw); + + if (destsize != NULL) + *destsize = size; + return (patch_t *)img; +} + #ifndef NO_PNG_LUMPS -boolean R_IsLumpPNG(UINT8 *d, size_t s) +// +// R_IsLumpPNG +// +// Returns true if the lump is a valid PNG. +// +boolean R_IsLumpPNG(const UINT8 *d, size_t s) { if (s < 67) // http://garethrees.org/2007/11/14/pngcrush/ return false; @@ -2599,21 +2797,49 @@ boolean R_IsLumpPNG(UINT8 *d, size_t s) } #ifdef HAVE_PNG + +#if PNG_LIBPNG_VER_DLLNUM < 14 +typedef PNG_CONST png_byte *png_const_bytep; +#endif typedef struct { - png_bytep buffer; + png_const_bytep buffer; png_uint_32 bufsize; png_uint_32 current_pos; -} png_ioread; +} png_io_t; static void PNG_IOReader(png_structp png_ptr, png_bytep data, png_size_t length) { - png_ioread *f = png_get_io_ptr(png_ptr); + png_io_t *f = png_get_io_ptr(png_ptr); if (length > (f->bufsize - f->current_pos)) png_error(png_ptr, "PNG_IOReader: buffer overrun"); memcpy(data, f->buffer + f->current_pos, length); f->current_pos += length; } +typedef struct +{ + char name[4]; + void *data; + size_t size; +} png_chunk_t; + +static png_byte *chunkname = NULL; +static png_chunk_t chunk; + +static int PNG_ChunkReader(png_structp png_ptr, png_unknown_chunkp chonk) +{ + (void)png_ptr; + if (!memcmp(chonk->name, chunkname, 4)) + { + memcpy(chunk.name, chonk->name, 4); + chunk.size = chonk->size; + chunk.data = Z_Malloc(chunk.size, PU_STATIC, NULL); + memcpy(chunk.data, chonk->data, chunk.size); + return 1; + } + return 0; +} + static void PNG_error(png_structp PNG, png_const_charp pngtext) { CONS_Debug(DBG_RENDER, "libpng error at %p: %s", PNG, pngtext); @@ -2625,7 +2851,7 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext) CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); } -static png_bytep *PNG_Read(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) +static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) { png_structp png_ptr; png_infop png_info_ptr; @@ -2638,11 +2864,13 @@ static png_bytep *PNG_Read(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) #endif #endif - png_ioread png_io; + png_io_t png_io; png_bytep *row_pointers; - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, - PNG_error, PNG_warn); + png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'}; + png_voidp *user_chunk_ptr; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) { CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); @@ -2672,19 +2900,24 @@ static png_bytep *PNG_Read(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) #endif // set our own read_function - png_io.buffer = (png_bytep)png; + png_io.buffer = (png_const_bytep)png; png_io.bufsize = size; png_io.current_pos = 0; png_set_read_fn(png_ptr, &png_io, PNG_IOReader); + memset(&chunk, 0x00, sizeof(png_chunk_t)); + chunkname = grAb_chunk; // I want to read a grAb chunk + + user_chunk_ptr = png_get_user_chunk_ptr(png_ptr); + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, PNG_ChunkReader); + png_set_keep_unknown_chunks(png_ptr, 2, chunkname, 1); + #ifdef PNG_SET_USER_LIMITS_SUPPORTED png_set_user_limits(png_ptr, 2048, 2048); #endif png_read_info(png_ptr, png_info_ptr); - - png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, - NULL, NULL, NULL); + png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth == 16) png_set_strip_16(png_ptr); @@ -2712,7 +2945,24 @@ static png_bytep *PNG_Read(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) for (y = 0; y < height; y++) row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, png_info_ptr)); png_read_image(png_ptr, row_pointers); + + // Read grAB chunk + if ((topoffset || leftoffset) && (chunk.data != NULL)) + { + INT32 *offsets = (INT32 *)chunk.data; + // read left offset + if (leftoffset != NULL) + *leftoffset = (INT16)BIGENDIAN_LONG(*offsets); + offsets++; + // read top offset + if (topoffset != NULL) + *topoffset = (INT16)BIGENDIAN_LONG(*offsets); + } + + // bye png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + if (chunk.data) + Z_Free(chunk.data); *w = (INT32)width; *h = (INT32)height; @@ -2720,11 +2970,11 @@ static png_bytep *PNG_Read(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) } // Convert a PNG to a raw image. -static UINT8 *PNG_RawConvert(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) +static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) { UINT8 *flat; png_uint_32 x, y; - png_bytep *row_pointers = PNG_Read(png, w, h, size); + png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, size); png_uint_32 width = *w, height = *h; if (!row_pointers) @@ -2748,121 +2998,31 @@ static UINT8 *PNG_RawConvert(UINT8 *png, UINT16 *w, UINT16 *h, size_t size) return flat; } +// +// R_PNGToFlat +// // Convert a PNG to a flat. -UINT8 *R_PNGToFlat(levelflat_t *levelflat, UINT8 *png, size_t size) +// +UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size) { - return PNG_RawConvert(png, &levelflat->width, &levelflat->height, size); + return PNG_RawConvert(png, width, height, NULL, NULL, size); } +// +// R_PNGToPatch +// // Convert a PNG to a patch. -static unsigned char imgbuf[1<<26]; -patch_t *R_PNGToPatch(UINT8 *png, size_t size) +// +patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency) { UINT16 width, height; - UINT8 *raw = PNG_RawConvert(png, &width, &height, size); - - UINT32 x, y; - UINT8 *img; - UINT8 *imgptr = imgbuf; - UINT8 *colpointers, *startofspan; - - #define WRITE8(buf, a) ({*buf = (a); buf++;}) - #define WRITE16(buf, a) ({*buf = (a)&255; buf++; *buf = (a)>>8; buf++;}) - #define WRITE32(buf, a) ({WRITE16(buf, (a)&65535); WRITE16(buf, (a)>>16);}) + INT16 topoffset = 0, leftoffset = 0; + UINT8 *raw = PNG_RawConvert(png, &width, &height, &topoffset, &leftoffset, size); if (!raw) I_Error("R_PNGToPatch: conversion failed"); - // Write image size and offset - WRITE16(imgptr, width); - WRITE16(imgptr, height); - // no offsets - WRITE16(imgptr, 0); - WRITE16(imgptr, 0); - - // Leave placeholder to column pointers - colpointers = imgptr; - imgptr += width*4; - - // Write columns - for (x = 0; x < width; x++) - { - int lastStartY = 0; - int spanSize = 0; - startofspan = NULL; - - //printf("%d ", x); - // Write column pointer (@TODO may be wrong) - WRITE32(colpointers, imgptr - imgbuf); - - // Write pixels - for (y = 0; y < height; y++) - { - UINT8 paletteIndex = raw[((y * width) + x)]; - - // Start new column if we need to - if (!startofspan || spanSize == 255) - { - int writeY = y; - - // If we reached the span size limit, finish the previous span - if (startofspan) - WRITE8(imgptr, 0); - - if (y > 254) - { - // Make sure we're aligned to 254 - if (lastStartY < 254) - { - WRITE8(imgptr, 254); - WRITE8(imgptr, 0); - imgptr += 2; - lastStartY = 254; - } - - // Write stopgap empty spans if needed - writeY = y - lastStartY; - - while (writeY > 254) - { - WRITE8(imgptr, 254); - WRITE8(imgptr, 0); - imgptr += 2; - writeY -= 254; - } - } - - startofspan = imgptr; - WRITE8(imgptr, writeY);///@TODO calculate starting y pos - imgptr += 2; - spanSize = 0; - - lastStartY = y; - } - - // Write the pixel - WRITE8(imgptr, paletteIndex); - spanSize++; - startofspan[1] = spanSize; - } - - if (startofspan) - WRITE8(imgptr, 0); - - WRITE8(imgptr, 0xFF); - } - - #undef WRITE8 - #undef WRITE16 - #undef WRITE32 - - size = imgptr-imgbuf; - img = malloc(size); - memcpy(img, imgbuf, size); - - Z_Free(raw); - - return (patch_t *)img; + return R_FlatToPatch(raw, width, height, leftoffset, topoffset, destsize, transparency); } boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) @@ -2877,7 +3037,7 @@ boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) #endif #endif - png_ioread png_io; + png_io_t png_io; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); @@ -2933,53 +3093,3 @@ boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) } #endif #endif - -void R_TextureToFlat(size_t tex, UINT8 *flat) -{ - texture_t *texture = textures[tex]; - - fixed_t col, ofs; - column_t *column; - UINT8 *desttop, *dest, *deststop; - UINT8 *source; - - desttop = flat; - deststop = desttop + (texture->width * texture->height); - - for (col = 0; col < texture->width; col++, desttop++) - { - column = (column_t *)R_GetColumn(tex, col); - if (!texture->holes) - { - dest = desttop; - source = (UINT8 *)(column); - for (ofs = 0; dest < deststop && ofs < texture->height; ofs++) - { - if (source[ofs] != TRANSPARENTPIXEL) - *dest = source[ofs]; - dest += texture->width; - } - } - else - { - INT32 topdelta, prevdelta = -1; - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - - dest = desttop + (topdelta * texture->width); - source = (UINT8 *)(column) + 3; - for (ofs = 0; dest < deststop && ofs < column->length; ofs++) - { - if (source[ofs] != TRANSPARENTPIXEL) - *dest = source[ofs]; - dest += texture->width; - } - column = (column_t *)((UINT8 *)column + column->length + 4); - } - } - } -} diff --git a/src/r_data.h b/src/r_data.h index 91301100b..e71d45766 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -25,7 +25,7 @@ // Possible alpha types for a patch. enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; -RGBA_t ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); +UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha); UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); @@ -159,16 +159,15 @@ const char *R_NameForColormap(extracolormap_t *extra_colormap); #define R_PutRgbaRGBA(r, g, b, a) (R_PutRgbaRGB(r, g, b) + R_PutRgbaA(a)) boolean R_CheckIfPatch(lumpnum_t lump); -UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); - -void R_PatchToFlat(patch_t *patch, UINT8 *flat); void R_TextureToFlat(size_t tex, UINT8 *flat); +void R_PatchToFlat(patch_t *patch, UINT8 *flat); +patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency); #ifndef NO_PNG_LUMPS -boolean R_IsLumpPNG(UINT8 *d, size_t s); +boolean R_IsLumpPNG(const UINT8 *d, size_t s); -UINT8 *R_PNGToFlat(levelflat_t *levelflat, UINT8 *png, size_t size); -patch_t *R_PNGToPatch(UINT8 *png, size_t size); +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); boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size); #endif diff --git a/src/r_defs.h b/src/r_defs.h index def7b46f3..4a5c38410 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -139,9 +139,9 @@ typedef enum FF_PLATFORM = 0x2000000, ///< You can jump up through this to the top. FF_REVERSEPLATFORM = 0x4000000, ///< A fall-through floor in normal gravity, a platform in reverse gravity. FF_INTANGABLEFLATS = 0x6000000, ///< Both flats are intangable, but the sides are still solid. - FF_SHATTER = 0x8000000, ///< Used with ::FF_BUSTUP. Thinks everyone's Knuckles. - FF_SPINBUST = 0x10000000, ///< Used with ::FF_BUSTUP. Jump or fall onto it while curled in a ball. - FF_ONLYKNUX = 0x20000000, ///< Used with ::FF_BUSTUP. Only Knuckles can break this rock. + FF_SHATTER = 0x8000000, ///< Used with ::FF_BUSTUP. Bustable on mere touch. + FF_SPINBUST = 0x10000000, ///< Used with ::FF_BUSTUP. Also bustable if you're in your spinning frames. + FF_STRONGBUST = 0x20000000, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee). FF_RIPPLE = 0x40000000, ///< Ripple the flats FF_COLORMAPONLY = 0x80000000, ///< Only copy the colormap, not the lightlevel FF_GOOWATER = FF_SHATTERBOTTOM, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. @@ -263,10 +263,15 @@ typedef struct pslope_s typedef enum { - SF_FLIPSPECIAL_FLOOR = 1, - SF_FLIPSPECIAL_CEILING = 2, - SF_FLIPSPECIAL_BOTH = 3, - SF_TRIGGERSPECIAL_TOUCH = 4, + // flipspecial - planes with effect + SF_FLIPSPECIAL_FLOOR = 1, + SF_FLIPSPECIAL_CEILING = 1<<1, + SF_FLIPSPECIAL_BOTH = (SF_FLIPSPECIAL_FLOOR|SF_FLIPSPECIAL_CEILING), + // triggerspecial - conditions under which plane touch causes effect + SF_TRIGGERSPECIAL_TOUCH = 1<<2, + SF_TRIGGERSPECIAL_HEADBUMP = 1<<3, + // invertprecip - inverts presence of precipitation + SF_INVERTPRECIP = 1<<4, } sectorflags_t; // diff --git a/src/r_draw.c b/src/r_draw.c index 1754403c4..bb70a319f 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -130,10 +130,11 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; #define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3) #define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4) #define BLINK_TT_CACHE_INDEX (MAXSKINS + 5) +#define DASHMODE_TT_CACHE_INDEX (MAXSKINS + 6) #define DEFAULT_STARTTRANSCOLOR 96 #define NUM_PALETTE_ENTRIES 256 -static UINT8** translationtablecache[MAXSKINS + 6] = {NULL}; +static UINT8** translationtablecache[MAXSKINS + 7] = {NULL}; const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = { // {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // SKINCOLOR_NONE @@ -569,6 +570,40 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U dest_colormap[Color_Index[SKINCOLOR_BLUE-1][12-i]] = Color_Index[SKINCOLOR_BLUE-1][i]; dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0; } + else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices + { + // greens -> ketchups + dest_colormap[96] = dest_colormap[97] = 48; + dest_colormap[98] = 49; + dest_colormap[99] = 51; + dest_colormap[100] = 52; + dest_colormap[101] = dest_colormap[102] = 54; + dest_colormap[103] = 34; + dest_colormap[104] = 37; + dest_colormap[105] = 39; + dest_colormap[106] = 41; + for (i = 0; i < 5; i++) + dest_colormap[107 + i] = 43 + i; + + // reds -> steel blues + dest_colormap[32] = 146; + dest_colormap[33] = 147; + dest_colormap[34] = dest_colormap[35] = 170; + dest_colormap[36] = 171; + dest_colormap[37] = dest_colormap[38] = 172; + dest_colormap[39] = dest_colormap[40] = dest_colormap[41] = 173; + dest_colormap[42] = dest_colormap[43] = dest_colormap[44] = 174; + dest_colormap[45] = dest_colormap[46] = dest_colormap[47] = 175; + dest_colormap[71] = 139; + + // steel blues -> oranges + dest_colormap[170] = 52; + dest_colormap[171] = 54; + dest_colormap[172] = 56; + dest_colormap[173] = 42; + dest_colormap[174] = 45; + dest_colormap[175] = 47; + } return; } else if (color == SKINCOLOR_NONE) @@ -628,6 +663,7 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) case TC_ALLWHITE: skintableindex = ALLWHITE_TT_CACHE_INDEX; break; case TC_RAINBOW: skintableindex = RAINBOW_TT_CACHE_INDEX; break; case TC_BLINK: skintableindex = BLINK_TT_CACHE_INDEX; break; + case TC_DASHMODE: skintableindex = DASHMODE_TT_CACHE_INDEX; break; default: skintableindex = skinnum; break; } diff --git a/src/r_draw.h b/src/r_draw.h index 3c1429722..a0ab74848 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -109,6 +109,7 @@ extern lumpnum_t viewborderlump[8]; #define TC_ALLWHITE -4 // For Cy-Brak-demon #define TC_RAINBOW -5 // For single colour #define TC_BLINK -6 // For item blinking, according to kart +#define TC_DASHMODE -7 // For Metal Sonic's dashmode // Initialize color translation tables, for player rendering etc. void R_InitTranslationTables(void); diff --git a/src/r_main.c b/src/r_main.c index 5135e57ce..9d9d1c39a 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1182,6 +1182,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_cam_speed); CV_RegisterVar(&cv_cam_rotate); CV_RegisterVar(&cv_cam_rotspeed); + CV_RegisterVar(&cv_cam_orbit); + CV_RegisterVar(&cv_cam_adjust); CV_RegisterVar(&cv_cam2_dist); CV_RegisterVar(&cv_cam2_still); @@ -1189,6 +1191,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_cam2_speed); CV_RegisterVar(&cv_cam2_rotate); CV_RegisterVar(&cv_cam2_rotspeed); + CV_RegisterVar(&cv_cam2_orbit); + CV_RegisterVar(&cv_cam2_adjust); CV_RegisterVar(&cv_showhud); CV_RegisterVar(&cv_translucenthud); diff --git a/src/r_plane.c b/src/r_plane.c index 51a69336e..9f417ee6b 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -44,6 +44,9 @@ // Quincunx antialiasing of flats! //#define QUINCUNX +// good night sweet prince +#define SHITPLANESPARENCY + //SoM: 3/23/2000: Use Boom visplane hashing. visplane_t *visplanes[MAXVISPLANES]; @@ -650,17 +653,33 @@ static void R_DrawSkyPlane(visplane_t *pl) } } +// +// R_CheckPowersOfTwo +// +// Self-explanatory? +// boolean R_CheckPowersOfTwo(void) { - if (ds_flatwidth & (ds_flatwidth - 1)) - ds_powersoftwo = false; - else if (ds_flatheight & (ds_flatheight - 1)) - ds_powersoftwo = false; - else if (ds_flatwidth == ds_flatheight) + boolean wpow2 = (!(ds_flatwidth & (ds_flatwidth - 1))); + boolean hpow2 = (!(ds_flatheight & (ds_flatheight - 1))); + + // Initially, the flat isn't powers-of-two-sized. + ds_powersoftwo = false; + + // But if the width and height are powers of two, + // and are EQUAL, then it's okay :] + if ((ds_flatwidth == ds_flatheight) && (wpow2 && hpow2)) ds_powersoftwo = true; + + // Just return ds_powersoftwo. return ds_powersoftwo; } +// +// R_CheckFlatLength +// +// Determine the flat's dimensions from the lump length. +// void R_CheckFlatLength(size_t size) { switch (size) @@ -717,7 +736,24 @@ void R_CheckFlatLength(size_t size) } } -static UINT8 *R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng) +// +// R_GenerateFlat +// +// Generate a flat from specified width and height. +// +static UINT8 *R_GenerateFlat(UINT16 width, UINT16 height) +{ + UINT8 *flat = Z_Malloc(width * height, PU_LEVEL, NULL); + memset(flat, TRANSPARENTPIXEL, width * height); + return flat; +} + +// +// R_GetTextureFlat +// +// Convert a texture or patch to a flat. +// +static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng) { UINT8 *flat; textureflat_t *texflat = &texflats[levelflat->texturenum]; @@ -741,14 +777,14 @@ static UINT8 *R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture, boole // If the texture changed, or the patch doesn't exist, convert either of them to a flat. if (levelflat->flatpatch == NULL || texturechanged) { + // Level texture if (leveltexture) { texture_t *texture = textures[levelflat->texturenum]; texflat->width = ds_flatwidth = texture->width; texflat->height = ds_flatheight = texture->height; - texflat->flat = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL); - memset(texflat->flat, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight); + texflat->flat = R_GenerateFlat(ds_flatwidth, ds_flatheight); R_TextureToFlat(levelflat->texturenum, texflat->flat); flat = texflat->flat; @@ -756,13 +792,14 @@ static UINT8 *R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture, boole levelflat->width = ds_flatwidth; levelflat->height = ds_flatheight; } + // Patch (never happens yet) else { patch = (patch_t *)ds_source; #ifndef NO_PNG_LUMPS if (ispng) { - levelflat->flatpatch = R_PNGToFlat(levelflat, ds_source, W_LumpLength(levelflat->lumpnum)); + levelflat->flatpatch = R_PNGToFlat(&levelflat->width, &levelflat->height, ds_source, W_LumpLength(levelflat->lumpnum)); levelflat->topoffset = levelflat->leftoffset = 0; ds_flatwidth = levelflat->width; ds_flatheight = levelflat->height; @@ -776,8 +813,7 @@ static UINT8 *R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture, boole levelflat->topoffset = patch->topoffset * FRACUNIT; levelflat->leftoffset = patch->leftoffset * FRACUNIT; - levelflat->flatpatch = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL); - memset(levelflat->flatpatch, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight); + levelflat->flatpatch = R_GenerateFlat(ds_flatwidth, ds_flatheight); R_PatchToFlat(patch, levelflat->flatpatch); } flat = levelflat->flatpatch; @@ -788,11 +824,11 @@ static UINT8 *R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture, boole flat = levelflat->flatpatch; ds_flatwidth = levelflat->width; ds_flatheight = levelflat->height; - - xoffs += levelflat->leftoffset; - yoffs += levelflat->topoffset; } + xoffs += levelflat->leftoffset; + yoffs += levelflat->topoffset; + levelflat->lasttexturenum = levelflat->texturenum; return flat; } @@ -806,6 +842,7 @@ void R_DrawSinglePlane(visplane_t *pl) size_t size; ffloor_t *rover; levelflat_t *levelflat; + boolean rawflat = false; if (!(pl->minx <= pl->maxx)) return; @@ -834,7 +871,11 @@ void R_DrawSinglePlane(visplane_t *pl) else // Opaque, but allow transparent flat pixels spanfunc = splatfunc; +#ifdef SHITPLANESPARENCY + if ((spanfunc == splatfunc) != (pl->extra_colormap && (pl->extra_colormap->fog & 4))) +#else if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) +#endif light = (pl->lightlevel >> LIGHTSEGSHIFT); else light = LIGHTLEVELS-1; @@ -888,7 +929,11 @@ void R_DrawSinglePlane(visplane_t *pl) else // Opaque, but allow transparent flat pixels spanfunc = splatfunc; +#ifdef SHITPLANESPARENCY + if ((spanfunc == splatfunc) != (pl->extra_colormap && (pl->extra_colormap->fog & 4))) +#else if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) +#endif light = (pl->lightlevel >> LIGHTSEGSHIFT); else light = LIGHTLEVELS-1; @@ -956,18 +1001,19 @@ void R_DrawSinglePlane(visplane_t *pl) // Check if the flat is actually a wall texture. if (levelflat->texturenum != 0 && levelflat->texturenum != -1) - flat = R_GetPatchFlat(levelflat, true, false); + flat = R_GetTextureFlat(levelflat, true, false); #ifndef NO_PNG_LUMPS // Maybe it's a PNG?! else if (R_IsLumpPNG(ds_source, size)) - flat = R_GetPatchFlat(levelflat, false, true); + flat = R_GetTextureFlat(levelflat, false, true); #endif // Maybe it's just a patch, then? else if (R_CheckIfPatch(levelflat->lumpnum)) - flat = R_GetPatchFlat(levelflat, false, false); + flat = R_GetTextureFlat(levelflat, false, false); // It's a raw flat. else { + rawflat = true; R_CheckFlatLength(size); flat = ds_source; } @@ -978,8 +1024,11 @@ void R_DrawSinglePlane(visplane_t *pl) if (ds_source == NULL) return; - // Check if the flat has dimensions that are powers-of-two numbers. - if (R_CheckPowersOfTwo()) + // Raw flats always have dimensions that are powers-of-two numbers. + if (rawflat) + ds_powersoftwo = true; + // Otherwise, check if this texture or patch has such dimensions. + else if (R_CheckPowersOfTwo()) { R_CheckFlatLength(ds_flatwidth * ds_flatheight); if (spanfunc == basespanfunc) @@ -1064,7 +1113,7 @@ void R_DrawSinglePlane(visplane_t *pl) temp = P_GetZAt(pl->slope, pl->viewx, pl->viewy); zeroheight = FIXED_TO_FLOAT(temp); -#define ANG2RAD(angle) ((float)((angle)*M_PI)/ANGLE_180) +#define ANG2RAD(angle) ((float)((angle)*M_PIl)/ANGLE_180) // p is the texture origin in view space // Don't add in the offsets at this stage, because doing so can result in @@ -1116,26 +1165,27 @@ void R_DrawSinglePlane(visplane_t *pl) ds_sz.z *= focallengthf; // Premultiply the texture vectors with the scale factors +#define SFMULT 65536.f if (ds_powersoftwo) { -#define SFMULT 65536.f*(1<patch, PU_CACHE); + patch_t *patch = W_CachePatchNum(vis->patch, PU_CACHE); fixed_t this_scale = vis->mobj->scale; INT32 x1, x2; INT64 overflow_test; @@ -740,6 +753,13 @@ static void R_DrawVisSprite(vissprite_t *vis) dc_transmap = vis->transmap; if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + else if (!(vis->cut & SC_PRECIP) + && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD + && (vis->mobj->player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) + && ((leveltime/2) & 1)) + { + dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); + } else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> { size_t skinnum = (skin_t*)vis->mobj->skin-skins; @@ -761,6 +781,13 @@ static void R_DrawVisSprite(vissprite_t *vis) // New colormap stuff for skins Tails 06-07-2002 if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + else if (!(vis->cut & SC_PRECIP) + && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD + && (vis->mobj->player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) + && ((leveltime/2) & 1)) + { + dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); + } else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! { size_t skinnum = (skin_t*)vis->mobj->skin-skins; @@ -870,7 +897,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) INT64 overflow_test; //Fab : R_InitSprites now sets a wad lump number - patch = W_CacheLumpNum(vis->patch, PU_CACHE); + patch = W_CachePatchNum(vis->patch, PU_CACHE); if (!patch) return; @@ -1217,7 +1244,7 @@ static void R_ProjectSprite(mobj_t *thing) else range = 1; - scalestep = (yscale2 - yscale)/range; + scalestep = (yscale2 - yscale)/range ?: 1; // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? // sortscale = max(yscale, yscale2); @@ -1624,7 +1651,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) mobj_t *thing; precipmobj_t *precipthing; // Tails 08-25-2002 INT32 lightnum; - fixed_t approx_dist, limit_dist; + fixed_t approx_dist, limit_dist, hoop_limit_dist; if (rendermode != render_soft) return; @@ -1655,7 +1682,9 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) // Handle all things in sector. // If a limit exists, handle things a tiny bit different. - if ((limit_dist = (fixed_t)((maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : cv_drawdist.value) << FRACBITS)) + limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS; + hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; + if (limit_dist || hoop_limit_dist) { for (thing = sec->thinglist; thing; thing = thing->snext) { @@ -1664,8 +1693,16 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - if (approx_dist > limit_dist) - continue; + if (thing->sprite == SPR_HOOP) + { + if (hoop_limit_dist && approx_dist > hoop_limit_dist) + continue; + } + else + { + if (limit_dist && approx_dist > limit_dist) + continue; + } R_ProjectSprite(thing); } @@ -2511,7 +2548,7 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) if (!skin) return 0; - if ((unsigned)(spr2 & ~FF_SPR2SUPER) >= free_spr2) + if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2) return 0; while (!(skin->sprites[spr2].numframes) @@ -2603,6 +2640,8 @@ static void Sk_SetDefaultValue(skin_t *skin) skin->followitem = 0; skin->highresscale = FRACUNIT; + skin->contspeed = 17; + skin->contangle = 0; skin->availability = 0; @@ -2771,9 +2810,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) } if (P_IsLocalPlayer(player)) - CONS_Alert(CONS_WARNING, M_GetText("Requested skin not found\n")); + CONS_Alert(CONS_WARNING, M_GetText("Requested skin %d not found\n"), skinnum); else if(server || IsPlayerAdmin(consoleplayer)) - CONS_Alert(CONS_WARNING, "Player %d (%s) skin not found\n", playernum, player_names[playernum]); + CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum); SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin } @@ -2869,6 +2908,8 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski for (sprite2 = 0; sprite2 < free_spr2; sprite2++) R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[sprite2], wadnum, *lump, *lastlump); + if (skin->sprites[0].numframes == 0) + I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]); } // returns whether found appropriate property @@ -2907,6 +2948,8 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) GETINT(thrustfactor) GETINT(accelstart) GETINT(acceleration) + GETINT(contspeed) + GETINT(contangle) #undef GETINT #define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value); diff --git a/src/r_things.h b/src/r_things.h index 9c3d16ab0..0fa9c4b94 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -122,6 +122,8 @@ typedef struct UINT8 prefoppositecolor; // if 0 use tables instead fixed_t highresscale; // scale of highres, default is 0.5 + UINT8 contspeed; // continue screen animation speed + UINT8 contangle; // initial angle on continue screen // specific sounds per skin sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table diff --git a/src/s_sound.c b/src/s_sound.c index 299e4b889..6134e338c 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -117,6 +117,10 @@ consvar_t cv_gamedigimusic = {"digimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_O consvar_t cv_gamemidimusic = {"midimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameMIDIMusic_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_gamesounds = {"sounds", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameSounds_OnChange, 0, NULL, NULL, 0, 0, NULL}; +// Window focus sound sytem toggles +consvar_t cv_playmusicifunfocused = {"playmusicifunfocused", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_playsoundsifunfocused = {"playsoundsifunfocused", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + #ifdef HAVE_OPENMPT static CV_PossibleValue_t interpolationfilter_cons_t[] = {{0, "Default"}, {1, "None"}, {2, "Linear"}, {4, "Cubic"}, {8, "Windowed sinc"}, {0, NULL}}; consvar_t cv_modfilter = {"modfilter", "0", CV_SAVE|CV_CALL, interpolationfilter_cons_t, ModFilter_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -278,6 +282,8 @@ void S_RegisterSoundStuff(void) CV_RegisterVar(&cv_samplerate); CV_RegisterVar(&cv_resetmusic); CV_RegisterVar(&cv_resetmusicbyheader); + CV_RegisterVar(&cv_playsoundsifunfocused); + CV_RegisterVar(&cv_playmusicifunfocused); CV_RegisterVar(&cv_gamesounds); CV_RegisterVar(&cv_gamedigimusic); CV_RegisterVar(&cv_gamemidimusic); @@ -373,6 +379,18 @@ lumpnum_t S_GetSfxLumpNum(sfxinfo_t *sfx) return W_GetNumForName("dsthok"); } +// +// Sound Status +// + +boolean S_SoundDisabled(void) +{ + return ( + sound_disabled || + ( window_notinfocus && ! cv_playsoundsifunfocused.value ) + ); +} + // Stop all sounds, load level info, THEN start sounds. void S_StopSounds(void) { @@ -540,7 +558,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) mobj_t *listenmobj = players[displayplayer].mo; mobj_t *listenmobj2 = NULL; - if (sound_disabled || !sound_started) + if (S_SoundDisabled() || !sound_started) return; // Don't want a sound? Okay then... @@ -730,7 +748,7 @@ dontplay: void S_StartSound(const void *origin, sfxenum_t sfx_id) { - if (sound_disabled) + if (S_SoundDisabled()) return; if (mariomode) // Sounds change in Mario mode! @@ -1434,6 +1452,13 @@ boolean S_MusicPaused(void) return I_SongPaused(); } +boolean S_MusicNotInFocus(void) +{ + return ( + ( window_notinfocus && ! cv_playmusicifunfocused.value ) + ); +} + musictype_t S_MusicType(void) { return I_SongType(); @@ -1867,6 +1892,10 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) } S_InitMusicVolume(); // switch between digi and sequence volume + + if (S_MusicNotInFocus()) + S_PauseAudio(); + return true; } @@ -2009,6 +2038,9 @@ void S_PauseAudio(void) void S_ResumeAudio(void) { + if (S_MusicNotInFocus()) + return; + if (I_SongPlaying() && I_SongPaused()) I_ResumeSong(); @@ -2202,7 +2234,7 @@ static void Command_RestartAudio_f(void) void GameSounds_OnChange(void) { - if (M_CheckParm("-nosound")) + if (M_CheckParm("-nosound") || M_CheckParm("-noaudio")) return; if (sound_disabled) @@ -2220,7 +2252,7 @@ void GameSounds_OnChange(void) void GameDigiMusic_OnChange(void) { - if (M_CheckParm("-nomusic")) + if (M_CheckParm("-nomusic") || M_CheckParm("-noaudio")) return; else if (M_CheckParm("-nodigmusic")) return; @@ -2262,7 +2294,7 @@ void GameDigiMusic_OnChange(void) void GameMIDIMusic_OnChange(void) { - if (M_CheckParm("-nomusic")) + if (M_CheckParm("-nomusic") || M_CheckParm("-noaudio")) return; else if (M_CheckParm("-nomidimusic")) return; @@ -2279,7 +2311,7 @@ void GameMIDIMusic_OnChange(void) else { midi_disabled = true; - if (S_MusicType() == MU_MID) + if (S_MusicType() == MU_MID || S_MusicType() == MU_MID_EX) { if (digital_disabled) S_StopMusic(); diff --git a/src/s_sound.h b/src/s_sound.h index 48128527c..20b2489a5 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -45,6 +45,9 @@ extern consvar_t cv_gamedigimusic; extern consvar_t cv_gamemidimusic; extern consvar_t cv_gamesounds; +extern consvar_t cv_playmusicifunfocused; +extern consvar_t cv_playsoundsifunfocused; + #ifdef HAVE_OPENMPT extern consvar_t cv_modfilter; #endif @@ -144,6 +147,12 @@ void S_StartEx(boolean reset); // lumpnum_t S_GetSfxLumpNum(sfxinfo_t *sfx); +// +// Sound Status +// + +boolean S_SoundDisabled(void); + // // Start sound for thing at using from sounds.h // @@ -164,6 +173,7 @@ boolean S_MIDIMusicDisabled(void); boolean S_MusicDisabled(void); boolean S_MusicPlaying(void); boolean S_MusicPaused(void); +boolean S_MusicNotInFocus(void); musictype_t S_MusicType(void); const char *S_MusicName(void); boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping); diff --git a/src/screen.c b/src/screen.c index 547036a60..9939aff93 100644 --- a/src/screen.c +++ b/src/screen.c @@ -421,9 +421,9 @@ void SCR_DisplayTicRate(void) else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP; V_DrawString(vid.width-(72*vid.dupx), h, - V_YELLOWMAP|V_NOSCALESTART, "FPS:"); + V_YELLOWMAP|V_NOSCALESTART|V_HUDTRANS, "FPS:"); V_DrawString(vid.width-(40*vid.dupx), h, - ticcntcolor|V_NOSCALESTART, va("%02d/%02u", totaltics, TICRATE)); + ticcntcolor|V_NOSCALESTART|V_HUDTRANS, va("%02d/%02u", totaltics, TICRATE)); lasttic = ontic; } diff --git a/src/screen.h b/src/screen.h index 3554b5520..79f21e8e4 100644 --- a/src/screen.h +++ b/src/screen.h @@ -39,13 +39,8 @@ // we try to re-allocate a minimum of buffers for stability of the memory, // so all the small-enough tables based on screen size, are allocated once // and for all at the maximum size. -#if defined (_WIN32_WCE) -#define MAXVIDWIDTH 320 -#define MAXVIDHEIGHT 200 -#else #define MAXVIDWIDTH 1920 // don't set this too high because actually #define MAXVIDHEIGHT 1200 // lots of tables are allocated with the MAX size. -#endif #define BASEVIDWIDTH 320 // NEVER CHANGE THIS! This is the original #define BASEVIDHEIGHT 200 // resolution of the graphics. diff --git a/src/sdl/IMG_xpm.c b/src/sdl/IMG_xpm.c index af76ec1dd..43fb4ded2 100644 --- a/src/sdl/IMG_xpm.c +++ b/src/sdl/IMG_xpm.c @@ -1,6 +1,6 @@ /* SDL_image: An example image loading library for use with SDL - Copyright (C) 1997-2018 Sam Lantinga + Copyright (C) 1997-2019 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -34,7 +34,7 @@ * * Besides the standard API, also provides * - * SDL_Surface *IMG_ReadXPMFromArray(char **xpm) + * SDL_Surface *IMG_ReadXPMFromArray(const char **xpm) * * that reads the image data from an XPM file included in the C source. * @@ -88,8 +88,8 @@ struct color_hash { struct hash_entry **table; struct hash_entry *entries; /* array of all entries */ struct hash_entry *next_free; - int size; - int maxnum; + size_t size; + size_t maxnum; }; static int hash_key(const char *key, int cpp, int size) @@ -103,14 +103,14 @@ static int hash_key(const char *key, int cpp, int size) return hash & (size - 1); } -static struct color_hash *create_colorhash(int maxnum) +static struct color_hash *create_colorhash(size_t maxnum) { - int bytes, s; + size_t bytes, s; struct color_hash *hash; /* we know how many entries we need, so we can allocate everything here */ - hash = (struct color_hash *)SDL_malloc(sizeof *hash); + hash = (struct color_hash *)SDL_calloc(1, sizeof(*hash)); if (!hash) return NULL; @@ -119,15 +119,29 @@ static struct color_hash *create_colorhash(int maxnum) ; hash->size = s; hash->maxnum = maxnum; + bytes = hash->size * sizeof(struct hash_entry **); - hash->entries = NULL; /* in case malloc fails */ - hash->table = (struct hash_entry **)SDL_malloc(bytes); + /* Check for overflow */ + if ((bytes / sizeof(struct hash_entry **)) != hash->size) { + IMG_SetError("memory allocation overflow"); + SDL_free(hash); + return NULL; + } + hash->table = (struct hash_entry **)SDL_calloc(1, bytes); if (!hash->table) { SDL_free(hash); return NULL; } - SDL_memset(hash->table, 0, bytes); - hash->entries = (struct hash_entry *)SDL_malloc(maxnum * sizeof(struct hash_entry)); + + bytes = maxnum * sizeof(struct hash_entry); + /* Check for overflow */ + if ((bytes / sizeof(struct hash_entry)) != maxnum) { + IMG_SetError("memory allocation overflow"); + SDL_free(hash->table); + SDL_free(hash); + return NULL; + } + hash->entries = (struct hash_entry *)SDL_calloc(1, bytes); if (!hash->entries) { SDL_free(hash->table); SDL_free(hash); @@ -138,7 +152,7 @@ static struct color_hash *create_colorhash(int maxnum) } static int add_colorhash(struct color_hash *hash, - char *key, int cpp, Uint32 color) + const char *key, int cpp, Uint32 color) { int index = hash_key(key, cpp, hash->size); struct hash_entry *e = hash->next_free++; @@ -995,10 +1009,11 @@ static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src) { Sint64 start = 0; SDL_Surface *image = NULL; - int index; + size_t index; int x, y; - int w, h, ncolors, cpp; - int indexed; + int w, h, cpp; + size_t ncolors; + size_t indexed; Uint8 *dst; struct color_hash *colors = NULL; SDL_Color *im_colors = NULL; @@ -1029,12 +1044,17 @@ static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src) * Right now we don't use the hotspots but it should be handled * one day. */ - if (SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 + if (SDL_sscanf(line, "%d %d %lu %d", &w, &h, &ncolors, &cpp) != 4 || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { error = "Invalid format description"; goto done; } + /* Check for allocation overflow */ + if ((size_t)(ncolors * cpp)/cpp != ncolors) { + error = "Invalid color specification"; + goto done; + } keystrings = (char *)SDL_malloc(ncolors * cpp); if (!keystrings) { error = "Out of memory"; @@ -1102,8 +1122,9 @@ static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src) c->g = (Uint8)(rgb >> 8); c->b = (Uint8)(rgb); pixel = index; - } else + } else { pixel = rgb; + } add_colorhash(colors, nextkey, cpp, pixel); nextkey += cpp; if (rgb == 0xffffffff) @@ -1192,7 +1213,7 @@ SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src) return(NULL); } -SDL_Surface *IMG_ReadXPMFromArray(char **xpm) +SDL_Surface *IMG_ReadXPMFromArray(const char **xpm) { return NULL; } diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm index 1d0f9d314..2180d782c 100644 --- a/src/sdl/SDL_icon.xpm +++ b/src/sdl/SDL_icon.xpm @@ -1,163 +1,99 @@ /* XPM */ -const char * SDL_icon_xpm[] = { -"96 96 64 1", +static const char *SDL_icon_xpm[] = { +"64 64 32 1", " c None", -". c #040656", -"+ c #0100B2", -"@ c #04056E", -"# c #0000BD", -"$ c #0B0C09", -"% c #0B0D26", -"& c #090C42", -"* c #060AA7", -"= c #1604DA", -"- c #020CD5", -"; c #100F8D", -"> c #040DE4", -", c #11129B", -"' c #1D1A83", -") c #2A10FD", -"! c #1318FA", -"~ c #25225B", -"{ c #252271", -"] c #312E2B", -"^ c #33334D", -"/ c #363775", -"( c #3D3B69", -"_ c #3A3B8B", -": c #373AFF", -"< c #4142AA", -"[ c #4B4864", -"} c #4D4B4A", -"| c #60492F", -"1 c #4F4C57", -"2 c #4A4A9E", -"3 c #4F4E85", -"4 c #474ADE", -"5 c #4E4FFE", -"6 c #5D5CB3", -"7 c #686663", -"8 c #666682", -"9 c #676875", -"0 c #66659E", -"a c #8B6538", -"b c #6465D5", -"c c #7F694F", -"d c #6767FF", -"e c #7272FF", -"f c #91795C", -"g c #7677FD", -"h c #828396", -"i c #A78153", -"j c #888989", -"k c #8D897E", -"l c #9190FD", -"m c #CA9048", -"n c #C09968", -"o c #A9A8A1", -"p c #A6A8B0", -"q c #B0B1FB", -"r c #EEAC61", -"s c #E3B478", -"t c #C3C4BE", -"u c #FFC68C", -"v c #FCCD90", -"w c #D4D7D3", -"x c #E3E5E0", -"y c #FCFFFB", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ttj7777777joot ", -" 9hh8830000088hh9 ", -" 9888(//__-*{^kt ", -" &,5b60^ (02*{} ", -" tp,-)!5egb3} ~_<4dgggeeeeeeeeeeeeeegb6/_2[amusf'#!<_'>))))))))))))!)>+{~ ", -" p;-))!5gb2^^'#5eggeeeeeeeeeeeeeeegg6/_23amrusi{#!+;;>))))))))))))))!!-'8p ", -" tp'#!)):d6(@*>5egeeeeeeeeeeeeeeeegg6_/<(amrrvvn{+)-,;>))))))!!!!!!)))!!>,~j ", -" p;#!))-'{'+-5eggeeeeeeeeeeeeeeeegb222(cmrruvvn{+)>,@>!)!!)!!>>>>======>-,/8 ", -" ;#)!-*.;-!5eggeeeeeeeeeeeeeeeegb2_<6|mrrsvvvn{+)!,.-!!!!>>=--######+++-#@(k ", -" h@-)+@.*>!5egeeeeeeeeeeeeeeeeeegb_>--###++++++###+;@{(9j ", -" kh,#+@@,>!:dggeeeeeeeeeeeeeeeeeeebbb_]mrruuvvsf'#)!*.+-###+++++++##+*;'3(&^9 ", -" 8*,@@*)):dggeeeeeeeeeeeeeeeeeeeeggg<(|iruvvvsc,=!!*.;*++++++++###+,@&1o ", -" 8@@@-!)!5eeeeeeeeeeeeeeeeeeeeeeeeeggb2[csvvvn^#)!!+@;*#+++++###*@~[ ", -" 9&@*!)):5geeeeeeeeeeeeeeeeeeeeeeeeegge637nsvf{>))!+;;*-######*;{.^ ", -" 9%;!!)):dgeeeeeeeeeeeeeeeeeeeeeeeeeeeggb_1ir7;>))!+;;,++++++*'(} ", -" 9{+!))!5egeeeeeeeeeeeeeeeeeddddeeeeeeeege2}|~#!))!#;@...@@@.^hp ", -" 8,=!))):dggeeeeeeeeeeeeeeeeggggeeeeeeeeggb_~,>!))!+@@@;;;;@&^o ", -" }(-)))))!:eegeeeeeeeeeeeeeegllllgeeeeeeeegd5+=))))!+;,#>--#,'/hj ", -" o8.>))))))!:dgggeeeeeeeeeeellqqqqlgeeeeggg5:!!!)))))-*+>)!:55db631 ", -" p8<*!)))))))!:5deggggggeeeegqqqqqqqqlggged5:!))))))))>->!!:5ddeegb3/ ", -" oh'#!))))))))))!:ddeeeeeeeeglqqqqqqqqlgedd:!)))))))))))))!:dggggeggg239 ", -" ^*>!))!)))))))))!::55dddeegglll600333_4:!!)))))))))))))):dggeeeeeeggb6(9o ", -" ~+=-+#>))))))))))!!!:::::5554<3889988[/,=)))))))))))))):5gggeeeeeeeggb6087 ", -" ~**@~'+>!))))))))))))))))!!>*{1kkooook7(,-!)))))))))))!:5deeeeeeeeeeeggb289 ", -" ~,'1o7(*>!))))))))))))))))=,[jtttwxxxwto^;>!))))))))))!!!::5deggeeeeeeegbb3] ", -" ~@/oxt7'#))))))))))))))))=,3ktwxxyyyyyyxk/+!))))))))))))))!:::5degggeeegggb3^ ", -" ^&8xyyt^,)))))))))))))))>,3otwxyyyyyyyyyxh'>)))))))))))))))))):5ddeeeeeeeggb3^ ", -" 771pyyyx7'=!)))))))))))!!#(jtxxyyyyyyyyyyyt3-)))))))))))))))))))!!::degggeeegb2[o ", -" 77tyyyxk/+!!)))))))))))-;9owxyyyyyyyyyyyywh*>)))))))))))))))))))))!::5ddgggggb68j ", -" owyyyyt8;>))))))))))))*(otwyyyyyyyyyyyyyxp'-)))))))))))))))))))))))!!:5deeeggg_8j ", -" jtxyyyyxh'>)))))))))!!#_ktxyyyyyyyyyyyyyyyt_+))))))))))))))))))))))))))!!:5deggg63j ", -" 7jwyyyyyyp/=))))))))))>,3owxyyyyyyyyyyyyyyyw/+))))))))))))))))))))))))))))!::5degb689 ", -" 7xyyyyyyo[#))))))))))-/jtwyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))!:5dgg_/ ", -" }xyyyyyyt9*=))))))))=*9owyyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))))!!:5d3} ", -" }xyyyyyywj'#!))))))!#@7oxyyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))))))!!:4/7 ", -" 7xyyyyyyxj&,!!))))!!,%}oyyyyyyyyyyyyyyyyyyw/*))))))))))))))))))))))))))))))))))))))>487 ", -" 7xyyyyyywk$@!!)))!!-.$]oyyyyyyyyyyyyyyyyyyw/+))))))))))))))))))))))))))))))!!!!))))!>' ", -" }xyyyyyywj$&+!!)!)>;%$]jyyyyyyyyyyyyyyyyyyt{#)))))))))))))))))))))!!!!!!))!)!!!!!!))!#' ", -" 7xyyyyyyt7$%@-!)!>*[]$$jyyyyyyyyyyyyyyyyyxp;-))))))))))))))))))!!!!!!!!!!!!>>>>>>>>>>!,^ ", -" 7xyyyyyyt}$][;-)=,(o7$$7yyyyyyyyyyyyyyyyyxp,-)))))))))))!!!!)!!!!>>>>=-----########--=+'9 ", -" jwyyyyyyo}$}o(';@~7wj$$7yyyyyyyyyyyyyyyyywh*>)))))))))))!>>>=>=---#####+########+++***;@17 ", -" otxyyyyyt}$7t7}1}7kw7$$7yyyyyyyyyyyyyyyyyt0-)))))))))!!!>--####+++++++++++++##+***,;''.&] ", -" ooowyyyyyt}$}j7owwojo}$$jyyyyyyyyyyyyyyyyyp2>)))))))!!!=##++++++++++++++###+*;@.~[8[9hph ", -" ojtyyyyywj$$}jwyyxo}$$]jyyyyyyyyyyyyyyyyyp'>))))))!>>-#++++++++++++####+,;'_3/&^}77kot ", -" 7tyyyyyxo]$$oxyyyt]$$}tyyyyyyyyyyyyyyyyx0*!)))!!!>-#++++++++++++#+##+*;.&1ko ", -" 7tyyyyyyx7]}xyyyyxj}]oxyyyyyyyyyyyyyyyyp<=)!!!!>-#++++++++++++####*;.(8h ", -" owxyxxyytooywptwwtppxyyyyyyyyyyyyyyyxp3,-=!)!>-#++++++++++###+*,'_{&1k ", -" jtwwttwtwwtj7kjowxyyyyyyyyyyyyyyyyxt7~'',+>=#+++++++++++###*;@&^j ", -" ]joojj7}]}]|innfc7jtwyyyyyyyyyyyxtjcfnnnf[@*#+++++++++###+@.&%% ", -" ]$}77}}$$$$]fsssnnifkkotwwwwwwwtpjkfinvvvsi}@*#++++++###*;@.@@&[ ", -" o7$]]]]]$$]|isvvvvvusifckopppopok7cisvvvvvvvn(,#++++++#+*@.&@*#;3o ", -" }}$]|||fnnsvvvuvvvuuvvsniffffffnnsvvvvuuuvvvc{*+#++##*@&.@*+#--<7 ", -" }]cninsuvvvvuuuuuuvvvvusnnnnnssuvvvvvuuuuvvc~*+#+++*@.@;*##=>>,^ ", -" 7fvvvvvvuuuuuuuuuuuuvvvvvvvvvvvuuuuuuuuuvvc~*+#+#+,.@*###->!!*~ ", -" pkivvvvuuuuuuuuuuuuuuuvvvvvvvvuuuvsnsuuuvvf~*+#++++*+++->!!)!#. ", -" kfsuvvuuuuuuuuuuuuuuuuuuuuuuuuuvvnfsuvuvvc{++#++++###->!!))!-;h ", -" kisvvvuuuuuuuuuuuuuuuuuuuuuuuvvvicsvvvvs1@##+++++++#>!!))))=,ho ", -" 7imuvvvuuuuuuuuuuuuuuuuuuuuvusfcivvuvvn~;##+++++++#>!!))))!#8k ", -" cimruuuuuvuuuuuuuuuuuuuuuuvsnfisuvvvsc@*#+++++++++#>!!))))-3} ", -" 7amrruuuuuuuuuuuuuuuuuuuuvsnnsvvuvvi^,##++++++++++#>!!)))>/^ ", -" kfamrruuuuvvvuuuuuuuuuuuuuvvvvvvvn1@+#++++++++++++#>!)))>{~ ", -" 7|iimrrruuuuuuuuuuuuuuuuvvvvuusn1'+#########++++++->!))>; ", -" 7cammrrrrruuuuuuvvvvvuuuuurrm|.*-#+#######+###+++->!!!*' ", -" ookcaimmrrrrrruuuuurrrrrmi|]%.@@@@@;,*,*+########->!!*6o ", -" p7}|ainiimmmmmmmmmmminnia|$%.....{3322_{''',,**+#=!!#6k ", -" j7||aaiiiiiaa||7j ookok711^&.';,*+=!>> c #2325EC", +", c #3C3883", +"' c #3D3A9E", +") c #5B5170", +"! c #4B4CFF", +"~ c #795339", +"{ c #5E5B5C", +"] c #5F5ED3", +"^ c #5E5EFB", +"/ c #7271FF", +"( c #B37F5D", +"_ c #8F8883", +": c #8887FF", +"< c #D59E76", +"[ c #ABABA9", +"} c #A9AAFF", +"| c #C1C3C1", +"1 c #FAC296", +"2 c #D4D6D3", +"3 c #F9FCF8", +" ", +" ", +" #***,,,**** ", +" *,,]]]]]]]]]]]]]',,** ", +" *,']//////////////////]]',* ", +" *,']/////////////////////////]'% ", +" *,]////////////////////^^!!>>>>>>>$+ ", +" *,]////////////////////!>---------->=@% ", +" * ,]///////////////////]^>------->==@@@$.# ", +" +', *']//////////////////],,,=---->=@@@@@$.% ", +" #.=^'* ,]//////////////////],']^]$--=@@@@@@@$+# ", +" %$=-^'* ,]/////////////////],]/!>-^'=@@@@@@@$.% ", +" +$=->/,*,//////////////////]'/^!,$-!,$@@@@@@$+* ", +" +@=--!''/////////////////]']^!,(()->%$@@@@@$+# ", +" +@=--='/////////////////]']^${(<<)->,$@@@@$% ", +" +@=->']/////////:::////]]/^'(<111)->,$@@@$% ", +" #+@@>$]////////::}}}://///!,(<1111)--%$@@.% ", +" #+@@$$^////////:}}}}}://^>$(<<1111)--+$@.% ", +" +@$.>^///////:}}}}}}:/^>->,(<111<'--+$$*# ", +" +$.=-!///////:}}}}}:^!-----@(111<@--+$,'],,* ", +" %+%=->^///////:}}}:!--------@(11(=--$=^////],* ", +" ,]]'>->^//////^^!!-----------'<1_>--@-!//////]'* ", +" '!->@--->>>>>>--->===>--------)<,-->@->^///////]', ", +" *$--->----------='){__{'>------>'=--=@-->!^///////],* ", +" %$.=---------->$)[22332[)=----------=>----->^^//////], ", +" %$_,--------->'_|3333333['----------=--------->!^////],# ", +" *'[{=--------'_2333333333_=---------------------->!^///,* ", +" #)[_@-------@_|33333333332,------------------------->!^/'* ", +" #)2[$------=)|333332|23333{>--------------------------->^'* ", +" {2|,------$[233333___3333_=----------------------------->$ ", +" ;22)=---->)|333332{2_2333[@-------------------------------$ ", +" &22{@----$_233333|{2||333|'--------------------------------$ ", +" &|3_.----,|333333[;2|[333|'--------------------------------=+ ", +" [3_%=--={2333333[&___333|'-------------------->>>====>>----@ ", +" _3[#$=@.[2333333[&&&_333[$------------->>==@@@@@@@@@@@@@@@==+", +" {3|;+$$)|3333333[&&&[333_=-------->==@@@@@@@@@@@@@@@$$$$.+++%", +" {23{*$${23333333|;&&|332)>----->=@@@@@@@@@@@@@@$$$.++%** ", +";{{;[3{&*)[333333333{&&|332,=---==@@@@@@@@@@@@$$.++%* ", +"{22_{|[;_|2333333333_&;233_$@@@@@@@@@@@@@@@@$$+%* ", +"&_|2{;{{[233333333332_[33[,$@@@@@@@@@@@@@$$+%# ", +" &;{&&&;~(_|3333333333332)$@@@@@@@@@@@@$.+%# ", +" &&&&&;(11([33333333332{$@@@@@@@@@@@$...$@$* ", +" &~((1111<[333333332{%.$@@@@@@@@@$$$$@=--$ ", +" ~<<11111<[33333|[_(<~,$@@@@@@@@@@@@@>-->. ", +" ;(<111111<(____(11111(+@@@@@@@@@@@@=----=% ", +" ~(<11111111<11111<(<<;$@@$$@@@@@@@=-----. ", +" ~(<1111111111111(~<1{$$$.$@@@@@@@=-----= ", +" ~(<1111111<<(((<11<*$+.$@@@@@@@@@>---->+ ", +" ;(<1111111<<1111<~%+$@@@@@@@@@@@=-----$ ", +" ~(<<111111111(~&*+$$$@@@@@@@@@@=----=% ", +" ;~((<<<<(~~; *%+$$@@@@@@@@@>----+ ", +" ;;; #%+$$@@@@@@@----. ", +" *+$$@@@@@=---@ ", +" *+$@@@@@>--= ", +" *.$@@@@-->% ", +" #%.$@@=->+ ", +" *+$@@>-$ ", +" %$@=-$ ", +" %.@>@ ", +" +=@ ", +" .. ", +" * ", +" ", +" "}; diff --git a/src/sdl/Srb2SDL.ico b/src/sdl/Srb2SDL.ico index 700276fd4..3b37433db 100644 Binary files a/src/sdl/Srb2SDL.ico and b/src/sdl/Srb2SDL.ico differ diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index f54f0d7c5..029febc05 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -26,6 +26,8 @@ #include #endif +#include "time.h" // For log timestamps + #ifdef HAVE_SDL #ifdef HAVE_TTF @@ -114,6 +116,7 @@ int main(int argc, char **argv) #endif { const char *logdir = NULL; + char logfile[MAX_WADPATH]; myargc = argc; myargv = argv; /// \todo pull out path to exe from this string @@ -125,15 +128,36 @@ int main(int argc, char **argv) #endif #endif - logdir = D_Home(); - #ifdef LOGMESSAGES + if (!M_CheckParm("-nolog")) + { + time_t my_time; + struct tm * timeinfo; + char buf[26]; + + logdir = D_Home(); + + my_time = time(NULL); + timeinfo = localtime(&my_time); + + strftime(buf, 26, "%Y-%m-%d %H-%M-%S", timeinfo); + strcpy(logfile, va("log-%s.txt", buf)); + #ifdef DEFAULTDIR - if (logdir) - logstream = fopen(va("%s/"DEFAULTDIR"/log.txt",logdir), "wt"); - else + if (logdir) + { + // 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); + logstream = fopen(va("%s%s"DEFAULTDIR"%slogs%s%s",logdir, PATHSEP, PATHSEP, PATHSEP, logfile), "wt"); + } + else #endif - logstream = fopen("./log.txt", "wt"); + { + I_mkdir("."PATHSEP"logs"PATHSEP, 0755); + logstream = fopen(va("."PATHSEP"logs"PATHSEP"%s", logfile), "wt"); + } + } #endif //I_OutputMsg("I_StartupSystem() ...\n"); @@ -160,6 +184,10 @@ int main(int argc, char **argv) // startup SRB2 CONS_Printf("Setting up SRB2...\n"); D_SRB2Main(); +#ifdef LOGMESSAGES + if (!M_CheckParm("-nolog")) + CONS_Printf("Logfile: %s\n", logfile); +#endif CONS_Printf("Entering main game loop...\n"); // never return D_SRB2Loop(); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index c4fb1c0fc..d7926e5b2 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -827,6 +827,23 @@ void I_JoyScale2(void) JoyInfo2.scale = Joystick2.bGamepadStyle?1:cv_joyscale2.value; } +// Cheat to get the device index for a joystick handle +INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev) +{ + INT32 i, count = SDL_NumJoysticks(); + + for (i = 0; dev && i < count; i++) + { + SDL_Joystick *test = SDL_JoystickOpen(i); + if (test && test == dev) + return i; + else if (JoyInfo.dev != test && JoyInfo2.dev != test) + SDL_JoystickClose(test); + } + + return -1; +} + /** \brief Joystick 1 buttons states */ static UINT64 lastjoybuttons = 0; @@ -842,7 +859,7 @@ static UINT64 lastjoyhats = 0; */ -static void I_ShutdownJoystick(void) +void I_ShutdownJoystick(void) { INT32 i; event_t event; @@ -876,14 +893,8 @@ static void I_ShutdownJoystick(void) joystick_started = 0; JoyReset(&JoyInfo); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) - { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - if (cv_usejoystick.value == 0) - { - I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n"); - } - } + + // don't shut down the subsystem here, because hotplugging } void I_GetJoystickEvents(void) @@ -1024,74 +1035,66 @@ void I_GetJoystickEvents(void) */ -static int joy_open(const char *fname) +static int joy_open(int joyindex) { - int joyindex = atoi(fname); + SDL_Joystick *newdev = NULL; int num_joy = 0; - int i; - if (joystick_started == 0 && joystick2_started == 0) + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) - { - CONS_Printf(M_GetText("Couldn't initialize gamepad: %s\n"), SDL_GetError()); - return -1; - } - else - { - num_joy = SDL_NumJoysticks(); - } + CONS_Printf(M_GetText("Joystick subsystem not started\n")); + return -1; + } - if (num_joy < joyindex) - { - CONS_Printf("Cannot use gamepad #%d/(%s), it doesn't exist\n",joyindex,fname); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - I_ShutdownJoystick(); - return -1; - } - } - else - { - JoyReset(&JoyInfo); - //I_ShutdownJoystick(); - //joy_open(fname); - } + if (joyindex <= 0) + return -1; num_joy = SDL_NumJoysticks(); - if (joyindex <= 0 || num_joy == 0 || JoyInfo.oldjoy == joyindex) + if (num_joy == 0) { -// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); - if (num_joy != 0) - { - CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - } - else - CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); - if (joyindex <= 0 || num_joy == 0) return 0; + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + return -1; } - JoyInfo.dev = SDL_JoystickOpen(joyindex-1); + newdev = SDL_JoystickOpen(joyindex-1); + + // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging + // This indexing is SDL's responsibility and there's not much we can do about it. + // + // Example: + // 1. Plug Controller A -> Index 0 opened + // 2. Plug Controller B -> Index 1 opened + // 3. Unplug Controller A -> Index 0 closed, Index 1 active + // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed + // 5. Plug Controller B -> Index 0 opened + // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B + if (JoyInfo.dev) + { + if (JoyInfo.dev == newdev // same device, nothing to do + || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo.dev))) // we failed, but already have a working device + return JoyInfo.axises; + // Else, we're changing devices, so send neutral joy events + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device is changing; resetting events...\n"); + I_ShutdownJoystick(); + } + + JoyInfo.dev = newdev; if (JoyInfo.dev == NULL) { - CONS_Printf(M_GetText("Couldn't open joystick: %s\n"), SDL_GetError()); - I_ShutdownJoystick(); + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: Couldn't open device - %s\n"), SDL_GetError()); return -1; } else { - CONS_Printf(M_GetText("Joystick: %s\n"), SDL_JoystickName(JoyInfo.dev)); + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: %s\n"), SDL_JoystickName(JoyInfo.dev)); JoyInfo.axises = SDL_JoystickNumAxes(JoyInfo.dev); if (JoyInfo.axises > JOYAXISSET*2) JoyInfo.axises = JOYAXISSET*2; -/* if (joyaxes<2) + /* if (joyaxes<2) { I_OutputMsg("Not enought axes?\n"); - I_ShutdownJoystick(); return 0; }*/ @@ -1126,7 +1129,7 @@ static UINT64 lastjoy2hats = 0; \return void */ -static void I_ShutdownJoystick2(void) +void I_ShutdownJoystick2(void) { INT32 i; event_t event; @@ -1160,14 +1163,8 @@ static void I_ShutdownJoystick2(void) joystick2_started = 0; JoyReset(&JoyInfo2); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) - { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - if (cv_usejoystick2.value == 0) - { - DEBFILE("I_Joystick2: SDL's Joystick system has been shutdown\n"); - } - } + + // don't shut down the subsystem here, because hotplugging } void I_GetJoystick2Events(void) @@ -1310,72 +1307,66 @@ void I_GetJoystick2Events(void) */ -static int joy_open2(const char *fname) +static int joy_open2(int joyindex) { - int joyindex = atoi(fname); + SDL_Joystick *newdev = NULL; int num_joy = 0; - int i; - if (joystick_started == 0 && joystick2_started == 0) + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) - { - CONS_Printf(M_GetText("Couldn't initialize gamepad: %s\n"), SDL_GetError()); - return -1; - } - else - num_joy = SDL_NumJoysticks(); + CONS_Printf(M_GetText("Joystick subsystem not started\n")); + return -1; + } - if (num_joy < joyindex) - { - CONS_Printf("Cannot use gamepad #%d/(%s), it doesn't exist\n",joyindex,fname); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - I_ShutdownJoystick2(); - return -1; - } - } - else - { - JoyReset(&JoyInfo2); - //I_ShutdownJoystick(); - //joy_open(fname); - } + if (joyindex <= 0) + return -1; num_joy = SDL_NumJoysticks(); - if (joyindex <= 0 || num_joy == 0 || JoyInfo2.oldjoy == joyindex) + if (num_joy == 0) { -// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); - if (num_joy != 0) - { - CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - } - else - CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); - if (joyindex <= 0 || num_joy == 0) return 0; + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + return -1; } - JoyInfo2.dev = SDL_JoystickOpen(joyindex-1); + newdev = SDL_JoystickOpen(joyindex-1); - if (!JoyInfo2.dev) + // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging + // This indexing is SDL's responsibility and there's not much we can do about it. + // + // Example: + // 1. Plug Controller A -> Index 0 opened + // 2. Plug Controller B -> Index 1 opened + // 3. Unplug Controller A -> Index 0 closed, Index 1 active + // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed + // 5. Plug Controller B -> Index 0 opened + // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B + if (JoyInfo2.dev) { - CONS_Printf(M_GetText("Couldn't open joystick2: %s\n"), SDL_GetError()); + if (JoyInfo2.dev == newdev // same device, nothing to do + || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo2.dev))) // we failed, but already have a working device + return JoyInfo.axises; + // Else, we're changing devices, so send neutral joy events + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device is changing; resetting events...\n"); I_ShutdownJoystick2(); + } + + JoyInfo2.dev = newdev; + + if (JoyInfo2.dev == NULL) + { + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: couldn't open device - %s\n"), SDL_GetError()); return -1; } else { - CONS_Printf(M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev)); + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev)); JoyInfo2.axises = SDL_JoystickNumAxes(JoyInfo2.dev); if (JoyInfo2.axises > JOYAXISSET*2) JoyInfo2.axises = JOYAXISSET*2; -/* if (joyaxes < 2) +/* if (joyaxes<2) { I_OutputMsg("Not enought axes?\n"); - I_ShutdownJoystick2(); return 0; }*/ @@ -1400,7 +1391,11 @@ static int joy_open2(const char *fname) // void I_InitJoystick(void) { - I_ShutdownJoystick(); + SDL_Joystick *newjoy = NULL; + + //I_ShutdownJoystick(); + if (M_CheckParm("-nojoy")) + return; if (M_CheckParm("-noxinput")) SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); @@ -1408,21 +1403,48 @@ void I_InitJoystick(void) if (M_CheckParm("-nohidapi")) SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE); - if (!strcmp(cv_usejoystick.string, "0") || M_CheckParm("-nojoy")) - return; - if (joy_open(cv_usejoystick.string) != -1) - JoyInfo.oldjoy = atoi(cv_usejoystick.string); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf("I_InitJoystick()...\n"); + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return; + } + } + + if (cv_usejoystick.value) + newjoy = SDL_JoystickOpen(cv_usejoystick.value-1); + + if (newjoy && JoyInfo2.dev == newjoy) // don't override an active device + cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (newjoy && joy_open(cv_usejoystick.value) != -1) + { + // SDL's device indexes are unstable, so cv_usejoystick may not match + // the actual device index. So let's cheat a bit and find the device's current index. + JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + joystick_started = 1; + } else { + if (JoyInfo.oldjoy) + I_ShutdownJoystick(); cv_usejoystick.value = 0; - return; + joystick_started = 0; } - joystick_started = 1; + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); } void I_InitJoystick2(void) { - I_ShutdownJoystick2(); + SDL_Joystick *newjoy = NULL; + + //I_ShutdownJoystick2(); + if (M_CheckParm("-nojoy")) + return; if (M_CheckParm("-noxinput")) SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); @@ -1430,64 +1452,77 @@ void I_InitJoystick2(void) if (M_CheckParm("-nohidapi")) SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE); - if (!strcmp(cv_usejoystick2.string, "0") || M_CheckParm("-nojoy")) - return; - if (joy_open2(cv_usejoystick2.string) != -1) - JoyInfo2.oldjoy = atoi(cv_usejoystick2.string); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf("I_InitJoystick2()...\n"); + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return; + } + } + + if (cv_usejoystick2.value) + newjoy = SDL_JoystickOpen(cv_usejoystick2.value-1); + + if (newjoy && JoyInfo.dev == newjoy) // don't override an active device + cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (newjoy && joy_open2(cv_usejoystick2.value) != -1) + { + // SDL's device indexes are unstable, so cv_usejoystick may not match + // the actual device index. So let's cheat a bit and find the device's current index. + JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + joystick2_started = 1; + } else { + if (JoyInfo2.oldjoy) + I_ShutdownJoystick2(); cv_usejoystick2.value = 0; - return; + joystick2_started = 0; } - joystick2_started = 1; + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); } static void I_ShutdownInput(void) { + // Yes, the name is misleading: these send neutral events to + // clean up the unplugged joystick's input + // Note these methods are internal to this file, not called elsewhere. + I_ShutdownJoystick(); + I_ShutdownJoystick2(); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { - JoyReset(&JoyInfo); - JoyReset(&JoyInfo2); + CONS_Printf("Shutting down joy system\n"); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n"); } - } INT32 I_NumJoys(void) { INT32 numjoy = 0; - if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) - { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1) - numjoy = SDL_NumJoysticks(); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } - else + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) numjoy = SDL_NumJoysticks(); return numjoy; } -static char joyname[255]; // MAX_PATH; joystick name is straight from the driver +static char joyname[255]; // joystick name is straight from the driver const char *I_GetJoyName(INT32 joyindex) { const char *tempname = NULL; + joyname[0] = 0; joyindex--; //SDL's Joystick System starts at 0, not 1 - if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) - { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1) - { - tempname = SDL_JoystickNameForIndex(joyindex); - if (tempname) - strncpy(joyname, tempname, 254); - } - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } - else + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { tempname = SDL_JoystickNameForIndex(joyindex); if (tempname) - strncpy(joyname, tempname, 254); + strncpy(joyname, tempname, 255); } return joyname; } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index b526e6124..57591af10 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -41,7 +41,7 @@ #ifdef HAVE_IMAGE #include "SDL_image.h" -#elif 1 +#elif defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) // Windows doesn't need this, as SDL will do it for us. #define LOAD_XPM //I want XPM! #include "IMG_xpm.c" //Alam: I don't want to add SDL_Image.dll/so #define HAVE_IMAGE //I have SDL_Image, sortof @@ -357,6 +357,14 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code) return 0; } +static void SDLdoGrabMouse(void) +{ + SDL_ShowCursor(SDL_DISABLE); + SDL_SetWindowGrab(window, SDL_TRUE); + if (SDL_SetRelativeMouseMode(SDL_TRUE) == 0) // already warps mouse if successful + wrapmouseok = SDL_TRUE; // TODO: is wrapmouseok or HalfWarpMouse needed anymore? +} + static void SDLdoUngrabMouse(void) { SDL_ShowCursor(SDL_ENABLE); @@ -579,12 +587,18 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) if (cv_usemouse.value) I_StartupMouse(); } //else firsttimeonmouse = SDL_FALSE; + + if (USE_MOUSEINPUT) + SDLdoGrabMouse(); } else if (!mousefocus && !kbfocus) { // Tell game we lost focus, pause music window_notinfocus = true; - S_PauseAudio(); + if (! cv_playmusicifunfocused.value) + S_PauseAudio(); + if (! cv_playsoundsifunfocused.value) + S_StopSounds(); if (!disable_mouse) { @@ -655,9 +669,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) // -- Monster Iestyn if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window) { - SDL_SetWindowGrab(window, SDL_TRUE); - if (SDL_SetRelativeMouseMode(SDL_TRUE) == 0) // already warps mouse if successful - wrapmouseok = SDL_TRUE; // TODO: is wrapmouseok or HalfWarpMouse needed anymore? + SDLdoGrabMouse(); } } } @@ -886,6 +898,136 @@ void I_GetEvent(void) case SDL_JOYBUTTONDOWN: Impl_HandleJoystickButtonEvent(evt.jbutton, evt.type); break; + case SDL_JOYDEVICEADDED: + { + SDL_Joystick *newjoy = SDL_JoystickOpen(evt.jdevice.which); + + CONS_Debug(DBG_GAMELOGIC, "Joystick device index %d added\n", evt.jdevice.which + 1); + + // Because SDL's device index is unstable, we're going to cheat here a bit: + // For the first joystick setting that is NOT active: + // 1. Set cv_usejoystickX.value to the new device index (this does not change what is written to config.cfg) + // 2. Set OTHERS' cv_usejoystickX.value to THEIR new device index, because it likely changed + // * If device doesn't exist, switch cv_usejoystick back to default value (.string) + // * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value! + if (newjoy && (!JoyInfo.dev || !SDL_JoystickGetAttached(JoyInfo.dev)) + && JoyInfo2.dev != newjoy) // don't override a currently active device + { + cv_usejoystick.value = evt.jdevice.which + 1; + + if (JoyInfo2.dev) + cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy + && atoi(cv_usejoystick2.string) != cv_usejoystick.value) + cv_usejoystick2.value = atoi(cv_usejoystick2.string); + else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy + && atoi(cv_usejoystick.string) != cv_usejoystick.value) + cv_usejoystick2.value = atoi(cv_usejoystick.string); + else // we tried... + cv_usejoystick2.value = 0; + } + else if (newjoy && (!JoyInfo2.dev || !SDL_JoystickGetAttached(JoyInfo2.dev)) + && JoyInfo.dev != newjoy) // don't override a currently active device + { + cv_usejoystick2.value = evt.jdevice.which + 1; + + if (JoyInfo.dev) + cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy + && atoi(cv_usejoystick.string) != cv_usejoystick2.value) + cv_usejoystick.value = atoi(cv_usejoystick.string); + else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy + && atoi(cv_usejoystick2.string) != cv_usejoystick2.value) + cv_usejoystick.value = atoi(cv_usejoystick2.string); + else // we tried... + cv_usejoystick.value = 0; + } + + // Was cv_usejoystick disabled in settings? + if (!strcmp(cv_usejoystick.string, "0") || !cv_usejoystick.value) + cv_usejoystick.value = 0; + else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + if (!strcmp(cv_usejoystick2.string, "0") || !cv_usejoystick2.value) + cv_usejoystick2.value = 0; + else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick2.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + // Update all joysticks' init states + // This is a little wasteful since cv_usejoystick already calls this, but + // we need to do this in case CV_SetValue did nothing because the string was already same. + // if the device is already active, this should do nothing, effectively. + I_InitJoystick(); + I_InitJoystick2(); + + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy); + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy); + + // update the menu + if (currentMenu == &OP_JoystickSetDef) + M_SetupJoystickMenu(0); + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); + } + break; + case SDL_JOYDEVICEREMOVED: + if (JoyInfo.dev && !SDL_JoystickGetAttached(JoyInfo.dev)) + { + CONS_Debug(DBG_GAMELOGIC, "Joystick1 removed, device index: %d\n", JoyInfo.oldjoy); + I_ShutdownJoystick(); + } + + if (JoyInfo2.dev && !SDL_JoystickGetAttached(JoyInfo2.dev)) + { + CONS_Debug(DBG_GAMELOGIC, "Joystick2 removed, device index: %d\n", JoyInfo2.oldjoy); + I_ShutdownJoystick2(); + } + + // Update the device indexes, because they likely changed + // * If device doesn't exist, switch cv_usejoystick back to default value (.string) + // * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value! + if (JoyInfo.dev) + cv_usejoystick.value = JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy) + cv_usejoystick.value = atoi(cv_usejoystick.string); + else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy) + cv_usejoystick.value = atoi(cv_usejoystick2.string); + else // we tried... + cv_usejoystick.value = 0; + + if (JoyInfo2.dev) + cv_usejoystick2.value = JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy) + cv_usejoystick2.value = atoi(cv_usejoystick2.string); + else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy) + cv_usejoystick2.value = atoi(cv_usejoystick.string); + else // we tried... + cv_usejoystick2.value = 0; + + // Was cv_usejoystick disabled in settings? + if (!strcmp(cv_usejoystick.string, "0")) + cv_usejoystick.value = 0; + else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + if (!strcmp(cv_usejoystick2.string, "0")) + cv_usejoystick2.value = 0; + else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick2.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy); + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy); + + // update the menu + if (currentMenu == &OP_JoystickSetDef) + M_SetupJoystickMenu(0); + break; case SDL_QUIT: I_Quit(); M_QuitResponse('y'); @@ -926,7 +1068,7 @@ void I_StartupMouse(void) else firsttimeonmouse = SDL_FALSE; if (cv_usemouse.value) - return; + SDLdoGrabMouse(); else SDLdoUngrabMouse(); } @@ -1034,8 +1176,11 @@ void I_FinishUpdate(void) if (cv_closedcaptioning.value) SCR_ClosedCaptions(); - if (cv_ticrate.value) - SCR_DisplayTicRate(); + if (st_overlay) + { + if (cv_ticrate.value) + SCR_DisplayTicRate(); + } if (rendermode == render_soft && screens[0]) { diff --git a/src/sdl/macosx/Srb2mac.icns b/src/sdl/macosx/Srb2mac.icns index 96cb8a36d..a3e37aab3 100644 Binary files a/src/sdl/macosx/Srb2mac.icns and b/src/sdl/macosx/Srb2mac.icns differ diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index d94010d9a..c4b2f98f4 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -878,7 +878,11 @@ boolean I_SetSongSpeed(float speed) #ifdef HAVE_OPENMPT if (openmpt_mhandle) { - char modspd[16]; + char modspd[13]; + + if (speed > 4.0f) + speed = 4.0f; // Limit this to 4x to prevent crashing, stupid fix but... ~SteelT 27/9/19 + sprintf(modspd, "%g", speed); openmpt_module_ctl_set(openmpt_mhandle, "play.tempo_factor", modspd); return true; diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index d12daaa8a..810c7dce1 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -31,6 +31,9 @@ extern SDL_bool framebuffer; #define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __func__, __LINE__) #endif +// So m_menu knows whether to store cv_usejoystick value or string +#define JOYSTICK_HOTPLUG + /** \brief The JoyInfo_s struct info about joystick @@ -67,6 +70,13 @@ extern SDLJoyInfo_t JoyInfo; */ extern SDLJoyInfo_t JoyInfo2; +// So we can call this from i_video event loop +void I_ShutdownJoystick(void); +void I_ShutdownJoystick2(void); + +// Cheat to get the device index for a joystick handle +INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev); + void I_GetConsoleEvents(void); void SDLforceUngrabMouse(void); diff --git a/src/sdl/srb2icon.png b/src/sdl/srb2icon.png deleted file mode 100644 index cdee18a84..000000000 Binary files a/src/sdl/srb2icon.png and /dev/null differ diff --git a/src/sounds.c b/src/sounds.c index 11ba1e0bc..8dc97b1e6 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -35,6 +35,23 @@ sfxinfo_t S_sfx[NUMSFX] = // name, singularity, priority, pitch, volume, data, length, skinsound, usefulness, lumpnum, caption {"none" , false, 0, 0, -1, NULL, 0, -1, -1, LUMPERROR, "///////////////////////////////"}, // maximum length + // A HUMBLE REQUEST FROM YOUR FRIENDLY NEIGHBORHOOD toaster! + // + // If you see a caption that's just "" (shows the lumpname in-game), + // and you intend to use the sound associated with it in a mod, + // PLEASE give it a caption through SOC or Lua. + // + // If the first character of the caption is '/', no caption will be + // produced; only do this for "unimportant" sounds that aren't used + // to indicate gameplay. + // + // (to whomstever updates the sounds list wiki page for 2.2, please + // either copy this comment across, or make sure its desire is + // codified in the initial paragraph of the page.) + // + // Closed Captioning may be a niche feature, but it's an important one. + // Thank you! ^u^ + // Skin Sounds {"altdi1", false, 192, 16, -1, NULL, 0, SKSPLDET1, -1, LUMPERROR, "Dying"}, {"altdi2", false, 192, 16, -1, NULL, 0, SKSPLDET2, -1, LUMPERROR, "Dying"}, @@ -195,10 +212,14 @@ sfxinfo_t S_sfx[NUMSFX] = {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"}, {"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"}, {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, + {"alart", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Caught red handed!"}, + {"vwre", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Clone fighter!"}, {"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"}, {"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"}, {"bsnipe", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Home-run smash"}, {"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!"}, // Menu, interface {"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"}, @@ -290,6 +311,139 @@ sfxinfo_t S_sfx[NUMSFX] = {"brakrl", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Rocket launch"}, {"brakrx", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Rocket explosion"}, + // Sonic 1 sounds + {"s1a0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1aa", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ab", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ac", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ad", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ae", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1af", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ba", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bd", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1be", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bf", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ca", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cd", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ce", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cf", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + + // Sonic 2 sounds + {"s220", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s221", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s222", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s223", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s224", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s225", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s226", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s227", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s228", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s229", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s230", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s231", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s232", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s233", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s234", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s235", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s236", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s237", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s238", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s239", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s240", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s241", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s242", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s243", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s244", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s245", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s246", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s247", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s248", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s249", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s250", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s251", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s252", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s253", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s254", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s255", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s256", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s257", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s258", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s259", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"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 {"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 @@ -334,7 +488,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k5b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Menu beep"}, {"s3k5c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric spark"}, {"s3k5d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"}, - {"s3k5e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, + {"s3k5e", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Releasing charge"}, {"s3k5f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"}, {"s3k60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accelerating"}, {"s3k61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drilling"}, @@ -352,7 +506,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical damage"}, {"s3k6f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, - {"s3k70", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, + {"s3k70", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, {"s3k71", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Basic Shield"}, {"s3k72", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Movement"}, {"s3k73", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Warp"}, @@ -403,7 +557,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3ka0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"}, {"s3ka1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3ka2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"}, - {"s3ka3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lift"}, + {"s3ka3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising charge"}, {"s3ka4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, {"s3ka5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3ka6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction fizzle"}, @@ -459,8 +613,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kcal", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, // ditto {"s3kcbs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, {"s3kcbl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, // ditto - {"s3kccs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, - {"s3kccl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, // ditto + {"s3kccs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bursting"}, + {"s3kccl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bursting"}, // ditto {"s3kcds", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, {"s3kcdl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, // ditto {"s3kces", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind tunnel"}, @@ -492,6 +646,174 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kdbs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running on water"}, {"s3kdbl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running on water"}, // ditto + // 3D Blast sounds (the "missing" ones are direct copies of S3K's, no minor differences what-so-ever) + {"3db06", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Collection"}, + {"3db09", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Peep"}, + {"3db14", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Chirp"}, + {"3db16", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + + // Sonic CD sounds + {"cdfm00", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Skid"}, + {"cdfm01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm02", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, + {"cdfm03", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dying"}, + {"cdfm04", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ring loss"}, + {"cdfm05", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, + {"cdfm06", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop"}, + {"cdfm07", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Shield"}, + {"cdfm08", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spring"}, + {"cdfm09", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm10", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm11", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm12", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm13", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm14", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm15", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm16", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm17", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm18", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm19", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm20", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm21", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm22", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm23", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm24", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm25", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm26", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm27", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm28", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm29", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble gasp"}, + {"cdfm30", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, + {"cdfm31", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Warp"}, + {"cdfm32", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm35", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm36", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm37", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm38", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drowning"}, + {"cdfm39", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Extra time"}, + {"cdfm45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"}, + {"cdfm50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Warp"}, + {"cdfm57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Speed boost"}, + {"cdfm63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm64", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm65", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm70", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm71", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm72", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm73", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm74", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm75", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm76", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm77", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm78", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm79", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdpcm0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Future."}, + {"cdpcm1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Past."}, + {"cdpcm2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "All right!"}, + {"cdpcm3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "I'm outta here..."}, + {"cdpcm4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Yes!"}, + {"cdpcm5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Yeah!"}, + {"cdpcm6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Giggles"}, + {"cdpcm7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Eep!"}, + {"cdpcm8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdpcm9", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, + + // Knuckles Chaotix sounds + {"kc2a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2e", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2f", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc30", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc31", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc32", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc35", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc36", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc37", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc38", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc39", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Confirm"}, + {"kc43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc46", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Select"}, + {"kc49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc51", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc57", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Sheer terror"}, + {"kc58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc59", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Shrink"}, + {"kc5a", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Grow"}, + {"kc5b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc64", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Terrifying rumble"}, + {"kc65", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ascending"}, + {"kc6c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // skin sounds free slots to add sounds at run time (Boris HACK!!!) // initialized to NULL }; diff --git a/src/sounds.h b/src/sounds.h index 20f89d9fb..9f6e0bab6 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -261,10 +261,14 @@ typedef enum sfx_boingf, sfx_corkp, sfx_corkh, + sfx_alart, + sfx_vwre, sfx_bowl, sfx_chuchu, sfx_bsnipe, sfx_sprong, + sfx_lvfal1, + sfx_pscree, // Menu, interface sfx_chchng, @@ -356,6 +360,139 @@ typedef enum sfx_brakrl, // Rocket launcher sfx_brakrx, // Rocket explodes + // S1 sounds + sfx_s1a0, + sfx_s1a1, + sfx_s1a2, + sfx_s1a3, + sfx_s1a4, + sfx_s1a5, + sfx_s1a6, + sfx_s1a7, + sfx_s1a8, + sfx_s1a9, + sfx_s1aa, + sfx_s1ab, + sfx_s1ac, + sfx_s1ad, + sfx_s1ae, + sfx_s1af, + sfx_s1b0, + sfx_s1b1, + sfx_s1b2, + sfx_s1b3, + sfx_s1b4, + sfx_s1b5, + sfx_s1b6, + sfx_s1b7, + sfx_s1b8, + sfx_s1b9, + sfx_s1ba, + sfx_s1bb, + sfx_s1bc, + sfx_s1bd, + sfx_s1be, + sfx_s1bf, + sfx_s1c0, + sfx_s1c1, + sfx_s1c2, + sfx_s1c3, + sfx_s1c4, + sfx_s1c5, + sfx_s1c6, + sfx_s1c7, + sfx_s1c8, + sfx_s1c9, + sfx_s1ca, + sfx_s1cb, + sfx_s1cc, + sfx_s1cd, + sfx_s1ce, + sfx_s1cf, + + // S2 sounds + sfx_s220, + sfx_s221, + sfx_s222, + sfx_s223, + sfx_s224, + sfx_s225, + sfx_s226, + sfx_s227, + sfx_s228, + sfx_s229, + sfx_s22a, + sfx_s22b, + sfx_s22c, + sfx_s22d, + sfx_s22e, + sfx_s22f, + sfx_s230, + sfx_s231, + sfx_s232, + sfx_s233, + sfx_s234, + sfx_s235, + sfx_s236, + sfx_s237, + sfx_s238, + sfx_s239, + sfx_s23a, + sfx_s23b, + sfx_s23c, + sfx_s23d, + sfx_s23e, + sfx_s23f, + sfx_s240, + sfx_s241, + sfx_s242, + sfx_s243, + sfx_s244, + sfx_s245, + sfx_s246, + sfx_s247, + sfx_s248, + sfx_s249, + sfx_s24a, + sfx_s24b, + sfx_s24c, + sfx_s24d, + sfx_s24e, + sfx_s24f, + sfx_s250, + sfx_s251, + sfx_s252, + sfx_s253, + sfx_s254, + sfx_s255, + sfx_s256, + sfx_s257, + sfx_s258, + sfx_s259, + sfx_s25a, + sfx_s25b, + sfx_s25c, + sfx_s25d, + 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_s3k33, sfx_s3k34, @@ -558,6 +695,174 @@ typedef enum sfx_s3kdbs, sfx_s3kdbl, + // 3DB sounds + sfx_3db06, + sfx_3db09, + sfx_3db14, + sfx_3db16, + + // SCD sounds + sfx_cdfm00, + sfx_cdfm01, + sfx_cdfm02, + sfx_cdfm03, + sfx_cdfm04, + sfx_cdfm05, + sfx_cdfm06, + sfx_cdfm07, + sfx_cdfm08, + sfx_cdfm09, + sfx_cdfm10, + sfx_cdfm11, + sfx_cdfm12, + sfx_cdfm13, + sfx_cdfm14, + sfx_cdfm15, + sfx_cdfm16, + sfx_cdfm17, + sfx_cdfm18, + sfx_cdfm19, + sfx_cdfm20, + sfx_cdfm21, + sfx_cdfm22, + sfx_cdfm23, + sfx_cdfm24, + sfx_cdfm25, + sfx_cdfm26, + sfx_cdfm27, + sfx_cdfm28, + sfx_cdfm29, + sfx_cdfm30, + sfx_cdfm31, + sfx_cdfm32, + sfx_cdfm33, + sfx_cdfm34, + sfx_cdfm35, + sfx_cdfm36, + sfx_cdfm37, + sfx_cdfm38, + sfx_cdfm39, + sfx_cdfm40, + sfx_cdfm41, + sfx_cdfm42, + sfx_cdfm43, + sfx_cdfm44, + sfx_cdfm45, + sfx_cdfm46, + sfx_cdfm47, + sfx_cdfm48, + sfx_cdfm49, + sfx_cdfm50, + sfx_cdfm51, + sfx_cdfm52, + sfx_cdfm53, + sfx_cdfm54, + sfx_cdfm55, + sfx_cdfm56, + sfx_cdfm57, + sfx_cdfm58, + sfx_cdfm59, + sfx_cdfm60, + sfx_cdfm61, + sfx_cdfm62, + sfx_cdfm63, + sfx_cdfm64, + sfx_cdfm65, + sfx_cdfm66, + sfx_cdfm67, + sfx_cdfm68, + sfx_cdfm69, + sfx_cdfm70, + sfx_cdfm71, + sfx_cdfm72, + sfx_cdfm73, + sfx_cdfm74, + sfx_cdfm75, + sfx_cdfm76, + sfx_cdfm77, + sfx_cdfm78, + sfx_cdfm79, + sfx_cdpcm0, + sfx_cdpcm1, + sfx_cdpcm2, + sfx_cdpcm3, + sfx_cdpcm4, + sfx_cdpcm5, + sfx_cdpcm6, + sfx_cdpcm7, + sfx_cdpcm8, + sfx_cdpcm9, + + // KC sounds + sfx_kc2a, + sfx_kc2b, + sfx_kc2c, + sfx_kc2d, + sfx_kc2e, + sfx_kc2f, + sfx_kc30, + sfx_kc31, + sfx_kc32, + sfx_kc33, + sfx_kc34, + sfx_kc35, + sfx_kc36, + sfx_kc37, + sfx_kc38, + sfx_kc39, + sfx_kc3a, + sfx_kc3b, + sfx_kc3c, + sfx_kc3d, + sfx_kc3e, + sfx_kc3f, + sfx_kc40, + sfx_kc41, + sfx_kc42, + sfx_kc43, + sfx_kc44, + sfx_kc45, + sfx_kc46, + sfx_kc47, + sfx_kc48, + sfx_kc49, + sfx_kc4a, + sfx_kc4b, + sfx_kc4c, + sfx_kc4d, + sfx_kc4e, + sfx_kc4f, + sfx_kc50, + sfx_kc51, + sfx_kc52, + sfx_kc53, + sfx_kc54, + sfx_kc55, + sfx_kc56, + sfx_kc57, + sfx_kc58, + sfx_kc59, + sfx_kc5a, + sfx_kc5b, + sfx_kc5c, + sfx_kc5d, + sfx_kc5e, + sfx_kc5f, + sfx_kc60, + sfx_kc61, + sfx_kc62, + sfx_kc63, + sfx_kc64, + sfx_kc65, + sfx_kc66, + sfx_kc67, + sfx_kc68, + sfx_kc69, + sfx_kc6b, + sfx_kc6c, + sfx_kc6d, + sfx_kc6e, + // free slots for S_AddSoundFx() at run-time -------------------- sfx_freeslot0, // diff --git a/src/st_stuff.c b/src/st_stuff.c index a90661ef3..392cb1c03 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -64,11 +64,12 @@ patch_t *sbotime; // Time logo patch_t *sbocolon; // Colon for time patch_t *sboperiod; // Period for time centiseconds patch_t *livesback; // Lives icon background +patch_t *stlivex; static patch_t *nrec_timer; // Timer for NiGHTS records static patch_t *sborings; -static patch_t *sboover; -static patch_t *timeover; -static patch_t *stlivex; +static patch_t *slidgame; +static patch_t *slidtime; +static patch_t *slidover; static patch_t *sboredrings; static patch_t *sboredtime; static patch_t *getall; // Special Stage HUD @@ -253,8 +254,10 @@ void ST_LoadGraphics(void) sbocolon = W_CachePatchName("STTCOLON", PU_HUDGFX); // Colon for time sboperiod = W_CachePatchName("STTPERIO", PU_HUDGFX); // Period for time centiseconds - sboover = W_CachePatchName("SBOOVER", PU_HUDGFX); - timeover = W_CachePatchName("TIMEOVER", PU_HUDGFX); + slidgame = W_CachePatchName("SLIDGAME", PU_HUDGFX); + slidtime = W_CachePatchName("SLIDTIME", PU_HUDGFX); + slidover = W_CachePatchName("SLIDOVER", PU_HUDGFX); + stlivex = W_CachePatchName("STLIVEX", PU_HUDGFX); livesback = W_CachePatchName("STLIVEBK", PU_HUDGFX); nrec_timer = W_CachePatchName("NGRTIMER", PU_HUDGFX); // Timer for NiGHTS @@ -348,7 +351,7 @@ void ST_LoadFaceGraphics(INT32 skinnum) if (skins[skinnum].sprites[SPR2_XTRA].numframes) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[0]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC]; faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes) { @@ -768,7 +771,12 @@ static inline void ST_drawRings(void) ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); - ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0)); + if (objectplacing) + ringnum = op_currentdoomednum; + else if (stplyr->rings < 0 || stplyr->spectator || stplyr->playerstate == PST_REBORN) + ringnum = 0; + else + ringnum = stplyr->rings; if (cv_timetic.value == 2) // Yes, even in modeattacking ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); @@ -877,6 +885,8 @@ static void ST_drawLivesArea(void) '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); else { + if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1))) + livescount++; if (livescount > 99) livescount = 99; V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, @@ -1464,12 +1474,9 @@ static void ST_drawNightsRecords(void) if (P_HasGrades(gamemap, stplyr->lastmare + 1)) { - if (aflag) - V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag, - ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]); - else - V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, 160, 0, - ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]); + UINT8 grade = P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare); + if (modeattacking || grade >= GRADE_A) + V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag, ngradeletters[grade]); } break; } @@ -1847,7 +1854,8 @@ static void ST_drawNiGHTSHUD(void) numbersize = 48/2; if ((oldspecialstage && leveltime & 2) - && (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))) + && (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) + && !(stplyr->powers[pw_shield] & SH_PROTECTWATER)) col = SKINCOLOR_ORANGE; ST_DrawNightsOverlayNum((160 + numbersize)<laps+1, cv_numlaps.value)) } - if (!stplyr->spectator && stplyr->exiting && cv_playersforexit.value && gametype == GT_COOP) - { - INT32 i, total = 0, exiting = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - if (players[i].lives <= 0) - continue; - - total++; - if (players[i].exiting) - exiting++; - } - - if (cv_playersforexit.value != 4) - { - total *= cv_playersforexit.value; - if (total & 3) - total += 4; // round up - total /= 4; - } - - if (exiting < total) - { - if (!splitscreen && !donef12) - { - textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) - donef12 = true; - } - total -= exiting; - textHUDdraw(va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))) - } - } - else if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) + if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) { if (!splitscreen && !donef12) { @@ -2072,7 +2045,7 @@ static void ST_drawTextHUD(void) donef12 = true; } } - else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. + else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) // Death overrides spectator text. { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; @@ -2092,7 +2065,7 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""JUMP:""\x80 Rise")) textHUDdraw(M_GetText("\x82""SPIN:""\x80 Lower")) - if (G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) + if (G_IsSpecialStage(gamemap)) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) else if (gametype == GT_COOP) { @@ -2125,7 +2098,46 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) } - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) + if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && stplyr->exiting) + { + UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); + if (numneeded) + { + INT32 i, total = 0, exiting = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + if (players[i].lives <= 0) + continue; + + total++; + if (players[i].exiting) + exiting++; + } + + if (numneeded != 4) + { + total *= cv_playersforexit.value; + if (total & 3) + total += 4; // round up + total /= 4; + } + + if (exiting < total) + { + if (!splitscreen && !donef12) + { + textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) + donef12 = true; + } + total -= exiting; + textHUDdraw(va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))) + } + } + } + else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) { if (leveltime < hidetime * TICRATE) { @@ -2409,25 +2421,20 @@ static void ST_overlayDrawer(void) } } - // GAME OVER pic + // GAME OVER hud if ((gametype == GT_COOP) && (netgame || multiplayer) && (cv_cooplives.value == 0)) ; - else if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) + else if ((G_GametypeUsesLives() || gametype == GT_RACE) && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) { - patch_t *p; - - if (countdown == 1) - p = timeover; - else - p = sboover; + INT32 i = MAXPLAYERS; + INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1)); if ((gametype == GT_COOP) && (netgame || multiplayer) && (cv_cooplives.value != 1)) { - INT32 i; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -2437,15 +2444,18 @@ static void ST_overlayDrawer(void) continue; if (players[i].lives > 0) - { - p = NULL; break; - } } } - if (p) - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, BASEVIDHEIGHT/2 - (SHORT(p->height)/2), V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p); + if (i == MAXPLAYERS && deadtimer >= 0) + { + INT32 lvlttlx = min(6*deadtimer, BASEVIDWIDTH/2); + UINT32 flags = V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS); + + V_DrawScaledPatch(lvlttlx - 8, BASEVIDHEIGHT/2, flags, (countdown == 1 ? slidtime : slidgame)); + V_DrawScaledPatch(BASEVIDWIDTH + 8 - lvlttlx, BASEVIDHEIGHT/2, flags, slidover); + } } if (G_GametypeHasTeams()) diff --git a/src/st_stuff.h b/src/st_stuff.h index 40574f46c..aaf01ca15 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -70,6 +70,7 @@ extern patch_t *sboperiod; extern patch_t *faceprefix[MAXSKINS]; // face status patches extern patch_t *superprefix[MAXSKINS]; // super face status patches extern patch_t *livesback; +extern patch_t *stlivex; extern patch_t *ngradeletters[7]; /** HUD location information (don't move this comment) diff --git a/src/v_video.c b/src/v_video.c index dfe56e37f..34d64cb04 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1046,9 +1046,15 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ prevdelta = topdelta; source = (const UINT8 *)(column) + 3; dest = desttop; - dest += FixedInt(FixedMul(topdelta< 0) + { + dest += FixedInt(FixedMul((topdelta-sy)<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) + for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) { if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) *dest = patchdrawfunc(dest, source, ofs); @@ -1065,17 +1071,17 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ // void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor) { - if (skinnum < 0 || skinnum >= numskins || (skins[skinnum].flags & SF_HIRES)) - V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); - else + if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes >= 4) { - spriteframe_t *sprframe = &skins[skinnum].sprites[SPR2_WAIT].spriteframes[0]; - patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE]; + patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE); - // No variant for translucency - V_DrawTinyMappedPatch(x, y, flags, patch, colormap); + V_DrawMappedPatch(x, y, flags, patch, colormap); } + else + V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); } // @@ -2186,7 +2192,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(hu_font[c]->width) * dupx; if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; @@ -2300,7 +2306,7 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(hu_font[c]->width) * dupx / 2; if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; @@ -2405,7 +2411,7 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) w = (SHORT(tny_font[c]->width) * dupx); if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; @@ -2503,7 +2509,7 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) w = SHORT(hu_font[c]->width) * dupx; if ((cx>>FRACBITS) > scrwidth) - break; + continue; if ((cx>>FRACBITS)+left + w < 0) //left boundary check { cx += w<width) * dupx; if ((cx>>FRACBITS) > scrwidth) - break; + continue; V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT); cx += w<= NT_FONTSIZE || !ntb_font[c] || !nto_font[c]) + { + cx += FixedMul((4 * dupx)*FRACUNIT, scale); + continue; + } + + w = FixedMul((SHORT(ntb_font[c]->width)+2 * dupx) * FRACUNIT, scale); + + if (FixedInt(cx) > scrwidth) + continue; + if (cx+(left*FRACUNIT) + w < 0) // left boundary check + { + cx += w; + continue; + } + + V_DrawFixedPatch(cx, cy, scale, option, nto_font[c], outlinecolormap); + V_DrawFixedPatch(cx, cy, scale, option, ntb_font[c], basecolormap); + + cx += w; + } +} + +// Looks familiar. +void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string) +{ + const char *text = string; + const char *first_token = text; + char *last_token = strchr(text, '\n'); + const INT32 lbreakheight = 21; + INT32 ntlines; + + if (option & V_CENTERNAMETAG) + { + ntlines = V_CountNameTagLines(string); + y -= FixedInt(FixedMul(((lbreakheight/2) * (ntlines-1))*FRACUNIT, scale)); + } + + // No line breaks? + // Draw entire string + if (!last_token) + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, string); + // Split string by the line break character + else + { + char *str = NULL; + INT32 len; + while (true) + { + // There are still lines left to draw + if (last_token) + { + size_t shift = 0; + // Free this line + if (str) + Z_Free(str); + // Find string length, do a malloc... + len = (last_token-first_token)+1; + str = ZZ_Alloc(len); + // Copy the line + strncpy(str, first_token, len-1); + str[len-1] = '\0'; + // Don't leave a line break character + // at the start of the string! + if ((strlen(str) >= 2) && (string[0] == '\n') && (string[1] != '\n')) + shift++; + // Then draw it + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, str+shift); + } + // No line break character was found + else + { + // Don't leave a line break character + // at the start of the string! + if ((strlen(first_token) >= 2) && (first_token[0] == '\n') && (first_token[1] != '\n')) + first_token++; + // Then draw it + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, first_token); + break; + } + + // Next line + y += FixedInt(FixedMul(lbreakheight*FRACUNIT, scale)); + if ((last_token-text)+1 >= (signed)strlen(text)) + last_token = NULL; + else + { + first_token = last_token; + last_token = strchr(first_token+1, '\n'); + } + } + // Free this line + if (str) + Z_Free(str); + } +} + +// Count the amount of lines in name tag string +INT32 V_CountNameTagLines(const char *string) +{ + INT32 ntlines = 1; + const char *text = string; + const char *first_token = text; + char *last_token = strchr(text, '\n'); + + // No line breaks? + if (!last_token) + return ntlines; + // Split string by the line break character + else + { + while (true) + { + if (last_token) + ntlines++; + // No line break character was found + else + break; + + // Next line + if ((last_token-text)+1 >= (signed)strlen(text)) + last_token = NULL; + else + { + first_token = last_token; + last_token = strchr(first_token+1, '\n'); + } + } + } + return ntlines; +} + +INT32 V_NameTagWidth(const char *string) +{ + INT32 c, w = 0; + size_t i; + + // It's possible for string to be a null pointer + if (!string) + return 0; + + for (i = 0; i < strlen(string); i++) + { + c = toupper(string[i]) - NT_FONTSTART; + if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c]) + w += 4; + else + w += SHORT(ntb_font[c]->width)+2; + } + + return w; +} + // Find string width from cred_font chars // INT32 V_CreditStringWidth(const char *string) @@ -2697,7 +2900,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(lt_font[c]->width) * dupx; if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; diff --git a/src/v_video.h b/src/v_video.h index 7eb990295..01d50cd57 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -112,6 +112,7 @@ extern RGBA_t *pMasterPalette; #define V_OFFSET 0x00400000 // account for offsets in patches #define V_ALLOWLOWERCASE 0x00800000 // (strings only) allow fonts that have lowercase letters to use them #define V_FLIP 0x00800000 // (patches only) Horizontal flip +#define V_CENTERNAMETAG 0x00800000 // (nametag only) center nametag lines #define V_SNAPTOTOP 0x01000000 // for centering #define V_SNAPTOBOTTOM 0x02000000 // for centering @@ -205,6 +206,11 @@ INT32 V_LevelActNumWidth(INT32 num); // act number width void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string); INT32 V_CreditStringWidth(const char *string); +// Draw a string using the nt_font +void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string); +INT32 V_CountNameTagLines(const char *string); +INT32 V_NameTagWidth(const char *string); + // Find string width from hu_font chars INT32 V_StringWidth(const char *string, INT32 option); // Find string width from hu_font chars, 0.5x scale diff --git a/src/w_wad.c b/src/w_wad.c index 2fda8674c..4d08b26dc 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -789,6 +789,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile) // set up caching // Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); + Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); #ifdef HWRENDER // allocates GLPatch info structures and store them in a tree @@ -1457,6 +1458,38 @@ boolean W_IsLumpCached(lumpnum_t lumpnum, void *ptr) return W_IsLumpCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr); } +// +// W_IsPatchCached +// +// If a patch is already cached return true, otherwise +// return false. +// +// no outside code uses the PWAD form, for now +static inline boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr) +{ + void *lcache; + + if (!TestValidLump(wad, lump)) + return false; + + lcache = wadfiles[wad]->patchcache[lump]; + + if (ptr) + { + if (ptr == lcache) + return true; + } + else if (lcache) + return true; + + return false; +} + +boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr) +{ + return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr); +} + // ========================================================================== // W_CacheLumpName // ========================================================================== @@ -1480,18 +1513,53 @@ void *W_CacheLumpName(const char *name, INT32 tag) // Cache a patch into heap memory, convert the patch format as necessary // -// Software-only compile cache the data without conversion -#ifdef HWRENDER -static inline void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) +void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { +#ifdef HWRENDER GLPatch_t *grPatch; - - if (rendermode == render_soft || rendermode == render_none) - return W_CacheLumpNumPwad(wad, lump, tag); +#endif if (!TestValidLump(wad, lump)) return NULL; +#ifdef HWRENDER + // Software-only compile cache the data without conversion + if (rendermode == render_soft || rendermode == render_none) + { +#endif + lumpcache_t *lumpcache = wadfiles[wad]->patchcache; + if (!lumpcache[lump]) + { + size_t len = W_LumpLengthPwad(wad, lump); + void *ptr, *lumpdata, *srcdata = NULL; + + ptr = Z_Malloc(len, tag, &lumpcache[lump]); + lumpdata = Z_Malloc(len, tag, NULL); + + // read the lump in full + W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); + +#ifndef NO_PNG_LUMPS + // lump is a png so convert it + if (R_IsLumpPNG((UINT8 *)lumpdata, len)) + { + size_t newlen; + srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen, true); + ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); + M_Memcpy(ptr, srcdata, newlen); + Z_Free(srcdata); + } + else // just copy it into the patch cache +#endif + M_Memcpy(ptr, lumpdata, len); + } + else + Z_ChangeTag(lumpcache[lump], tag); + + return lumpcache[lump]; +#ifdef HWRENDER + } + grPatch = HWR_GetCachedGLPatchPwad(wad, lump); if (grPatch->mipmap.grInfo.data) @@ -1515,6 +1583,7 @@ static inline void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) // return GLPatch_t, which can be casted to (patch_t) with valid patch header info return (void *)grPatch; +#endif } void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag) @@ -1522,8 +1591,6 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag) return W_CachePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag); } -#endif // HWRENDER - void W_UnlockCachedPatch(void *patch) { // The hardware code does its own memory management, as its patches @@ -1619,13 +1686,145 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5) #endif } +// Verify versions for different archive +// formats. checklist assumed to be valid. + +static int +W_VerifyName (const char *name, lumpchecklist_t *checklist, boolean status) +{ + size_t j; + for (j = 0; checklist[j].len && checklist[j].name; ++j) + { + if (( strncmp(name, checklist[j].name, + checklist[j].len) != false ) == status) + { + return true; + } + } + return false; +} + +static int +W_VerifyWAD (FILE *fp, lumpchecklist_t *checklist, boolean status) +{ + size_t i; + + // assume wad file + wadinfo_t header; + filelump_t lumpinfo; + + // read the header + if (fread(&header, 1, sizeof header, fp) == sizeof header + && header.numlumps < INT16_MAX + && strncmp(header.identification, "ZWAD", 4) + && strncmp(header.identification, "IWAD", 4) + && strncmp(header.identification, "PWAD", 4) + && strncmp(header.identification, "SDLL", 4)) + { + return true; + } + + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + + // let seek to the lumpinfo list + if (fseek(fp, header.infotableofs, SEEK_SET) == -1) + return true; + + for (i = 0; i < header.numlumps; i++) + { + // fill in lumpinfo for this wad file directory + if (fread(&lumpinfo, sizeof (lumpinfo), 1 , fp) != 1) + return true; + + lumpinfo.filepos = LONG(lumpinfo.filepos); + lumpinfo.size = LONG(lumpinfo.size); + + if (lumpinfo.size == 0) + continue; + + if (! W_VerifyName(lumpinfo.name, checklist, status)) + return false; + } + + return true; +} + +static int +W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) +{ + zend_t zend; + zentry_t zentry; + + UINT16 numlumps; + size_t i; + + char pat_central[] = {0x50, 0x4b, 0x01, 0x02, 0x00}; + char pat_end[] = {0x50, 0x4b, 0x05, 0x06, 0x00}; + + char lumpname[9]; + + // Haha the ResGetLumpsZip function doesn't + // check for file errors, so neither will I. + + // Central directory bullshit + + fseek(fp, 0, SEEK_END); + if (!ResFindSignature(fp, pat_end, max(0, ftell(fp) - (22 + 65536)))) + return true; + + fseek(fp, -4, SEEK_CUR); + if (fread(&zend, 1, sizeof zend, fp) < sizeof zend) + return true; + + numlumps = zend.entries; + + fseek(fp, zend.cdiroffset, SEEK_SET); + for (i = 0; i < numlumps; i++) + { + char* fullname; + char* trimname; + char* dotpos; + + if (fread(&zentry, 1, sizeof(zentry_t), fp) < sizeof(zentry_t)) + return true; + if (memcmp(zentry.signature, pat_central, 4)) + return true; + + fullname = malloc(zentry.namelen + 1); + if (fgets(fullname, zentry.namelen + 1, fp) != fullname) + return true; + + // Strip away file address and extension for the 8char name. + if ((trimname = strrchr(fullname, '/')) != 0) + trimname++; + else + trimname = fullname; // Care taken for root files. + + if (*trimname) // Ignore directories + { + if ((dotpos = strrchr(trimname, '.')) == 0) + dotpos = fullname + strlen(fullname); // Watch for files without extension. + + memset(lumpname, '\0', 9); // Making sure they're initialized to 0. Is it necessary? + strncpy(lumpname, trimname, min(8, dotpos - trimname)); + + if (! W_VerifyName(lumpname, checklist, status)) + return false; + } + + free(fullname); + } + + return true; +} + // Note: This never opens lumps themselves and therefore doesn't have to // deal with compressed lumps. static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, boolean status) { FILE *handle; - size_t i, j; int goodfile = false; if (!checklist) @@ -1634,66 +1833,18 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, if ((handle = W_OpenWadFile(&filename, false)) == NULL) return -1; - // detect wad file by the absence of the other supported extensions - if (stricmp(&filename[strlen(filename) - 4], ".soc") -#ifdef HAVE_BLUA - && stricmp(&filename[strlen(filename) - 4], ".lua") -#endif - && stricmp(&filename[strlen(filename) - 4], ".pk3")) + if (stricmp(&filename[strlen(filename) - 4], ".pk3") == 0) + goodfile = W_VerifyPK3(handle, checklist, status); + else { - // assume wad file - wadinfo_t header; - filelump_t lumpinfo; - - // read the header - if (fread(&header, 1, sizeof header, handle) == sizeof header - && header.numlumps < INT16_MAX - && strncmp(header.identification, "ZWAD", 4) - && strncmp(header.identification, "IWAD", 4) - && strncmp(header.identification, "PWAD", 4) - && strncmp(header.identification, "SDLL", 4)) + // detect wad file by the absence of the other supported extensions + if (stricmp(&filename[strlen(filename) - 4], ".soc") +#ifdef HAVE_BLUA + && stricmp(&filename[strlen(filename) - 4], ".lua") +#endif + ) { - fclose(handle); - return true; - } - - header.numlumps = LONG(header.numlumps); - header.infotableofs = LONG(header.infotableofs); - - // let seek to the lumpinfo list - if (fseek(handle, header.infotableofs, SEEK_SET) == -1) - { - fclose(handle); - return false; - } - - goodfile = true; - for (i = 0; i < header.numlumps; i++) - { - // fill in lumpinfo for this wad file directory - if (fread(&lumpinfo, sizeof (lumpinfo), 1 , handle) != 1) - { - fclose(handle); - return -1; - } - - lumpinfo.filepos = LONG(lumpinfo.filepos); - lumpinfo.size = LONG(lumpinfo.size); - - if (lumpinfo.size == 0) - continue; - - for (j = 0; j < NUMSPRITES; j++) - if (sprnames[j] && !strncmp(lumpinfo.name, sprnames[j], 4)) // Sprites - continue; - - goodfile = false; - for (j = 0; checklist[j].len && checklist[j].name && !goodfile; j++) - if ((strncmp(lumpinfo.name, checklist[j].name, checklist[j].len) != false) == status) - goodfile = true; - - if (!goodfile) - break; + goodfile = W_VerifyWAD(handle, checklist, status); } } fclose(handle); diff --git a/src/w_wad.h b/src/w_wad.h index 651738850..91d4e733e 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -102,6 +102,7 @@ typedef struct wadfile_s restype_t type; lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; + lumpcache_t *patchcache; #ifdef HWRENDER aatree_t *hwrcache; // patches are cached in renderer's native format #endif @@ -167,17 +168,13 @@ void *W_CacheLumpNum(lumpnum_t lump, INT32 tag); void *W_CacheLumpNumForce(lumpnum_t lumpnum, INT32 tag); boolean W_IsLumpCached(lumpnum_t lump, void *ptr); +boolean W_IsPatchCached(lumpnum_t lump, void *ptr); void *W_CacheLumpName(const char *name, INT32 tag); void *W_CachePatchName(const char *name, INT32 tag); -#ifdef HWRENDER -//void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch_t +void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch_t void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t -#else -//#define W_CachePatchNumPwad(wad, lump, tag) W_CacheLumpNumPwad(wad, lump, tag) -#define W_CachePatchNum(lumpnum, tag) W_CacheLumpNum(lumpnum, tag) -#endif void W_UnlockCachedPatch(void *patch); diff --git a/src/win32/Srb2win.ico b/src/win32/Srb2win.ico index 700276fd4..3b37433db 100644 Binary files a/src/win32/Srb2win.ico and b/src/win32/Srb2win.ico differ diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index b60ba750d..8e7fdccc9 100644 --- a/src/win32/Srb2win.rc +++ b/src/win32/Srb2win.rc @@ -1,6 +1,7 @@ //Microsoft Developer Studio generated resource script. // #include "resource.h" +#include "winver.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -62,9 +63,11 @@ END // Version // +#include "../doomdef.h" // Needed for version string + VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,9,0 - PRODUCTVERSION 1,0,9,0 + FILEVERSION 2,2,0,0 + PRODUCTVERSION 2,2,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -82,14 +85,14 @@ BEGIN VALUE "Comments", "Visit our web site at www.srb2.org for news and updates!\0" VALUE "CompanyName", "Sonic Team Junior\0" VALUE "FileDescription", "Sonic Robo Blast 2\0" - VALUE "FileVersion", "1, 09\0" + VALUE "FileVersion", VERSIONSTRING VALUE "InternalName", "srb2\0" - VALUE "LegalCopyright", "Copyright � 1998-2018 by Sonic Team Junior\0" + VALUE "LegalCopyright", "Copyright 1998-2019 by Sonic Team Junior\0" VALUE "LegalTrademarks", "Sonic the Hedgehog and related characters are trademarks of Sega.\0" VALUE "OriginalFilename", "srb2win.exe\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "Sonic Robo Blast 2\0" - VALUE "ProductVersion", "1, 09\0" + VALUE "ProductVersion", VERSIONSTRING VALUE "SpecialBuild", "\0" END END diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c index ce007af25..4ea792a25 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -102,7 +102,7 @@ static loadfunc_t hwdFuncTable[] = { {"FinishUpdate@4", &hwdriver.pfnFinishUpdate}, {"Draw2DLine@12", &hwdriver.pfnDraw2DLine}, {"DrawPolygon@16", &hwdriver.pfnDrawPolygon}, - {"RenderSkyDome@16", &hwdriver.pfnRenderDome}, + {"RenderSkyDome@16", &hwdriver.pfnRenderSkyDome}, {"SetBlend@4", &hwdriver.pfnSetBlend}, {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, {"SetTexture@4", &hwdriver.pfnSetTexture}, @@ -134,7 +134,7 @@ static loadfunc_t hwdFuncTable[] = { {"FinishUpdate", &hwdriver.pfnFinishUpdate}, {"Draw2DLine", &hwdriver.pfnDraw2DLine}, {"DrawPolygon", &hwdriver.pfnDrawPolygon}, - {"RenderSkyDome", &hwdriver.pfnRenderDome}, + {"RenderSkyDome", &hwdriver.pfnRenderSkyDome}, {"SetBlend", &hwdriver.pfnSetBlend}, {"ClearBuffer", &hwdriver.pfnClearBuffer}, {"SetTexture", &hwdriver.pfnSetTexture}, diff --git a/src/y_inter.c b/src/y_inter.c index 975902ab0..2fed35de3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -35,6 +35,7 @@ #include "p_local.h" #include "m_cond.h" // condition sets +#include "lua_hook.h" // IntermissionThinker hook #ifdef HWRENDER #include "hardware/hw_main.h" @@ -261,7 +262,7 @@ void Y_IntermissionDrawer(void) // draw time ST_DrawPatchFromHud(HUD_TIME, sbotime); - if (cv_timetic.value == 1) + if (cv_timetic.value == 3) ST_DrawNumFromHud(HUD_SECONDS, data.coop.tics); else { @@ -275,8 +276,7 @@ void Y_IntermissionDrawer(void) ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon); // Colon ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2); // Seconds - // we should show centiseconds on the intermission screen too, if the conditions are right. - if (modeattacking || cv_timetic.value == 2) + if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! { ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics @@ -429,7 +429,7 @@ void Y_IntermissionDrawer(void) { if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) break; - V_DrawContinueIcon(246 + xoffset5 - (i*12), 162+yoffset, 0, *data.spec.playerchar, *data.spec.playercolor); + V_DrawContinueIcon(246 + xoffset5 - (i*20), 162+yoffset, 0, *data.spec.playerchar, *data.spec.playercolor); } } } @@ -803,6 +803,10 @@ void Y_Ticker(void) if (paused || P_AutoPause()) return; +#ifdef HAVE_BLUA + LUAh_IntermissionThinker(); +#endif + intertic++; // Team scramble code for team match and CTF. @@ -1048,6 +1052,9 @@ static void Y_UpdateRecordReplays(void) if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings) mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); + if (data.coop.gotperfbonus) + mainrecords[gamemap-1]->gotperfect = true; + // Save demo! bestdemo[255] = '\0'; lastdemo[255] = '\0'; diff --git a/tools/flatb/Makefile b/tools/flatb/Makefile new file mode 100644 index 000000000..2134973e6 --- /dev/null +++ b/tools/flatb/Makefile @@ -0,0 +1,9 @@ +.PHONY : all clean + +all : flatb + +flatb.exe : flatb.c + i686-w64-mingw32-gcc $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ $< + +clean : + $(RM) flatb flatb.exe diff --git a/tools/flatb/flatb.c b/tools/flatb/flatb.c new file mode 100644 index 000000000..edc089232 --- /dev/null +++ b/tools/flatb/flatb.c @@ -0,0 +1,566 @@ +#define HELP \ +"Usage: flatb WAD-file list-file" "\n"\ +"Replace flats and textures by name in a DOOM WAD." "\n"\ +"\n"\ +"list-file may have the following format:" "\n"\ +"\n"\ +"GFZFLR01 GFZFLR02" "\n"\ +"# Comment" "\n"\ +"GFZROCK GFZBLOCK" "\n"\ +"\n"\ +"The first name and second name may be delimited by any whitespace." "\n"\ +"\n"\ +"Copyright 2019 James R." "\n"\ +"All rights reserved." "\n" + +/* +Copyright 2019 James R. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#define cchar const char +#define cvoid const void + +#define LONG int32_t + +#define va_inline( __ap,__last, ... )\ +(\ + va_start (__ap,__last),\ + __VA_ARGS__,\ + va_end (__ap)\ +) + +#define DELIM "\t\n\r " + +typedef struct +{ + FILE * fp; + cchar * filename; +} +File; + +int (*le32)(cvoid *); + +void +Pexit (int c, cchar *s, ...) +{ + va_list ap; + va_inline (ap, s, + + vfprintf(stderr, s, ap) + + ); + exit(c); +} + +void +Prexit (cchar *pr, ...) +{ + va_list ap; + va_inline (ap, pr, + + vfprintf(stderr, pr, ap) + + ); + perror(""); + exit(-1); +} + +void +Fopen (File *f, cchar *filename, const char *mode) +{ + FILE *fp; + if (!( fp = fopen(filename, mode) )) + Prexit("%s", filename); + f->filename = filename; + f->fp = fp; +} + +void +Ferr (File *f) +{ + if (ferror(f->fp)) + Prexit("%s", f->filename); +} + +char * +Fgets (File *f, int b, char *p) +{ + if (!( p = fgets(p, b, f->fp) )) + Ferr(f); + return p; +} + +void +Fread (File *f, int b, void *p) +{ + if (fread(p, 1, b, f->fp) < b) + Ferr(f); +} + +void +Fwrite (File *f, int b, cvoid *s) +{ + if (fwrite(s, 1, b, f->fp) < b) + Ferr(f); +} + +void +Fseek (File *f, long o) +{ + if (fseek(f->fp, o, SEEK_SET) == -1) + Prexit("%s", f->filename); +} + +void * +Malloc (int b) +{ + void *p; + if (!( p = malloc(b) )) + Prexit("%d", b); + return p; +} + +void * +Calloc (int c, int b) +{ + void *p; + if (!( p = calloc(c, b) )) + Prexit("(%d)%d", c, b); + return p; +} + +void +Reallocp (void *pp, int b) +{ + void *p; + if (!( p = realloc((*(void **)pp), b) )) + Prexit("%d", b); + (*(void **)pp) = p; +} + +void +strucpy (char *p, cchar *s, int n) +{ + int c; + int i; + for (i = 0; i < n && ( c = s[i] ); ++i) + p[i] = toupper(c); +} + +int +e32 (cvoid *s) +{ + unsigned int c; + c = *(LONG *)s; + return ( + ( c >> 24 ) | + (( c >> 8 )& 0x00FF00 )| + (( c << 8 )& 0xFF0000 )| + ( c << 24 ) + ); +} + +int +n32 (cvoid *s) +{ + return *(LONG *)s; +} + +void +Ie () +{ + int c; + c = 1; + if (*(char *)&c == 1) + le32 = n32; + else + le32 = e32; +} + +File wad_file; +File list_file; + +int list_c; +char *** list_v; + +char * directory; +char * lump; +int lumpsize; + +char * sectors; +int sectors_c; + +char * sides; +int sides_c; + +int st_floors; +int st_ceilings; +int st_sectors; + +int st_sides; +int st_uppers; +int st_mids; +int st_lowers; + +/* this is horseshit */ +char * old; +char * new; +int did; + +void +Itable () +{ + char a[1024]; + + char ***ttt; + char ***ppp; + + char **pp; + + int c; + + while (Fgets(&list_file, sizeof a, a)) + { + c = a[0]; + if (!( + c == '\n' || + c == '#' + )) + { + list_c++; + } + } + + rewind(list_file.fp); + + list_v = Calloc(list_c, sizeof (char **)); + for ( + ttt = ( ppp = list_v ) + list_c; + ppp < ttt; + ++ppp + ) + { + (*ppp) = pp = Calloc(2, sizeof (char *)); + pp[0] = Malloc(9); + pp[1] = Malloc(9); + } +} + +void +Iwad () +{ + char buf[12]; + + char * t; + char * p; + int map; + + char *sector_p; + char * side_p; + + int n; + int h; + + Fread(&wad_file, 12, buf); + if ( + memcmp(buf, "IWAD", 4) != 0 && + memcmp(buf, "PWAD", 4) != 0 + ) + { + Pexit(-1,"%s: Not a WAD\n", wad_file.filename); + } + + Fseek(&wad_file, (*le32)(&buf[8])); + + n = (*le32)(&buf[4]) * 8; + h = n / 9; + n *= 2; + directory = Malloc(n); + /* minimum number of lumps for a map */ + sectors = Malloc(h); + sides = Malloc(h); + + Fread(&wad_file, n, directory); + + sector_p = sectors; + side_p = sides; + map = 3; + for (t = ( p = directory ) + n; p < t; p += 16) + { + /* looking for SECTORS? Hopefully order doesn't matter in real world. */ + /* also search for fucking SIDES MY SIDES AAAAAAAAAA */ + switch (map) + { + case 0: + case 2: + if (strncmp(&p[8], "SECTORS", 8) == 0) + { + /* copy file offset and size */ + memcpy(sector_p, p, 8); + sector_p += 8; + sectors_c++; + map |= 1; + } + case 1: + if (strncmp(&p[8], "SIDEDEFS", 8) == 0) + { + memcpy(side_p, p, 8); + side_p += 8; + sides_c++; + map |= 2; + } + } + if (map == 3) + { + /* MAP marker */ + if (p[13] == '\0' && strncmp(&p[8], "MAP", 3) == 0) + map = 0; + } + } +} + +void +Fuckyou (char *p, int f, int *st) +{ + if (strncmp(p, old, 8) == 0) + { + strncpy(p, new, 8); + (*st)++; + did |= f; + } +} + +void +Epic (char *p, char *t) +{ + char *top; + char *bot; + int i; + /* oh hi magic number! */ + for (; p < t; p += 26) + { + bot = &p [4]; + top = &p[12]; + did = 0; + for (i = 0; i < list_c; ++i) + { + old = list_v[i][0]; + new = list_v[i][1]; + switch (did) + { + case 0: + case 2: + Fuckyou(bot, 1, &st_floors); + case 1: + Fuckyou(top, 2, &st_ceilings); + } + if (did == 3) + break; + } + if (did) + st_sectors++; + } +} + +void +Epic2 (char *p, char *t) +{ + char *top; + char *mid; + char *bot; + int i; + for (; p < t; p += 30) + { + top = &p [4]; + bot = &p[12]; + mid = &p[20]; + did = 0; + for (i = 0; i < list_c; ++i) + { + old = list_v[i][0]; + new = list_v[i][1]; + switch (did) + { + case 0: + case 2: + case 4: + case 6: + Fuckyou(top, 1, &st_uppers); + case 1: + case 5: + Fuckyou(mid, 2, &st_mids); + case 3: + Fuckyou(bot, 4, &st_lowers); + } + if (did == 7) + break; + } + if (did) + st_sides++; + } +} + +void +Fuck (char *p, int c, void (*fn)(char *,char *)) +{ + char *t; + int offs; + int size; + for (t = p + c * 8; p < t; p += 8) + { + offs = (*le32)(p); + size = (*le32)(p + 4); + if (lumpsize < size) + { + Reallocp(&lump, size); + lumpsize = size; + } + Fseek(&wad_file, offs); + Fread(&wad_file, size, lump); + (*fn)(lump, lump + size); + Fseek(&wad_file, offs); + Fwrite(&wad_file, size, lump); + } +} + +void +Awad () +{ + Fuck (sectors, sectors_c, Epic); + Fuck (sides, sides_c, Epic2); +} + +void +Readtable () +{ + char a[1024]; + + int s; + char *old; + char *new; + + int c; + + s = 0; + + while (Fgets(&list_file, sizeof a, a)) + { + c = a[0]; + if (!( + c == '\n' || + c == '#' + )) + { + if ( + ( old = strtok(a, DELIM) ) && + ( new = strtok(0, DELIM) ) + ) + { + strucpy(list_v[s][0], old, 8); + strucpy(list_v[s][1], new, 8); + ++s; + } + } + } +} + +void +Cleanup () +{ + char ***ttt; + char ***ppp; + + char **pp; + + free(lump); + free(sides); + free(sectors); + free(directory); + + if (list_v) + { + for ( + ttt = ( ppp = list_v ) + list_c; + ppp < ttt && ( pp = (*ppp) ); + ++ppp + ) + { + free(pp[0]); + free(pp[1]); + free(pp); + } + free(list_v); + } +} + +int +main (int ac, char **av) +{ + int n; + + if (ac < 3) + Pexit(0,HELP); + + Fopen (& wad_file, av[1], "rb+"); + Fopen (&list_file, av[2], "r"); + + if (atexit(Cleanup) != 0) + Pexit(-1,"Failed to register cleanup function.\n"); + + Itable(); + Readtable(); + + Ie(); + + Iwad(); + Awad(); + + printf( + "%5d sectors changed.\n" + "%5d floors.\n" + "%5d ceilings.\n" + "\n" + "%5d sides.\n" + "%5d upper textures.\n" + "%5d mid textures.\n" + "%5d lower textures.\n", + + st_sectors, + + st_floors, + st_ceilings, + + st_sides, + + st_uppers, + st_mids, + st_lowers); + + return 0; +}