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/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/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/b_bot.c b/src/b_bot.c index 7d6732365..fdccd08a4 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -375,6 +375,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 @@ -460,7 +463,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. @@ -494,11 +502,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 476bb1a1e..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()) { @@ -2870,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; @@ -2948,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) @@ -2969,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 }; @@ -3199,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); @@ -3231,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') @@ -3245,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? @@ -3331,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) @@ -3404,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) @@ -3475,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 @@ -3494,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]) @@ -3534,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 @@ -3841,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 @@ -4175,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) @@ -4203,7 +4210,6 @@ static void HandlePacketFromPlayer(SINT8 node) } break; -#endif case PT_SERVERCFG: break; case PT_FILEFRAGMENT: @@ -4699,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(); @@ -4717,7 +4723,6 @@ void TryRunTics(tic_t realtics) } } -#ifdef NEWPING static inline void PingUpdate(void) { INT32 i; @@ -4775,7 +4780,6 @@ static inline void PingUpdate(void) pingmeasurecount = 1; //Reset count } -#endif void NetUpdate(void) { @@ -4800,7 +4804,6 @@ void NetUpdate(void) gametime = nowtime; -#ifdef NEWPING if (server) { if (netgame && !(gametime % 255)) @@ -4811,7 +4814,6 @@ void NetUpdate(void) realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); pingmeasurecount++; } -#endif if (client) maketic = neededtic; @@ -4853,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 37637edd6..52f1d2997 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -359,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 @@ -852,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")); @@ -1145,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. @@ -1157,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 @@ -1244,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 bd57c2481..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}; @@ -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); @@ -740,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); @@ -879,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; @@ -920,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 @@ -1056,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) { @@ -1186,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) { @@ -1304,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) { @@ -1692,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) { @@ -2032,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")); @@ -2053,6 +2051,7 @@ static void Command_Suicide(void) return; } + WRITEINT32(cp, consoleplayer); SendNetXCmd(XD_SUICIDE, &buf, 4); } @@ -4465,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 4cdffd5ed..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); } @@ -2447,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 @@ -4185,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", @@ -4284,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", @@ -4432,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", @@ -4618,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", @@ -5861,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", @@ -5882,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 @@ -5894,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", @@ -5925,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", @@ -5945,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", @@ -5952,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 @@ -6603,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", @@ -6623,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", @@ -7234,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) @@ -7252,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 @@ -7273,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", @@ -7384,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 @@ -7601,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", @@ -7618,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 @@ -7628,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", @@ -7649,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", @@ -7656,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 @@ -7784,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 @@ -8269,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 @@ -8609,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 @@ -8830,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. @@ -8963,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}, @@ -8996,6 +9196,7 @@ struct { {"TC_ALLWHITE",TC_ALLWHITE}, {"TC_RAINBOW",TC_RAINBOW}, {"TC_BLINK",TC_BLINK}, + {"TC_DASHMODE",TC_DASHMODE}, #endif {NULL,0} @@ -9982,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 8d44d0896..676c86e0d 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -509,13 +509,17 @@ INT32 I_GetKey(void); // 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. @@ -561,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 57e37f72d..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 @@ -433,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 ee22ecb2f..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(); } 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/g_game.c b/src/g_game.c index 6c31ce9e3..e2f43e4f2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -361,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}; @@ -966,8 +968,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) forcefullinput = true; if (twodlevel || (player->mo && (player->mo->flags2 & MF2_TWOD)) - || (!demoplayback && (player->climbing - || (player->powers[pw_carry] == CR_NIGHTSMODE) + || (!demoplayback && ((player->powers[pw_carry] == CR_NIGHTSMODE) || (player->pflags & (PF_SLIDING|PF_FORCESTRAFE))))) // Analog forcestrafe = true; if (forcestrafe) @@ -1148,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) { @@ -1713,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)) @@ -1848,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); @@ -3341,6 +3341,7 @@ void G_LoadGameData(void) UINT32 recscore; tic_t rectime; UINT16 recrings; + boolean gotperf; UINT8 recmares; INT32 curmare; @@ -3433,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; @@ -3444,6 +3446,9 @@ void G_LoadGameData(void) mainrecords[i]->time = rectime; mainrecords[i]->rings = recrings; } + + if (gotperf) + mainrecords[i]->gotperfect = gotperf; } // Nights records @@ -3575,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); } } diff --git a/src/g_game.h b/src/g_game.h index df1301dd7..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; 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_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_drv.h b/src/hardware/hw_drv.h index e2fa90eb0..e0507bc70 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -47,6 +47,7 @@ EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal, RGBA_t *pgamma); EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl); EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color); EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags); +EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform); EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); @@ -89,6 +90,7 @@ struct hwdriver_s FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; + RenderSkyDome pfnRenderSkyDome; SetBlend pfnSetBlend; ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index b613fdae1..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,7 +201,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_EGGO &lspr[NOLIGHT], // SPR_SEBH &lspr[NOLIGHT], // SPR_FAKE - &lspr[NOLIGHT], // SPR_SHCK + &lspr[LBLUESHINE_L],// SPR_SHCK // Boss 4 (Castle Eggman) &lspr[NOLIGHT], // SPR_EGGP @@ -260,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 @@ -377,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 @@ -388,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 @@ -415,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 @@ -469,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 4a075d376..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); @@ -5869,86 +5886,122 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) // ========================================================================== // // ========================================================================== -static void HWR_DrawSkyBackground(void) +static void HWR_DrawSkyBackground(player_t *player) { - FOutVector v[4]; - angle_t angle; - float dimensionmultiply; - float aspectratio; - float angleturn; - - HWR_GetTexture(texturetranslation[skytexture]); - aspectratio = (float)vid.width/(float)vid.height; - - //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 - // because it's called just after clearing the screen - // and thus, the near clipping plane is set to 3.99 - // Sryder: Just use the near clipping plane value then - - // 3--2 - // | /| - // |/ | - // 0--1 - v[0].x = v[3].x = -ZCLIP_PLANE-1; - v[1].x = v[2].x = ZCLIP_PLANE+1; - v[0].y = v[1].y = -ZCLIP_PLANE-1; - v[2].y = v[3].y = ZCLIP_PLANE+1; - - v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1; - - // X - - // NOTE: This doesn't work right with texture widths greater than 1024 - // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly - // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture - - angle = (dup_viewangle + gr_xtoviewangle[0]); - - dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); - - v[0].sow = v[3].sow = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left - v[2].sow = v[1].sow = v[0].sow + (1.0f/dimensionmultiply); // right (or left + 1.0f) - // use +angle and -1.0f above instead if you wanted old backwards behavior - - // Y - angle = aimingangle; - dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); - - if (splitscreen) + if (cv_grskydome.value) { - dimensionmultiply *= 2; - angle *= 2; - } + FTransform transform; + const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd); + postimg_t *type; - // Middle of the sky should always be at angle 0 - // need to keep correct aspect ratio with X - if (atransform.flip) - { - // During vertical flip the sky should be flipped and it's y movement should also be flipped obviously - v[3].tow = v[2].tow = -(0.5f-(0.5f/dimensionmultiply)); // top - v[0].tow = v[1].tow = v[3].tow - (1.0f/dimensionmultiply); // bottom (or top - 1.0f) + if (splitscreen && player == &players[secondarydisplayplayer]) + type = &postimgtype2; + else + type = &postimgtype; + + memset(&transform, 0x00, sizeof(FTransform)); + + //04/01/2000: Hurdler: added for T&L + // It should replace all other gr_viewxxx when finished + transform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + transform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + + if (*type == postimg_flip) + transform.flip = true; + else + transform.flip = false; + + transform.scalex = 1; + transform.scaley = (float)vid.width/vid.height; + transform.scalez = 1; + transform.fovxangle = fpov; // Tails + transform.fovyangle = fpov; // Tails + transform.splitscreen = splitscreen; + + HWR_GetTexture(texturetranslation[skytexture]); + HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, transform); } else { - v[0].tow = v[1].tow = -(0.5f-(0.5f/dimensionmultiply)); // bottom - v[3].tow = v[2].tow = v[0].tow - (1.0f/dimensionmultiply); // top (or bottom - 1.0f) - } + FOutVector v[4]; + angle_t angle; + float dimensionmultiply; + float aspectratio; + float angleturn; - angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; + HWR_GetTexture(texturetranslation[skytexture]); + aspectratio = (float)vid.width/(float)vid.height; - if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa - { - angle = InvAngle(angle); - v[3].tow = v[2].tow += ((float) angle / angleturn); - v[0].tow = v[1].tow += ((float) angle / angleturn); - } - else - { - v[3].tow = v[2].tow -= ((float) angle / angleturn); - v[0].tow = v[1].tow -= ((float) angle / angleturn); - } + //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 + // because it's called just after clearing the screen + // and thus, the near clipping plane is set to 3.99 + // Sryder: Just use the near clipping plane value then - HWD.pfnDrawPolygon(NULL, v, 4, 0); + // 3--2 + // | /| + // |/ | + // 0--1 + v[0].x = v[3].x = -ZCLIP_PLANE-1; + v[1].x = v[2].x = ZCLIP_PLANE+1; + v[0].y = v[1].y = -ZCLIP_PLANE-1; + v[2].y = v[3].y = ZCLIP_PLANE+1; + + v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1; + + // X + + // NOTE: This doesn't work right with texture widths greater than 1024 + // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly + // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture + + angle = (dup_viewangle + gr_xtoviewangle[0]); + + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); + + v[0].sow = v[3].sow = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left + v[2].sow = v[1].sow = v[0].sow + (1.0f/dimensionmultiply); // right (or left + 1.0f) + // use +angle and -1.0f above instead if you wanted old backwards behavior + + // Y + angle = aimingangle; + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); + + if (splitscreen) + { + dimensionmultiply *= 2; + angle *= 2; + } + + // Middle of the sky should always be at angle 0 + // need to keep correct aspect ratio with X + if (atransform.flip) + { + // During vertical flip the sky should be flipped and it's y movement should also be flipped obviously + v[3].tow = v[2].tow = -(0.5f-(0.5f/dimensionmultiply)); // top + v[0].tow = v[1].tow = v[3].tow - (1.0f/dimensionmultiply); // bottom (or top - 1.0f) + } + else + { + v[0].tow = v[1].tow = -(0.5f-(0.5f/dimensionmultiply)); // bottom + v[3].tow = v[2].tow = v[0].tow - (1.0f/dimensionmultiply); // top (or bottom - 1.0f) + } + + angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; + + if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa + { + angle = InvAngle(angle); + v[3].tow = v[2].tow += ((float) angle / angleturn); + v[0].tow = v[1].tow += ((float) angle / angleturn); + } + else + { + v[3].tow = v[2].tow -= ((float) angle / angleturn); + v[0].tow = v[1].tow -= ((float) angle / angleturn); + } + + HWD.pfnDrawPolygon(NULL, v, 4, 0); + } } @@ -6100,7 +6153,7 @@ if (0) } if (drawsky) - HWR_DrawSkyBackground(); + HWR_DrawSkyBackground(player); //Hurdler: it doesn't work in splitscreen mode drawsky = splitscreen; @@ -6317,7 +6370,7 @@ if (0) } if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox - HWR_DrawSkyBackground(); + HWR_DrawSkyBackground(player); //Hurdler: it doesn't work in splitscreen mode drawsky = splitscreen; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index f8524990f..31e97cc13 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -98,6 +98,7 @@ extern consvar_t cv_voodoocompatibility; extern consvar_t cv_grfovchange; extern consvar_t cv_grsolvetjoin; extern consvar_t cv_grspritebillboarding; +extern consvar_t cv_grskydome; extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowy; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index cd1b957f0..b847fdbc3 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1277,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; @@ -1308,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 dfee19857..ac989613a 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1427,6 +1427,219 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, Clamp2D(GL_TEXTURE_WRAP_T); } +typedef struct vbo_vertex_s +{ + float x, y, z; + float u, v; + unsigned char r, g, b, a; +} vbo_vertex_t; + +typedef struct +{ + int mode; + int vertexcount; + int vertexindex; + int use_texture; +} GLSkyLoopDef; + +typedef struct +{ + int id; + int rows, columns; + int loopcount; + GLSkyLoopDef *loops; + vbo_vertex_t *data; +} GLSkyVBO; + +// The texture offset to be applied to the texture coordinates in SkyVertex(). +static int rows, columns; +static boolean yflip; +static int texw, texh; +static boolean foglayer; +static float delta = 0.0f; + +static int gl_sky_detail = 16; + +static INT32 lasttex = -1; + +#define MAP_COEFF 128.0f + +static void SkyVertex(vbo_vertex_t *vbo, int r, int c) +{ + const float radians = (M_PIl / 180.0f); + const float scale = 10000.0f; + const float maxSideAngle = 60.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) + { + vbo->r = 255; + vbo->g = 255; + vbo->b = 255; + vbo->a = (r == 0 ? 0 : 255); + + // And the texture coordinates. + vbo->u = (-timesRepeat * c / (float)columns); + if (!yflip) // Flipped Y is for the lower hemisphere. + vbo->v = (r / (float)rows) + 0.5f; + else + vbo->v = 1.0f + ((rows - r) / (float)rows) + 0.5f; + } + + if (r != 4) + { + y += 300.0f; + } + + // And finally the vertex. + vbo->x = x; + vbo->y = y + delta; + vbo->z = z; +} + +static GLSkyVBO sky_vbo; + +static void gld_BuildSky(int row_count, int col_count) +{ + int c, r; + vbo_vertex_t *vertex_p; + int vertex_count = 2 * row_count * (col_count * 2 + 2) + col_count * 2; + + GLSkyVBO *vbo = &sky_vbo; + + if ((vbo->columns != col_count) || (vbo->rows != row_count)) + { + free(vbo->loops); + free(vbo->data); + memset(vbo, 0, sizeof(&vbo)); + } + + if (!vbo->data) + { + memset(vbo, 0, sizeof(&vbo)); + vbo->loops = malloc((row_count * 2 + 2) * sizeof(vbo->loops[0])); + // create vertex array + vbo->data = malloc(vertex_count * sizeof(vbo->data[0])); + } + + vbo->columns = col_count; + vbo->rows = row_count; + + vertex_p = &vbo->data[0]; + vbo->loopcount = 0; + + for (yflip = 0; yflip < 2; yflip++) + { + vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_FAN; + vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; + vbo->loops[vbo->loopcount].vertexcount = col_count; + vbo->loops[vbo->loopcount].use_texture = false; + vbo->loopcount++; + + delta = 0.0f; + foglayer = true; + for (c = 0; c < col_count; c++) + { + SkyVertex(vertex_p, 1, c); + vertex_p->r = 255; + vertex_p->g = 255; + vertex_p->b = 255; + vertex_p->a = 255; + vertex_p++; + } + foglayer = false; + + delta = (yflip ? 5.0f : -5.0f) / MAP_COEFF; + + for (r = 0; r < row_count; r++) + { + 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; + vbo->loopcount++; + + for (c = 0; c <= col_count; c++) + { + SkyVertex(vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0)); + SkyVertex(vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0)); + } + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +static void RenderDome(INT32 skytexture) +{ + int i, j; + GLSkyVBO *vbo = &sky_vbo; + + pglRotatef(270.0f, 0.0f, 1.0f, 0.0f); + + rows = 4; + columns = 4 * gl_sky_detail; + + if (lasttex != skytexture) + { + lasttex = skytexture; + gld_BuildSky(rows, columns); + } + + pglScalef(1.0f, (float)texh / 230.0f, 1.0f); + + for (j = 0; j < 2; j++) + { + for (i = 0; i < vbo->loopcount; i++) + { + GLSkyLoopDef *loop = &vbo->loops[i]; + + if (j == 0 ? loop->use_texture : !loop->use_texture) + continue; + else + { + int k; + pglBegin(loop->mode); + for (k = loop->vertexindex; k < (loop->vertexindex + loop->vertexcount); k++) + { + vbo_vertex_t *v = &vbo->data[k]; + if (loop->use_texture) + pglTexCoord2f(v->u, v->v); + pglColor4f(v->r, v->g, v->b, v->a); + pglVertex3f(v->x, v->y, v->z); + } + pglEnd(); + } + } + } + + pglScalef(1.0f, 1.0f, 1.0f); + pglColor4f(1.0f, 1.0f, 1.0f, 1.0f); +} + +EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform) +{ + SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); + SetTransform(&transform); + texw = texture_width; + texh = texture_height; + 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 5fb4d3070..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 @@ -149,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 @@ -263,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 @@ -272,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 @@ -283,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 @@ -291,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 @@ -310,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 @@ -364,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 @@ -516,6 +533,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "TIRE", "GLID", + "LAND", "CLNG", "CLMB", @@ -523,7 +541,6 @@ char spr2names[NUMPLAYERSPRITES][5] = "FRUN", "BNCE", - "BLND", "FIRE", @@ -619,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, @@ -626,7 +644,6 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_RUN , // SPR2_FRUN, SPR2_FALL, // SPR2_BNCE, - SPR2_ROLL, // SPR2_BLND, 0, // SPR2_FIRE, @@ -749,6 +766,7 @@ state_t states[NUMSTATES] = // 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 @@ -758,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 @@ -849,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 @@ -996,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 @@ -1184,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 @@ -2462,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 @@ -2483,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 @@ -2498,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 @@ -2532,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 @@ -2552,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 @@ -2559,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 @@ -3214,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 @@ -3234,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 @@ -3545,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 @@ -3998,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 @@ -4028,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 @@ -4422,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 @@ -4430,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 @@ -4460,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 @@ -4780,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 }, @@ -4807,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 }, @@ -5027,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 @@ -7364,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 @@ -10908,7 +11341,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SMALLMACE - -1, // doomednum + 1130, // doomednum S_SMALLMACE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10935,7 +11368,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGMACE - -1, // doomednum + 1131, // doomednum S_BIGMACE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10990,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 @@ -11016,7 +11449,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_YELLOWSPRINGBALL - -1, // doomednum + 1134, // doomednum S_YELLOWSPRINGBALL, // spawnstate 1000, // spawnhealth S_YELLOWSPRINGBALL2, // seestate @@ -11043,7 +11476,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_REDSPRINGBALL - -1, // doomednum + 1135, // doomednum S_REDSPRINGBALL, // spawnstate 1000, // spawnhealth S_REDSPRINGBALL2, // seestate @@ -11070,7 +11503,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SMALLFIREBAR - -1, // doomednum + 1136, // doomednum S_SMALLFIREBAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11097,7 +11530,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGFIREBAR - -1, // doomednum + 1137, // doomednum S_BIGFIREBAR1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11633,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 @@ -12199,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 }, @@ -12335,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 @@ -12527,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 @@ -12550,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 }, @@ -12851,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 @@ -12986,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 @@ -13445,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 @@ -13580,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 @@ -16635,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 79a191ccc..e7f41f585 100644 --- a/src/info.h +++ b/src/info.h @@ -268,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 @@ -298,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 @@ -316,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 @@ -397,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 @@ -511,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 @@ -520,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 @@ -531,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 @@ -558,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 @@ -612,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 @@ -771,6 +796,7 @@ typedef enum playersprite SPR2_TIRE, // tired SPR2_GLID, // glide + SPR2_LAND, // landing after glide/bounce SPR2_CLNG, // cling SPR2_CLMB, // climb @@ -778,7 +804,6 @@ typedef enum playersprite SPR2_FRUN, // float run SPR2_BNCE, // bounce - SPR2_BLND, // bounce landing SPR2_FIRE, // fire @@ -854,6 +879,12 @@ typedef enum playersprite 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, @@ -900,6 +931,7 @@ typedef enum state // CA_GLIDEANDCLIMB S_PLAY_GLIDE, + S_PLAY_GLIDE_LANDING, S_PLAY_CLING, S_PLAY_CLIMB, @@ -999,6 +1031,9 @@ typedef enum state S_TAILSOVERLAY_GASP, S_TAILSOVERLAY_EDGE, + // [: + S_JETFUMEFLASH, + // Blue Crawla S_POSS_STND, S_POSS_RUN1, @@ -1147,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, @@ -1333,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, @@ -2576,7 +2642,7 @@ typedef enum state // Saloon door S_SALOONDOOR, - S_SALOONDOORTHINKER, + S_SALOONDOORCENTER, // Train cameo S_TRAINCAMEOSPAWNER_1, @@ -2597,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 @@ -2609,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, @@ -2640,6 +2734,9 @@ typedef enum state S_TARGET_RESPAWN, S_TARGET_ALLDONE, + // ATZ's green flame + S_GREENFLAME, + // Stalagmites S_STG0, S_STG1, @@ -2660,6 +2757,7 @@ typedef enum state S_LAMPPOST1, // normal S_LAMPPOST2, // with snow S_HANGSTAR, + S_MISTLETOE, // Xmas GFZ bushes S_XMASBLUEBERRYBUSH, S_XMASBERRYBUSH, @@ -2667,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 @@ -3318,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, @@ -3338,6 +3457,9 @@ typedef enum state S_SPLISH8, S_SPLISH9, + // Lava Splish + S_LAVASPLISH, + // added water splash S_SPLASH1, S_SPLASH2, @@ -3971,6 +4093,7 @@ typedef enum mobj_type MT_THOK, // Thok! mobj MT_PLAYER, MT_TAILSOVERLAY, // c: + MT_METALJETFUME, // Enemies MT_BLUECRAWLA, // Crawla (Blue) @@ -3989,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 @@ -4010,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, @@ -4121,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 @@ -4338,7 +4473,7 @@ typedef enum mobj_type MT_MINECARTSIDEMARK, MT_MINECARTSPARK, MT_SALOONDOOR, - MT_SALOONDOORTHINKER, + MT_SALOONDOORCENTER, MT_TRAINCAMEOSPAWNER, MT_TRAINSEG, MT_TRAINDUSTSPAWNER, @@ -4355,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 @@ -4365,6 +4514,7 @@ typedef enum mobj_type MT_TRAPGOYLEDOWN, MT_TRAPGOYLELONG, MT_TARGET, // AKA Red Crystal + MT_GREENFLAME, // Stalagmites MT_STALAGMITE0, @@ -4386,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, @@ -4393,6 +4544,8 @@ typedef enum mobj_type // FHZ MT_FHZICE1, MT_FHZICE2, + MT_ROSY, + MT_CDLHRT, // Halloween Scenery // Pumpkins @@ -4521,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 a69e8a188..8f173e32e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -816,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; } 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_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/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 1ab361b80..8fe782cac 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -127,7 +127,6 @@ const char *quitmsg[NUM_QUITMESSAGES]; description_t description[MAXSKINS]; INT16 char_on = -1, startchar = 0; static char *char_notes = NULL; -static fixed_t char_scroll = 0; boolean menuactive = false; boolean fromlevelselect = false; @@ -167,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 // @@ -247,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); @@ -386,9 +396,12 @@ 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"} + {NUMMAPS, "MAX"}, + {0,NULL} }; consvar_t cv_nextmap = {"nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -406,7 +419,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} }; @@ -433,7 +446,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} }; @@ -442,7 +456,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}; // ========================================================================== @@ -743,8 +757,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}, @@ -1224,11 +1238,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[] = @@ -1322,22 +1337,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 }; @@ -1960,18 +1978,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 @@ -2294,8 +2303,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); } @@ -2388,7 +2399,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; @@ -2506,7 +2517,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); } @@ -2572,8 +2583,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(); @@ -2786,31 +2795,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) { - if (cv->flags & CV_FLOAT && (currentMenu->menuitems[itemOn].status & IT_CV_FLOATSLIDER) == IT_CV_FLOATSLIDER) + 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,cv->value+(choice)); - } - else if (cv->flags & CV_FLOAT) - { - if (currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP) - { CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice)); - } - else - { - char s[20]; - sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); - CV_Set(cv,s); - } } else CV_AddValue(cv,choice); @@ -2895,6 +2892,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 // @@ -2923,6 +2929,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) @@ -3029,6 +3036,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; @@ -3045,11 +3054,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 @@ -3321,7 +3326,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)) @@ -3476,6 +3481,7 @@ void M_ClearMenus(boolean callexitmenufunc) if (currentMenu == &MessageDef) // Oh sod off! currentMenu = &MainDef; // Not like it matters menuactive = false; + hidetitlemap = false; } // @@ -3514,6 +3520,8 @@ void M_SetupNextMenu(menu_t *menudef) } } } + + hidetitlemap = false; } // @@ -3546,6 +3554,8 @@ void M_Init(void) { int i; + COM_AddCommand("manual", Command_Manual_f); + CV_RegisterVar(&cv_nextmap); CV_RegisterVar(&cv_newgametype); CV_RegisterVar(&cv_chooseskin); @@ -3621,9 +3631,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; } } @@ -3886,7 +3900,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)); @@ -4325,7 +4339,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)); @@ -4545,10 +4559,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 */ @@ -4894,13 +4910,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); @@ -4914,17 +4942,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])); @@ -4957,7 +4997,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); @@ -4987,7 +5027,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); @@ -5016,7 +5056,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); @@ -5168,18 +5208,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); } @@ -5187,7 +5396,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); } @@ -5196,7 +5411,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 @@ -5388,7 +5609,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); } @@ -6080,9 +6313,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 @@ -6664,7 +6897,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 @@ -7615,6 +7848,8 @@ static void M_HandleLoadSave(INT32 choice) } if (exitmenu) { + // Is this a hack? + charseltimer = 0; if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7691,7 +7926,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. @@ -7700,8 +7935,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. @@ -7719,20 +7967,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); } } @@ -7752,8 +8007,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); @@ -7767,7 +8036,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); } @@ -7782,6 +8055,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: @@ -7789,7 +8065,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); } @@ -7805,7 +8081,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); } @@ -7831,6 +8107,8 @@ static void M_HandleChoosePlayerMenu(INT32 choice) if (exitmenu) { + // Is this a hack? + charseltimer = 0; if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7839,100 +8117,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)); @@ -8236,16 +8627,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); @@ -8296,10 +8698,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 @@ -8319,6 +8721,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); @@ -8330,17 +8733,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)"); @@ -8349,39 +8807,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! @@ -8400,6 +8842,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; @@ -8440,12 +8915,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); @@ -8503,7 +8977,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); @@ -8520,10 +8994,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 @@ -8565,10 +9039,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); @@ -8576,6 +9050,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); @@ -8604,6 +9082,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); @@ -9386,6 +9867,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); } @@ -9450,6 +9937,8 @@ static void M_ConnectIP(INT32 choice) return; } + M_ClearMenus(true); + COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); // A little "please wait" message. @@ -9481,7 +9970,6 @@ static void M_HandleConnectIP(INT32 choice) case KEY_ENTER: S_StartSound(NULL,sfx_menu1); // Tails - M_ClearMenus(true); M_ConnectIP(1); break; @@ -9531,6 +10019,7 @@ static void M_HandleConnectIP(INT32 choice) if (exitmenu) { + currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) M_SetupNextMenu (currentMenu->prevMenu); else @@ -10035,7 +10524,7 @@ static void M_DrawJoystick(void) compareval = cv_usejoystick.value; #else compareval2 = cv_usejoystick2.value; - compareval = cv_usejoystick.value + compareval = cv_usejoystick.value; #endif if ((setupcontrols_secondaryplayer && (i == compareval2)) diff --git a/src/m_menu.h b/src/m_menu.h index 05962d2b1..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, @@ -103,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, @@ -323,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 @@ -374,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[]; diff --git a/src/m_misc.c b/src/m_misc.c index aaaf30d67..f7d5cf961 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -197,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; diff --git a/src/p_enemy.c b/src/p_enemy.c index 000b5cbfb..cc2d64e8b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -298,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 @@ -2019,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; } @@ -2079,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); @@ -2162,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; } @@ -5343,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; } @@ -5420,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; @@ -5469,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++) { @@ -5482,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 @@ -8408,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) { @@ -8420,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 @@ -12197,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); } } @@ -12237,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; @@ -12251,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) @@ -12276,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 @@ -13455,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) { @@ -13668,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); @@ -13684,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. @@ -13704,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); @@ -13738,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; @@ -13893,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 @@ -13998,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 403f36b53..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; @@ -1765,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); @@ -1775,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; @@ -2457,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) @@ -2602,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); diff --git a/src/p_local.h b/src/p_local.h index 4a5865027..02f497850 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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 8035d64a5..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,8 +375,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (horizspeed) { - object->player->drawangle = spring->angle; - object->angle = spring->angle; + object->angle = object->player->drawangle = spring->angle; if (!demoplayback || P_AnalogMove(object->player)) { @@ -356,11 +386,25 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } } - 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. @@ -368,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; @@ -382,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); } @@ -490,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; @@ -604,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 // @@ -854,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 @@ -872,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; @@ -885,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; @@ -1560,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 @@ -1964,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)) ; @@ -2629,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; @@ -2645,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; @@ -3334,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) { @@ -3479,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 @@ -3639,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 5c4609f04..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,43 +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) { - fixed_t topheight; - - I_Assert(mo != NULL); - I_Assert(!P_MobjWasRemoved(mo)); - - // not a lava block with solid planes - if (!(rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 - && !(rover->master->flags & ML_BLOCKMONSTERS))) - return false; - - // is solid from the sides - if (rover->master->flags & ML_EFFECT3) - return true; - - if (mo->eflags & MFE_VERTICALFLIP) - { - topheight = - #ifdef ESLOPE - *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : - #endif - *rover->bottomheight; - - if (mo->z+mo->height-mo->momz < topheight + FixedMul(16*FRACUNIT, mo->scale)) - return true; - return false; - } - - topheight = - #ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : - #endif - *rover->topheight; - - if (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; } @@ -3350,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) { @@ -3391,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; } @@ -3464,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. @@ -3478,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); } @@ -3513,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); } @@ -3536,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! @@ -4146,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) @@ -4694,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; @@ -4711,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) @@ -4907,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! } @@ -7054,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 // @@ -7520,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; @@ -7564,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); } @@ -7619,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]) { @@ -7683,13 +7739,244 @@ 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, mobj->movedir)*3; + strength = min(mobj->fuse, (INT32)mobj->movedir)*3; if (strength < 10) mobj->frame |= ((10-strength)<<(FF_TRANSSHIFT)); } @@ -8896,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) @@ -8912,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: @@ -9113,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) { @@ -9343,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: @@ -9812,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; @@ -9837,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; @@ -9895,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; @@ -9915,11 +10424,23 @@ 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; } @@ -10237,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); @@ -10250,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); @@ -11070,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 @@ -11283,9 +11814,10 @@ 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_FANG: case MT_METALSONIC_RACE: case MT_METALSONIC_BATTLE: + case MT_FANG: + case MT_ROSY: if (mthing->options & MTF_EXTRA) { mobj->color = SKINCOLOR_SILVER; @@ -11957,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; } @@ -12155,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) @@ -12194,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 69c942236..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) diff --git a/src/p_setup.c b/src/p_setup.c index c83c8cd5c..cef176636 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2606,7 +2606,6 @@ boolean P_SetupLevel(boolean skipprecip) boolean loadedbm = false; sector_t *ss; boolean chase; - levelloading = true; // This is needed. Don't touch. @@ -3047,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 e4792c107..f81f6d956 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)) @@ -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; @@ -2249,7 +2263,20 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) else if (!player->skidtime) player->pflags &= ~PF_GLIDING; } - else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + 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) { @@ -2301,7 +2328,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) { if (player->cmomx || player->cmomy) { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) + 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)) @@ -2314,7 +2341,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) } else { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) + 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)) @@ -2445,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); @@ -3062,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; @@ -3446,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); @@ -3462,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; @@ -3486,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) @@ -3689,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 @@ -4142,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); @@ -4212,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. @@ -4225,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. @@ -4311,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) { @@ -4324,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) @@ -4332,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; @@ -4457,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 @@ -4481,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) { @@ -4643,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; @@ -5242,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; @@ -5259,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); @@ -5685,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; } @@ -5842,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! @@ -5909,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 @@ -5943,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) { @@ -7350,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) @@ -7639,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) @@ -7655,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; @@ -7753,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()) @@ -7908,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! @@ -7932,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 @@ -8012,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) @@ -8030,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++; @@ -8070,18 +8170,9 @@ 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) { @@ -8115,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) @@ -8855,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); @@ -10254,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; @@ -10426,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; } } @@ -10641,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); @@ -10852,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 // @@ -11240,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; @@ -11266,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: @@ -11282,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 { @@ -11306,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) @@ -11326,22 +11562,24 @@ 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->powers[pw_nocontrol] + 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) @@ -11383,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. @@ -11465,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_noautobrake] && player->powers[pw_noautobrake] < UINT16_MAX) + player->powers[pw_noautobrake]--; + if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER))) { if (player->powers[pw_underwater] <= 12*TICRATE+1) @@ -11573,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)) @@ -11586,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; @@ -11608,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; @@ -11653,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 // @@ -11968,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; } @@ -12016,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) @@ -12032,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 b8b363021..524baad15 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -35,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 @@ -483,7 +483,7 @@ 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)) @@ -557,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; @@ -2520,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; @@ -2565,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; @@ -2599,7 +2668,124 @@ 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 +// +// 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/ @@ -2812,125 +2998,31 @@ static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topo 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, NULL, NULL, 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(const UINT8 *png, size_t size, size_t *destsize, boolean transparency) { UINT16 width, height; INT16 topoffset = 0, leftoffset = 0; UINT8 *raw = PNG_RawConvert(png, &width, &height, &topoffset, &leftoffset, size); - UINT32 x, y; - UINT8 *img; - UINT8 *imgptr = imgbuf; - UINT8 *colpointers, *startofspan; - if (!raw) I_Error("R_PNGToPatch: conversion failed"); - // 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; - - //printf("%d ", x); - // Write column pointer (@TODO may be wrong) - 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);///@TODO calculate starting y pos - 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; + return R_FlatToPatch(raw, width, height, leftoffset, topoffset, destsize, transparency); } boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) @@ -3001,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 c2fd284ff..e71d45766 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -159,15 +159,14 @@ 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(const UINT8 *d, size_t s); -UINT8 *R_PNGToFlat(levelflat_t *levelflat, 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 9cce41288..9d9d1c39a 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1219,6 +1219,7 @@ void R_RegisterEngineStuff(void) #endif CV_RegisterVar(&cv_grmd2); CV_RegisterVar(&cv_grspritebillboarding); + CV_RegisterVar(&cv_grskydome); #endif #ifdef HWRENDER diff --git a/src/r_plane.c b/src/r_plane.c index db5fb0f24..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,6 +653,11 @@ static void R_DrawSkyPlane(visplane_t *pl) } } +// +// R_CheckPowersOfTwo +// +// Self-explanatory? +// boolean R_CheckPowersOfTwo(void) { boolean wpow2 = (!(ds_flatwidth & (ds_flatwidth - 1))); @@ -667,6 +675,11 @@ boolean R_CheckPowersOfTwo(void) return ds_powersoftwo; } +// +// R_CheckFlatLength +// +// Determine the flat's dimensions from the lump length. +// void R_CheckFlatLength(size_t size) { switch (size) @@ -723,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]; @@ -747,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; @@ -762,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; @@ -782,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; @@ -794,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; } @@ -841,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; @@ -895,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; @@ -963,15 +1001,15 @@ 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 { @@ -1075,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 diff --git a/src/r_things.c b/src/r_things.c index 43e006a30..00eaae1c2 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -753,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; @@ -774,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; @@ -1230,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); @@ -1637,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; @@ -1668,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) { @@ -1677,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); } @@ -2786,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 } 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/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 05ac6450e..103398405 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -79,6 +79,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(Init); GETFUNC(Draw2DLine); GETFUNC(DrawPolygon); + GETFUNC(RenderSkyDome); GETFUNC(SetBlend); GETFUNC(ClearBuffer); GETFUNC(SetTexture); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 46c05aea9..57591af10 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -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(); } } } @@ -1056,7 +1068,7 @@ void I_StartupMouse(void) else firsttimeonmouse = SDL_FALSE; if (cv_usemouse.value) - return; + SDLdoGrabMouse(); else SDLdoUngrabMouse(); } @@ -1164,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]) { @@ -1629,6 +1644,7 @@ void I_StartupGraphics(void) HWD.pfnFinishUpdate = NULL; HWD.pfnDraw2DLine = hwSym("Draw2DLine",NULL); HWD.pfnDrawPolygon = hwSym("DrawPolygon",NULL); + HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL); HWD.pfnSetBlend = hwSym("SetBlend",NULL); HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); 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/sounds.c b/src/sounds.c index 6940cd9ee..8dc97b1e6 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -218,6 +218,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"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"}, @@ -504,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"}, @@ -555,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"}, @@ -713,7 +715,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"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, ""}, + {"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, ""}, diff --git a/src/sounds.h b/src/sounds.h index e5568b59a..9f6e0bab6 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -267,6 +267,8 @@ typedef enum sfx_chuchu, sfx_bsnipe, sfx_sprong, + sfx_lvfal1, + sfx_pscree, // Menu, interface sfx_chchng, diff --git a/src/st_stuff.c b/src/st_stuff.c index 20a132b3a..392cb1c03 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -351,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) { @@ -1474,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; } @@ -1857,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)<= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes >= 4) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[3]; + 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); @@ -2191,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; @@ -2305,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; @@ -2410,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; @@ -2508,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) @@ -2702,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/win32/win_dll.c b/src/win32/win_dll.c index 71eda0437..4ea792a25 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -102,6 +102,7 @@ static loadfunc_t hwdFuncTable[] = { {"FinishUpdate@4", &hwdriver.pfnFinishUpdate}, {"Draw2DLine@12", &hwdriver.pfnDraw2DLine}, {"DrawPolygon@16", &hwdriver.pfnDrawPolygon}, + {"RenderSkyDome@16", &hwdriver.pfnRenderSkyDome}, {"SetBlend@4", &hwdriver.pfnSetBlend}, {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, {"SetTexture@4", &hwdriver.pfnSetTexture}, @@ -133,6 +134,7 @@ static loadfunc_t hwdFuncTable[] = { {"FinishUpdate", &hwdriver.pfnFinishUpdate}, {"Draw2DLine", &hwdriver.pfnDraw2DLine}, {"DrawPolygon", &hwdriver.pfnDrawPolygon}, + {"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 0d6a3d03c..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" @@ -802,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. @@ -1047,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; +}