diff --git a/.circleci/config.yml b/.circleci/config.yml index 61e508e4d..8ecee2b19 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,8 +51,8 @@ jobs: - /var/cache/apt/archives - checkout - run: - name: Compile without network support and BLUA - command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 NO_LUA=1 + name: Compile without network support + command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 - run: name: wipe build command: make -C src LINUX=1 cleandep diff --git a/CMakeLists.txt b/CMakeLists.txt index 855393de1..1e46f5dc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) # DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string. # Version change is fine. project(SRB2 - VERSION 2.2.1 + VERSION 2.2.4 LANGUAGES C) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) diff --git a/appveyor.yml b/appveyor.yml index 20b18d7d5..5d599a516 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.2.1.{branch}-{build} +version: 2.2.4.{branch}-{build} os: MinGW environment: diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 0636c1e59..095349418 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -19,7 +19,8 @@ set(SRB2_ASSET_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/installer" set(SRB2_ASSET_HASHED "srb2.pk3;\ player.dta;\ -zones.pk3" +zones.pk3;\ +patch.pk3" CACHE STRING "Asset filenames to apply MD5 checks. No spaces between entries!" ) diff --git a/extras/conf/Includes/Game_SRB222.cfg b/extras/conf/Includes/Game_SRB222.cfg deleted file mode 100644 index 3c4b11e9f..000000000 --- a/extras/conf/Includes/Game_SRB222.cfg +++ /dev/null @@ -1,77 +0,0 @@ -// Default lump name for new map -defaultlumpname = "MAP01"; -//GZDB specific. Don't try to load lumps that don't exist. -basegame = 0; - -//Sky textures for vanilla maps -defaultskytextures -{ - SKY1 = "MAP01,MAP02,MAP03,MAP33,MAP50,MAP60,MAPF0,MAPM0"; - SKY2 = "MAPM7,MAPMB"; - SKY4 = "MAP04,MAP06,MAP61,MAPF6,MAPM1"; - SKY6 = "MAP05,MAP51,MAPMA"; - SKY7 = "MAPM2,MAPM5"; - SKY8 = "MAP07,MAP08,MAP09,MAP52,MAP62,MAPF1"; - SKY10 = "MAP10,MAP12,MAP53,MAP63,MAPM3"; - SKY11 = "MAP11,MAPF7"; - SKY13 = "MAP13,MAP64"; - SKY14 = "MAP14"; - SKY15 = "MAP15,MAP54"; - SKY17 = "MAP70"; - SKY20 = "MAP32,MAP55,MAP65,MAPF2,MAPF5"; - SKY21 = "MAPM4"; - SKY22 = "MAP22,MAP23,MAP25,MAP26,MAP27,MAP56,MAP66,MAPF4,MAPM6"; - SKY30 = "MAP30"; - SKY31 = "MAP31"; - SKY35 = "MAP42"; - SKY40 = "MAP41,MAP71,MAPM9"; - SKY55 = "MAPF3,MAPM8"; - SKY68 = "MAPF8"; - SKY99 = "MAP57,MAPZ0"; - SKY159 = "MAP16"; - SKY172 = "MAP40"; - SKY300 = "MAP72"; - SKY301 = "MAP73"; -} - -// Skill levels -skills -{ - 1 = "Normal"; -} - -// Skins -skins -{ - Sonic; - Tails; - Knuckles; - Amy; - Fang; - Metalsonic; -} - -// Gametypes -gametypes -{ - -1 = "Single Player"; - 0 = "Co-op"; - 1 = "Competition"; - 2 = "Race"; - 3 = "Match"; - 4 = "Team Match"; - 5 = "Tag"; - 6 = "Hide and Seek"; - 7 = "CTF"; -} - -// Texture loading options -defaultwalltexture = "GFZROCK"; -defaultfloortexture = "GFZFLR01"; -defaultceilingtexture = "F_SKY1"; - -// Default texture sets -// (these are not required, but useful for new users) -texturesets -{ -} \ No newline at end of file diff --git a/extras/conf/Includes/SRB222_common.cfg b/extras/conf/Includes/SRB222_common.cfg deleted file mode 100644 index a832e6cef..000000000 --- a/extras/conf/Includes/SRB222_common.cfg +++ /dev/null @@ -1,309 +0,0 @@ -common -{ - // Some common settings - - - - // Default testing parameters - testparameters = "-file \"%AP\" \"%F\" -warp %L"; - testshortpaths = true; - - // Action special help (mxd) - actionspecialhelp = "https://wiki.srb2.org/wiki/Linedef_type_%K"; - - // Default nodebuilder configurations - defaultsavecompiler = "zennode_normal"; - defaulttestcompiler = "zennode_fast"; - - // Generalized actions - generalizedlinedefs = false; - generalizedsectors = true; - - mixtexturesflats = true; - defaulttexturescale = 1.0f; - defaultflatscale = 1.0f; - scaledtextureoffsets = true; - - // Thing number for start position in 3D Mode - start3dmode = 3328; - - // Texture sources - textures - { - include("SRB222_misc.cfg", "textures"); - } - - // Patch sources - patches - { - include("SRB222_misc.cfg", "patches"); - } - - // Sprite sources - sprites - { - include("SRB222_misc.cfg", "sprites"); - } - - // Flat sources - flats - { - include("SRB222_misc.cfg", "flats"); - } -} - -mapformat_doom -{ - // The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder - formatinterface = "SRB2MapSetIO"; - - /* - GAME DETECT PATTERN - Used to guess the game for which a WAD file is made. - - 1 = One of these lumps must exist - 2 = None of these lumps must exist - 3 = All of these lumps must exist - */ - - gamedetect - { - EXTENDED = 2; - - - BEHAVIOR = 2; - - E#M# = 2; - - MAP?? = 1; - } - - /* - MAP LUMP NAMES - Map lumps are loaded with the map as long as they are right after each other. When the editor - meets a lump which is not defined in this list it will ignore the map if not satisfied. - The order of items defines the order in which lumps will be written to WAD file on save. - To indicate the map header lump, use ~MAP - - Legenda: - required = Lump is required to exist. - blindcopy = Lump will be copied along with the map blindly. (usefull for lumps Doom Builder doesn't use) - nodebuild = The nodebuilder generates this lump. - allowempty = The nodebuilder is allowed to leave this lump empty. - script = This lump is a text-based script. Specify the filename of the script configuration to use. - */ - - maplumpnames - { - include("SRB222_misc.cfg", "doommaplumpnames"); - } - - // When this is set to true, sectors with the same tag will light up when a line is highlighted - linetagindicatesectors = true; - - // Special linedefs - include("SRB222_misc.cfg", "speciallinedefs"); - - // Default flags for first new thing (As far as 2.2 goes, they're empty just like in 2.1) - defaultthingflags - { - } - - // DEFAULT SECTOR BRIGHTNESS LEVELS - sectorbrightness - { - include("SRB222_misc.cfg", "sectorbrightness"); - } - - // SECTOR TYPES----------------------------------------------------------------- - sectortypes - { - include("SRB222_sectors.cfg", "sectortypes"); - } - - // GENERALISED SECTOR TYPES----------------------------------------------------------------- - gen_sectortypes - { - include("SRB222_sectors.cfg", "gen_sectortypes"); - } - - // LINEDEF FLAGS - linedefflags - { - include("SRB222_misc.cfg", "linedefflags"); - } - - // Linedef flags UDMF translation table - // This is needed for copy/paste and prefabs to work properly - // When the UDMF field name is prefixed with ! it is inverted - linedefflagstranslation - { - include("SRB222_misc.cfg", "linedefflagstranslation"); - } - - // LINEDEF ACTIVATIONS - linedefactivations - { - } - - // LINEDEF TYPES - linedeftypes - { - include("SRB222_linedefs.cfg", "doom"); - } - - // THING FLAGS - thingflags - { - include("SRB222_misc.cfg", "thingflags"); - } - - // Thing flags UDMF translation table - // This is needed for copy/paste and prefabs to work properly - // When the UDMF field name is prefixed with ! it is inverted - thingflagstranslation - { - include("SRB222_misc.cfg", "thingflagstranslation"); - } - - // THING FLAGS ERROR MASK - // Mask for the thing flags which indicates the options - // that make the same thing appear in the same modes - thingflagsmask1 = 7; // 1 + 2 + 4 - thingflagsmask2 = 0; -} - -mapformat_udmf -{ - // The format interface handles the map data format - formatinterface = "UniversalMapSetIO"; - - // Enables support for long (> 8 chars) texture names - // WARNING: this should only be enabled for UDMF game configurations! - // WARNING: enabling this will make maps incompatible with Doom Builder 2 and can lead to problems in Slade 3! - longtexturenames = false; - - // Default nodebuilder configurations - defaultsavecompiler = "zdbsp_udmf_normal"; - defaulttestcompiler = "zdbsp_udmf_fast"; - - engine = "srb2"; // override that so that DB2 uses the correct namespace - - maplumpnames - { - include("UDMF_misc.cfg", "udmfmaplumpnames_begin"); - include("SRB222_misc.cfg", "udmfmaplumpnames"); - include("UDMF_misc.cfg", "udmfmaplumpnames_end"); - } - - universalfields - { -// include("SRB222_misc.cfg", "universalfields"); - } - - // When this is set to true, sectors with the same tag will light up when a line is highlighted - linetagindicatesectors = false; - - // Special linedefs - include("SRB222_misc.cfg", "speciallinedefs_udmf"); - - // Default flags for first new thing (As far as 2.2 goes, they're empty just like in 2.1) - defaultthingflags - { - } - - // Generalized actions - generalizedlinedefs = false; - - // SECTOR FLAGS - sectorflags - { -// include("SRB222_misc.cfg", "sectorflags"); - } - - // DEFAULT SECTOR BRIGHTNESS LEVELS - sectorbrightness - { - include("SRB222_misc.cfg", "sectorbrightness"); - } - - // SECTOR TYPES - sectortypes - { - include("SRB222_sectors.cfg", "sectortypes"); - } - - // SECTOR RENSERSTYLES -/* sectorrenderstyles - { - include("SRB222_misc.cfg", "sectorrenderstyles"); - }*/ - - // LINEDEF FLAGS - linedefflags - { - include("SRB222_misc.cfg", "linedefflags_udmf"); - } - - // LINEDEF ACTIVATIONS - linedefactivations - { - include("SRB222_misc.cfg", "linedefactivations_udmf"); - } - - linedefflagstranslation - { - } - - - // LINEDEF RENSERSTYLES - linedefrenderstyles - { - include("SRB222_misc.cfg", "linedefrenderstyles"); - } - - //SIDEDEF FLAGS -/* sidedefflags - { - include("UDMF_misc.cfg", "sidedefflags"); - }*/ - - // THING FLAGS - thingflags - { - include("SRB222_misc.cfg", "thingflags_udmf"); - } - - // Thing flags UDMF translation table - // This is needed for copy/paste and prefabs to work properly - // When the UDMF field name is prefixed with ! it is inverted - thingflagstranslation - { - include("SRB222_misc.cfg", "thingflagstranslation"); - } - - // THING RENSERSTYLES -/* thingrenderstyles - { - include("SRB222_misc.cfg", "thingrenderstyles"); - }*/ - - // How to compare thing flags (for the stuck things error checker) -/* thingflagscompare - { - include("UDMF_misc.cfg", "thingflagscompare"); - }*/ - - //mxd. Thing flags UDMF translation table - // This is needed for copy/paste and prefabs to work properly - // When the UDMF field name is prefixed with ! it is inverted - thingflagstranslation - { - } - - // LINEDEF TYPES - linedeftypes - { - include("SRB222_linedefs.cfg", "udmf"); - } -} \ No newline at end of file diff --git a/extras/conf/Includes/SRB222_linedefs.cfg b/extras/conf/Includes/SRB222_linedefs.cfg deleted file mode 100644 index fdf191850..000000000 --- a/extras/conf/Includes/SRB222_linedefs.cfg +++ /dev/null @@ -1,2486 +0,0 @@ -doom -{ - 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 end item"; - flags256text = "[8] Spawn link 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"; - } - - 462 - { - title = "Stop Timer/Exit Stage in Record Attack"; - prefix = "(462)"; - } - } - - 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)"; - } - } -} - -udmf -{ - misc - { - title = "Miscellaneous"; - - 0 - { - title = "None"; - prefix = "(0)"; - } - } -} \ No newline at end of file diff --git a/extras/conf/Includes/SRB222_misc.cfg b/extras/conf/Includes/SRB222_misc.cfg deleted file mode 100644 index ce23388b2..000000000 --- a/extras/conf/Includes/SRB222_misc.cfg +++ /dev/null @@ -1,726 +0,0 @@ -linedefflags -{ - 1 = "[0] Impassable"; - 2 = "[1] Block Enemies"; - 4 = "[2] Double-Sided"; - 8 = "[3] Upper Unpegged"; - 16 = "[4] Lower Unpegged"; - 32 = "[5] Slope Skew (E1)"; - 64 = "[6] Not Climbable"; - 128 = "[7] No Midtexture Skew (E2)"; - 256 = "[8] Peg Midtexture (E3)"; - 512 = "[9] Solid Midtexture (E4)"; - 1024 = "[10] Repeat Midtexture (E5)"; - 2048 = "[11] Netgame Only"; - 4096 = "[12] No Netgame"; - 8192 = "[13] Effect 6"; - 16384 = "[14] Bouncy Wall"; - 32768 = "[15] Transfer Line"; -} - - -// LINEDEF ACTIVATIONS -// Make sure these are in order from lowest value to highest value -linedefactivations -{ -} - - -// Linedef flags UDMF translation table -// This is needed for copy/paste and prefabs to work properly -// When the UDMF field name is prefixed with ! it is inverted -linedefflagstranslation -{ - 1 = "blocking"; - 2 = "blockmonsters"; - 4 = "twosided"; - 8 = "dontpegtop"; - 16 = "dontpegbottom"; - 32 = "skewtd"; - 64 = "noclimb"; - 128 = "noskew"; - 256 = "midpeg"; - 512 = "midsolid"; - 1024 = "wrapmidtex"; - 2048 = "netonly"; - 4096 = "nonet"; - 8192 = "effect6"; - 16384 = "bouncy"; - 32768 = "transfer"; -} - - -linedefflags_udmf -{ - blocking = "Impassable"; - blockmonsters = "Block Enemies"; - twosided = "Double-Sided"; - dontpegtop = "Upper Unpegged"; - dontpegbottom = "Lower Unpegged"; - skewtd = "Slope Skew"; - noclimb = "Not Climbable"; - noskew = "No Midtexture Skew"; - midpeg = "Peg Midtexture"; - midsolid = "Solid Midtexture"; - wrapmidtex = "Repeat Midtexture"; -// netonly = "Netgame-Only special"; -// nonet = "No netgame special"; -// effect6 = "Effect 6"; - bouncy = "Bouncy Wall"; -// transfer = "Transfer Line"; -} - - -linedefactivations_udmf -{ - notriggerorder = "Out of Order"; - netonly = "Netgame-Only"; - nonet = "No netgame"; -} - -sidedefflags -{ - clipmidtex = "Clip middle texture"; - wrapmidtex = "Wrap middle texture"; - smoothlighting = "Smooth lighting"; - nofakecontrast = "Even lighting"; - nodecals = "No decals"; - lightfog = "Use sidedef brightness on fogged walls"; -} - -//RENDER STYLES -thingrenderstyles -{ -} - -linedefrenderstyles -{ - translucent = "Translucent"; - fog = "Fog"; -} - -sectorrenderstyles -{ -} - -thingflags -{ - 1 = "[1] Extra"; - 2 = "[2] Flip"; - 4 = "[4] Special"; - 8 = "[8] Ambush"; -} - -// THING FLAGS -thingflags_udmf -{ - extra = "Extra"; - flip = "Flip"; - special = "Special"; - ambush = "Ambush"; -} - - -// Thing flags UDMF translation table -// This is needed for copy/paste and prefabs to work properly -// When the UDMF field name is prefixed with ! it is inverted -thingflagstranslation -{ - 1 = "extra"; - 2 = "flip"; - 4 = "special"; - 8 = "ambush"; -} - - -// DEFAULT SECTOR BRIGHTNESS LEVELS -sectorbrightness -{ - 255; - 248; - 240; - 232; - 224; - 216; - 208; - 200; - 192; - 184; - 176; - 168; - 160; - 152; - 144; - 136; - 128; - 120; - 112; - 104; - 96; - 88; - 80; - 72; - 64; - 56; - 48; - 40; - 32; - 24; - 16; - 8; - 0; -} - -/* -TEXTURES AND FLAT SOURCES -This tells Doom Builder where to find the information for textures -and flats in the IWAD file, Addition WAD file and Map WAD file. - -Start and end lumps must be given in a structure (of which the -key name doesnt matter) and any textures or flats in between them -are loaded in either the textures category or flats category. - -For textures: PNAMES, TEXTURE1 and TEXTURE2 are loaded by default. -*/ -textures -{ - zdoom1 - { - start = "TX_START"; - end = "TX_END"; - } -} - -/* -ADDITIONAL UNIVERSAL DOOM MAP FORMAT FIELD DEFINITIONS -Only add fields here that Doom Builder does not edit with its own user-interface! -The "default" field must match the UDMF specifications! - -Field data types: -0 = integer * -1 = float -2 = string -3 = bool -4 = linedef action (integer) * -5 = sector effect (integer) * -6 = texture (string) -7 = flat (string) -8 = angle in degrees (integer) -9 = angle in radians (float) -10 = XXRRGGBB color (integer) -11 = enum option (integer) * -12 = enum bits (integer) * -13 = sector tag (integer) * -14 = thing tag (integer) * -15 = linedef tag (integer) * -16 = enum option (string) -17 = angle in degrees (float) -22 = byte angle (integer) -*/ -universalfields -{ - sector - { - friction - { - name = "Friction"; - type = 1; - default = 1; - } - - specialeffectplanes - { - type = 11; - enum = "floorceiling"; - default = 0; - } - - colormapbegin - { - type = 0; - default = 0; - } - - colormapend - { - type = 0; - default = 33; - } - - foglighting - { - type = 3; - default = false; - } - - teambase - { - type = 11; - enum = "ctfteam"; - default = 0; - } - - triggersector - { - type = 3; - default = false; - } - - triggerobject - { - type = 11; - enum = "triggerobjects"; - default = 0; - } - - triggersurface - { - type = 11; - enum = "triggersurfaces"; - default = 0; - } - - ringdrain - { - type = 1; - default = 0; - } - } - - linedef - { - executordelay - { - type = 0; - default = 0; - } - midtexrepetitions - { - type = 0; - default = 0; - } - arg5 - { - type = 0; - default = 0; - } - arg1str - { - type = 2; - default = ""; - } - } - - thing - { - } -} - -/* -MAP LUMP NAMES -Map lumps are loaded with the map as long as they are right after each other. When the editor -meets a lump which is not defined in this list it will ignore the map if not satisfied. -The order of items defines the order in which lumps will be written to WAD file on save. -To indicate the map header lump, use ~MAP - -Legenda: -required = Lump is required to exist. -blindcopy = Lump will be copied along with the map blindly. (useful for lumps Doom Builder doesn't use) -nodebuild = The nodebuilder generates this lump. -allowempty = The nodebuilder is allowed to leave this lump empty. -scriptbuild = This lump is a text-based script, which should be compiled using current script compiler; -script = This lump is a text-based script. Specify the filename of the script configuration to use. -*/ - -doommaplumpnames -{ - ~MAP - { - required = true; - blindcopy = true; - nodebuild = false; - } - - THINGS - { - required = true; - nodebuild = true; - allowempty = true; - } - - LINEDEFS - { - required = true; - nodebuild = true; - allowempty = false; - } - - SIDEDEFS - { - required = true; - nodebuild = true; - allowempty = false; - } - - VERTEXES - { - required = true; - nodebuild = true; - allowempty = false; - } - - SEGS - { - required = false; - nodebuild = true; - allowempty = false; - } - - SSECTORS - { - required = false; - nodebuild = true; - allowempty = false; - } - - NODES - { - required = false; - nodebuild = true; - allowempty = false; - } - - SECTORS - { - required = true; - nodebuild = true; - allowempty = false; - } - - REJECT - { - required = false; - nodebuild = true; - allowempty = false; - } - - BLOCKMAP - { - required = false; - nodebuild = true; - allowempty = true; - } -} - -udmfmaplumpnames -{ - ZNODES - { - required = false; - nodebuild = true; - allowempty = false; - } - - REJECT - { - required = false; - nodebuild = true; - allowempty = false; - } - - BLOCKMAP - { - required = false; - nodebuild = true; - allowempty = true; - } -} - -// ENUMERATIONS -// These are enumerated lists for linedef types and UDMF fields. -// Reserved names are: angledeg, anglerad, color, texture, flat -enums -{ - falsetrue - { - 0 = "False"; - 1 = "True"; - } - - yesno - { - 0 = "Yes"; - 1 = "No"; - } - - noyes - { - 0 = "No"; - 1 = "Yes"; - } - - onoff - { - 0 = "On"; - 1 = "Off"; - } - - offon - { - 0 = "Off"; - 1 = "On"; - } - - updown - { - 0 = "Up"; - 1 = "Down"; - } - - downup - { - 0 = "Down"; - 1 = "Up"; - } - - addset - { - 0 = "Add"; - 1 = "Set"; - } - - floorceiling - { - 0 = "Floor"; - 1 = "Ceiling"; - 2 = "Floor and ceiling"; - } - - triggertype - { - 0 = "Continuous"; - 1 = "Each Time (Enter)"; - 2 = "Each Time (Enter and leave)"; - 3 = "Once"; - } - - frontback - { - 0 = "None"; - 1 = "Front"; - 2 = "Back"; - } - - ctfteam - { - 0 = "None"; - 1 = "Red"; - 2 = "Blue"; - } - - triggerobjects - { - 0 = "Any player"; - 1 = "All players"; - 2 = "Pushable object"; - 3 = "Any object with thinker"; - } - - triggersurfaces - { - 0 = "Floor touch"; - 1 = "Ceiling touch"; - 2 = "Floor or ceiling touch"; - 3 = "Anywhere in sector"; - } - - tangibility - { - 1 = "Intangible from top"; - 2 = "Intangible from bottom"; - 4 = "Don't block players"; - 8 = "Don't block non-players"; - } -} - -//Default things filters -thingsfilters -{ - - filter0 - { - name = "Player starts"; - category = "starts"; - type = -1; - } - - - filter1 - { - name = "Enemies"; - category = "enemies"; - type = -1; - - } - - - filter2 - { - name = "NiGHTS Track"; - category = "nightstrk"; - type = -1; - - } - - - filter3 - { - name = "Normal Gravity"; - category = ""; - type = -1; - - fields - { - 2 = false; - } - - } - - - filter4 - { - name = "Reverse Gravity"; - category = ""; - type = -1; - - fields - { - 2 = true; - } - - } -} - -thingsfilters_udmf -{ -} - -// Special linedefs -speciallinedefs -{ - soundlinedefflag = 64; // See linedefflags - singlesidedflag = 1; // See linedefflags - doublesidedflag = 4; // See linedefflags - impassableflag = 1; - upperunpeggedflag = 8; - lowerunpeggedflag = 16; - repeatmidtextureflag = 1024; - pegmidtextureflag = 256; -} - -speciallinedefs_udmf -{ - soundlinedefflag = "noclimb"; - singlesidedflag = "blocking"; - doublesidedflag = "twosided"; - impassableflag = "blocking"; - upperunpeggedflag = "dontpegtop"; - lowerunpeggedflag = "dontpegbottom"; - repeatmidtextureflag = "wrapmidtex"; - pegmidtextureflag = "midpeg"; -} - -scriptlumpnames -{ - MAINCFG - { - script = "SOC.cfg"; - } - - OBJCTCFG - { - script = "SOC.cfg"; - } - - SOC_ - { - script = "SOC.cfg"; - isprefix = true; - } - - LUA_ - { - script = "Lua.cfg"; - isprefix = true; - } -} - -// Texture sources -textures -{ - zdoom1 - { - start = "TX_START"; - end = "TX_END"; - } -} - -// Patch sources -patches -{ - standard1 - { - start = "P_START"; - end = "P_END"; - } - - standard2 - { - start = "PP_START"; - end = "PP_END"; - } -} - -// Sprite sources -sprites -{ - standard1 - { - start = "S_START"; - end = "S_END"; - } - - standard2 - { - start = "SS_START"; - end = "SS_END"; - } -} - -// Flat sources -flats -{ - standard1 - { - start = "F_START"; - end = "F_END"; - } - - standard2 - { - start = "FF_START"; - end = "FF_END"; - } - - standard3 - { - start = "FF_START"; - end = "F_END"; - } - - standard4 - { - start = "F_START"; - end = "FF_END"; - } -} \ No newline at end of file diff --git a/extras/conf/Includes/SRB222_sectors.cfg b/extras/conf/Includes/SRB222_sectors.cfg deleted file mode 100644 index 3bcbeb1b1..000000000 --- a/extras/conf/Includes/SRB222_sectors.cfg +++ /dev/null @@ -1,109 +0,0 @@ -sectortypes -{ - 0 = "Normal"; - 1 = "Damage"; - 2 = "Damage (Water)"; - 3 = "Damage (Fire)"; - 4 = "Damage (Electrical)"; - 5 = "Spikes"; - 6 = "Death Pit (Camera Tilt)"; - 7 = "Death Pit (No Camera Tilt)"; - 8 = "Instant Kill"; - 9 = "Ring Drainer (Floor Touch)"; - 10 = "Ring Drainer (Anywhere in Sector)"; - 11 = "Special Stage Damage"; - 12 = "Space Countdown"; - 13 = "Ramp Sector (double step-up/down)"; - 14 = "Non-Ramp Sector (no step-down)"; - 15 = "Bouncy FOF"; - 16 = "Trigger Line Ex. (Pushable Objects)"; - 32 = "Trigger Line Ex. (Anywhere, All Players)"; - 48 = "Trigger Line Ex. (Floor Touch, All Players)"; - 64 = "Trigger Line Ex. (Anywhere in Sector)"; - 80 = "Trigger Line Ex. (Floor Touch)"; - 96 = "Trigger Line Ex. (Emerald Check)"; - 112 = "Trigger Line Ex. (NiGHTS Mare)"; - 128 = "Check for Linedef Executor on FOFs"; - 144 = "Egg Capsule"; - 160 = "Special Stage Time/Rings Parameters"; - 176 = "Custom Global Gravity"; - 512 = "Wind/Current"; - 1024 = "Conveyor Belt"; - 1280 = "Speed Pad"; - 4096 = "Star Post Activator"; - 8192 = "Exit/Special Stage Pit/Return Flag"; - 12288 = "CTF Red Team Base"; - 16384 = "CTF Blue Team Base"; - 20480 = "Fan Sector"; - 24576 = "Super Sonic Transform"; - 28672 = "Force Spin"; - 32768 = "Zoom Tube Start"; - 36864 = "Zoom Tube End"; - 40960 = "Circuit Finish Line"; - 45056 = "Rope Hang"; - 49152 = "Intangible to the Camera"; -} - -gen_sectortypes -{ - first - { - 0 = "Normal"; - 1 = "Damage"; - 2 = "Damage (Water)"; - 3 = "Damage (Fire)"; - 4 = "Damage (Electrical)"; - 5 = "Spikes"; - 6 = "Death Pit (Camera Tilt)"; - 7 = "Death Pit (No Camera Tilt)"; - 8 = "Instant Kill"; - 9 = "Ring Drainer (Floor Touch)"; - 10 = "Ring Drainer (Anywhere in Sector)"; - 11 = "Special Stage Damage"; - 12 = "Space Countdown"; - 13 = "Ramp Sector (double step-up/down)"; - 14 = "Non-Ramp Sector (no step-down)"; - 15 = "Bouncy FOF"; - } - - second - { - 0 = "Normal"; - 16 = "Trigger Line Ex. (Pushable Objects)"; - 32 = "Trigger Line Ex. (Anywhere, All Players)"; - 48 = "Trigger Line Ex. (Floor Touch, All Players)"; - 64 = "Trigger Line Ex. (Anywhere in Sector)"; - 80 = "Trigger Line Ex. (Floor Touch)"; - 96 = "Trigger Line Ex. (Emerald Check)"; - 112 = "Trigger Line Ex. (NiGHTS Mare)"; - 128 = "Check for Linedef Executor on FOFs"; - 144 = "Egg Capsule"; - 160 = "Special Stage Time/Rings Parameters"; - 176 = "Custom Global Gravity"; - } - - third - { - 0 = "Normal"; - 512 = "Wind/Current"; - 1024 = "Conveyor Belt"; - 1280 = "Speed Pad"; - } - - fourth - { - 0 = "Normal"; - 4096 = "Star Post Activator"; - 8192 = "Exit/Special Stage Pit/Return Flag"; - 12288 = "CTF Red Team Base"; - 16384 = "CTF Blue Team Base"; - 20480 = "Fan Sector"; - 24576 = "Super Sonic Transform"; - 28672 = "Force Spin"; - 32768 = "Zoom Tube Start"; - 36864 = "Zoom Tube End"; - 40960 = "Circuit Finish Line"; - 45056 = "Rope Hang"; - 49152 = "Intangible to the Camera"; - } -} \ No newline at end of file diff --git a/extras/conf/Includes/SRB222_things.cfg b/extras/conf/Includes/SRB222_things.cfg deleted file mode 100644 index 194e43630..000000000 --- a/extras/conf/Includes/SRB222_things.cfg +++ /dev/null @@ -1,3398 +0,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 - -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 = "Lance-a-Bot"; - sprite = "CBFSA1"; - width = 32; - height = 72; - } - 1113 - { - title = "Suspicious Lance-a-Bot 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 = "MNUSA0"; - 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"; - } - 137 - { - title = "Dragonbomber"; - sprite = "DRABA1"; - width = 28; - height = 48; - } - 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 = "Buggle"; - 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; - flags1text = "[1] No origin-fling death"; - 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 = 0; - height = 0; - sprite = "UNKNA0"; - sort = 1; - fixedsize = true; - blocking = 0; - - 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; - flags1text = "[1] Solid gold"; - 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 = "Lance-a-Bot 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 = "Glaregoyle"; - sprite = "BGARA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1501 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Up)"; - sprite = "BGARA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1502 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Down)"; - sprite = "BGARA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1503 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Long)"; - sprite = "BGARA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1504 - { - title = "ATZ Target"; - sprite = "RCRYB0"; - width = 24; - height = 32; - } - 1505 - { - title = "Green Flame"; - sprite = "CFLMA0E0"; - width = 8; - height = 32; - } - 1506 - { - arrow = 1; - blocking = 2; - title = "Blue Gargoyle"; - sprite = "BGARD1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } -} - -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"; - } -} \ No newline at end of file diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index ec318321d..a0d40cdf0 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -15,7 +15,7 @@ * Oogaland * Rob * Shadow Hog - * Spherallic + * sphere * SRB2-Playah * SSNTails * SteelT @@ -435,7 +435,7 @@ sectortypes 112 = "Trigger Line Ex. (NiGHTS Mare)"; 128 = "Check for Linedef Executor on FOFs"; 144 = "Egg Capsule"; - 160 = "Special Stage Time/Rings Parameters"; + 160 = "Special Stage Time/Spheres Parameters"; 176 = "Custom Global Gravity"; 512 = "Wind/Current"; 1024 = "Conveyor Belt"; @@ -490,7 +490,7 @@ gen_sectortypes 112 = "Trigger Line Ex. (NiGHTS Mare)"; 128 = "Check for Linedef Executor on FOFs"; 144 = "Egg Capsule"; - 160 = "Special Stage Time/Rings Parameters"; + 160 = "Special Stage Time/Spheres Parameters"; 176 = "Custom Global Gravity"; } @@ -738,12 +738,6 @@ linedeftypes flags2text = "[1] Use control sector tag"; flags64text = "[6] No sound effect"; } - - 65 - { - title = "Bridge Thinker "; - prefix = "(65)"; - } } polyobject @@ -756,20 +750,17 @@ linedeftypes prefix = "(20)"; } - 21 - { - title = "Explicitly Include Line "; - prefix = "(21)"; - } - 22 { title = "Parameters"; prefix = "(22)"; + flags8text = "[3] Set translucency by X offset"; + flags32text = "[5] Render outer sides only"; flags64text = "[6] Trigger linedef executor"; flags128text = "[7] Intangible"; flags256text = "[8] Stopped by pushables"; flags512text = "[9] Render flats"; + flags8192text = "[13] Cut cyan flat pixels"; } 30 @@ -788,7 +779,6 @@ linedeftypes { 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"; } @@ -925,6 +915,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Render insides"; flags128text = "[7] Only block non-players"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "195F"; flags643dfloorflagsadd = "7C80"; @@ -984,6 +975,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Don't cast shadow"; flags128text = "[7] Render insides/block non-plr"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "200191F"; flags1283dfloorflagsadd = "7C80"; @@ -997,6 +989,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Don't cast shadow"; flags128text = "[7] Render insides/block non-plr"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "2001917"; flags1283dfloorflagsadd = "7C80"; @@ -1024,6 +1017,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Don't cast shadow"; flags128text = "[7] Render insides/block non-plr"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "400191F"; flags1283dfloorflagsadd = "7C80"; @@ -1037,6 +1031,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Don't cast shadow"; flags128text = "[7] Render insides/block non-plr"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "4001917"; flags1283dfloorflagsadd = "7C80"; @@ -1082,6 +1077,7 @@ linedeftypes flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; flags1024text = "[10] Ripple effect"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "9F39"; flags643dfloorflagsadd = "20000"; @@ -1110,6 +1106,7 @@ linedeftypes flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; flags1024text = "[10] Ripple effect"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "1F31"; flags643dfloorflagsadd = "20000"; @@ -1125,6 +1122,7 @@ linedeftypes flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; flags1024text = "[10] Ripple effect"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "209F39"; flags643dfloorflagsadd = "20000"; @@ -1136,10 +1134,10 @@ linedeftypes { 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"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "201F31"; flags643dfloorflagsadd = "20000"; @@ -1162,6 +1160,7 @@ linedeftypes prefix = "(221)"; flags8text = "[3] Slope skew sides"; flags64text = "[6] Cast shadow"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "1B59"; flags643dfloorflagsremove = "40"; @@ -1227,6 +1226,18 @@ linedeftypes 3dfloorflags = "19F"; } + 153 + { + title = "Dynamically Sinking Platform"; + prefix = "(153)"; + 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"; @@ -1273,6 +1284,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Spindash to move"; flags128text = "[7] Only block non-players"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "195F"; } @@ -1282,7 +1294,6 @@ linedeftypes 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"; @@ -1313,6 +1324,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Spindash, no shadow"; flags128text = "[7] Only block non-players"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "2009D1F"; flags643dfloorflagsadd = "40"; @@ -1379,6 +1391,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Don't cast shadow"; flags128text = "[7] Only block non-players"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "210959F"; flags643dfloorflagsadd = "40"; @@ -1392,6 +1405,7 @@ linedeftypes flags32text = "[5] Only block player"; flags64text = "[6] Don't cast shadow"; flags128text = "[7] Only block non-players"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "218959F"; flags643dfloorflagsadd = "40"; @@ -1488,16 +1502,22 @@ linedeftypes { title = "Mario Block"; prefix = "(250)"; + flags8text = "[3] Slope skew sides"; flags32text = "[5] Invisible block"; flags64text = "[6] Brick block"; 3dfloor = true; 3dfloorflags = "40019F"; + flags323dfloorflagsremove = "19E"; + flags643dfloorflagsadd = "200000"; } 251 { title = "Thwomp Block"; prefix = "(251)"; + flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; + flags128text = "[7] Only block non-players"; flags512text = "[9] Custom crushing sound"; flags1024text = "[10] Custom speed"; 3dfloor = true; @@ -1513,8 +1533,8 @@ linedeftypes flags512text = "[9] Shattered by pushables"; flags1024text = "[10] Trigger linedef executor"; 3dfloor = true; - 3dfloorflags = "8800019"; - flags643dfloorflagsadd = "200006"; + 3dfloorflags = "880001D"; + flags643dfloorflagsadd = "200002"; } 253 @@ -1524,8 +1544,9 @@ linedeftypes flags8text = "[3] Slope skew sides"; flags512text = "[9] Shattered by pushables"; flags1024text = "[10] Trigger linedef executor"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; - 3dfloorflags = "8801019"; + 3dfloorflags = "880101D"; } 254 @@ -1533,6 +1554,7 @@ linedeftypes title = "Bustable Block"; prefix = "(254)"; flags8text = "[3] Slope skew sides"; + flags32text = "[5] Only block player"; flags64text = "[6] Strong characters only"; flags128text = "[7] Only block non-players"; flags512text = "[9] Shattered by pushables"; @@ -1564,6 +1586,7 @@ linedeftypes flags128text = "[7] Only block non-players"; flags512text = "[9] Shattered by pushables"; flags1024text = "[10] Trigger linedef executor"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "1080101F"; } @@ -1585,6 +1608,7 @@ linedeftypes prefix = "(258)"; flags8text = "[3] Slope skew sides"; flags32text = "[5] Don't damage bosses"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorflags = "959"; } @@ -1593,10 +1617,12 @@ linedeftypes { title = "Custom FOF"; prefix = "(259)"; + 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"; + flags8192text = "[13] Cut cyan flat pixels"; 3dfloor = true; 3dfloorcustom = true; } @@ -1896,6 +1922,27 @@ linedeftypes prefix = "(333)"; } + 334 + { + title = "Object Dye - Continuous"; + flags64text = "[6] Disable for this color"; + prefix = "(334)"; + } + + 335 + { + title = "Object Dye - Each Time"; + flags64text = "[6] Disable for this color"; + prefix = "(335)"; + } + + 336 + { + title = "Object Dye - Once"; + flags64text = "[6] Disable for this color"; + prefix = "(336)"; + } + 399 { title = "Level Load"; @@ -2161,6 +2208,14 @@ linedeftypes flags8text = "[3] Set delay by backside sector"; } + 449 + { + title = "Enable Bosses with Parameter"; + prefix = "(449)"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Disable bosses"; + } + 457 { title = "Track Object's Angle"; @@ -2180,12 +2235,15 @@ linedeftypes { title = "Award Rings"; prefix = "(460)"; + flags8text = "[3] Set delay by backside sector"; } 461 { title = "Spawn Object"; prefix = "(461)"; + flags8text = "[3] Set delay by backside sector"; + flags32text = "[5] Use line angle for object"; flags64text = "[6] Spawn inside a range"; } @@ -2193,6 +2251,20 @@ linedeftypes { title = "Stop Timer/Exit Stage in Record Attack"; prefix = "(462)"; + flags8text = "[3] Set delay by backside sector"; + } + + 463 + { + title = "Dye Object"; + prefix = "(463)"; + } + + 464 + { + title = "Trigger Egg Capsule"; + prefix = "(464)"; + flags64text = "[6] Don't end level"; } } @@ -2206,7 +2278,7 @@ linedeftypes prefix = "(413)"; flags2text = "[1] Keep after death"; flags8text = "[3] Set delay by backside sector"; - flags32text = "[5] Seek to current song position"; + flags32text = "[5] Seek from current position"; flags64text = "[6] For everyone"; flags128text = "[7] Fade to custom volume"; flags512text = "[9] Don't loop"; @@ -2220,7 +2292,7 @@ linedeftypes flags2text = "[1] From calling sector"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] From nowhere for triggerer"; - flags512text = "[9] For everyone"; + flags512text = "[9] From nowhere for everyone"; flags1024text = "[10] From tagged sectors"; } @@ -2298,7 +2370,6 @@ linedeftypes flags8text = "[3] Set delay by backside sector"; } - 445 { title = "Make FOF Disappear/Reappear"; @@ -2325,8 +2396,8 @@ linedeftypes 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"; + flags256text = "[8] Set relative to current"; + flags32768text = "[15] Use backside colormap"; } 448 @@ -2359,7 +2430,7 @@ linedeftypes prefix = "(452)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Do not handle FF_TRANS"; - flags256text = "[8] Set relative to current val"; + flags256text = "[8] Set relative to current"; } 453 @@ -2371,7 +2442,7 @@ linedeftypes 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"; + flags256text = "[8] Set relative to current"; flags512text = "[9] Speed = Tic Duration"; flags1024text = "[10] Override existing fade"; flags16384text = "[14] Do not handle collision"; @@ -2395,11 +2466,11 @@ linedeftypes flags32text = "[5] Subtract Red value"; flags64text = "[6] Subtract Green value"; flags128text = "[7] Subtract Blue value"; - flags256text = "[8] Calc relative values"; + flags256text = "[8] Set relative to current"; flags512text = "[9] Speed = Tic Duration"; flags1024text = "[10] Override existing fade"; flags16384text = "[14] Fade from invisible black"; - flags32768text = "[15] Use back side colormap"; + flags32768text = "[15] Use backside colormap"; } 456 @@ -2416,9 +2487,7 @@ linedeftypes 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"; + flags128text = "[7] Don't disable controls"; flags32768text = "[15] Find prompt by name"; } } @@ -2524,7 +2593,7 @@ linedeftypes prefix = "(491)"; flags8text = "[3] Set delay by backside sector"; flags16text = "[4] Set raw alpha by Front X"; - flags256text = "[8] Calc relative values"; + flags256text = "[8] Set relative to current"; } 492 @@ -2534,7 +2603,7 @@ linedeftypes 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"; + flags256text = "[8] Set relative to current"; flags512text = "[9] Speed = Tic Duration"; flags1024text = "[10] Override existing fade"; flags16384text = "[14] Do not handle collision"; @@ -2547,45 +2616,63 @@ linedeftypes 500 { - title = "Scroll Wall Front Side Left"; + title = "Scroll Front Wall Left"; prefix = "(500)"; } 501 { - title = "Scroll Wall Front Side Right"; + title = "Scroll Front Wall Right"; prefix = "(501)"; } 502 { - title = "Scroll Wall According to Linedef"; + title = "Scroll Tagged Wall"; prefix = "(502)"; + flags128text = "[7] Use texture offsets"; + flags256text = "[8] Scroll back side"; } 503 { - title = "Scroll Wall According to Linedef (Accelerative)"; + title = "Scroll Tagged Wall (Accelerative)"; prefix = "(503)"; + flags128text = "[7] Use texture offsets"; + flags256text = "[8] Scroll back side"; } 504 { - title = "Scroll Wall According to Linedef (Displacement)"; + title = "Scroll Tagged Wall (Displacement)"; prefix = "(504)"; + flags128text = "[7] Use texture offsets"; + flags256text = "[8] Scroll back side"; } 505 { - title = "Scroll Texture by Front Side Offsets"; + title = "Scroll Front Wall by Front Side Offsets"; prefix = "(505)"; } 506 { - title = "Scroll Texture by Back Side Offsets"; + title = "Scroll Front Wall by Back Side Offsets"; prefix = "(506)"; } + + 507 + { + title = "Scroll Back Wall by Front Side Offsets"; + prefix = "(507)"; + } + + 508 + { + title = "Scroll Back Wall by Back Side Offsets"; + prefix = "(508)"; + } } planescroll @@ -2632,76 +2719,84 @@ linedeftypes { title = "Carry Objects on Floor"; prefix = "(520)"; + flags64text = "[6] Exclusive"; } 521 { title = "Carry Objects on Floor (Accelerative)"; prefix = "(521)"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 522 { title = "Carry Objects on Floor (Displacement)"; prefix = "(522)"; + flags64text = "[6] Exclusive"; } 523 { title = "Carry Objects on Ceiling"; prefix = "(523)"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 524 { title = "Carry Objects on Ceiling (Accelerative)"; prefix = "(524)"; + flags64text = "[6] Exclusive"; } 525 { title = "Carry Objects on Ceiling (Displacement)"; prefix = "(525)"; + flags64text = "[6] Exclusive"; } 530 { title = "Scroll Floor Texture and Carry Objects"; prefix = "(530)"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 531 { title = "Scroll Floor Texture and Carry Objects (Accelerative)"; prefix = "(531)"; + flags64text = "[6] Exclusive"; } 532 { title = "Scroll Floor Texture and Carry Objects (Displacement)"; prefix = "(532)"; + flags64text = "[6] Exclusive"; } 533 { title = "Scroll Ceiling Texture and Carry Objects"; prefix = "(533)"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 534 { title = "Scroll Ceiling Texture and Carry Objects (Accelerative)"; prefix = "(534)"; + flags64text = "[6] Exclusive"; } 535 { title = "Scroll Ceiling Texture and Carry Objects (Displacement)"; prefix = "(535)"; + flags64text = "[6] Exclusive"; } } @@ -2714,7 +2809,7 @@ linedeftypes title = "Wind"; prefix = "(541)"; flags512text = "[9] Player slides"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 542 @@ -2722,7 +2817,7 @@ linedeftypes title = "Upwards Wind"; prefix = "(542)"; flags512text = "[9] Player slides"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 543 @@ -2730,7 +2825,7 @@ linedeftypes title = "Downwards Wind"; prefix = "(543)"; flags512text = "[9] Player slides"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 544 @@ -2738,7 +2833,7 @@ linedeftypes title = "Current"; prefix = "(544)"; flags512text = "[9] Player slides"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 545 @@ -2746,7 +2841,7 @@ linedeftypes title = "Upwards Current"; prefix = "(545)"; flags512text = "[9] Player slides"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 546 @@ -2754,13 +2849,14 @@ linedeftypes title = "Downwards Current"; prefix = "(546)"; flags512text = "[9] Player slides"; - flags64text = "[6] Even across edges"; + flags64text = "[6] Exclusive"; } 547 { title = "Push/Pull"; prefix = "(547)"; + flags64text = "[6] Exclusive"; } } @@ -3407,8 +3503,8 @@ thingtypes sprite = "ESHIA1"; width = 16; height = 48; - flags1text = "[1] 90 degrees counter-clockwise"; - flags4text = "[4] 90 degrees clockwise"; + flags1text = "[1] 90 degrees clockwise"; + flags4text = "[4] 90 degrees counter-clockwise"; flags8text = "[8] Double speed"; } 115 @@ -3674,6 +3770,7 @@ thingtypes width = 8; height = 16; sprite = "internal:capsule"; + angletext = "Tag"; } 292 { @@ -3870,6 +3967,8 @@ thingtypes { title = "Emerald Hunt Location"; sprite = "SHRDA0"; + flags8height = 24; + flags8text = "[8] Float"; } 321 { @@ -3897,9 +3996,10 @@ thingtypes title = "Monitors"; width = 18; height = 40; - flags1text = "[1] Run Linedef Executor on pop"; + flags1text = "[1] Run linedef executor on pop"; flags4text = "[4] Random (Strong)"; flags8text = "[8] Random (Weak)"; + angletext = "Tag"; 400 { @@ -4029,7 +4129,8 @@ thingtypes title = "Monitors (Respawning)"; width = 20; height = 44; - flags1text = "[1] Run Linedef Executor on pop"; + flags1text = "[1] Run linedef executor on pop"; + angletext = "Tag"; 431 { @@ -4125,7 +4226,9 @@ thingtypes sprite = "STPTA0M0"; width = 64; height = 128; + flags4text = "[4] Respawn at center"; angletext = "Angle/Order"; + parametertext = "Order"; } 520 { @@ -4152,6 +4255,7 @@ thingtypes sprite = "WSPKALAR"; width = 16; height = 14; + arrow = 1; flags1text = "[1] Start retracted"; flags4text = "[4] Retractable"; flags8text = "[8] Intangible"; @@ -4558,6 +4662,7 @@ thingtypes sprite = "TOADA0"; width = 32; height = 16; + angletext = "Tag"; } 757 { @@ -5832,7 +5937,7 @@ thingtypes sprite = "CAPSA0"; width = 72; height = 144; - angletext = "Rings"; + angletext = "Spheres"; parametertext = "Mare"; } } @@ -6273,7 +6378,7 @@ thingtypes sprite = "PUMKA0"; width = 16; height = 40; - flags1text = "Don't flicker"; + flags1text = "[1] Don't flicker"; } 2007 { @@ -6281,7 +6386,7 @@ thingtypes sprite = "PUMKB0"; width = 16; height = 40; - flags1text = "Don't flicker"; + flags1text = "[1] Don't flicker"; } 2008 { @@ -6289,7 +6394,7 @@ thingtypes sprite = "PUMKC0"; width = 16; height = 40; - flags1text = "Don't flicker"; + flags1text = "[1] Don't flicker"; } 2009 { diff --git a/extras/conf/SRB2_22Doom.cfg b/extras/conf/SRB2_22Doom.cfg deleted file mode 100644 index 65e49d387..000000000 --- a/extras/conf/SRB2_22Doom.cfg +++ /dev/null @@ -1,38 +0,0 @@ -/************************************************************************\ - Zone Builder Game Configuration for Sonic Robo Blast 2 Version 2.2 -\************************************************************************/ - -// This is required to prevent accidental use of a different configuration -type = "Doom Builder 2 Game Configuration"; - -// This is the title to show for this game -game = "Sonic Robo Blast 2 - 2.2 (Doom format)"; - -// This is the simplified game engine/sourceport name -engine = "zdoom"; - -// Settings common to all games and all map formats -include("Includes\\SRB222_common.cfg", "common"); - -// Settings common to Doom map format -include("Includes\\SRB222_common.cfg", "mapformat_doom"); - -include("Includes\\Game_SRB222.cfg"); - -// Script lumps detection -scriptlumpnames -{ - include("Includes\\SRB222_misc.cfg", "scriptlumpnames"); -} - -// THING TYPES -thingtypes -{ - include("Includes\\SRB222_things.cfg"); -} - -//Default things filters -thingsfilters -{ - include("Includes\\SRB222_misc.cfg", "thingsfilters"); -} \ No newline at end of file diff --git a/extras/conf/SRB2_22UDMF.cfg b/extras/conf/SRB2_22UDMF.cfg deleted file mode 100644 index 52104ed09..000000000 --- a/extras/conf/SRB2_22UDMF.cfg +++ /dev/null @@ -1,47 +0,0 @@ -/************************************************************************\ - Zone Builder Game Configuration for Sonic Robo Blast 2 Version 2.2 -\************************************************************************/ - -// This is required to prevent accidental use of a different configuration -type = "Doom Builder 2 Game Configuration"; - -// This is the title to show for this game -game = "Sonic Robo Blast 2 - 2.2 (UDMF)"; - -// This is the simplified game engine/sourceport name -engine = "zdoom"; - -// Settings common to all games and all map formats -include("Includes\\SRB222_common.cfg", "common"); - -// Settings common to Doom map format -include("Includes\\SRB222_common.cfg", "mapformat_udmf"); - -include("Includes\\Game_SRB222.cfg"); - -// Script lumps detection -scriptlumpnames -{ - include("Includes\\SRB222_misc.cfg", "scriptlumpnames"); -} - -// THING TYPES -thingtypes -{ - include("Includes\\SRB222_things.cfg"); -} - -//Default things filters -thingsfilters -{ - include("Includes\\SRB222_misc.cfg", "thingsfilters"); -} - -// ENUMERATIONS -// Each engine has its own additional thing types -// These are enumerated lists for linedef types and UDMF fields. -enums -{ - // Basic game enums - include("Includes\\SRB222_misc.cfg", "enums"); -} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8c9c3182..7a3f0564d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,7 @@ set(SRB2_CORE_SOURCES f_finale.c f_wipe.c filesrch.c + g_demo.c g_game.c g_input.c hu_stuff.c @@ -71,6 +72,7 @@ set(SRB2_CORE_HEADERS f_finale.h fastcmp.h filesrch.h + g_demo.h g_game.h g_input.h g_state.h @@ -120,6 +122,7 @@ set(SRB2_CORE_RENDER_SOURCES r_main.c r_plane.c r_segs.c + r_skins.c r_sky.c r_splats.c r_things.c @@ -134,6 +137,7 @@ set(SRB2_CORE_RENDER_SOURCES r_main.h r_plane.h r_segs.h + r_skins.h r_sky.h r_splats.h r_state.h @@ -214,8 +218,6 @@ source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES}) ### Configuration -set(SRB2_CONFIG_HAVE_BLUA ON CACHE BOOL - "Enable Lua interpreter support") set(SRB2_CONFIG_HAVE_PNG ON CACHE BOOL "Enable PNG support. Depends on zlib, so will be disabled if you don't enable that too.") set(SRB2_CONFIG_HAVE_ZLIB ON CACHE BOOL @@ -239,92 +241,90 @@ if(${CMAKE_SYSTEM} MATCHES "Windows") ###set on Windows only "Use SRB2's internal copies of required dependencies (SDL2, PNG, zlib, GME, OpenMPT).") endif() -if(${SRB2_CONFIG_HAVE_BLUA}) - add_definitions(-DHAVE_BLUA) - set(SRB2_LUA_SOURCES - lua_baselib.c - lua_blockmaplib.c - lua_consolelib.c - lua_hooklib.c - lua_hudlib.c - lua_infolib.c - lua_maplib.c - lua_mathlib.c - lua_mobjlib.c - lua_playerlib.c - lua_script.c - lua_skinlib.c - lua_thinkerlib.c - ) - set(SRB2_LUA_HEADERS - lua_hook.h - lua_hud.h - lua_libs.h - lua_script.h - ) +set(SRB2_LUA_SOURCES + lua_baselib.c + lua_blockmaplib.c + lua_consolelib.c + lua_hooklib.c + lua_hudlib.c + lua_infolib.c + lua_maplib.c + lua_mathlib.c + lua_mobjlib.c + lua_playerlib.c + lua_script.c + lua_skinlib.c + lua_thinkerlib.c +) +set(SRB2_LUA_HEADERS + lua_hook.h + lua_hud.h + lua_libs.h + lua_script.h +) - prepend_sources(SRB2_LUA_SOURCES) - prepend_sources(SRB2_LUA_HEADERS) +prepend_sources(SRB2_LUA_SOURCES) +prepend_sources(SRB2_LUA_HEADERS) - source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS}) +source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS}) - set(SRB2_BLUA_SOURCES - blua/lapi.c - blua/lauxlib.c - blua/lbaselib.c - blua/lcode.c - blua/ldebug.c - blua/ldo.c - blua/ldump.c - blua/lfunc.c - blua/lgc.c - blua/linit.c - blua/llex.c - blua/lmem.c - blua/lobject.c - blua/lopcodes.c - blua/lparser.c - blua/lstate.c - blua/lstring.c - blua/lstrlib.c - blua/ltable.c - blua/ltablib.c - blua/ltm.c - blua/lundump.c - blua/lvm.c - blua/lzio.c - ) - set(SRB2_BLUA_HEADERS - blua/lapi.h - blua/lauxlib.h - blua/lcode.h - blua/ldebug.h - blua/ldo.h - blua/lfunc.h - blua/lgc.h - blua/llex.h - blua/llimits.h - blua/lmem.h - blua/lobject.h - blua/lopcodes.h - blua/lparser.h - blua/lstate.h - blua/lstring.h - blua/ltable.h - blua/ltm.h - blua/lua.h - blua/luaconf.h - blua/lualib.h - blua/lundump.h - blua/lvm.h - blua/lzio.h - ) +set(SRB2_BLUA_SOURCES + blua/lapi.c + blua/lauxlib.c + blua/lbaselib.c + blua/lcode.c + blua/ldebug.c + blua/ldo.c + blua/ldump.c + blua/lfunc.c + blua/lgc.c + blua/linit.c + blua/liolib.c + blua/llex.c + blua/lmem.c + blua/lobject.c + blua/lopcodes.c + blua/lparser.c + blua/lstate.c + blua/lstring.c + blua/lstrlib.c + blua/ltable.c + blua/ltablib.c + blua/ltm.c + blua/lundump.c + blua/lvm.c + blua/lzio.c +) +set(SRB2_BLUA_HEADERS + blua/lapi.h + blua/lauxlib.h + blua/lcode.h + blua/ldebug.h + blua/ldo.h + blua/lfunc.h + blua/lgc.h + blua/llex.h + blua/llimits.h + blua/lmem.h + blua/lobject.h + blua/lopcodes.h + blua/lparser.h + blua/lstate.h + blua/lstring.h + blua/ltable.h + blua/ltm.h + blua/lua.h + blua/luaconf.h + blua/lualib.h + blua/lundump.h + blua/lvm.h + blua/lzio.h +) - prepend_sources(SRB2_BLUA_SOURCES) - prepend_sources(SRB2_BLUA_HEADERS) +prepend_sources(SRB2_BLUA_SOURCES) +prepend_sources(SRB2_BLUA_HEADERS) - source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS}) -endif() +source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS}) if(${SRB2_CONFIG_HAVE_GME}) if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES}) @@ -418,6 +418,7 @@ endif() if(${SRB2_CONFIG_HWRENDER}) add_definitions(-DHWRENDER) set(SRB2_HWRENDER_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_bsp.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.c @@ -433,6 +434,7 @@ if(${SRB2_CONFIG_HWRENDER}) ) set (SRB2_HWRENDER_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_data.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_defs.h diff --git a/src/Makefile b/src/Makefile index c30c236de..e00c84bc9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,7 @@ # GNU Make makefile for SRB2 ############################################################################# # Copyright (C) 1998-2000 by DooM Legacy Team. -# Copyright (C) 2003-2019 by Sonic Team Junior. +# Copyright (C) 2003-2020 by Sonic Team Junior. # # This program is free software distributed under the # terms of the GNU General Public License, version 2. @@ -222,12 +222,10 @@ endif ifdef NOHW OPTS+=-DNOHW else - #Hurdler: not really supported and not tested recently - #OPTS+=-DUSE_PALETTED_TEXTURE OPTS+=-DHWRENDER OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o \ - $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o + $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o endif ifdef NOHS @@ -340,9 +338,7 @@ CFLAGS+=-DHAVE_MINIUPNPC endif endif -ifndef NO_LUA - include blua/Makefile.cfg -endif +include blua/Makefile.cfg ifdef NOMD5 OPTS+=-DNOMD5 @@ -424,6 +420,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/z_zone.o \ $(OBJDIR)/f_finale.o \ $(OBJDIR)/f_wipe.o \ + $(OBJDIR)/g_demo.o \ $(OBJDIR)/g_game.o \ $(OBJDIR)/g_input.o \ $(OBJDIR)/am_map.o \ @@ -468,6 +465,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_main.o \ $(OBJDIR)/r_plane.o \ $(OBJDIR)/r_segs.o \ + $(OBJDIR)/r_skins.o \ $(OBJDIR)/r_sky.o \ $(OBJDIR)/r_splats.o \ $(OBJDIR)/r_things.o \ @@ -682,9 +680,7 @@ $(OBJDIR)/depend.dep: ifndef NOHW $(CC) $(CFLAGS) -MM hardware/*.c >> $(OBJDIR)/depend.ped endif -ifndef NO_LUA $(CC) $(CFLAGS) -MM blua/*.c >> $(OBJDIR)/depend.ped -endif @sed -e 's,\(.*\)\.o: ,$(subst /,\/,$(OBJDIR))\/&,g' < $(OBJDIR)/depend.ped > $(OBJDIR)/depend.dep $(REMOVE) $(OBJDIR)/depend.ped @echo "Created dependency file, depend.dep" diff --git a/src/am_map.c b/src/am_map.c index b2c7de442..53a7480a5 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -920,10 +920,8 @@ static inline void AM_drawWalls(void) { size_t i; static mline_t l; -#ifdef ESLOPE fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends fixed_t backf1 = 0, backf2 = 0, backc1 = 0, backc2 = 0; // back floor ceiling ends -#endif for (i = 0; i < numlines; i++) { @@ -931,13 +929,10 @@ static inline void AM_drawWalls(void) l.a.y = lines[i].v1->y >> FRACTOMAPBITS; l.b.x = lines[i].v2->x >> FRACTOMAPBITS; l.b.y = lines[i].v2->y >> FRACTOMAPBITS; -#ifdef ESLOPE + #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, lines[i].v1->x, lines[i].v1->y); \ - end2 = P_GetZAt(slope, lines[i].v2->x, lines[i].v2->y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, lines[i].v1->x, lines[i].v1->y, normalheight); \ + end2 = P_GetZAt(slope, lines[i].v2->x, lines[i].v2->y, normalheight); SLOPEPARAMS(lines[i].frontsector->f_slope, frontf1, frontf2, lines[i].frontsector->floorheight) SLOPEPARAMS(lines[i].frontsector->c_slope, frontc1, frontc2, lines[i].frontsector->ceilingheight) @@ -946,7 +941,6 @@ static inline void AM_drawWalls(void) SLOPEPARAMS(lines[i].backsector->c_slope, backc1, backc2, lines[i].backsector->ceilingheight) } #undef SLOPEPARAMS -#endif if (!lines[i].backsector) // 1-sided { @@ -955,19 +949,11 @@ static inline void AM_drawWalls(void) else AM_drawMline(&l, WALLCOLORS); } -#ifdef ESLOPE else if ((backf1 == backc1 && backf2 == backc2) // Back is thok barrier || (frontf1 == frontc1 && frontf2 == frontc2)) // Front is thok barrier { if (backf1 == backc1 && backf2 == backc2 && frontf1 == frontc1 && frontf2 == frontc2) // BOTH are thok barriers -#else - else if (lines[i].backsector->floorheight == lines[i].backsector->ceilingheight // Back is thok barrier - || lines[i].frontsector->floorheight == lines[i].frontsector->ceilingheight) // Front is thok barrier - { - if (lines[i].backsector->floorheight == lines[i].backsector->ceilingheight - && lines[i].frontsector->floorheight == lines[i].frontsector->ceilingheight) // BOTH are thok barriers -#endif { if (lines[i].flags & ML_NOCLIMB) AM_drawMline(&l, NOCLIMBTSWALLCOLORS); @@ -985,20 +971,10 @@ static inline void AM_drawWalls(void) else { if (lines[i].flags & ML_NOCLIMB) { -#ifdef ESLOPE if (backf1 != frontf1 || backf2 != frontf2) { -#else - if (lines[i].backsector->floorheight - != lines[i].frontsector->floorheight) { -#endif AM_drawMline(&l, NOCLIMBFDWALLCOLORS); // floor level change } -#ifdef ESLOPE else if (backc1 != frontc1 || backc2 != frontc2) { -#else - else if (lines[i].backsector->ceilingheight - != lines[i].frontsector->ceilingheight) { -#endif AM_drawMline(&l, NOCLIMBCDWALLCOLORS); // ceiling level change } else @@ -1006,20 +982,10 @@ static inline void AM_drawWalls(void) } else { -#ifdef ESLOPE if (backf1 != frontf1 || backf2 != frontf2) { -#else - if (lines[i].backsector->floorheight - != lines[i].frontsector->floorheight) { -#endif AM_drawMline(&l, FDWALLCOLORS); // floor level change } -#ifdef ESLOPE else if (backc1 != frontc1 || backc2 != frontc2) { -#else - else if (lines[i].backsector->ceilingheight - != lines[i].frontsector->ceilingheight) { -#endif AM_drawMline(&l, CDWALLCOLORS); // ceiling level change } else diff --git a/src/am_map.h b/src/am_map.h index 0560207bb..1c8fa70e4 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/android/i_video.c b/src/android/i_video.c index b8bb4fefb..1909cd71a 100644 --- a/src/android/i_video.c +++ b/src/android/i_video.c @@ -19,10 +19,10 @@ boolean allow_fullscreen = false; consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; void I_StartupGraphics(void){} -void I_StartupHardwareGraphics(void){} - void I_ShutdownGraphics(void){} +void VID_StartupOpenGL(void){} + void I_SetPalette(RGBA_t *palette) { (void)palette; @@ -52,10 +52,8 @@ INT32 VID_SetMode(INT32 modenum) return 0; } -void VID_CheckRenderer(void) -{ - // .............. -} +void VID_CheckRenderer(void) {} +void VID_CheckGLLoaded(rendermode_t oldrender) {} const char *VID_GetModeName(INT32 modenum) { diff --git a/src/apng.c b/src/apng.c index 694b3d1e8..0abbe541d 100644 --- a/src/apng.c +++ b/src/apng.c @@ -1,5 +1,5 @@ /* -Copyright 2019, James R. +Copyright 2019-2020, James R. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/apng.h b/src/apng.h index 0f22dca6d..a8b5c8f24 100644 --- a/src/apng.h +++ b/src/apng.h @@ -1,5 +1,5 @@ /* -Copyright 2019, James R. +Copyright 2019-2020, James R. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/asm_defs.inc b/src/asm_defs.inc index 82149f70e..ec286b0bd 100644 --- a/src/asm_defs.inc +++ b/src/asm_defs.inc @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/b_bot.c b/src/b_bot.c index f83aaa34c..4397938c1 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2011-2019 by Sonic Team Junior. +// Copyright (C) 2011-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -74,11 +74,9 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) if (!sonic || sonic->health <= 0) return; -#ifdef HAVE_BLUA // Lua can handle it! if (LUAh_BotAI(sonic, tails, cmd)) return; -#endif if (tails->player->powers[pw_carry] == CR_MACESPIN || tails->player->powers[pw_carry] == CR_GENERIC) { @@ -364,11 +362,9 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) // Bot AI isn't programmed in analog. CV_SetValue(&cv_analog[1], false); -#ifdef HAVE_BLUA // Let Lua scripts build ticcmds if (LUAh_BotTiccmd(player, cmd)) return; -#endif // We don't have any main character AI, sorry. D: if (player-players == consoleplayer) @@ -463,6 +459,19 @@ boolean B_CheckRespawn(player_t *player) if (!sonic || sonic->health <= 0) return false; + // B_RespawnBot doesn't do anything if the condition above this isn't met + { + UINT8 shouldForce = LUAh_BotRespawn(sonic, tails); + + if (P_MobjWasRemoved(sonic) || P_MobjWasRemoved(tails)) + return (shouldForce == 1); // mobj was removed + + if (shouldForce == 1) + return true; + else if (shouldForce == 2) + return false; + } + // Check if Sonic is busy first. // If he's doing any of these things, he probably doesn't want to see us. if (sonic->player->pflags & (PF_GLIDING|PF_SLIDING|PF_BOUNCING) diff --git a/src/b_bot.h b/src/b_bot.h index 54ef300a3..2806bd68f 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/blua/Makefile.cfg b/src/blua/Makefile.cfg index 8d2e73714..12ea064b4 100644 --- a/src/blua/Makefile.cfg +++ b/src/blua/Makefile.cfg @@ -10,14 +10,13 @@ WFLAGS+=-Wno-logical-op endif endif -OPTS+=-DHAVE_BLUA - OBJS:=$(OBJS) \ $(OBJDIR)/lapi.o \ $(OBJDIR)/lbaselib.o \ $(OBJDIR)/ldo.o \ $(OBJDIR)/lfunc.o \ $(OBJDIR)/linit.o \ + $(OBJDIR)/liolib.o \ $(OBJDIR)/llex.o \ $(OBJDIR)/lmem.o \ $(OBJDIR)/lobject.o \ diff --git a/src/blua/lbaselib.c b/src/blua/lbaselib.c index 3c919cb64..644565c28 100644 --- a/src/blua/lbaselib.c +++ b/src/blua/lbaselib.c @@ -11,6 +11,10 @@ #include #include +#include "../doomdef.h" +#include "../lua_script.h" +#include "../w_wad.h" + #define lbaselib_c #define LUA_LIB @@ -263,6 +267,27 @@ static int luaB_ipairs (lua_State *L) { } +// Edited to load PK3 entries instead +static int luaB_dofile (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + char fullfilename[256]; + UINT16 lumpnum; + int n = lua_gettop(L); + + if (wadfiles[numwadfiles - 1]->type != RET_PK3) + luaL_error(L, "dofile() only works with PK3 files"); + + snprintf(fullfilename, sizeof(fullfilename), "Lua/%s", filename); + lumpnum = W_CheckNumForFullNamePK3(fullfilename, numwadfiles - 1, 0); + if (lumpnum == INT16_MAX) + luaL_error(L, "can't find script " LUA_QS, fullfilename); + + LUA_LoadLump(numwadfiles - 1, lumpnum, false); + + return lua_gettop(L) - n; +} + + static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) @@ -380,6 +405,7 @@ static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"error", luaB_error}, + {"dofile", luaB_dofile}, {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, {"getmetatable", luaB_getmetatable}, diff --git a/src/blua/linit.c b/src/blua/linit.c index 52b02dbe7..d17390b20 100644 --- a/src/blua/linit.c +++ b/src/blua/linit.c @@ -17,6 +17,7 @@ static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, {LUA_STRLIBNAME, luaopen_string}, {NULL, NULL} }; diff --git a/src/blua/liolib.c b/src/blua/liolib.c new file mode 100644 index 000000000..a055aad3f --- /dev/null +++ b/src/blua/liolib.c @@ -0,0 +1,640 @@ +/* +** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define liolib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" +#include "../i_system.h" +#include "../g_game.h" +#include "../d_netfil.h" +#include "../lua_libs.h" +#include "../byteptr.h" +#include "../lua_script.h" +#include "../m_misc.h" + + +#define IO_INPUT 1 +#define IO_OUTPUT 2 + +#define FILELIMIT (1024 * 1024) // Size limit for reading/writing files + +#define FMT_FILECALLBACKID "file_callback_%d" + + +// Allow scripters to write files of these types to SRB2's folder +static const char *whitelist[] = { + ".bmp", + ".cfg", + ".csv", + ".dat", + ".png", + ".sav2", + ".txt", +}; + + +static int pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (filename) + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + else + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + + +static int io_type (lua_State *L) { + void *ud; + luaL_checkany(L, 1); + ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static FILE *tofile (lua_State *L) { + FILE **f = tofilep(L); + if (*f == NULL) + luaL_error(L, "attempt to use a closed file"); + return *f; +} + + + +/* +** When creating file handles, always creates a `closed' file handle +** before opening the actual file; so, if there is a memory error, the +** file is not left opened. +*/ +static FILE **newfile (lua_State *L) { + FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, LUA_FILEHANDLE); + lua_setmetatable(L, -2); + return pf; +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + FILE **p = tofilep(L); + int ok = (fclose(*p) == 0); + *p = NULL; + return pushresult(L, ok, NULL); +} + + +static int aux_close (lua_State *L) { + lua_getfenv(L, 1); + lua_getfield(L, -1, "__close"); + return (lua_tocfunction(L, -1))(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + tofile(L); /* make sure argument is a file */ + return aux_close(L); +} + + +static int io_gc (lua_State *L) { + FILE *f = *tofilep(L); + /* ignore closed files */ + if (f != NULL) + aux_close(L); + return 0; +} + + +static int io_tostring (lua_State *L) { + FILE *f = *tofilep(L); + if (f == NULL) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", f); + return 1; +} + + +// Create directories in the path +void MakePathDirs(char *path) +{ + char *c; + + for (c = path; *c; c++) + if (*c == '/' || *c == '\\') + { + char sep = *c; + *c = '\0'; + I_mkdir(path, 0755); + *c = sep; + } +} + + +static int CheckFileName(lua_State *L, const char *filename) +{ + int length = strlen(filename); + boolean pass = false; + size_t i; + + if (strchr(filename, '\\')) + { + luaL_error(L, "access denied to %s: \\ is not allowed, use / instead", filename); + return pushresult(L,0,filename); + } + + for (i = 0; i < (sizeof (whitelist) / sizeof(const char *)); i++) + if (!stricmp(&filename[length - strlen(whitelist[i])], whitelist[i])) + { + pass = true; + break; + } + if (strstr(filename, "./") + || strstr(filename, "..") || strchr(filename, ':') + || filename[0] == '/' + || !pass) + { + luaL_error(L, "access denied to %s", filename); + return pushresult(L,0,filename); + } + + return 0; +} + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + int checkresult; + + checkresult = CheckFileName(L, filename); + if (checkresult) + return checkresult; + + luaL_checktype(L, 3, LUA_TFUNCTION); + + if (!(strchr(mode, 'r') || strchr(mode, '+'))) + luaL_error(L, "open() is only for reading, use openlocal() for writing"); + + AddLuaFileTransfer(filename, mode); + + return 0; +} + + +static int io_openlocal (lua_State *L) { + FILE **pf; + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + char *realfilename; + luafiletransfer_t *filetransfer; + int checkresult; + + checkresult = CheckFileName(L, filename); + if (checkresult) + return checkresult; + + realfilename = va("%s" PATHSEP "%s", luafiledir, filename); + + if (client && strnicmp(filename, "client/", strlen("client/"))) + I_Error("Access denied to %s\n" + "Clients can only access files stored in luafiles/client/\n", + filename); + + // Prevent access if the file is being downloaded + for (filetransfer = luafiletransfers; filetransfer; filetransfer = filetransfer->next) + if (!stricmp(filetransfer->filename, filename)) + I_Error("Access denied to %s\n" + "Files can't be opened while being downloaded\n", + filename); + + MakePathDirs(realfilename); + + // Open and return the file + pf = newfile(L); + *pf = fopen(realfilename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + +void Got_LuaFile(UINT8 **cp, INT32 playernum) +{ + FILE **pf = NULL; + UINT8 success = READUINT8(*cp); // The first (and only) byte indicates whether the file could be opened + + if (playernum != serverplayer) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal luafile command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL); + return; + } + + if (!luafiletransfers) + I_Error("No Lua file transfer\n"); + + // Retrieve the callback and push it on the stack + lua_pushfstring(gL, FMT_FILECALLBACKID, luafiletransfers->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + + // Push the first argument (file handle or nil) on the stack + if (success) + { + char mode[4]; + + // Ensure we are opening in binary mode + // (if it's a text file, newlines have been converted already) + strcpy(mode, luafiletransfers->mode); + if (!strchr(mode, 'b')) + strcat(mode, "b"); + + pf = newfile(gL); // Create and push the file handle + *pf = fopen(luafiletransfers->realfilename, mode); // Open the file + if (!*pf) + I_Error("Can't open file \"%s\"\n", luafiletransfers->realfilename); // The file SHOULD exist + } + else + lua_pushnil(gL); + + // Push the second argument (file name) on the stack + lua_pushstring(gL, luafiletransfers->filename); + + // Call the callback + LUA_Call(gL, 2); + + if (success) + { + // Close the file + if (*pf) + { + fclose(*pf); + *pf = NULL; + } + + if (client) + remove(luafiletransfers->realfilename); + } + + RemoveLuaFileTransfer(); + + if (waitingforluafilecommand) + { + waitingforluafilecommand = false; + CL_PrepareDownloadLuaFile(); + } + + if (server && luafiletransfers) + SV_PrepareSendLuaFile(); +} + + +void StoreLuaFileCallback(INT32 id) +{ + lua_pushfstring(gL, FMT_FILECALLBACKID, id); + lua_pushvalue(gL, 3); // Parameter 3 is the callback + lua_settable(gL, LUA_REGISTRYINDEX); // registry[callbackid] = callback +} + + +void RemoveLuaFileCallback(INT32 id) +{ + lua_pushfstring(gL, FMT_FILECALLBACKID, id); + lua_pushnil(gL); + lua_settable(gL, LUA_REGISTRYINDEX); // registry[callbackid] = nil +} + + +static int io_tmpfile (lua_State *L) { + FILE **pf = newfile(L); + *pf = tmpfile(); + return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; +} + + +static int io_readline (lua_State *L); + + +static void aux_lines (lua_State *L, int idx, int toclose) { + lua_pushvalue(L, idx); + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 2); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 1, 0); + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +static int read_number (lua_State *L, FILE *f) { + lua_Number d; + if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { + lua_pushnumber(L, d); + return 1; + } + else return 0; /* read fails */ +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); + lua_pushlstring(L, NULL, 0); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f) { + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + size_t l; + char *p = luaL_prepbuffer(&b); + if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_objlen(L, -1) > 0); /* check whether read something */ + } + l = strlen(p); + if (l == 0 || p[l-1] != '\n') + luaL_addsize(&b, l); + else { + luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_pushresult(&b); /* close buffer */ + return 1; /* read at least an `eol' */ + } + } +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t rlen; /* how much to read */ + size_t nr; /* number of chars actually read */ + luaL_Buffer b; + luaL_buffinit(L, &b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + do { + char *p = luaL_prepbuffer(&b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(&b); /* close buffer */ + return (n == 0 || lua_objlen(L, -1) > 0); +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)lua_tointeger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = lua_tostring(L, n); + luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); + switch (p[1]) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return pushresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +static int io_readline (lua_State *L) { + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); + int sucess; + if (f == NULL) /* file is already closed? */ + luaL_error(L, "file is already closed"); + sucess = read_line(L, f); + if (ferror(f)) + return luaL_error(L, "%s", strerror(errno)); + if (sucess) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - 1; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = status && + fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + if (ftell(f) + l > FILELIMIT) { + luaL_error(L,"write limit bypassed in file. Changes have been discarded."); + break; + } + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + return pushresult(L, status, NULL); +} + + +static int f_write (lua_State *L) { + return g_write(L, tofile(L), 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + long offset = luaL_optlong(L, 3, 0); + op = fseek(f, offset, mode[op]); + if (op) + return pushresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], sz); + return pushresult(L, res == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return pushresult(L, fflush(tofile(L)) == 0, NULL); +} + + +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"open", io_open}, + {"openlocal", io_openlocal}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {NULL, NULL} +}; + + +static const luaL_Reg flib[] = { + {"close", io_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", io_gc}, + {"__tostring", io_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, flib); /* file methods */ +} + + +static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { + *newfile(L) = f; + if (k > 0) { + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_ENVIRONINDEX, k); + } + lua_pushvalue(L, -2); /* copy environment */ + lua_setfenv(L, -2); /* set it */ + lua_setfield(L, -3, fname); +} + + +static void newfenv (lua_State *L, lua_CFunction cls) { + lua_createtable(L, 0, 1); + lua_pushcfunction(L, cls); + lua_setfield(L, -2, "__close"); +} + + +LUALIB_API int luaopen_io (lua_State *L) { + createmeta(L); + /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ + newfenv(L, io_fclose); + lua_replace(L, LUA_ENVIRONINDEX); + /* open library */ + luaL_register(L, LUA_IOLIBNAME, iolib); + /* create (and set) default files */ + newfenv(L, io_noclose); /* close function for default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, 0, "stderr"); + lua_pop(L, 1); /* pop environment for default files */ + return 1; +} + diff --git a/src/blua/lualib.h b/src/blua/lualib.h index 6ebe27287..4ea97edf3 100644 --- a/src/blua/lualib.h +++ b/src/blua/lualib.h @@ -21,6 +21,9 @@ LUALIB_API int (luaopen_base) (lua_State *L); #define LUA_TABLIBNAME "table" LUALIB_API int (luaopen_table) (lua_State *L); +#define LUA_IOLIBNAME "io" +LUALIB_API int (luaopen_io) (lua_State *L); + #define LUA_STRLIBNAME "string" LUALIB_API int (luaopen_string) (lua_State *L); diff --git a/src/byteptr.h b/src/byteptr.h index 57fe9cb75..933c2af34 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/command.c b/src/command.c index cb6803b57..f5c02d877 100644 --- a/src/command.c +++ b/src/command.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -80,7 +80,7 @@ static boolean joyaxis2_default = false; static INT32 joyaxis_count = 0; static INT32 joyaxis2_count = 0; -#define COM_BUF_SIZE 8192 // command buffer size +#define COM_BUF_SIZE (32<<10) // command buffer size #define MAX_ALIAS_RECURSION 100 // max recursion allowed for aliases static INT32 com_wait; // one command per frame (for cmd sequences) @@ -481,13 +481,11 @@ void COM_AddCommand(const char *name, com_func_t func) { if (!stricmp(name, cmd->name)) //case insensitive now that we have lower and uppercase! { -#ifdef HAVE_BLUA // don't I_Error for Lua commands // Lua commands can replace game commands, and they have priority. // BUT, if for some reason we screwed up and made two console commands with the same name, // it's good to have this here so we find out. if (cmd->function != COM_Lua_f) -#endif I_Error("Command %s already exists\n", name); return; @@ -501,7 +499,6 @@ void COM_AddCommand(const char *name, com_func_t func) com_commands = cmd; } -#ifdef HAVE_BLUA /** Adds a console command for Lua. * No I_Errors allowed; return a negative code instead. * @@ -534,7 +531,6 @@ int COM_AddLuaCommand(const char *name) com_commands = cmd; return 0; } -#endif /** Tests if a command exists. * @@ -1427,9 +1423,7 @@ finish: } var->flags |= CV_MODIFIED; // raise 'on change' code -#ifdef HAVE_BLUA LUA_CVarChanged(var->name); // let consolelib know what cvar this is. -#endif if (var->flags & CV_CALL && !stealth) var->func(); diff --git a/src/command.h b/src/command.h index e7371b2fa..404052ce4 100644 --- a/src/command.h +++ b/src/command.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/config.h.in b/src/config.h.in index 498f3086d..3b2579965 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -27,13 +27,15 @@ /* Manually defined asset hashes for non-CMake builds * Last updated 2020 / 02 / 15 - v2.2.1 - main assets - * Last updated 20?? / ?? / ?? - v2.2.? - patch.pk3 + * Last updated 2020 / 02 / 22 - v2.2.2 - patch.pk3 + * Last updated 2020 / 05 / 10 - v2.2.3 - player.dta & patch.pk3 + * Last updated 2020 / 05 / 11 - v2.2.4 - patch.pk3 */ #define ASSET_HASH_SRB2_PK3 "0277c9416756627004e83cbb5b2e3e28" #define ASSET_HASH_ZONES_PK3 "f7e88afb6af7996a834c7d663144bead" -#define ASSET_HASH_PLAYER_DTA "ad49e07b17cc662f1ad70c454910b4ae" +#define ASSET_HASH_PLAYER_DTA "8a4507ddf9bc0682c09174400f26ad65" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_PK3 "there is no patch.pk3, only zuul" +#define ASSET_HASH_PATCH_PK3 "bbbf6af3b20349612ee06e0b55979a76" #endif #endif diff --git a/src/console.c b/src/console.c index 59d2b3e6c..aac94d473 100644 --- a/src/console.c +++ b/src/console.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -97,6 +97,7 @@ static void CON_InputInit(void); static void CON_RecalcSize(void); static void CON_ChangeHeight(void); +static void CON_DrawBackpic(void); static void CONS_hudlines_Change(void); static void CONS_backcolor_Change(void); @@ -613,15 +614,6 @@ void CON_Ticker(void) con_tick++; con_tick &= 7; - // if the menu is open then close the console. - if (menuactive && con_destlines) - { - consoletoggle = false; - con_destlines = 0; - CON_ClearHUD(); - I_UpdateMouseGrab(); - } - // console key was pushed if (consoletoggle) { @@ -778,7 +770,7 @@ boolean CON_Responder(event_t *ev) // check for console toggle key if (ev->type != ev_console) { - if (modeattacking || metalrecording) + if (modeattacking || metalrecording || marathonmode) return false; if (key == gamecontrol[gc_console][0] || key == gamecontrol[gc_console][1]) @@ -793,7 +785,7 @@ boolean CON_Responder(event_t *ev) // check other keys only if console prompt is active if (!consoleready && key < NUMINPUTS) // metzgermeister: boundary check!! { - if (bindtable[key]) + if (! menuactive && bindtable[key]) { COM_BufAddText(bindtable[key]); COM_BufAddText("\n"); @@ -1539,6 +1531,51 @@ static void CON_DrawHudlines(void) con_clearlines = y; // this is handled by HU_Erase(); } +// Lactozilla: Draws the console's background picture. +static void CON_DrawBackpic(void) +{ + patch_t *con_backpic; + lumpnum_t piclump; + int x, w, h; + + // Get the lumpnum for CONSBACK, or fallback into MISSING. + piclump = W_CheckNumForName("CONSBACK"); + if (piclump == LUMPERROR) + piclump = W_GetNumForName("MISSING"); + + // Cache the Software patch. + con_backpic = W_CacheSoftwarePatchNum(piclump, PU_PATCH); + + // Center the backpic, and draw a vertically cropped patch. + w = (con_backpic->width * vid.dupx); + x = (vid.width / 2) - (w / 2); + h = con_curlines/vid.dupy; + + // If the patch doesn't fill the entire screen, + // then fill the sides with a solid color. + if (x > 0) + { + column_t *column = (column_t *)((UINT8 *)(con_backpic) + LONG(con_backpic->columnofs[0])); + if (!column->topdelta) + { + UINT8 *source = (UINT8 *)(column) + 3; + INT32 color = (source[0] | V_NOSCALESTART); + // left side + V_DrawFill(0, 0, x, con_curlines, color); + // right side + V_DrawFill((x + w), 0, (vid.width - w), con_curlines, color); + } + } + + // Cache the patch normally. + con_backpic = W_CachePatchNum(piclump, PU_PATCH); + V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic, + 0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); + + // Unlock the cached patch. + W_UnlockCachedPatch(con_backpic); +} + // draw the console background, text, and prompt if enough place // static void CON_DrawConsole(void) @@ -1560,19 +1597,7 @@ static void CON_DrawConsole(void) // draw console background if (cons_backpic.value || con_forcepic) - { - patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH); - int h; - - h = con_curlines/vid.dupy; - - // Jimita: CON_DrawBackpic just called V_DrawScaledPatch - //V_DrawScaledPatch(0, 0, 0, con_backpic); - V_DrawCroppedPatch(0, 0, FRACUNIT, 0, con_backpic, - 0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); - - W_UnlockCachedPatch(con_backpic); - } + CON_DrawBackpic(); else { // inu: no more width (was always 0 and vid.width) @@ -1624,10 +1649,7 @@ void CON_Drawer(void) return; if (needpatchrecache) - { - W_FlushCachedPatches(); HU_LoadGraphics(); - } if (con_recalc) { diff --git a/src/console.h b/src/console.h index 7a55c4b92..2be92d62b 100644 --- a/src/console.h +++ b/src/console.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 77118110e..78d4555bd 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -45,7 +45,7 @@ #include "lua_hook.h" #include "md5.h" -#ifdef CLIENT_LOADINGSCREEN +#ifndef NONET // cl loading screen #include "v_video.h" #include "f_finale.h" @@ -85,6 +85,10 @@ 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? +// Incremented by cv_joindelay when a client joins, decremented each tic. +// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled. +static tic_t joindelay = 0; + 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. @@ -191,24 +195,25 @@ static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) // of 512 bytes is like 0.1) UINT16 software_MAXPACKETLENGTH; -/** Guesses the value of a tic from its lowest byte and from maketic +/** Guesses the full value of a tic from its lowest byte, for a specific node * * \param low The lowest byte of the tic value + * \param node The node to deduce the tic for * \return The full tic value * */ -tic_t ExpandTics(INT32 low) +tic_t ExpandTics(INT32 low, INT32 node) { INT32 delta; - delta = low - (maketic & UINT8_MAX); + delta = low - (nettics[node] & UINT8_MAX); if (delta >= -64 && delta <= 64) - return (maketic & ~UINT8_MAX) + low; + return (nettics[node] & ~UINT8_MAX) + low; else if (delta > 64) - return (maketic & ~UINT8_MAX) - 256 + low; + return (nettics[node] & ~UINT8_MAX) - 256 + low; else //if (delta < -64) - return (maketic & ~UINT8_MAX) + 256 + low; + return (nettics[node] & ~UINT8_MAX) + 256 + low; } // ----------------------------------------------------------------- @@ -518,6 +523,9 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->pflags = (UINT32)LONG(players[i].pflags); //pflags_t rsp->panim = (UINT8)players[i].panim; //panim_t + rsp->angleturn = (INT16)SHORT(players[i].angleturn); + rsp->oldrelangleturn = (INT16)SHORT(players[i].oldrelangleturn); + rsp->aiming = (angle_t)LONG(players[i].aiming); rsp->currentweapon = LONG(players[i].currentweapon); rsp->ringweapons = LONG(players[i].ringweapons); @@ -659,6 +667,9 @@ static void resynch_read_player(resynch_pak *rsp) players[i].pflags = (UINT32)LONG(rsp->pflags); //pflags_t players[i].panim = (UINT8)rsp->panim; //panim_t + players[i].angleturn = (INT16)SHORT(rsp->angleturn); + players[i].oldrelangleturn = (INT16)SHORT(rsp->oldrelangleturn); + players[i].aiming = (angle_t)LONG(rsp->aiming); players[i].currentweapon = LONG(rsp->currentweapon); players[i].ringweapons = LONG(rsp->ringweapons); @@ -1096,19 +1107,13 @@ static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg) static INT16 Consistancy(void); -#ifndef NONET -#define JOININGAME -#endif - typedef enum { CL_SEARCHING, CL_DOWNLOADFILES, CL_ASKJOIN, CL_WAITJOINRESPONSE, -#ifdef JOININGAME CL_DOWNLOADSAVEGAME, -#endif CL_CONNECTED, CL_ABORTED } cl_mode_t; @@ -1151,7 +1156,498 @@ static void CV_LoadPlayerNames(UINT8 **p) } } -#ifdef CLIENT_LOADINGSCREEN +#ifndef NONET +#define SNAKE_SPEED 5 + +#define SNAKE_NUM_BLOCKS_X 20 +#define SNAKE_NUM_BLOCKS_Y 10 +#define SNAKE_BLOCK_SIZE 12 +#define SNAKE_BORDER_SIZE 12 + +#define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) +#define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) + +#define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) +#define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) +#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) +#define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) + +enum snake_bonustype_s { + SNAKE_BONUS_NONE = 0, + SNAKE_BONUS_SLOW, + SNAKE_BONUS_FAST, + SNAKE_BONUS_GHOST, + SNAKE_BONUS_NUKE, + SNAKE_BONUS_SCISSORS, + SNAKE_BONUS_REVERSE, + SNAKE_BONUS_EGGMAN, + SNAKE_NUM_BONUSES, +}; + +static const char *snake_bonuspatches[] = { + NULL, + "DL_SLOW", + "TVSSC0", + "TVIVC0", + "TVARC0", + "DL_SCISSORS", + "TVRCC0", + "TVEGC0", +}; + +static const char *snake_backgrounds[] = { + "RVPUMICF", + "FRSTRCKF", + "TAR", + "MMFLRB4", + "RVDARKF1", + "RVZWALF1", + "RVZWALF4", + "RVZWALF5", + "RVZGRS02", + "RVZGRS04", +}; + +typedef struct snake_s +{ + boolean paused; + boolean pausepressed; + tic_t time; + tic_t nextupdate; + boolean gameover; + UINT8 background; + + UINT16 snakelength; + enum snake_bonustype_s snakebonus; + tic_t snakebonustime; + UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + + UINT8 applex; + UINT8 appley; + + enum snake_bonustype_s bonustype; + UINT8 bonusx; + UINT8 bonusy; +} snake_t; + +static snake_t *snake = NULL; + +static void Snake_Initialise(void) +{ + if (!snake) + snake = malloc(sizeof(snake_t)); + + snake->paused = false; + snake->pausepressed = false; + snake->time = 0; + snake->nextupdate = SNAKE_SPEED; + snake->gameover = false; + snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); + + snake->snakelength = 1; + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + snake->snakedir[0] = 0; + snake->snakedir[1] = 0; + + snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + snake->bonustype = SNAKE_BONUS_NONE; +} + +static UINT8 Snake_GetOppositeDir(UINT8 dir) +{ + if (dir == 1 || dir == 3) + return dir + 1; + else if (dir == 2 || dir == 4) + return dir - 1; + else + return 12 + 5 - dir; +} + +static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y, UINT8 headx, UINT8 heady) +{ + UINT16 i; + + do + { + *x = M_RandomKey(SNAKE_NUM_BLOCKS_X); + *y = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + for (i = 0; i < snake->snakelength; i++) + if (*x == snake->snakex[i] && *y == snake->snakey[i]) + break; + } while (i < snake->snakelength || (*x == headx && *y == heady)); +} + +static void Snake_Handle(void) +{ + UINT8 x, y; + UINT8 oldx, oldy; + UINT16 i; + + // Handle retry + if (snake->gameover && (PLAYER1INPUTDOWN(gc_jump) || gamekeydown[KEY_ENTER])) + { + Snake_Initialise(); + snake->pausepressed = true; // Avoid accidental pause on respawn + } + + // Handle pause + if (PLAYER1INPUTDOWN(gc_pause) || gamekeydown[KEY_ENTER]) + { + if (!snake->pausepressed) + snake->paused = !snake->paused; + snake->pausepressed = true; + } + else + snake->pausepressed = false; + + if (snake->paused) + return; + + snake->time++; + + x = snake->snakex[0]; + y = snake->snakey[0]; + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + + // Update direction + if (gamekeydown[KEY_LEFTARROW]) + { + if (snake->snakelength < 2 || x <= oldx) + snake->snakedir[0] = 1; + } + else if (gamekeydown[KEY_RIGHTARROW]) + { + if (snake->snakelength < 2 || x >= oldx) + snake->snakedir[0] = 2; + } + else if (gamekeydown[KEY_UPARROW]) + { + if (snake->snakelength < 2 || y <= oldy) + snake->snakedir[0] = 3; + } + else if (gamekeydown[KEY_DOWNARROW]) + { + if (snake->snakelength < 2 || y >= oldy) + snake->snakedir[0] = 4; + } + + if (snake->snakebonustime) + { + snake->snakebonustime--; + if (!snake->snakebonustime) + snake->snakebonus = SNAKE_BONUS_NONE; + } + + snake->nextupdate--; + if (snake->nextupdate) + return; + if (snake->snakebonus == SNAKE_BONUS_SLOW) + snake->nextupdate = SNAKE_SPEED * 2; + else if (snake->snakebonus == SNAKE_BONUS_FAST) + snake->nextupdate = SNAKE_SPEED * 2 / 3; + else + snake->nextupdate = SNAKE_SPEED; + + if (snake->gameover) + return; + + // Find new position + switch (snake->snakedir[0]) + { + case 1: + if (x > 0) + x--; + else + snake->gameover = true; + break; + case 2: + if (x < SNAKE_NUM_BLOCKS_X - 1) + x++; + else + snake->gameover = true; + break; + case 3: + if (y > 0) + y--; + else + snake->gameover = true; + break; + case 4: + if (y < SNAKE_NUM_BLOCKS_Y - 1) + y++; + else + snake->gameover = true; + break; + } + + // Check collision with snake + if (snake->snakebonus != SNAKE_BONUS_GHOST) + for (i = 1; i < snake->snakelength - 1; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + { + if (snake->snakebonus == SNAKE_BONUS_SCISSORS) + { + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakelength = i; + S_StartSound(NULL, sfx_adderr); + } + else + snake->gameover = true; + } + + if (snake->gameover) + { + S_StartSound(NULL, sfx_lose); + return; + } + + // Check collision with apple + if (x == snake->applex && y == snake->appley) + { + if (snake->snakelength + 1 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y) + { + snake->snakelength++; + snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; + snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2]; + snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; + } + + // Spawn new apple + Snake_FindFreeSlot(&snake->applex, &snake->appley, x, y); + + // Spawn new bonus + if (!(snake->snakelength % 5)) + { + do + { + snake->bonustype = M_RandomKey(SNAKE_NUM_BONUSES - 1) + 1; + } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 + && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); + + Snake_FindFreeSlot(&snake->bonusx, &snake->bonusy, x, y); + } + + S_StartSound(NULL, sfx_s3k6b); + } + + if (snake->snakelength > 1 && snake->snakedir[0]) + { + UINT8 dir = snake->snakedir[0]; + + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + + // Move + for (i = snake->snakelength - 1; i > 0; i--) + { + snake->snakex[i] = snake->snakex[i - 1]; + snake->snakey[i] = snake->snakey[i - 1]; + snake->snakedir[i] = snake->snakedir[i - 1]; + } + + // Handle corners + if (x < oldx && dir == 3) + dir = 5; + else if (x > oldx && dir == 3) + dir = 6; + else if (x < oldx && dir == 4) + dir = 7; + else if (x > oldx && dir == 4) + dir = 8; + else if (y < oldy && dir == 1) + dir = 9; + else if (y < oldy && dir == 2) + dir = 10; + else if (y > oldy && dir == 1) + dir = 11; + else if (y > oldy && dir == 2) + dir = 12; + snake->snakedir[1] = dir; + } + + snake->snakex[0] = x; + snake->snakey[0] = y; + + // Check collision with bonus + if (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy) + { + S_StartSound(NULL, sfx_ncchip); + + switch (snake->bonustype) + { + case SNAKE_BONUS_SLOW: + snake->snakebonus = SNAKE_BONUS_SLOW; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_FAST: + snake->snakebonus = SNAKE_BONUS_FAST; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_GHOST: + snake->snakebonus = SNAKE_BONUS_GHOST; + snake->snakebonustime = 10 * TICRATE; + break; + case SNAKE_BONUS_NUKE: + for (i = 0; i < snake->snakelength; i++) + { + snake->snakex [i] = snake->snakex [0]; + snake->snakey [i] = snake->snakey [0]; + snake->snakedir[i] = snake->snakedir[0]; + } + + S_StartSound(NULL, sfx_bkpoof); + break; + case SNAKE_BONUS_SCISSORS: + snake->snakebonus = SNAKE_BONUS_SCISSORS; + snake->snakebonustime = 60 * TICRATE; + break; + case SNAKE_BONUS_REVERSE: + for (i = 0; i < (snake->snakelength + 1) / 2; i++) + { + UINT16 i2 = snake->snakelength - 1 - i; + UINT8 tmpx = snake->snakex [i]; + UINT8 tmpy = snake->snakey [i]; + UINT8 tmpdir = snake->snakedir[i]; + + // Swap first segment with last segment + snake->snakex [i] = snake->snakex [i2]; + snake->snakey [i] = snake->snakey [i2]; + snake->snakedir[i] = Snake_GetOppositeDir(snake->snakedir[i2]); + snake->snakex [i2] = tmpx; + snake->snakey [i2] = tmpy; + snake->snakedir[i2] = Snake_GetOppositeDir(tmpdir); + } + + snake->snakedir[0] = 0; + + S_StartSound(NULL, sfx_gravch); + break; + default: + if (snake->snakebonus != SNAKE_BONUS_GHOST) + { + snake->gameover = true; + S_StartSound(NULL, sfx_lose); + } + } + + snake->bonustype = SNAKE_BONUS_NONE; + } +} + +static void Snake_Draw(void) +{ + INT16 i; + + // Background + V_DrawFlatFill( + SNAKE_LEFT_X + SNAKE_BORDER_SIZE, + SNAKE_TOP_Y + SNAKE_BORDER_SIZE, + SNAKE_MAP_WIDTH, + SNAKE_MAP_HEIGHT, + W_GetNumForName(snake_backgrounds[snake->background]) + ); + + // Borders + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_TOP_Y, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Right + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Bottom + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left + + // Apple + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + FRACUNIT / 4, + 0, + W_CachePatchLongName("DL_APPLE", PU_HUDGFX), + NULL + ); + + // Bonus + if (snake->bonustype != SNAKE_BONUS_NONE) + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->bonusx * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 ) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchLongName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), + NULL + ); + + // Snake + if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over + { + for (i = snake->snakelength - 1; i >= 0; i--) + { + const char *patchname; + UINT8 dir = snake->snakedir[i]; + + if (i == 0) // Head + { + switch (dir) + { + case 1: patchname = "DL_SNAKEHEAD_L"; break; + case 2: patchname = "DL_SNAKEHEAD_R"; break; + case 3: patchname = "DL_SNAKEHEAD_T"; break; + case 4: patchname = "DL_SNAKEHEAD_B"; break; + default: patchname = "DL_SNAKEHEAD_M"; + } + } + else // Body + { + switch (dir) + { + case 1: patchname = "DL_SNAKEBODY_L"; break; + case 2: patchname = "DL_SNAKEBODY_R"; break; + case 3: patchname = "DL_SNAKEBODY_T"; break; + case 4: patchname = "DL_SNAKEBODY_B"; break; + case 5: patchname = "DL_SNAKEBODY_LT"; break; + case 6: patchname = "DL_SNAKEBODY_RT"; break; + case 7: patchname = "DL_SNAKEBODY_LB"; break; + case 8: patchname = "DL_SNAKEBODY_RB"; break; + case 9: patchname = "DL_SNAKEBODY_TL"; break; + case 10: patchname = "DL_SNAKEBODY_TR"; break; + case 11: patchname = "DL_SNAKEBODY_BL"; break; + case 12: patchname = "DL_SNAKEBODY_BR"; break; + default: patchname = "DL_SNAKEBODY_B"; + } + } + + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, + snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, + W_CachePatchLongName(patchname, PU_HUDGFX), + NULL + ); + } + } + + // Length + V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); + + // Bonus + if (snake->snakebonus != SNAKE_BONUS_NONE + && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) + V_DrawFixedPatch( + (SNAKE_RIGHT_X + 10) * FRACUNIT, + (SNAKE_TOP_Y + 24) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchLongName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), + NULL + ); +} + // // CL_DrawConnectionStatus // @@ -1166,8 +1662,8 @@ static inline void CL_DrawConnectionStatus(void) V_DrawFadeScreen(0xFF00, 16); // force default // Draw the bottom box. - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-24, V_YELLOWMAP, "Press ESC to abort"); + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); if (cl_mode != CL_DOWNLOADFILES) { @@ -1176,26 +1672,37 @@ static inline void CL_DrawConnectionStatus(void) // 15 pal entries total. const char *cltext; - for (i = 0; i < 16; ++i) - V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15)); + if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) + for (i = 0; i < 16; ++i) + V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) { -#ifdef JOININGAME case CL_DOWNLOADSAVEGAME: if (lastfilenum != -1) { + UINT32 currentsize = fileneeded[lastfilenum].currentsize; + UINT32 totalsize = fileneeded[lastfilenum].totalsize; + INT32 dldlength; + cltext = M_GetText("Downloading game state..."); Net_GetNetStat(); - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, - va(" %4uK",fileneeded[lastfilenum].currentsize>>10)); - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, + + dldlength = (INT32)((currentsize/(double)totalsize) * 256); + if (dldlength > 256) + dldlength = 256; + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); + + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %4uK/%4uK",currentsize>>10,totalsize>>10)); + + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); } else cltext = M_GetText("Waiting to download game state..."); break; -#endif case CL_ASKJOIN: case CL_WAITJOINRESPONSE: cltext = M_GetText("Requesting to join..."); @@ -1204,7 +1711,7 @@ static inline void CL_DrawConnectionStatus(void) cltext = M_GetText("Connecting to server..."); break; } - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, cltext); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, cltext); } else { @@ -1215,12 +1722,14 @@ static inline void CL_DrawConnectionStatus(void) fileneeded_t *file = &fileneeded[lastfilenum]; char *filename = file->filename; + Snake_Draw(); + Net_GetNetStat(); dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); if (dldlength > 256) dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 96); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); memset(tempname, 0, sizeof(tempname)); // offset filename to just the name only part @@ -1238,15 +1747,15 @@ static inline void CL_DrawConnectionStatus(void) strncpy(tempname, filename, sizeof(tempname)-1); } - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, va(M_GetText("Downloading \"%s\""), tempname)); - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); } else - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, M_GetText("Waiting to download files...")); } } @@ -1289,6 +1798,37 @@ static boolean CL_SendJoin(void) return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); } +static INT32 FindRejoinerNum(SINT8 node) +{ + char strippednodeaddress[64]; + const char *nodeaddress; + char *port; + INT32 i; + + // Make sure there is no dead dress before proceeding to the stripping + if (!I_GetNodeAddress) + return -1; + nodeaddress = I_GetNodeAddress(node); + if (!nodeaddress) + return -1; + + // Strip the address of its port + strcpy(strippednodeaddress, nodeaddress); + port = strchr(strippednodeaddress, ':'); + if (port) + *port = '\0'; + + // Check if any player matches the stripped address + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX + && !strcmp(playeraddress[i], strippednodeaddress)) + return i; + } + + return -1; +} + static void SV_SendServerInfo(INT32 node, tic_t servertime) { UINT8 *p; @@ -1306,6 +1846,16 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; + + if (!node || FindRejoinerNum(node) != -1) + netbuffer->u.serverinfo.refusereason = 0; + else if (!cv_allownewplayer.value) + netbuffer->u.serverinfo.refusereason = 1; + else if (D_NumPlayers() >= cv_maxplayers.value) + netbuffer->u.serverinfo.refusereason = 2; + else + netbuffer->u.serverinfo.refusereason = 0; + strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], sizeof netbuffer->u.serverinfo.gametypename); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; @@ -1450,7 +2000,7 @@ static boolean SV_SendServerConfig(INT32 node) if (!playeringame[i]) continue; netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; - netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor; + netbuffer->u.servercfg.playercolor[i] = (UINT16)players[i].skincolor; netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)LONG(players[i].availabilities); } @@ -1490,7 +2040,7 @@ static boolean SV_SendServerConfig(INT32 node) return waspacketsent; } -#ifdef JOININGAME +#ifndef NONET #define SAVEGAMESIZE (768*1024) static void SV_SendSaveGame(INT32 node) @@ -1553,7 +2103,7 @@ static void SV_SendSaveGame(INT32 node) WRITEUINT32(savebuffer, 0); } - SV_SendRam(node, buffertosend, length, SF_RAM, 0); + AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); save_p = NULL; // Remember when we started sending the savegame so we can handle timeouts @@ -1645,7 +2195,7 @@ static void CL_LoadReceivedSavegame(void) // load a base level if (P_LoadNetGame()) { - const INT32 actnum = mapheaderinfo[gamemap-1]->actnum; + const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, "")) { @@ -1863,12 +2413,17 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) } // Quit here rather than downloading files and being refused later. - if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer) + if (serverlist[i].info.refusereason) { D_QuitNetGame(); CL_Reset(); D_StartTitle(); - M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING); + if (serverlist[i].info.refusereason == 1) + M_StartMessage(M_GetText("The server is not accepting\njoins for the moment.\n\nPress ESC\n"), NULL, MM_NOTHING); + else if (serverlist[i].info.refusereason == 2) + M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING); + else + M_StartMessage(M_GetText("You can't join.\nI don't know why,\nbut you can't join.\n\nPress ESC\n"), NULL, MM_NOTHING); return false; } @@ -1928,8 +2483,13 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) return false; } // no problem if can't send packet, we will retry later - if (CL_SendRequestFile()) + if (CL_SendFileRequest()) + { cl_mode = CL_DOWNLOADFILES; +#ifndef NONET + Snake_Initialise(); +#endif + } } } else @@ -1993,12 +2553,20 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic if (waitmore) break; // exit the case +#ifndef NONET + if (snake) + { + free(snake); + snake = NULL; + } +#endif + cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now /* FALLTHRU */ case CL_ASKJOIN: CL_LoadServerFiles(); -#ifdef JOININGAME +#ifndef NONET // prepare structures to save the file // WARNING: this can be useless in case of server not in GS_LEVEL // but since the network layer doesn't provide ordered packets... @@ -2008,7 +2576,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic cl_mode = CL_WAITJOINRESPONSE; break; -#ifdef JOININGAME +#ifndef NONET case CL_DOWNLOADSAVEGAME: // At this state, the first (and only) needed file is the gamestate if (fileneeded[0].status == FS_FOUND) @@ -2039,36 +2607,58 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic // Call it only once by tic if (*oldtic != I_GetTime()) { - INT32 key; - I_OsPolling(); - key = I_GetKey(); - if (key == KEY_ESCAPE || key == KEY_JOY1+1) + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + G_MapEventsToControls(&events[eventtail]); + + if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1]) { CONS_Printf(M_GetText("Network game synchronization aborted.\n")); // M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + +#ifndef NONET + if (snake) + { + free(snake); + snake = NULL; + } +#endif + D_QuitNetGame(); CL_Reset(); D_StartTitle(); + memset(gamekeydown, 0, NUMKEYS); return false; } +#ifndef NONET + else if (cl_mode == CL_DOWNLOADFILES && snake) + Snake_Handle(); +#endif + + if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) + FileReceiveTicker(); // why are these here? this is for servers, we're a client //if (key == 's' && server) // doomcom->numnodes = (INT16)pnumnodes; - //SV_FileSendTicker(); + //FileSendTicker(); *oldtic = I_GetTime(); -#ifdef CLIENT_LOADINGSCREEN +#ifndef NONET if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) { - F_MenuPresTicker(true); // title sky - F_TitleScreenTicker(true); - F_TitleScreenDrawer(); + if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_DOWNLOADSAVEGAME) + { + F_MenuPresTicker(true); // title sky + F_TitleScreenTicker(true); + F_TitleScreenDrawer(); + } CL_DrawConnectionStatus(); I_UpdateNoVsync(); // page flip or blit buffer if (moviemode) M_SaveFrame(); + S_UpdateSounds(); + S_UpdateClosedCaptions(); } #else CON_Drawer(); @@ -2093,20 +2683,16 @@ static void CL_ConnectToServer(boolean viams) tic_t oldtic; #ifndef NONET tic_t asksent; -#endif -#ifdef JOININGAME char tmpsave[256]; sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + lastfilenum = -1; #endif cl_mode = CL_SEARCHING; -#ifdef CLIENT_LOADINGSCREEN - lastfilenum = -1; -#endif - -#ifdef JOININGAME +#ifndef NONET // Don't get a corrupt savegame error because tmpsave already exists if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) I_Error("Can't delete %s\n", tmpsave); @@ -2439,14 +3025,14 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) if (!playeringame[playernum]) return; - if (server && !demoplayback) + if (server && !demoplayback && playernode[playernum] != UINT8_MAX) { INT32 node = playernode[playernum]; playerpernode[node]--; if (playerpernode[node] <= 0) { - nodeingame[playernode[playernum]] = false; - Net_CloseConnection(playernode[playernum]); + nodeingame[node] = false; + Net_CloseConnection(node); ResetNode(node); } } @@ -2501,20 +3087,14 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } } -#ifdef HAVE_BLUA LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting -#else - (void)reason; -#endif // don't look through someone's view who isn't there if (playernum == displayplayer) { -#ifdef HAVE_BLUA // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], true); -#endif + LUAh_ViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -2535,9 +3115,7 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } -#ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); -#endif if (G_TagGametype()) //Check if you still have a game. Location flexible. =P P_CheckSurvivors(); @@ -2792,16 +3370,13 @@ static void Command_Kick(void) if (pn == -1 || pn == 0) return; - if (server) + // Special case if we are trying to kick a player who is downloading the game state: + // trigger a timeout instead of kicking them, because a kick would only + // take effect after they have finished downloading + if (server && playernode[pn] != UINT8_MAX && sendingsavegame[playernode[pn]]) { - // Special case if we are trying to kick a player who is downloading the game state: - // trigger a timeout instead of kicking them, because a kick would only - // take effect after they have finished downloading - if (sendingsavegame[playernode[pn]]) - { - Net_ConnectionTimeout(playernode[pn]); - return; - } + Net_ConnectionTimeout(playernode[pn]); + return; } WRITESINT8(p, pn); @@ -2859,7 +3434,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) // Is playernum authorized to make this kick? if (playernum != serverplayer && !IsPlayerAdmin(playernum) - && !(playerpernode[playernode[playernum]] == 2 + && !(playernode[playernum] != UINT8_MAX && playerpernode[playernode[playernum]] == 2 && nodetoplayer2[playernode[playernum]] == pnum)) { // We received a kick command from someone who isn't the @@ -2997,6 +3572,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (pnum == consoleplayer) { + if (Playing()) + LUAh_GameQuit(); #ifdef DUMPCONSISTENCY if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); #endif @@ -3018,7 +3595,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } else if (keepbody) { - if (server && !demoplayback) + if (server && !demoplayback && playernode[pnum] != UINT8_MAX) { INT32 node = playernode[pnum]; playerpernode[node]--; @@ -3042,6 +3619,8 @@ consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, consvar_t cv_joinnextround = {"joinnextround", "Off", 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 joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; +consvar_t cv_joindelay = {"joindelay", "10", CV_SAVE, joindelay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; consvar_t cv_rejointimeout = {"rejointimeout", "Off", CV_SAVE|CV_FLOAT, rejointimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -3129,14 +3708,14 @@ void SV_ResetServer(void) neededtic = maketic; tictoclear = maketic; + joindelay = 0; + for (i = 0; i < MAXNETNODES; i++) ResetNode(i); for (i = 0; i < MAXPLAYERS; i++) { -#ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[i]); -#endif playeringame[i] = false; playernode[i] = UINT8_MAX; memset(playeraddress[i], 0, sizeof(*playeraddress)); @@ -3197,6 +3776,9 @@ void D_QuitNetGame(void) // abort send/receive of files CloseNetFile(); + RemoveAllLuaFileTransfers(); + waitingforluafiletransfer = false; + waitingforluafilecommand = false; if (server) { @@ -3230,37 +3812,6 @@ void D_QuitNetGame(void) #endif } -static INT32 FindRejoinerNum(SINT8 node) -{ - char strippednodeaddress[64]; - const char *nodeaddress; - char *port; - INT32 i; - - // Make sure there is no dead dress before proceeding to the stripping - if (!I_GetNodeAddress) - return -1; - nodeaddress = I_GetNodeAddress(node); - if (!nodeaddress) - return -1; - - // Strip the address of its port - strcpy(strippednodeaddress, nodeaddress); - port = strchr(strippednodeaddress, ':'); - if (port) - *port = '\0'; - - // Check if any player matches the stripped address - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX - && !strcmp(playeraddress[i], strippednodeaddress)) - return i; - } - - return -1; -} - // Adds a node to the game (player will follow at map change or at savegame....) static inline void SV_AddNode(INT32 node) { @@ -3279,7 +3830,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) boolean splitscreenplayer; boolean rejoined; player_t *newplayer; - char *port; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -3310,10 +3860,15 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (server && I_GetNodeAddress) { - strcpy(playeraddress[newplayernum], I_GetNodeAddress(node)); - port = strchr(playeraddress[newplayernum], ':'); - if (port) - *port = '\0'; + const char *address = I_GetNodeAddress(node); + char *port = NULL; + if (address) // MI: fix msvcrt.dll!_mbscat crash? + { + strcpy(playeraddress[newplayernum], address); + port = strchr(playeraddress[newplayernum], ':'); + if (port) + *port = '\0'; + } } } @@ -3334,6 +3889,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) displayplayer = newplayernum; secondarydisplayplayer = newplayernum; DEBFILE("spawning me\n"); + ticcmd_oldangleturn[0] = newplayer->oldrelangleturn; } else { @@ -3341,7 +3897,9 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) DEBFILE("spawning my brother\n"); if (botingame) newplayer->bot = 1; + ticcmd_oldangleturn[1] = newplayer->oldrelangleturn; } + P_ForceLocalAngle(newplayer, (angle_t)(newplayer->angleturn << 16)); D_SendPlayerConfig(); addedtogame = true; @@ -3349,11 +3907,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) { if (newplayer->mo) { - if (!splitscreenplayer) - localangle = newplayer->mo->angle; - else - localangle2 = newplayer->mo->angle; - newplayer->viewheight = 41*newplayer->height/48; if (newplayer->mo->eflags & MFE_VERTICALFLIP) @@ -3398,10 +3951,8 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (server && multiplayer && motd[0] != '\0') COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); -#ifdef HAVE_BLUA if (!rejoined) LUAh_PlayerJoin(newplayernum); -#endif } static boolean SV_AddWaitingPlayers(const char *name, const char *name2) @@ -3591,7 +4142,7 @@ static void HandleConnect(SINT8 node) rejoinernum = FindRejoinerNum(node); if (bannednode && bannednode[node]) - SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server")); + SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server.")); else if (netbuffer->u.clientcfg._255 != 255 || netbuffer->u.clientcfg.packetversion != PACKETVERSION) SV_SendRefuse(node, "Incompatible packet formats."); @@ -3602,13 +4153,18 @@ static void HandleConnect(SINT8 node) || netbuffer->u.clientcfg.subversion != SUBVERSION) SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION)); else if (!cv_allownewplayer.value && node && rejoinernum == -1) - SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment")); + SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment.")); else if (D_NumPlayers() >= cv_maxplayers.value && rejoinernum == -1) SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value)); else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client? SV_SendRefuse(node, M_GetText("Too many players from\nthis node.")); else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join? SV_SendRefuse(node, M_GetText("No players from\nthis node.")); + else if (luafiletransfers) + SV_SendRefuse(node, M_GetText("The server is broadcasting a file\nrequested by a Lua script.\nPlease wait a bit and then\ntry rejoining.")); + else if (netgame && joindelay > 2 * (tic_t)cv_joindelay.value * TICRATE) + SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."), + (joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE)); else { #ifndef NONET @@ -3657,7 +4213,7 @@ static void HandleConnect(SINT8 node) G_SetGamestate(backupstate); DEBFILE("new node joined\n"); } -#ifdef JOININGAME +#ifndef NONET if (nodewaiting[node]) { if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) @@ -3666,13 +4222,9 @@ static void HandleConnect(SINT8 node) DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(names[0], names[1]); + joindelay += cv_joindelay.value * TICRATE; player_joining = true; } -#else -#ifndef NONET - // I guess we have no use for this if we aren't doing mid-level joins? - (void)newnode; -#endif #endif } } @@ -3685,6 +4237,8 @@ static void HandleConnect(SINT8 node) static void HandleShutdown(SINT8 node) { (void)node; + if (Playing()) + LUAh_GameQuit(); D_QuitNetGame(); CL_Reset(); D_StartTitle(); @@ -3699,6 +4253,8 @@ static void HandleShutdown(SINT8 node) static void HandleTimeout(SINT8 node) { (void)node; + if (Playing()) + LUAh_GameQuit(); D_QuitNetGame(); CL_Reset(); D_StartTitle(); @@ -3850,7 +4406,7 @@ static void HandlePacketFromAwayNode(SINT8 node) playernode[(UINT8)serverplayer] = servernode; if (netgame) -#ifdef JOININGAME +#ifndef NONET CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); #else CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); @@ -3861,7 +4417,7 @@ static void HandlePacketFromAwayNode(SINT8 node) for (j = 0; j < MAXPLAYERS; j++) { if (netbuffer->u.servercfg.playerskins[j] == 0xFF - && netbuffer->u.servercfg.playercolor[j] == 0xFF + && netbuffer->u.servercfg.playercolor[j] == 0xFFFF && netbuffer->u.servercfg.playeravailabilities[j] == 0xFFFFFFFF) continue; // not in game @@ -3874,7 +4430,7 @@ static void HandlePacketFromAwayNode(SINT8 node) scp = netbuffer->u.servercfg.varlengthinputs; CV_LoadPlayerNames(&scp); CV_LoadNetVars(&scp); -#ifdef JOININGAME +#ifndef NONET /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? /// Also, according to HandleConnect, the server will send the savegame even during intermission... @@ -3895,13 +4451,23 @@ static void HandlePacketFromAwayNode(SINT8 node) break; } SERVERONLY - Got_Filetxpak(); + PT_FileFragment(); + break; + + case PT_FILEACK: + if (server) + PT_FileAck(); + break; + + case PT_FILERECEIVED: + if (server) + PT_FileReceived(); break; case PT_REQUESTFILE: if (server) { - if (!cv_downloading.value || !Got_RequestFilePak(node)) + if (!cv_downloading.value || !PT_RequestFile(node)) Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway } else @@ -3945,7 +4511,9 @@ static void HandlePacketFromPlayer(SINT8 node) INT32 netconsole; tic_t realend, realstart; UINT8 *pak, *txtpak, numtxtpak; +#ifndef NOMD5 UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ +#endif txtpak = NULL; @@ -3964,7 +4532,7 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_RESYNCHGET: if (client) break; - SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); + SV_AcknowledgeResynchAck(node, netbuffer->u.resynchgot); break; case PT_CLIENTCMD: case PT_CLIENT2CMD: @@ -3981,8 +4549,8 @@ static void HandlePacketFromPlayer(SINT8 node) // To save bytes, only the low byte of tic numbers are sent // Use ExpandTics to figure out what the rest of the bytes are - realstart = ExpandTics(netbuffer->u.clientpak.client_tic); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom); + realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS || netbuffer->packettype == PT_NODEKEEPALIVEMIS @@ -4193,6 +4761,14 @@ static void HandlePacketFromPlayer(SINT8 node) Net_CloseConnection(node); nodeingame[node] = false; break; + case PT_ASKLUAFILE: + if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) + AddLuaFileToSendQueue(node, luafiletransfers->realfilename); + break; + case PT_HASLUAFILE: + if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) + SV_HandleLuaFileSent(node); + break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_RESYNCHEND: // Only accept PT_RESYNCHEND from the server. @@ -4222,15 +4798,15 @@ static void HandlePacketFromPlayer(SINT8 node) break; } - realstart = ExpandTics(netbuffer->u.serverpak.starttic); + realstart = netbuffer->u.serverpak.starttic; realend = realstart + netbuffer->u.serverpak.numtics; if (!txtpak) txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots * netbuffer->u.serverpak.numtics]; - if (realend > gametic + BACKUPTICS) - realend = gametic + BACKUPTICS; + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; cl_packetmissed = realstart > neededtic; if (realstart <= neededtic && realend > neededtic) @@ -4318,7 +4894,19 @@ static void HandlePacketFromPlayer(SINT8 node) break; } if (client) - Got_Filetxpak(); + PT_FileFragment(); + break; + case PT_FILEACK: + if (server) + PT_FileAck(); + break; + case PT_FILERECEIVED: + if (server) + PT_FileReceived(); + break; + case PT_SENDINGLUAFILE: + if (client) + CL_PrepareDownloadLuaFile(); break; default: DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", @@ -4569,11 +5157,11 @@ static void SV_SendTics(void) for (n = 1; n < MAXNETNODES; n++) if (nodeingame[n]) { - lasttictosend = maketic; - // assert supposedtics[n]>=nettics[n] realfirsttic = supposedtics[n]; - if (realfirsttic >= maketic) + lasttictosend = min(maketic, realfirsttic + CLIENTBACKUPTICS); + + if (realfirsttic >= lasttictosend) { // well we have sent all tics we will so use extrabandwidth // to resent packet that are supposed lost (this is necessary since lost @@ -4582,7 +5170,7 @@ static void SV_SendTics(void) DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", n, maketic, supposedtics[n], nettics[n])); realfirsttic = nettics[n]; - if (realfirsttic >= maketic || (I_GetTime() + n)&3) + if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) // all tic are ok continue; DEBFILE(va("Sent %d anyway\n", realfirsttic)); @@ -4625,7 +5213,7 @@ static void SV_SendTics(void) // Send the tics netbuffer->packettype = PT_SERVERTICS; - netbuffer->u.serverpak.starttic = (UINT8)realfirsttic; + netbuffer->u.serverpak.starttic = realfirsttic; netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; @@ -4687,41 +5275,6 @@ static void Local_Maketic(INT32 realtics) localcmds2.angleturn |= TICCMD_RECEIVED; } -// This function is utter bullshit and is responsible for -// the random desynch that happens when a player spawns. -// This is because ticcmds are resent to clients if a packet -// was dropped, and thus modifying them can lead to several -// clients having their ticcmds set to different values. -void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle) -{ - tic_t tic; - UINT8 numadjust = 0; - - (void)x; - (void)y; - - // Revisionist history: adjust the angles in the ticcmds received - // for this player, because they actually preceded the player - // spawning, but will be applied afterwards. - - for (tic = server ? maketic : (neededtic - 1); tic >= gametic; tic--) - { - if (numadjust++ == BACKUPTICS) - { - DEBFILE(va("SV_SpawnPlayer: All netcmds for player %d adjusted!\n", playernum)); - // We already adjusted them all, waste of time doing the same thing over and over - // This shouldn't happen normally though, either gametic was 0 (which is handled now anyway) - // or maketic >= gametic + BACKUPTICS - // -- Monster Iestyn 16/01/18 - break; - } - netcmds[tic%BACKUPTICS][playernum].angleturn = (INT16)((angle>>16) | TICCMD_RECEIVED); - - if (!tic) // failsafe for gametic == 0 -- Monster Iestyn 16/01/18 - break; - } -} - // create missed tic static void SV_Maketic(void) { @@ -4853,7 +5406,8 @@ static inline void PingUpdate(void) { for (i = 1; i < MAXPLAYERS; i++) { - if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) + if (playeringame[i] && !players[i].quittime + && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) { if (players[i].jointime > 30 * TICRATE) laggers[i] = true; @@ -4872,8 +5426,8 @@ static inline void PingUpdate(void) if (playeringame[i] && laggers[i]) { pingtimeout[i]++; + // ok your net has been bad for too long, you deserve to die. if (pingtimeout[i] > cv_pingtimeout.value) -// ok your net has been bad for too long, you deserve to die. { pingtimeout[i] = 0; SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY); @@ -4941,8 +5495,8 @@ void NetUpdate(void) PingUpdate(); // update node latency values so we can take an average later. for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); + if (playeringame[i] && playernode[i] != UINT8_MAX) + realpingtable[i] += GetLag(playernode[i]) * (1000.00f / TICRATE); pingmeasurecount++; } @@ -5015,12 +5569,21 @@ void NetUpdate(void) hu_resynching = true; } } + Net_AckTicker(); + // Handle timeouts to prevent definitive freezes from happenning if (server) + { for (i = 1; i < MAXNETNODES; i++) if (nodeingame[i] && freezetimeout[i] < I_GetTime()) Net_ConnectionTimeout(i); + + // In case the cvar value was lowered + if (joindelay) + joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE); + } + nowtime /= NEWTICRATERATIO; if (nowtime > resptime) { @@ -5028,7 +5591,8 @@ void NetUpdate(void) M_Ticker(); CON_Ticker(); } - SV_FileSendTicker(); + + FileSendTicker(); } /** Returns the number of players playing. diff --git a/src/d_clisrv.h b/src/d_clisrv.h index df93fe31d..cb23883a8 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -20,14 +20,11 @@ #include "d_player.h" /* -The 'packet version' may be used with packets whose -format is expected to change between versions. - -This version is independent of the mod name, and standard -version and subversion. It should only account for the -basic fields of the packet, and change infrequently. +The 'packet version' is used to distinguish packet formats. +This version is independent of VERSION and SUBVERSION. Different +applications may follow different packet versions. */ -#define PACKETVERSION 2 +#define PACKETVERSION 3 // Network play related stuff. // There is a data struct that stores network @@ -36,7 +33,8 @@ basic fields of the packet, and change infrequently. // be transmitted. // Networking and tick handling related. -#define BACKUPTICS 32 +#define BACKUPTICS 1024 +#define CLIENTBACKUPTICS 32 #define MAXTEXTCMD 256 // // Packet structure @@ -67,6 +65,10 @@ typedef enum PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic PT_RESYNCHGET, // Player got resynch packet + PT_SENDINGLUAFILE, // Server telling a client Lua needs to open a file + PT_ASKLUAFILE, // Client telling the server they don't have the file + PT_HASLUAFILE, // Client telling the server they have the file + // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL @@ -74,6 +76,8 @@ typedef enum // In addition, this packet can't occupy all the available slots. PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file. + PT_FILEACK, + PT_FILERECEIVED, PT_TEXTCMD, // Extra text commands from the client. PT_TEXTCMD2, // Splitscreen text commands. @@ -127,7 +131,7 @@ typedef struct // this packet is too large typedef struct { - UINT8 starttic; + tic_t starttic; UINT8 numtics; UINT8 numslots; // "Slots filled": Highest player number in use plus one. ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large @@ -170,6 +174,9 @@ typedef struct UINT32 pflags; // pflags_t UINT8 panim; // panim_t + INT16 angleturn; + INT16 oldrelangleturn; + angle_t aiming; INT32 currentweapon; INT32 ringweapons; @@ -187,7 +194,7 @@ typedef struct SINT8 xtralife; SINT8 pity; - UINT8 skincolor; + UINT16 skincolor; INT32 skin; UINT32 availabilities; // Just in case Lua does something like @@ -307,7 +314,7 @@ typedef struct // 0xFF == not in game; else player skin num UINT8 playerskins[MAXPLAYERS]; - UINT8 playercolor[MAXPLAYERS]; + UINT16 playercolor[MAXPLAYERS]; UINT32 playeravailabilities[MAXPLAYERS]; UINT8 gametype; @@ -319,13 +326,30 @@ typedef struct UINT8 varlengthinputs[0]; // Playernames and netvars } ATTRPACK serverconfig_pak; -typedef struct { +typedef struct +{ UINT8 fileid; + UINT32 filesize; + UINT8 iteration; UINT32 position; UINT16 size; UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH } ATTRPACK filetx_pak; +typedef struct +{ + UINT32 start; + UINT32 acks; +} ATTRPACK fileacksegment_t; + +typedef struct +{ + UINT8 fileid; + UINT8 iteration; + UINT8 numsegments; + fileacksegment_t segments[0]; +} ATTRPACK fileack_pak; + #ifdef _MSC_VER #pragma warning(default : 4200) #endif @@ -361,6 +385,7 @@ typedef struct UINT8 subversion; UINT8 numberofplayer; UINT8 maxplayer; + UINT8 refusereason; // 0: joinable, 1: joins disabled, 2: full char gametypename[24]; UINT8 modifiedgame; UINT8 cheatsenabled; @@ -412,7 +437,7 @@ typedef struct { char name[MAXPLAYERNAME+1]; UINT8 skin; - UINT8 color; + UINT16 color; UINT32 pflags; UINT32 score; UINT8 ctfteam; @@ -440,6 +465,8 @@ typedef struct UINT8 resynchgot; // UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) filetx_pak filetxpak; // 139 bytes + fileack_pak fileack; + UINT8 filereceived; clientconfig_pak clientcfg; // 136 bytes UINT8 md5sum[16]; serverinfo_pak serverinfo; // 1024 bytes @@ -513,12 +540,12 @@ extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; extern tic_t servermaxping; -extern consvar_t cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_rejointimeout; +extern consvar_t cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout; extern consvar_t cv_resynchattempts, cv_blamecfail; extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; // Used in d_net, the only dependence -tic_t ExpandTics(INT32 low); +tic_t ExpandTics(INT32 low, INT32 node); void D_ClientServerInit(void); // Initialise the other field @@ -532,7 +559,6 @@ void NetUpdate(void); void SV_StartSinglePlayerServer(void); boolean SV_SpawnServer(void); -void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle); void SV_StopServer(void); void SV_ResetServer(void); void CL_AddSplitscreenPlayer(void); diff --git a/src/d_event.h b/src/d_event.h index c61b9460a..3cce8fad1 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_main.c b/src/d_main.c index 1f35ff64c..28570b909 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -91,9 +91,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "hardware/hw3sound.h" #endif -#ifdef HAVE_BLUA #include "lua_script.h" -#endif // platform independant focus loss UINT8 window_notinfocus = false; @@ -127,6 +125,12 @@ boolean advancedemo; INT32 debugload = 0; #endif +UINT16 numskincolors; +menucolor_t *menucolorhead, *menucolortail; + +char savegamename[256]; +char liveeventbackup[256]; + char srb2home[256] = "."; char srb2path[256] = "."; boolean usehome = true; @@ -312,7 +316,9 @@ static void D_Display(void) F_WipeStartScreen(); // Check for Mega Genesis fade wipestyleflags = WSF_FADEOUT; - if (F_TryColormapFade(31)) + if (wipegamestate == (gamestate_t)FORCEWIPE) + F_WipeColorFill(31); + else if (F_TryColormapFade(31)) wipetypepost = -1; // Don't run the fade below this one F_WipeEndScreen(); F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); @@ -411,6 +417,7 @@ static void D_Display(void) if (!automapactive && !dedicated && cv_renderview.value) { + rs_rendercalltime = I_GetTimeMicros(); if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { topleft = screens[0] + viewwindowy*vid.width + viewwindowx; @@ -457,6 +464,7 @@ static void D_Display(void) if (postimgtype2) V_DoPostProcessor(1, postimgtype2, postimgparam2); } + rs_rendercalltime = I_GetTimeMicros() - rs_rendercalltime; } if (lastdraw) @@ -508,13 +516,11 @@ static void D_Display(void) // vid size change is now finished if it was on... vid.recalc = 0; - // FIXME: draw either console or menu, not the two - if (gamestate != GS_TIMEATTACK) - CON_Drawer(); - M_Drawer(); // menu is drawn even on top of everything // focus lost moved to M_Drawer + CON_Drawer(); + // // wipe update // @@ -593,23 +599,97 @@ static void D_Display(void) snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); } + + if (cv_renderstats.value) + { + char s[50]; + int frametime = I_GetTimeMicros() - rs_prevframetime; + int divisor = 1; + rs_prevframetime = I_GetTimeMicros(); + if (rs_rendercalltime > 10000) divisor = 1000; + + snprintf(s, sizeof s - 1, "ft %d", frametime / divisor); + V_DrawThinString(30, 10, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "rtot %d", rs_rendercalltime / divisor); + V_DrawThinString(30, 20, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "bsp %d", rs_bsptime / divisor); + V_DrawThinString(30, 30, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "nbsp %d", rs_numbspcalls); + V_DrawThinString(80, 10, V_MONOSPACE | V_BLUEMAP, s); + snprintf(s, sizeof s - 1, "nspr %d", rs_numsprites); + V_DrawThinString(80, 20, V_MONOSPACE | V_BLUEMAP, s); + snprintf(s, sizeof s - 1, "nnod %d", rs_numdrawnodes); + V_DrawThinString(80, 30, V_MONOSPACE | V_BLUEMAP, s); + snprintf(s, sizeof s - 1, "npob %d", rs_numpolyobjects); + V_DrawThinString(80, 40, V_MONOSPACE | V_BLUEMAP, s); + if (rendermode == render_opengl) // OpenGL specific stats + { + snprintf(s, sizeof s - 1, "nsrt %d", rs_hw_nodesorttime / divisor); + V_DrawThinString(30, 40, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "ndrw %d", rs_hw_nodedrawtime / divisor); + V_DrawThinString(30, 50, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "ssrt %d", rs_hw_spritesorttime / divisor); + V_DrawThinString(30, 60, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "sdrw %d", rs_hw_spritedrawtime / divisor); + V_DrawThinString(30, 70, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "fin %d", rs_swaptime / divisor); + V_DrawThinString(30, 80, V_MONOSPACE | V_YELLOWMAP, s); + if (cv_grbatching.value) + { + snprintf(s, sizeof s - 1, "bsrt %d", rs_hw_batchsorttime / divisor); + V_DrawThinString(80, 55, V_MONOSPACE | V_REDMAP, s); + snprintf(s, sizeof s - 1, "bdrw %d", rs_hw_batchdrawtime / divisor); + V_DrawThinString(80, 65, V_MONOSPACE | V_REDMAP, s); + + snprintf(s, sizeof s - 1, "npol %d", rs_hw_numpolys); + V_DrawThinString(130, 10, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "ndc %d", rs_hw_numcalls); + V_DrawThinString(130, 20, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "nshd %d", rs_hw_numshaders); + V_DrawThinString(130, 30, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "nvrt %d", rs_hw_numverts); + V_DrawThinString(130, 40, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "ntex %d", rs_hw_numtextures); + V_DrawThinString(185, 10, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "npf %d", rs_hw_numpolyflags); + V_DrawThinString(185, 20, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "ncol %d", rs_hw_numcolors); + V_DrawThinString(185, 30, V_MONOSPACE | V_PURPLEMAP, s); + } + } + else // software specific stats + { + snprintf(s, sizeof s - 1, "prtl %d", rs_sw_portaltime / divisor); + V_DrawThinString(30, 40, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "plns %d", rs_sw_planetime / divisor); + V_DrawThinString(30, 50, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "mskd %d", rs_sw_maskedtime / divisor); + V_DrawThinString(30, 60, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "fin %d", rs_swaptime / divisor); + V_DrawThinString(30, 70, V_MONOSPACE | V_YELLOWMAP, s); + } + } + + rs_swaptime = I_GetTimeMicros(); I_FinishUpdate(); // page flip or blit buffer + rs_swaptime = I_GetTimeMicros() - rs_swaptime; } needpatchflush = false; needpatchrecache = false; } -// Lactozilla: Check the renderer's state +// Check the renderer's state // after a possible renderer switch. void D_CheckRendererState(void) { // flush all patches from memory - // (also frees memory tagged with PU_CACHE) - // (which are not necessarily patches but I don't care) if (needpatchflush) + { Z_FlushCachedPatches(); + needpatchflush = false; + } // some patches have been freed, // so cache them again @@ -665,7 +745,7 @@ void D_SRB2Loop(void) */ /* Smells like a hack... Don't fade Sonic's ass into the title screen. */ if (gamestate != GS_TITLESCREEN) - V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE)); + V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_PATCH)); for (;;) { @@ -748,9 +828,7 @@ void D_SRB2Loop(void) HW3S_EndFrameUpdate(); #endif -#ifdef HAVE_BLUA LUA_Step(); -#endif } } @@ -819,6 +897,7 @@ void D_StartTitle(void) // In case someone exits out at the same time they start a time attack run, // reset modeattacking modeattacking = ATTACKING_NONE; + marathonmode = 0; // empty maptol so mario/etc sounds don't play in sound test when they shouldn't maptol = 0; @@ -882,6 +961,40 @@ static inline void D_CleanFile(void) } } +///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so. +/// Done because browsers (at least, Firefox on Windows) launch the game from the browser's directory, which causes problems. +static void ChangeDirForUrlHandler(void) +{ + // URL handlers are opened by web browsers (at least Firefox) from the browser's working directory, not the game's stored directory, + // so chdir to that directory unless overridden. + if (M_GetUrlProtocolArg() != NULL && !M_CheckParm("-nochdir")) + { + size_t i; + + CONS_Printf("%s connect links load game files from the SRB2 application's stored directory. Switching to ", SERVER_URL_PROTOCOL); + strlcpy(srb2path, myargv[0], sizeof(srb2path)); + + // Get just the directory, minus the EXE name + for (i = strlen(srb2path)-1; i > 0; i--) + { + if (srb2path[i] == '/' || srb2path[i] == '\\') + { + srb2path[i] = '\0'; + break; + } + } + + CONS_Printf("%s\n", srb2path); + +#if defined (_WIN32) + SetCurrentDirectoryA(srb2path); +#else + if (chdir(srb2path) == -1) + I_OutputMsg("Couldn't change working directory\n"); +#endif + } +} + // ========================================================================== // Identify the SRB2 version, and IWAD file to use. // ========================================================================== @@ -963,6 +1076,7 @@ static void IdentifyVersion(void) } MUSICTEST("music.dta") + MUSICTEST("patch_music.pk3") #ifdef DEVELOP // remove when music_new.dta is merged into music.dta MUSICTEST("music_new.dta") #endif @@ -1041,7 +1155,7 @@ void D_SRB2Main(void) // Print GPL notice for our console users (Linux) CONS_Printf( "\n\nSonic Robo Blast 2\n" - "Copyright (C) 1998-2019 by Sonic Team Junior\n\n" + "Copyright (C) 1998-2020 by Sonic Team Junior\n\n" "This program comes with ABSOLUTELY NO WARRANTY.\n\n" "This is free software, and you are welcome to redistribute it\n" "and/or modify it under the terms of the GNU General Public License\n" @@ -1070,6 +1184,9 @@ void D_SRB2Main(void) // Test Dehacked lists DEH_Check(); + // Netgame URL special case: change working dir to EXE folder. + ChangeDirForUrlHandler(); + // identify the main IWAD file to use IdentifyVersion(); @@ -1097,6 +1214,7 @@ void D_SRB2Main(void) // default savegame strcpy(savegamename, SAVEGAMENAME"%u.ssg"); + strcpy(liveeventbackup, "live"SAVEGAMENAME".bkp"); // intentionally not ending with .ssg { const char *userhome = D_Home(); //Alam: path to home @@ -1125,8 +1243,10 @@ void D_SRB2Main(void) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); + strcatbf(liveeventbackup, srb2home, PATHSEP); -#else + snprintf(luafiledir, sizeof luafiledir, "%s" PATHSEP "luafiles", srb2home); +#else // DEFAULTDIR snprintf(srb2home, sizeof srb2home, "%s", userhome); snprintf(downloaddir, sizeof downloaddir, "%s", userhome); if (dedicated) @@ -1136,7 +1256,10 @@ void D_SRB2Main(void) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, userhome, PATHSEP); -#endif + strcatbf(liveeventbackup, userhome, PATHSEP); + + snprintf(luafiledir, sizeof luafiledir, "%s" PATHSEP "luafiles", userhome); +#endif // DEFAULTDIR } configfile[sizeof configfile - 1] = '\0'; @@ -1148,13 +1271,26 @@ void D_SRB2Main(void) // rand() needs seeded regardless of password srand((unsigned int)time(NULL)); + rand(); + rand(); + rand(); if (M_CheckParm("-password") && M_IsNextParm()) D_SetPassword(M_GetNextParm()); + // player setup menu colors must be initialized before + // any wad file is added, as they may contain colors themselves + M_InitPlayerSetupColors(); + + CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); + Z_Init(); + + // Do this up here so that WADs loaded through the command line can use ExecCfg + COM_Init(); + // add any files specified on the command line with -file wadfile // to the wad list - if (!(M_CheckParm("-connect") && !M_CheckParm("-server"))) + if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server"))) { if (M_CheckParm("-file")) { @@ -1179,9 +1315,6 @@ void D_SRB2Main(void) if (M_CheckParm("-server") || dedicated) netgame = server = true; - CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); - Z_Init(); - // adapt tables to SRB2's needs, including extra slots for dehacked file support P_PatchInfoTables(); @@ -1189,7 +1322,7 @@ void D_SRB2Main(void) M_InitMenuPresTables(); // init title screen display params - if (M_CheckParm("-connect")) + if (M_GetUrlProtocolArg() || M_CheckParm("-connect")) F_InitMenuPresValues(); //---------------------------------------------------- READY TIME @@ -1215,14 +1348,14 @@ void D_SRB2Main(void) W_InitMultipleFiles(startupwadfiles, mainwads); D_CleanFile(); -#ifndef DEVELOP // md5s last updated 16/02/20 (ddmmyy) +#ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy) // Check MD5s of autoloaded files W_VerifyFileMD5(0, ASSET_HASH_SRB2_PK3); // srb2.pk3 W_VerifyFileMD5(1, ASSET_HASH_ZONES_PK3); // zones.pk3 W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta #ifdef USE_PATCH_DTA - W_VerifyFileMD5(3, ASSET_HASH_PATCH_DTA); // patch.pk3 + W_VerifyFileMD5(3, ASSET_HASH_PATCH_PK3); // 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. @@ -1230,20 +1363,6 @@ void D_SRB2Main(void) mainwadstally = packetsizetally; // technically not accurate atm, remember to port the two-stage -file process from kart in 2.2.x - if (M_CheckParm("-warp") && M_IsNextParm()) - { - const char *word = M_GetNextParm(); - pstartmap = G_FindMapByNameOrCode(word, 0); - if (! pstartmap) - I_Error("Cannot find a map remotely named '%s'\n", word); - else - { - if (!M_CheckParm("-server")) - G_SetGameModified(true); - autostart = true; - } - } - cht_Init(); //---------------------------------------------------- READY SCREEN @@ -1267,7 +1386,6 @@ void D_SRB2Main(void) CONS_Printf("HU_Init(): Setting up heads up display.\n"); HU_Init(); - COM_Init(); CON_Init(); D_RegisterServerCommands(); @@ -1292,13 +1410,19 @@ void D_SRB2Main(void) // Lactozilla: Does the render mode need to change? if ((setrenderneeded != 0) && (setrenderneeded != rendermode)) { - CONS_Printf("Switching the renderer...\n"); + CONS_Printf(M_GetText("Switching the renderer...\n")); + Z_PreparePatchFlush(); + + // set needpatchflush / needpatchrecache true for D_CheckRendererState needpatchflush = true; needpatchrecache = true; + + // Set cv_renderer to the new render mode VID_CheckRenderer(); - SCR_ChangeRendererCVars(setrenderneeded); + SCR_ChangeRendererCVars(rendermode); + + // check the renderer's state D_CheckRendererState(); - setrenderneeded = 0; } wipegamestate = gamestate; @@ -1307,6 +1431,23 @@ void D_SRB2Main(void) //------------------------------------------------ COMMAND LINE PARAMS + // this must be done after loading gamedata, + // to avoid setting off the corrupted gamedata code in G_LoadGameData if a SOC with custom gamedata is added + // -- Monster Iestyn 20/02/20 + if (M_CheckParm("-warp") && M_IsNextParm()) + { + const char *word = M_GetNextParm(); + pstartmap = G_FindMapByNameOrCode(word, 0); + if (! pstartmap) + I_Error("Cannot find a map remotely named '%s'\n", word); + else + { + if (!M_CheckParm("-server")) + G_SetGameModified(true); + autostart = true; + } + } + // Initialize CD-Audio if (M_CheckParm("-usecd") && !dedicated) I_InitCD(); diff --git a/src/d_main.h b/src/d_main.h index b0cd3cb88..81de0634d 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_net.c b/src/d_net.c index 573c9cfe9..2823ce219 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -715,6 +715,8 @@ void Net_CloseConnection(INT32 node) InitNode(&nodes[node]); SV_AbortSendFiles(node); + if (server) + SV_AbortLuaFileTransfer(node); I_NetFreeNodenum(node); #endif } @@ -799,12 +801,20 @@ static const char *packettypename[NUMPACKETTYPE] = "RESYNCHEND", "RESYNCHGET", + "SENDINGLUAFILE", + "ASKLUAFILE", + "HASLUAFILE", + "FILEFRAGMENT", + "FILEACK", + "FILERECEIVED", + "TEXTCMD", "TEXTCMD2", "CLIENTJOIN", "NODETIMEOUT", "RESYNCHING", + "LOGIN", "PING" }; @@ -831,7 +841,7 @@ static void DebugPrintpacket(const char *header) size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd; fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ", - (UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd)); + (UINT32)serverpak->starttic, serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd)); /// \todo Display more readable information about net commands fprintfstringnewline((char *)cmd, ntxtcmd); /*fprintfstring((char *)cmd, 3); @@ -850,8 +860,8 @@ static void DebugPrintpacket(const char *header) case PT_NODEKEEPALIVE: case PT_NODEKEEPALIVEMIS: fprintf(debugfile, " tic %4u resendfrom %u\n", - (UINT32)ExpandTics(netbuffer->u.clientpak.client_tic), - (UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom)); + (UINT32)ExpandTics(netbuffer->u.clientpak.client_tic, doomcom->remotenode), + (UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom, doomcom->remotenode)); break; case PT_TEXTCMD: case PT_TEXTCMD2: diff --git a/src/d_net.h b/src/d_net.h index c6fe4a27f..ed4f66284 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 623a83c47..b5ebad6d6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,7 +22,7 @@ #include "g_input.h" #include "m_menu.h" #include "r_local.h" -#include "r_things.h" +#include "r_skins.h" #include "p_local.h" #include "p_setup.h" #include "s_sound.h" @@ -157,10 +157,8 @@ static void Command_Isgamemodified_f(void); static void Command_Cheats_f(void); #ifdef _DEBUG static void Command_Togglemodified_f(void); -#ifdef HAVE_BLUA static void Command_Archivetest_f(void); #endif -#endif // ========================================================================= // CLIENT VARIABLES @@ -227,6 +225,7 @@ consvar_t cv_allowseenames = {"allowseenames", "Yes", CV_NETVAR, CV_YesNo, NULL, consvar_t cv_playername = {"name", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_playername2 = {"name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange, 0, NULL, NULL, 0, 0, NULL}; // player colors +UINT16 lastgoodcolor = SKINCOLOR_BLUE, lastgoodcolor2 = SKINCOLOR_BLUE; consvar_t cv_playercolor = {"color", "Blue", CV_CALL|CV_NOINIT, Color_cons_t, Color_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_playercolor2 = {"color2", "Orange", CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange, 0, NULL, NULL, 0, 0, NULL}; // player's skin, saved for commodity, when using a favorite skins wad.. @@ -415,10 +414,9 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "DELFILE", // replace next time we add an XD "SETMOTD", "SUICIDE", -#ifdef HAVE_BLUA "LUACMD", - "LUAVAR" -#endif + "LUAVAR", + "LUAFILE" }; // ========================================================================= @@ -451,9 +449,8 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_PAUSE, Got_Pause); RegisterNetXCmd(XD_SUICIDE, Got_Suicide); RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd); -#ifdef HAVE_BLUA RegisterNetXCmd(XD_LUACMD, Got_Luacmd); -#endif + RegisterNetXCmd(XD_LUAFILE, Got_LuaFile); // Remote Administration COM_AddCommand("password", Command_Changepassword_f); @@ -502,10 +499,10 @@ void D_RegisterServerCommands(void) COM_AddCommand("cheats", Command_Cheats_f); // test #ifdef _DEBUG COM_AddCommand("togglemodified", Command_Togglemodified_f); -#ifdef HAVE_BLUA COM_AddCommand("archivetest", Command_Archivetest_f); #endif -#endif + + COM_AddCommand("downloads", Command_Downloads_f); // for master server connection AddMServCommands(); @@ -579,6 +576,7 @@ void D_RegisterServerCommands(void) // d_clisrv CV_RegisterVar(&cv_maxplayers); + CV_RegisterVar(&cv_joindelay); CV_RegisterVar(&cv_rejointimeout); CV_RegisterVar(&cv_resynchattempts); CV_RegisterVar(&cv_maxsend); @@ -624,7 +622,7 @@ void D_RegisterClientCommands(void) for (i = 0; i < MAXSKINCOLORS; i++) { Color_cons_t[i].value = i; - Color_cons_t[i].strvalue = Color_Names[i]; + Color_cons_t[i].strvalue = skincolors[i].name; } Color_cons_t[MAXSKINCOLORS].value = 0; Color_cons_t[MAXSKINCOLORS].strvalue = NULL; @@ -913,7 +911,7 @@ void D_RegisterClientCommands(void) #ifdef _DEBUG COM_AddCommand("causecfail", Command_CauseCfail_f); #endif -#if defined(HAVE_BLUA) && defined(LUA_ALLOW_BYTECODE) +#ifdef LUA_ALLOW_BYTECODE COM_AddCommand("dumplua", Command_Dumplua_f); #endif } @@ -1158,7 +1156,7 @@ UINT8 CanChangeSkin(INT32 playernum) // Server has skin change restrictions. if (cv_restrictskinchange.value) { - if (gametype == GT_COOP) + if (gametyperules & GTR_FRIENDLY) return true; // Can change skin during initial countdown. @@ -1226,15 +1224,20 @@ static void SendNameAndColor(void) CV_StealthSetValue(&cv_playercolor, skincolor_blueteam); } - // never allow the color "none" - if (!cv_playercolor.value) + // don't allow inaccessible colors + if (!skincolors[cv_playercolor.value].accessible) { - if (players[consoleplayer].skincolor) + if (players[consoleplayer].skincolor && skincolors[players[consoleplayer].skincolor].accessible) CV_StealthSetValue(&cv_playercolor, players[consoleplayer].skincolor); - else if (skins[players[consoleplayer].skin].prefcolor) - CV_StealthSetValue(&cv_playercolor, skins[players[consoleplayer].skin].prefcolor); - else + else if (skincolors[atoi(cv_playercolor.defaultvalue)].accessible) CV_StealthSet(&cv_playercolor, cv_playercolor.defaultvalue); + else if (skins[players[consoleplayer].skin].prefcolor && skincolors[skins[players[consoleplayer].skin].prefcolor].accessible) + CV_StealthSetValue(&cv_playercolor, skins[players[consoleplayer].skin].prefcolor); + else { + UINT16 i = 0; + while (icolor = players[consoleplayer].skincolor; if (metalrecording) @@ -1281,10 +1284,10 @@ static void SendNameAndColor(void) { CV_StealthSetValue(&cv_playercolor, skins[cv_skin.value].prefcolor); - players[consoleplayer].skincolor = cv_playercolor.value % MAXSKINCOLORS; + players[consoleplayer].skincolor = cv_playercolor.value % numskincolors; if (players[consoleplayer].mo) - players[consoleplayer].mo->color = (UINT8)players[consoleplayer].skincolor; + players[consoleplayer].mo->color = (UINT16)players[consoleplayer].skincolor; }*/ } else @@ -1322,7 +1325,7 @@ static void SendNameAndColor(void) // Finally write out the complete packet and send it off. WRITESTRINGN(p, cv_playername.zstring, MAXPLAYERNAME); WRITEUINT32(p, (UINT32)players[consoleplayer].availabilities); - WRITEUINT8(p, (UINT8)cv_playercolor.value); + WRITEUINT16(p, (UINT16)cv_playercolor.value); WRITEUINT8(p, (UINT8)cv_skin.value); SendNetXCmd(XD_NAMEANDCOLOR, buf, p - buf); } @@ -1349,15 +1352,20 @@ static void SendNameAndColor2(void) CV_StealthSetValue(&cv_playercolor2, skincolor_blueteam); } - // never allow the color "none" - if (!cv_playercolor2.value) + // don't allow inaccessible colors + if (!skincolors[cv_playercolor2.value].accessible) { - if (players[secondplaya].skincolor) + if (players[secondplaya].skincolor && skincolors[players[secondplaya].skincolor].accessible) CV_StealthSetValue(&cv_playercolor2, players[secondplaya].skincolor); - else if (skins[players[secondplaya].skin].prefcolor) + else if (skincolors[atoi(cv_playercolor2.defaultvalue)].accessible) + CV_StealthSet(&cv_playercolor, cv_playercolor2.defaultvalue); + else if (skins[players[secondplaya].skin].prefcolor && skincolors[skins[players[secondplaya].skin].prefcolor].accessible) CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor); - else - CV_StealthSet(&cv_playercolor2, cv_playercolor2.defaultvalue); + else { + UINT16 i = 0; + while (icolor = players[secondplaya].skincolor; + SetPlayerSkinByNum(secondplaya, botskin-1); return; } @@ -1384,7 +1393,7 @@ static void SendNameAndColor2(void) // don't use secondarydisplayplayer: the second player must be 1 players[secondplaya].skincolor = cv_playercolor2.value; - if (players[secondplaya].mo) + if (players[secondplaya].mo && !players[secondplaya].powers[pw_dye]) players[secondplaya].mo->color = players[secondplaya].skincolor; if (cv_forceskin.value >= 0 && (netgame || multiplayer)) // Server wants everyone to use the same player @@ -1409,7 +1418,7 @@ static void SendNameAndColor2(void) { CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor); - players[secondplaya].skincolor = cv_playercolor2.value % MAXSKINCOLORS; + players[secondplaya].skincolor = cv_playercolor2.value % numskincolors; if (players[secondplaya].mo) players[secondplaya].mo->color = players[secondplaya].skincolor; @@ -1432,7 +1441,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) { player_t *p = &players[playernum]; char name[MAXPLAYERNAME+1]; - UINT8 color, skin; + UINT16 color; + UINT8 skin; #ifdef PARANOIA if (playernum < 0 || playernum > MAXPLAYERS) @@ -1451,7 +1461,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) READSTRINGN(*cp, name, MAXPLAYERNAME); p->availabilities = READUINT32(*cp); - color = READUINT8(*cp); + color = READUINT16(*cp); skin = READUINT8(*cp); // set name @@ -1459,9 +1469,9 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) SetPlayerName(playernum, name); // set color - p->skincolor = color % MAXSKINCOLORS; + p->skincolor = color % numskincolors; if (p->mo) - p->mo->color = (UINT8)p->skincolor; + p->mo->color = (UINT16)p->skincolor; // normal player colors if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer])) @@ -1478,8 +1488,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) kick = true; } - // don't allow color "none" - if (!p->skincolor) + // don't allow inaccessible colors + if (skincolors[p->skincolor].accessible == false) kick = true; // availabilities @@ -1737,7 +1747,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese } CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene); - if ((netgame || multiplayer) && !((gametype == newgametype) && (newgametype == GT_COOP))) + if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN))) FLS = false; if (delay != 2) @@ -1979,7 +1989,7 @@ static void Command_Map_f(void) fromlevelselect = ( netgame || multiplayer ) && newgametype == gametype && - newgametype == GT_COOP; + gametypedefaultrules[newgametype] & GTR_CAMPAIGN; } } @@ -2027,9 +2037,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) UINT8 flags; INT32 resetplayer = 1, lastgametype; UINT8 skipprecutscene, FLS; -#ifdef HAVE_BLUA INT16 mapnumber; -#endif if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -2091,10 +2099,8 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) CV_StealthSetValue(&cv_playercolor, players[0].skincolor); } -#ifdef HAVE_BLUA mapnumber = M_MapNumber(mapname[3], mapname[4]); LUAh_MapChange(mapnumber); -#endif G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene, FLS); if (demoplayback && !timingdemo) @@ -2678,11 +2684,9 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) return; } -#ifdef HAVE_BLUA // Don't switch team, just go away, please, go awaayyyy, aaauuauugghhhghgh if (!LUAh_TeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled)) return; -#endif //no status changes after hidetime if ((gametyperules & GTR_HIDEFROZEN) && (leveltime >= (hidetime * TICRATE))) @@ -2775,7 +2779,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) players[playernum].spectator = false; //If joining after hidetime in normal tag, default to being IT. - if (gametype == GT_TAG && (leveltime > (hidetime * TICRATE))) + if (((gametyperules & (GTR_TAG|GTR_HIDEFROZEN)) == GTR_TAG) && (leveltime > (hidetime * TICRATE))) { NetPacket.packet.newteam = 1; //minor hack, causes the "is it" message to be printed later. players[playernum].pflags |= PF_TAGIT; //make the player IT. @@ -2839,12 +2843,10 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) //reset view if you are changed, or viewing someone who was changed. if (playernum == consoleplayer || displayplayer == playernum) { -#ifdef HAVE_BLUA // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. if (displayplayer != consoleplayer) // You're already viewing yourself. No big deal. - LUAh_ViewpointSwitch(&players[playernum], &players[displayplayer], true); -#endif + LUAh_ViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -3342,10 +3344,6 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) boolean kick = false; boolean toomany = false; INT32 i,j; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; READSTRINGN(*cp, filename, 240); READMEM(*cp, md5sum, 16); @@ -3572,6 +3570,8 @@ static void Command_Playintro_f(void) */ FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void) { + if (Playing()) + LUAh_GameQuit(); I_Quit(); } @@ -3629,7 +3629,7 @@ static void PointLimit_OnChange(void) static void NumLaps_OnChange(void) { // Just don't be verbose - if (gametype == GT_RACE) + if ((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) CONS_Printf(M_GetText("Number of laps set to %d\n"), cv_numlaps.value); } @@ -3743,7 +3743,7 @@ static void ExitMove_OnChange(void) { UINT8 i; - if (!(netgame || multiplayer) || gametype != GT_COOP) + if (!(netgame || multiplayer) || !(gametyperules & GTR_FRIENDLY)) return; if (cv_exitmove.value) @@ -3753,11 +3753,11 @@ static void ExitMove_OnChange(void) { if (players[i].mo->target && players[i].mo->target->type == MT_SIGN) P_SetTarget(&players[i].mo->target, NULL); - + if (players[i].pflags & PF_FINISHED) P_GiveFinishFlags(&players[i]); } - + CONS_Printf(M_GetText("Players can now move after completing the level.\n")); } else @@ -4233,6 +4233,9 @@ void Command_ExitGame_f(void) { INT32 i; + if (Playing()) + LUAh_GameQuit(); + D_QuitNetGame(); CL_Reset(); CV_ClearChangedFlags(); @@ -4334,7 +4337,6 @@ static void Command_Togglemodified_f(void) modifiedgame = !modifiedgame; } -#ifdef HAVE_BLUA extern UINT8 *save_p; static void Command_Archivetest_f(void) { @@ -4379,7 +4381,6 @@ static void Command_Archivetest_f(void) CONS_Printf("Done. No crash.\n"); } #endif -#endif /** Makes a change to ::cv_forceskin take effect immediately. * @@ -4491,25 +4492,30 @@ static void Skin2_OnChange(void) */ static void Color_OnChange(void) { - if (!Playing()) - return; // do whatever you want - - if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player. - { - CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); - return; - } - - if (!P_PlayerMoving(consoleplayer)) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(); + if (!Playing()) { + if (!cv_playercolor.value || !skincolors[cv_playercolor.value].accessible) + CV_StealthSetValue(&cv_playercolor, lastgoodcolor); } else { - CV_StealthSetValue(&cv_playercolor, - players[consoleplayer].skincolor); + if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player. + { + CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); + return; + } + + if (!P_PlayerMoving(consoleplayer) && skincolors[players[consoleplayer].skincolor].accessible == true) + { + // Color change menu scrolling fix is no longer necessary + SendNameAndColor(); + } + else + { + CV_StealthSetValue(&cv_playercolor, + players[consoleplayer].skincolor); + } } + lastgoodcolor = cv_playercolor.value; } /** Sends a color change for the secondary splitscreen player, unless that @@ -4520,18 +4526,24 @@ static void Color_OnChange(void) static void Color2_OnChange(void) { if (!Playing() || !splitscreen) - return; // do whatever you want - - if (!P_PlayerMoving(secondarydisplayplayer)) { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor2(); + if (!cv_playercolor2.value || !skincolors[cv_playercolor2.value].accessible) + CV_StealthSetValue(&cv_playercolor2, lastgoodcolor2); } else { - CV_StealthSetValue(&cv_playercolor2, - players[secondarydisplayplayer].skincolor); + if (!P_PlayerMoving(secondarydisplayplayer) && skincolors[players[secondarydisplayplayer].skincolor].accessible == true) + { + // Color change menu scrolling fix is no longer necessary + SendNameAndColor2(); + } + else + { + CV_StealthSetValue(&cv_playercolor2, + players[secondarydisplayplayer].skincolor); + } } + lastgoodcolor2 = cv_playercolor2.value; } /** Displays the result of the chat being muted or unmuted. @@ -4608,7 +4620,7 @@ static void Command_ShowTime_f(void) static void BaseNumLaps_OnChange(void) { - if (gametype == GT_RACE) + if ((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) { if (cv_basenumlaps.value) CONS_Printf(M_GetText("Number of laps will be changed to map defaults next round.\n")); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index f258cde62..897c28968 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -142,10 +142,9 @@ typedef enum XD_SETMOTD, // 19 XD_SUICIDE, // 20 XD_DEMOTED, // 21 -#ifdef HAVE_BLUA XD_LUACMD, // 22 XD_LUAVAR, // 23 -#endif + XD_LUAFILE, // 24 MAXNETXCMD } netxcmd_t; diff --git a/src/d_netfil.c b/src/d_netfil.c index 93b4b1990..8f661bb5f 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -56,7 +56,7 @@ #include // Prototypes -static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid); +static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid); // Sender structure typedef struct filetx_s @@ -76,8 +76,13 @@ typedef struct filetx_s typedef struct filetran_s { filetx_t *txlist; // Linked list of all files for the node + UINT8 iteration; + UINT8 ackediteration; UINT32 position; // The current position in the file + boolean *ackedfragments; + UINT32 ackedsize; FILE *currentfile; // The file currently being sent/received + tic_t dontsenduntil; } filetran_t; static filetran_t transfer[MAXNETNODES]; @@ -87,13 +92,31 @@ static filetran_t transfer[MAXNETNODES]; // Receiver structure INT32 fileneedednum; // Number of files needed to join the server fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files +static tic_t lasttimeackpacketsent = 0; char downloaddir[512] = "DOWNLOAD"; -#ifdef CLIENT_LOADINGSCREEN +// For resuming failed downloads +typedef struct +{ + char filename[MAX_WADPATH]; + UINT8 md5sum[16]; + boolean *receivedfragments; + UINT32 fragmentsize; + UINT32 currentsize; +} pauseddownload_t; +static pauseddownload_t *pauseddownload = NULL; + +#ifndef NONET // for cl loading screen INT32 lastfilenum = -1; #endif +luafiletransfer_t *luafiletransfers = NULL; +boolean waitingforluafiletransfer = false; +boolean waitingforluafilecommand = false; +char luafiledir[256 + 16] = "luafiles"; + + /** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. @@ -153,6 +176,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) for (i = 0; i < fileneedednum; i++) { fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet + fileneeded[i].justdownloaded = false; filestatus = READUINT8(p); // The first byte is the file status fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size @@ -164,8 +188,13 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) void CL_PrepareDownloadSaveGame(const char *tmpsave) { +#ifndef NONET + lastfilenum = -1; +#endif + fileneedednum = 1; fileneeded[0].status = FS_REQUESTED; + fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; fileneeded[0].file = NULL; memset(fileneeded[0].md5sum, 0, 16); @@ -238,6 +267,31 @@ boolean CL_CheckDownloadable(void) return false; } +/** Returns true if a needed file transfer can be resumed + * + * \param file The needed file to resume the transfer for + * \return True if the transfer can be resumed + * + */ +static boolean CL_CanResumeDownload(fileneeded_t *file) +{ + return pauseddownload + && !strcmp(pauseddownload->filename, file->filename) // Same name + && !memcmp(pauseddownload->md5sum, file->md5sum, 16) // Same checksum + && pauseddownload->fragmentsize == file->fragmentsize; // Same fragment size +} + +void CL_AbortDownloadResume(void) +{ + if (!pauseddownload) + return; + + free(pauseddownload->receivedfragments); + remove(pauseddownload->filename); + free(pauseddownload); + pauseddownload = NULL; +} + /** Sends requests for files in the ::fileneeded table with a status of * ::FS_NOTFOUND. * @@ -245,7 +299,7 @@ boolean CL_CheckDownloadable(void) * \note Sends a PT_REQUESTFILE packet * */ -boolean CL_SendRequestFile(void) +boolean CL_SendFileRequest(void) { char *p; INT32 i; @@ -290,7 +344,7 @@ boolean CL_SendRequestFile(void) // get request filepak and put it on the send queue // returns false if a requested file was not found or cannot be sent -boolean Got_RequestFilePak(INT32 node) +boolean PT_RequestFile(INT32 node) { char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; @@ -301,7 +355,7 @@ boolean Got_RequestFilePak(INT32 node) if (id == 0xFF) break; READSTRINGN(p, wad, MAX_WADPATH); - if (!SV_SendFile(node, wad, id)) + if (!AddFileToSendQueue(node, wad, id)) { SV_AbortSendFiles(node); return false; // don't read the rest of the files @@ -448,6 +502,196 @@ void CL_LoadServerFiles(void) } } +void AddLuaFileTransfer(const char *filename, const char *mode) +{ + luafiletransfer_t **prevnext; // A pointer to the "next" field of the last transfer in the list + luafiletransfer_t *filetransfer; + static INT32 id; + + // Find the last transfer in the list and set a pointer to its "next" field + prevnext = &luafiletransfers; + while (*prevnext) + prevnext = &((*prevnext)->next); + + // Allocate file transfer information and append it to the transfer list + filetransfer = malloc(sizeof(luafiletransfer_t)); + if (!filetransfer) + I_Error("AddLuaFileTransfer: Out of memory\n"); + *prevnext = filetransfer; + filetransfer->next = NULL; + + // Allocate the file name + filetransfer->filename = strdup(filename); + if (!filetransfer->filename) + I_Error("AddLuaFileTransfer: Out of memory\n"); + + // Create and allocate the real file name + if (server) + filetransfer->realfilename = strdup(va("%s" PATHSEP "%s", + luafiledir, filename)); + else + filetransfer->realfilename = strdup(va("%s" PATHSEP "client" PATHSEP "$$$%d%d.tmp", + luafiledir, rand(), rand())); + if (!filetransfer->realfilename) + I_Error("AddLuaFileTransfer: Out of memory\n"); + + strlcpy(filetransfer->mode, mode, sizeof(filetransfer->mode)); + + // Only if there is no transfer already going on + if (server && filetransfer == luafiletransfers) + SV_PrepareSendLuaFile(); + else + filetransfer->ongoing = false; + + // Store the callback so it can be called once everyone has the file + filetransfer->id = id; + StoreLuaFileCallback(id); + id++; + + if (waitingforluafiletransfer) + { + waitingforluafiletransfer = false; + CL_PrepareDownloadLuaFile(); + } +} + +static void SV_PrepareSendLuaFileToNextNode(void) +{ + INT32 i; + UINT8 success = 1; + + // Find a client to send the file to + for (i = 1; i < MAXNETNODES; i++) + if (nodeingame[i] && luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting + { + // Tell the client we're about to send them the file + netbuffer->packettype = PT_SENDINGLUAFILE; + if (!HSendPacket(i, true, 0, 0)) + I_Error("Failed to send a PT_SENDINGLUAFILE packet\n"); // !!! Todo: Handle failure a bit better lol + + luafiletransfers->nodestatus[i] = LFTNS_ASKED; + + return; + } + + // No client found, everyone has the file + // Send a net command with 1 as its first byte to indicate the file could be opened + SendNetXCmd(XD_LUAFILE, &success, 1); +} + +void SV_PrepareSendLuaFile(void) +{ + char *binfilename; + INT32 i; + + luafiletransfers->ongoing = true; + + // Set status to "waiting" for everyone + for (i = 0; i < MAXNETNODES; i++) + luafiletransfers->nodestatus[i] = LFTNS_WAITING; + + if (FIL_ReadFileOK(luafiletransfers->realfilename)) + { + // If opening in text mode, convert all newlines to LF + if (!strchr(luafiletransfers->mode, 'b')) + { + binfilename = strdup(va("%s" PATHSEP "$$$%d%d.tmp", + luafiledir, rand(), rand())); + if (!binfilename) + I_Error("SV_PrepareSendLuaFile: Out of memory\n"); + + if (!FIL_ConvertTextFileToBinary(luafiletransfers->realfilename, binfilename)) + I_Error("SV_PrepareSendLuaFile: Failed to convert file newlines\n"); + + // Use the temporary file instead + free(luafiletransfers->realfilename); + luafiletransfers->realfilename = binfilename; + } + + SV_PrepareSendLuaFileToNextNode(); + } + else + { + // Send a net command with 0 as its first byte to indicate the file couldn't be opened + UINT8 success = 0; + SendNetXCmd(XD_LUAFILE, &success, 1); + } +} + +void SV_HandleLuaFileSent(UINT8 node) +{ + luafiletransfers->nodestatus[node] = LFTNS_SENT; + SV_PrepareSendLuaFileToNextNode(); +} + +void RemoveLuaFileTransfer(void) +{ + luafiletransfer_t *filetransfer = luafiletransfers; + + // If it was a temporary file, delete it + if (server && !strchr(filetransfer->mode, 'b')) + remove(filetransfer->realfilename); + + RemoveLuaFileCallback(filetransfer->id); + + luafiletransfers = filetransfer->next; + + free(filetransfer->filename); + free(filetransfer->realfilename); + free(filetransfer); +} + +void RemoveAllLuaFileTransfers(void) +{ + while (luafiletransfers) + RemoveLuaFileTransfer(); +} + +void SV_AbortLuaFileTransfer(INT32 node) +{ + if (luafiletransfers + && (luafiletransfers->nodestatus[node] == LFTNS_ASKED + || luafiletransfers->nodestatus[node] == LFTNS_SENDING)) + { + luafiletransfers->nodestatus[node] = LFTNS_WAITING; + SV_PrepareSendLuaFileToNextNode(); + } +} + +void CL_PrepareDownloadLuaFile(void) +{ + // If there is no transfer in the list, this normally means the server + // called io.open before us, so we have to wait until we call it too + if (!luafiletransfers) + { + waitingforluafiletransfer = true; + return; + } + + if (luafiletransfers->ongoing) + { + waitingforluafilecommand = true; + return; + } + + // Tell the server we are ready to receive the file + netbuffer->packettype = PT_ASKLUAFILE; + HSendPacket(servernode, true, 0, 0); + + fileneedednum = 1; + fileneeded[0].status = FS_REQUESTED; + fileneeded[0].justdownloaded = false; + fileneeded[0].totalsize = UINT32_MAX; + fileneeded[0].file = NULL; + memset(fileneeded[0].md5sum, 0, 16); + strcpy(fileneeded[0].filename, luafiletransfers->realfilename); + + // Make sure all directories in the file path exist + MakePathDirs(fileneeded[0].filename); + + luafiletransfers->ongoing = true; +} + // Number of files to send // Little optimization to quickly test if there is a file in the queue static INT32 filestosend = 0; @@ -456,11 +700,12 @@ static INT32 filestosend = 0; * * \param node The node to send the file to * \param filename The file to send - * \param fileid ??? - * \sa SV_SendRam + * \param fileid The index of the file in the list of added files + * \sa AddRamToSendQueue + * \sa AddLuaFileToSendQueue * */ -static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) +static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request @@ -478,7 +723,7 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) // Allocate a file request and append it to the file list p = *q = (filetx_t *)malloc(sizeof (filetx_t)); if (!p) - I_Error("SV_SendFile: No more memory\n"); + I_Error("AddFileToSendQueue: No more memory\n"); // Initialise with zeros memset(p, 0, sizeof (filetx_t)); @@ -486,7 +731,7 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) // Allocate the file name p->id.filename = (char *)malloc(MAX_WADPATH); if (!p->id.filename) - I_Error("SV_SendFile: No more memory\n"); + I_Error("AddFileToSendQueue: No more memory\n"); // Set the file name and get rid of the path strlcpy(p->id.filename, filename, MAX_WADPATH); @@ -546,11 +791,12 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) * \param data The memory block to send * \param size The size of the block in bytes * \param freemethod How to free the block after it has been sent - * \param fileid ??? - * \sa SV_SendFile + * \param fileid The index of the file in the list of added files + * \sa AddFileToSendQueue + * \sa AddLuaFileToSendQueue * */ -void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid) +void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request @@ -563,7 +809,7 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UI // Allocate a file request and append it to the file list p = *q = (filetx_t *)malloc(sizeof (filetx_t)); if (!p) - I_Error("SV_SendRam: No more memory\n"); + I_Error("AddRamToSendQueue: No more memory\n"); // Initialise with zeros memset(p, 0, sizeof (filetx_t)); @@ -579,6 +825,52 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UI filestosend++; } +/** Adds a file requested by Lua to the file list for a node + * + * \param node The node to send the file to + * \param filename The file to send + * \sa AddFileToSendQueue + * \sa AddRamToSendQueue + * + */ +boolean AddLuaFileToSendQueue(INT32 node, const char *filename) +{ + filetx_t **q; // A pointer to the "next" field of the last file in the list + filetx_t *p; // The new file request + //INT32 i; + //char wadfilename[MAX_WADPATH]; + + luafiletransfers->nodestatus[node] = LFTNS_SENDING; + + // Find the last file in the list and set a pointer to its "next" field + q = &transfer[node].txlist; + while (*q) + q = &((*q)->next); + + // Allocate a file request and append it to the file list + p = *q = (filetx_t *)malloc(sizeof (filetx_t)); + if (!p) + I_Error("AddLuaFileToSendQueue: No more memory\n"); + + // Initialise with zeros + memset(p, 0, sizeof (filetx_t)); + + // Allocate the file name + p->id.filename = (char *)malloc(MAX_WADPATH); // !!! + if (!p->id.filename) + I_Error("AddLuaFileToSendQueue: No more memory\n"); + + // Set the file name and get rid of the path + strlcpy(p->id.filename, filename, MAX_WADPATH); // !!! + //nameonly(p->id.filename); + + DEBFILE(va("Sending Lua file %s to %d\n", filename, node)); + p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it + p->next = NULL; // End of list + filestosend++; + return true; +} + /** Stops sending a file for a node, and removes the file request from the list, * either because the file has been fully sent or because the node was disconnected * @@ -589,7 +881,8 @@ static void SV_EndFileSend(INT32 node) { filetx_t *p = transfer[node].txlist; - // Free the file request according to the freemethod parameter used with SV_SendFile/Ram + // Free the file request according to the freemethod + // parameter used with AddFileToSendQueue/AddRamToSendQueue switch (p->ram) { case SF_FILE: // It's a file, close it and free its filename @@ -614,43 +907,32 @@ static void SV_EndFileSend(INT32 node) // Indicate that the transmission is over transfer[node].currentfile = NULL; + if (transfer[node].ackedfragments) + free(transfer[node].ackedfragments); + transfer[node].ackedfragments = NULL; filestosend--; } #define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH) +#define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE)) /** Handles file transmission - * - * \todo Use an acknowledging method more adapted to file transmission - * The current download speed suffers from lack of ack packets, - * especially when the one downloading has high latency * */ -void SV_FileSendTicker(void) +void FileSendTicker(void) { static INT32 currentnode = 0; filetx_pak *p; - size_t size; + size_t fragmentsize; filetx_t *f; INT32 packetsent, ram, i, j; - INT32 maxpacketsent; if (!filestosend) // No file to send return; - if (cv_downloadspeed.value) // New (and experimental) behavior - { + if (cv_downloadspeed.value) // New behavior packetsent = cv_downloadspeed.value; - // Don't send more packets than we have free acks -#ifndef NONET - maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case -#else - maxpacketsent = 1; -#endif - if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet - packetsent = maxpacketsent; - } else // Old behavior { packetsent = PACKETPERTIC; @@ -667,11 +949,12 @@ void SV_FileSendTicker(void) i = (i+1) % MAXNETNODES, j++) { if (transfer[i].txlist) - goto found; + break; } // no transfer to do - I_Error("filestosend=%d but no file to send found\n", filestosend); - found: + if (j >= MAXNETNODES) + I_Error("filestosend=%d but no file to send found\n", filestosend); + currentnode = (i+1) % MAXNETNODES; f = transfer[i].txlist; ram = f->ram; @@ -705,48 +988,232 @@ void SV_FileSendTicker(void) } else // Sending RAM transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open + + transfer[i].iteration = 1; + transfer[i].ackediteration = 0; transfer[i].position = 0; + transfer[i].ackedsize = 0; + + transfer[i].ackedfragments = calloc(f->size / FILEFRAGMENTSIZE + 1, sizeof(*transfer[i].ackedfragments)); + if (!transfer[i].ackedfragments) + I_Error("FileSendTicker: No more memory\n"); + + transfer[i].dontsenduntil = 0; + } + + // If the client hasn't acknowledged any fragment from the previous iteration, + // it is most likely because their acks haven't had enough time to reach the server + // yet, due to latency. In that case, we wait a little to avoid useless resend. + if (I_GetTime() < transfer[i].dontsenduntil) + continue; + + // Find the first non-acknowledged fragment + while (transfer[i].ackedfragments[transfer[i].position / FILEFRAGMENTSIZE]) + { + transfer[i].position += FILEFRAGMENTSIZE; + if (transfer[i].position >= f->size) + { + if (transfer[i].ackediteration < transfer[i].iteration) + transfer[i].dontsenduntil = I_GetTime() + TICRATE / 2; + + transfer[i].position = 0; + transfer[i].iteration++; + } } // Build a packet containing a file fragment p = &netbuffer->u.filetxpak; - size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE); - if (f->size-transfer[i].position < size) - size = f->size-transfer[i].position; + fragmentsize = FILEFRAGMENTSIZE; + if (f->size-transfer[i].position < fragmentsize) + fragmentsize = f->size-transfer[i].position; if (ram) - M_Memcpy(p->data, &f->id.ram[transfer[i].position], size); - else if (fread(p->data, 1, size, transfer[i].currentfile) != size) - I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); + M_Memcpy(p->data, &f->id.ram[transfer[i].position], fragmentsize); + else + { + fseek(transfer[i].currentfile, transfer[i].position, SEEK_SET); + + if (fread(p->data, 1, fragmentsize, transfer[i].currentfile) != fragmentsize) + I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(fragmentsize), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); + } + p->iteration = transfer[i].iteration; p->position = LONG(transfer[i].position); - // Put flag so receiver knows the total size - if (transfer[i].position + size == f->size) - p->position |= LONG(0x80000000); p->fileid = f->fileid; - p->size = SHORT((UINT16)size); + p->filesize = LONG(f->size); + p->size = SHORT((UINT16)FILEFRAGMENTSIZE); // Send the packet - if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND + if (HSendPacket(i, false, 0, FILETXHEADER + fragmentsize)) // Don't use the default acknowledgement system { // Success - transfer[i].position = (UINT32)(transfer[i].position + size); - if (transfer[i].position == f->size) // Finish? - SV_EndFileSend(i); + transfer[i].position = (UINT32)(transfer[i].position + fragmentsize); + if (transfer[i].position >= f->size) + { + if (transfer[i].ackediteration < transfer[i].iteration) + transfer[i].dontsenduntil = I_GetTime() + TICRATE / 2; + + transfer[i].position = 0; + transfer[i].iteration++; + } } else { // Not sent for some odd reason, retry at next call - if (!ram) - fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET); // Exit the while (can't send this one so why should i send the next?) break; } } } -void Got_Filetxpak(void) +void PT_FileAck(void) +{ + fileack_pak *packet = &netbuffer->u.fileack; + INT32 node = doomcom->remotenode; + filetran_t *trans = &transfer[node]; + INT32 i, j; + + // Wrong file id? Ignore it, it's probably a late packet + if (!(trans->txlist && packet->fileid == trans->txlist->fileid)) + return; + + if (packet->numsegments * sizeof(*packet->segments) != doomcom->datalength - BASEPACKETSIZE - sizeof(*packet)) + { + Net_CloseConnection(node); + return; + } + + if (packet->iteration > trans->ackediteration) + { + trans->ackediteration = packet->iteration; + if (trans->ackediteration >= trans->iteration - 1) + trans->dontsenduntil = 0; + } + + for (i = 0; i < packet->numsegments; i++) + { + fileacksegment_t *segment = &packet->segments[i]; + + for (j = 0; j < 32; j++) + if (LONG(segment->acks) & (1 << j)) + { + if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size) + { + Net_CloseConnection(node); + return; + } + + if (!trans->ackedfragments[LONG(segment->start) + j]) + { + trans->ackedfragments[LONG(segment->start) + j] = true; + trans->ackedsize += FILEFRAGMENTSIZE; + + // If the last missing fragment was acked, finish! + if (trans->ackedsize == trans->txlist->size) + { + SV_EndFileSend(node); + return; + } + } + } + } +} + +void PT_FileReceived(void) +{ + filetx_t *trans = transfer[doomcom->remotenode].txlist; + + if (trans && netbuffer->u.filereceived == trans->fileid) + SV_EndFileSend(doomcom->remotenode); +} + +static void SendAckPacket(fileack_pak *packet, UINT8 fileid) +{ + size_t packetsize; + INT32 i; + + packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments); + + // Finalise the packet + packet->fileid = fileid; + for (i = 0; i < packet->numsegments; i++) + { + packet->segments[i].start = LONG(packet->segments[i].start); + packet->segments[i].acks = LONG(packet->segments[i].acks); + } + + // Send the packet + netbuffer->packettype = PT_FILEACK; + M_Memcpy(&netbuffer->u.fileack, packet, packetsize); + HSendPacket(servernode, false, 0, packetsize); + + // Clear the packet + memset(packet, 0, sizeof(*packet) + 512); +} + +static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32 fragmentpos, UINT8 fileid) +{ + fileacksegment_t *segment = &packet->segments[packet->numsegments - 1]; + + packet->iteration = max(packet->iteration, iteration); + + if (packet->numsegments == 0 + || fragmentpos < segment->start + || fragmentpos - segment->start >= 32) + { + // If the packet becomes too big, send it + if ((packet->numsegments + 1) * sizeof(*segment) > 512) + SendAckPacket(packet, fileid); + + packet->numsegments++; + segment = &packet->segments[packet->numsegments - 1]; + segment->start = fragmentpos; + } + + // Set the bit that represents the fragment + segment->acks |= 1 << (fragmentpos - segment->start); +} + +void FileReceiveTicker(void) +{ + INT32 i; + + for (i = 0; i < fileneedednum; i++) + { + fileneeded_t *file = &fileneeded[i]; + + if (file->status == FS_DOWNLOADING) + { + if (lasttimeackpacketsent - I_GetTime() > TICRATE / 2) + SendAckPacket(file->ackpacket, i); + + // When resuming a tranfer, start with telling + // the server what parts we already received + if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING) + { + // Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s + INT32 j; + for (j = 0; j < 2048; j++) + { + if (file->receivedfragments[file->ackresendposition]) + AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i); + + file->ackresendposition++; + if (file->ackresendposition * file->fragmentsize >= file->totalsize) + { + file->ackresendposition = UINT32_MAX; + break; + } + } + } + } + } +} + +void PT_FileFragment(void) { INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; + UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); + UINT16 fragmentsize = SHORT(netbuffer->u.filetxpak.size); + UINT16 boundedfragmentsize = doomcom->datalength - BASEPACKETSIZE - sizeof(netbuffer->u.filetxpak); char *filename; - static INT32 filetime = 0; filename = va("%s", file->filename); nameonly(filename); @@ -771,43 +1238,105 @@ void Got_Filetxpak(void) if (file->status == FS_REQUESTED) { if (file->file) - I_Error("Got_Filetxpak: already open file\n"); - file->file = fopen(filename, "wb"); - if (!file->file) - I_Error("Can't create file %s: %s", filename, strerror(errno)); - CONS_Printf("\r%s...\n",filename); - file->currentsize = 0; + I_Error("PT_FileFragment: already open file\n"); + file->status = FS_DOWNLOADING; + file->fragmentsize = fragmentsize; + file->iteration = 0; + + file->ackpacket = calloc(1, sizeof(*file->ackpacket) + 512); + if (!file->ackpacket) + I_Error("FileSendTicker: No more memory\n"); + + if (CL_CanResumeDownload(file)) + { + file->file = fopen(filename, "r+b"); + if (!file->file) + I_Error("Can't reopen file %s: %s", filename, strerror(errno)); + CONS_Printf("\r%s...\n", filename); + + CONS_Printf("Resuming download...\n"); + file->currentsize = pauseddownload->currentsize; + file->receivedfragments = pauseddownload->receivedfragments; + file->ackresendposition = 0; + + free(pauseddownload); + pauseddownload = NULL; + } + else + { + CL_AbortDownloadResume(); + + file->file = fopen(filename, "wb"); + if (!file->file) + I_Error("Can't create file %s: %s", filename, strerror(errno)); + + CONS_Printf("\r%s...\n",filename); + + file->currentsize = 0; + file->totalsize = LONG(netbuffer->u.filetxpak.filesize); + file->ackresendposition = UINT32_MAX; // Only used for resumed downloads + + file->receivedfragments = calloc(file->totalsize / fragmentsize + 1, sizeof(*file->receivedfragments)); + if (!file->receivedfragments) + I_Error("FileSendTicker: No more memory\n"); + } + + lasttimeackpacketsent = I_GetTime(); } if (file->status == FS_DOWNLOADING) { - UINT32 pos = LONG(netbuffer->u.filetxpak.position); - UINT16 size = SHORT(netbuffer->u.filetxpak.size); - // Use a special trick to know when the file is complete (not always used) - // WARNING: file fragments can arrive out of order so don't stop yet! - if (pos & 0x80000000) - { - pos &= ~0x80000000; - file->totalsize = pos + size; - } - // We can receive packet in the wrong order, anyway all os support gaped file - fseek(file->file, pos, SEEK_SET); - if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1) - I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); - file->currentsize += size; + if (fragmentpos >= file->totalsize) + I_Error("Invalid file fragment\n"); - // Finished? - if (file->currentsize == file->totalsize) + file->iteration = max(file->iteration, netbuffer->u.filetxpak.iteration); + + if (!file->receivedfragments[fragmentpos / fragmentsize]) // Not received yet { - fclose(file->file); - file->file = NULL; - file->status = FS_FOUND; - CONS_Printf(M_GetText("Downloading %s...(done)\n"), - filename); + file->receivedfragments[fragmentpos / fragmentsize] = true; + + // We can receive packets in the wrong order, anyway all OSes support gaped files + fseek(file->file, fragmentpos, SEEK_SET); + if (fragmentsize && fwrite(netbuffer->u.filetxpak.data, boundedfragmentsize, 1, file->file) != 1) + I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); + file->currentsize += boundedfragmentsize; + + AddFragmentToAckPacket(file->ackpacket, file->iteration, fragmentpos / fragmentsize, filenum); + + // Finished? + if (file->currentsize == file->totalsize) + { + fclose(file->file); + file->file = NULL; + free(file->receivedfragments); + free(file->ackpacket); + file->status = FS_FOUND; + file->justdownloaded = true; + CONS_Printf(M_GetText("Downloading %s...(done)\n"), + filename); + + // Tell the server we have received the file + netbuffer->packettype = PT_FILERECEIVED; + netbuffer->u.filereceived = filenum; + HSendPacket(servernode, true, 0, 1); + + if (luafiletransfers) + { + // Tell the server we have received the file + netbuffer->packettype = PT_HASLUAFILE; + HSendPacket(servernode, true, 0, 0); + } + } + } + else // Already received + { + // If they are sending us the fragment again, it's probably because + // they missed our previous ack, so we must re-acknowledge it + AddFragmentToAckPacket(file->ackpacket, file->iteration, fragmentpos / fragmentsize, filenum); } } - else + else if (!file->justdownloaded) { const char *s; switch(file->status) @@ -830,14 +1359,8 @@ void Got_Filetxpak(void) } I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s); } - // Send ack back quickly - if (++filetime == 3) - { - Net_SendAcks(servernode); - filetime = 0; - } -#ifdef CLIENT_LOADINGSCREEN +#ifndef NONET lastfilenum = filenum; #endif } @@ -848,7 +1371,7 @@ void Got_Filetxpak(void) * \return True if the node is downloading a file * */ -boolean SV_SendingFile(INT32 node) +boolean SendingFile(INT32 node) { return transfer[node].txlist != NULL; } @@ -877,12 +1400,62 @@ void CloseNetFile(void) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { fclose(fileneeded[i].file); - // File is not complete delete it - remove(fileneeded[i].filename); - } + free(fileneeded[i].ackpacket); - // Remove PT_FILEFRAGMENT from acknowledge list - Net_AbortPacketType(PT_FILEFRAGMENT); + if (!pauseddownload && i != 0) // 0 is either srb2.srb or the gamestate... + { + // Don't remove the file, save it for later in case we resume the download + pauseddownload = malloc(sizeof(*pauseddownload)); + if (!pauseddownload) + I_Error("CloseNetFile: No more memory\n"); + + strcpy(pauseddownload->filename, fileneeded[i].filename); + memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16); + pauseddownload->currentsize = fileneeded[i].currentsize; + pauseddownload->receivedfragments = fileneeded[i].receivedfragments; + pauseddownload->fragmentsize = fileneeded[i].fragmentsize; + } + else + { + free(fileneeded[i].receivedfragments); + // File is not complete delete it + remove(fileneeded[i].filename); + } + } +} + +void Command_Downloads_f(void) +{ + INT32 node; + + for (node = 0; node < MAXNETNODES; node++) + if (transfer[node].txlist + && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? + { + const char *name = transfer[node].txlist->id.filename; + UINT32 position = transfer[node].ackedsize; + UINT32 size = transfer[node].txlist->size; + char ratecolor; + + // Avoid division by zero errors + if (!size) + size = 1; + + name = &name[strlen(name) - nameonlylength(name)]; + switch (4 * (position - 1) / size) + { + case 0: ratecolor = '\x85'; break; + case 1: ratecolor = '\x87'; break; + case 2: ratecolor = '\x82'; break; + case 3: ratecolor = '\x83'; break; + default: ratecolor = '\x80'; + } + + CONS_Printf("%2d %c%s ", node, ratecolor, name); // Node and file name + CONS_Printf("\x80%uK\x84/\x80%uK ", position / 1024, size / 1024); // Progress in kB + CONS_Printf("\x80(%c%u%%\x80) ", ratecolor, (UINT32)(100.0 * position / size)); // Progress in % + CONS_Printf("%s\n", I_GetNodeAddress(node)); // Address and newline + } } // Functions cut and pasted from Doomatic :) diff --git a/src/d_netfil.h b/src/d_netfil.h index 17aeb8b7e..1b399be75 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -13,6 +13,8 @@ #ifndef __D_NETFIL__ #define __D_NETFIL__ +#include "d_net.h" +#include "d_clisrv.h" #include "w_wad.h" typedef enum @@ -38,18 +40,25 @@ typedef struct UINT8 willsend; // Is the server willing to send it? char filename[MAX_WADPATH]; UINT8 md5sum[16]; + filestatus_t status; // The value returned by recsearch + boolean justdownloaded; // To prevent late fragments from causing an I_Error + // Used only for download FILE *file; + boolean *receivedfragments; + UINT32 fragmentsize; + UINT8 iteration; + fileack_pak *ackpacket; UINT32 currentsize; UINT32 totalsize; - filestatus_t status; // The value returned by recsearch + UINT32 ackresendposition; // Used when resuming downloads } fileneeded_t; extern INT32 fileneedednum; extern fileneeded_t fileneeded[MAX_WADFILES]; extern char downloaddir[512]; -#ifdef CLIENT_LOADINGSCREEN +#ifndef NONET extern INT32 lastfilenum; #endif @@ -59,19 +68,63 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave); INT32 CL_CheckFiles(void); void CL_LoadServerFiles(void); -void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, +void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid); -void SV_FileSendTicker(void); -void Got_Filetxpak(void); -boolean SV_SendingFile(INT32 node); +void FileSendTicker(void); +void PT_FileAck(void); +void PT_FileReceived(void); +boolean SendingFile(INT32 node); + +void FileReceiveTicker(void); +void PT_FileFragment(void); boolean CL_CheckDownloadable(void); -boolean CL_SendRequestFile(void); -boolean Got_RequestFilePak(INT32 node); +boolean CL_SendFileRequest(void); +boolean PT_RequestFile(INT32 node); + +typedef enum +{ + LFTNS_WAITING, // This node is waiting for the server to send the file + LFTNS_ASKED, // The server has told the node they're ready to send the file + LFTNS_SENDING, // The server is sending the file to this node + LFTNS_SENT // The node already has the file +} luafiletransfernodestatus_t; + +typedef struct luafiletransfer_s +{ + char *filename; + char *realfilename; + char mode[4]; // rb+/wb+/ab+ + null character + INT32 id; // Callback ID + boolean ongoing; + luafiletransfernodestatus_t nodestatus[MAXNETNODES]; + struct luafiletransfer_s *next; +} luafiletransfer_t; + +extern luafiletransfer_t *luafiletransfers; +extern boolean waitingforluafiletransfer; +extern boolean waitingforluafilecommand; +extern char luafiledir[256 + 16]; + +void AddLuaFileTransfer(const char *filename, const char *mode); +void SV_PrepareSendLuaFile(void); +boolean AddLuaFileToSendQueue(INT32 node, const char *filename); +void SV_HandleLuaFileSent(UINT8 node); +void RemoveLuaFileTransfer(void); +void RemoveAllLuaFileTransfers(void); +void SV_AbortLuaFileTransfer(INT32 node); +void CL_PrepareDownloadLuaFile(void); +void Got_LuaFile(UINT8 **cp, INT32 playernum); +void StoreLuaFileCallback(INT32 id); +void RemoveLuaFileCallback(INT32 id); +void MakePathDirs(char *path); void SV_AbortSendFiles(INT32 node); void CloseNetFile(void); +void CL_AbortDownloadResume(void); + +void Command_Downloads_f(void); boolean fileexist(char *filename, time_t ptime); diff --git a/src/d_player.h b/src/d_player.h index 6a2d04129..fba2a6837 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -48,6 +48,7 @@ typedef enum SF_FASTEDGE = 1<<12, // Faster edge teeter? SF_MULTIABILITY = 1<<13, // Revenge of Final Demo. SF_NONIGHTSROTATION = 1<<14, // Disable sprite rotation for NiGHTS + SF_NONIGHTSSUPER = 1<<15, // Disable super colors for NiGHTS (if you have SF_SUPER) // free up to and including 1<<31 } skinflags_t; @@ -238,7 +239,8 @@ typedef enum CR_MACESPIN, CR_MINECART, CR_ROLLOUT, - CR_PTERABYTE + CR_PTERABYTE, + CR_DUSTDEVIL } carrytype_t; // pw_carry // Player powers. (don't edit this comment) @@ -278,6 +280,9 @@ typedef enum pw_nights_linkfreeze, pw_nocontrol, //for linedef exec 427 + + pw_dye, // for dyes + pw_justlaunched, // Launched off a slope this tic (0=none, 1=standard launch, 2=half-pipe launch) NUMPOWERS @@ -327,6 +332,9 @@ typedef struct player_s angle_t viewrollangle; + INT16 angleturn; + INT16 oldrelangleturn; + // Mouse aiming, where the guy is looking at! // It is updated with cmd->aiming. angle_t aiming; @@ -361,7 +369,7 @@ typedef struct player_s UINT16 flashpal; // Player skin colorshift, 0-15 for which color to draw player. - UINT8 skincolor; + UINT16 skincolor; INT32 skin; UINT32 availabilities; diff --git a/src/d_think.h b/src/d_think.h index c56551c21..4bdac4627 100644 --- a/src/d_think.h +++ b/src/d_think.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index 337be1ff0..0a8012bb1 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/dehacked.c b/src/dehacked.c index 2d3fe40ed..78120c5c4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -31,6 +31,7 @@ #include "r_data.h" #include "r_draw.h" #include "r_patch.h" +#include "r_things.h" // R_Char2Frame #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" @@ -39,9 +40,7 @@ #include "m_cond.h" -#ifdef HAVE_BLUA #include "v_video.h" // video flags (for lua) -#endif #ifdef HWRENDER #include "hardware/hw_light.h" @@ -57,10 +56,12 @@ int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); // The crazy word-reading stuff uses these. static char *FREE_STATES[NUMSTATEFREESLOTS]; static char *FREE_MOBJS[NUMMOBJFREESLOTS]; +static char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; static UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. #define initfreeslots() {\ memset(FREE_STATES,0,sizeof(char *) * NUMSTATEFREESLOTS);\ memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ +memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ } @@ -76,10 +77,9 @@ static UINT16 get_mus(const char *word, UINT8 dehacked_mode); #endif static hudnum_t get_huditem(const char *word); static menutype_t get_menutype(const char *word); -#ifndef HAVE_BLUA -static INT16 get_gametype(const char *word); -static powertype_t get_power(const char *word); -#endif +//static INT16 get_gametype(const char *word); +//static powertype_t get_power(const char *word); +skincolornum_t get_skincolor(const char *word); boolean deh_loaded = false; static int dbg_line; @@ -395,7 +395,7 @@ static void readPlayer(MYFILE *f, INT32 num) // It works down here, though. { INT32 numline = 0; - for (i = 0; i < MAXLINELEN-1; i++) + for (i = 0; (size_t)i < sizeof(description[num].notes)-1; i++) { if (numline < 20 && description[num].notes[i] == '\n') numline++; @@ -452,7 +452,7 @@ static void readPlayer(MYFILE *f, INT32 num) else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR")) { SLOTFOUND - description[num].oppositecolor = (UINT8)get_number(word2); + description[num].oppositecolor = (UINT16)get_number(word2); } else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME")) { @@ -462,12 +462,12 @@ static void readPlayer(MYFILE *f, INT32 num) else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR")) { SLOTFOUND - description[num].tagtextcolor = (UINT8)get_number(word2); + description[num].tagtextcolor = (UINT16)get_number(word2); } else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR")) { SLOTFOUND - description[num].tagoutlinecolor = (UINT8)get_number(word2); + description[num].tagoutlinecolor = (UINT16)get_number(word2); } else if (fastcmp(word, "STATUS")) { @@ -574,6 +574,16 @@ static void readfreeslots(MYFILE *f) break; } } + else if (fastcmp(type, "SKINCOLOR")) + { + for (i = 0; i < NUMCOLORFREESLOTS; i++) + if (!FREE_SKINCOLORS[i]) { + FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_SKINCOLORS[i],word); + M_AddMenuColor(numskincolors++); + break; + } + } else if (fastcmp(type, "SPR2")) { // Search if we already have an SPR2 by that name... @@ -756,6 +766,84 @@ static void readthing(MYFILE *f, INT32 num) Z_Free(s); } +static void readskincolor(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + + Color_cons_t[num].value = num; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + + if (fastcmp(word, "NAME")) + { + deh_strlcpy(skincolors[num].name, word2, + sizeof (skincolors[num].name), va("Skincolor %d: name", num)); + } + else if (fastcmp(word, "RAMP")) + { + UINT8 i; + tmp = strtok(word2,","); + for (i = 0; i < COLORRAMPSIZE; i++) { + skincolors[num].ramp[i] = (UINT8)get_number(tmp); + if ((tmp = strtok(NULL,",")) == NULL) + break; + } + } + else if (fastcmp(word, "INVCOLOR")) + { + skincolors[num].invcolor = (UINT16)get_number(word2); + } + else if (fastcmp(word, "INVSHADE")) + { + skincolors[num].invshade = get_number(word2)%COLORRAMPSIZE; + } + else if (fastcmp(word, "CHATCOLOR")) + { + skincolors[num].chatcolor = get_number(word2); + } + else if (fastcmp(word, "ACCESSIBLE")) + { + if (num > FIRSTSUPERCOLOR) + skincolors[num].accessible = (boolean)(atoi(word2) || word2[0] == 'T' || word2[0] == 'Y'); + } + else + deh_warning("Skincolor %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + #ifdef HWRENDER static void readlight(MYFILE *f, INT32 num) { @@ -1177,7 +1265,7 @@ static void readgametype(MYFILE *f, char *gtname) // It works down here, though. { INT32 numline = 0; - for (i = 0; i < MAXLINELEN-1; i++) + for (i = 0; (size_t)i < sizeof(gtdescription)-1; i++) { if (numline < 20 && gtdescription[i] == '\n') numline++; @@ -1249,7 +1337,7 @@ static void readgametype(MYFILE *f, char *gtname) newgttol = (UINT32)i; else { - UINT16 tol = 0; + UINT32 tol = 0; tmp = strtok(word2,","); do { for (i = 0; TYPEOFLEVEL[i].name; i++) @@ -1415,7 +1503,6 @@ static void readlevelheader(MYFILE *f, INT32 num) // Lua custom options also go above, contents may be case sensitive. if (fastncmp(word, "LUA.", 4)) { -#ifdef HAVE_BLUA UINT8 j; customoption_t *modoption; @@ -1449,9 +1536,6 @@ static void readlevelheader(MYFILE *f, INT32 num) modoption->option[31] = '\0'; strncpy(modoption->value, word2, 255); modoption->value[255] = '\0'; -#else - // Silently ignore. -#endif continue; } @@ -1564,7 +1648,7 @@ static void readlevelheader(MYFILE *f, INT32 num) } else if (fastcmp(word, "ACT")) { - if (i >= 0 && i < 20) // 0 for no act number, TTL1 through TTL19 + if (i >= 0 && i <= 99) // 0 for no act number mapheaderinfo[num-1]->actnum = (UINT8)i; else deh_warning("Level header %d: invalid act number %d", num, i); @@ -1585,13 +1669,29 @@ static void readlevelheader(MYFILE *f, INT32 num) mapheaderinfo[num-1]->nextlevel = (INT16)i; } + else if (fastcmp(word, "MARATHONNEXT")) + { + if (fastcmp(word2, "TITLE")) i = 1100; + else if (fastcmp(word2, "EVALUATION")) i = 1101; + else if (fastcmp(word2, "CREDITS")) i = 1102; + else if (fastcmp(word2, "ENDING")) i = 1103; + else + // Support using the actual map name, + // i.e., MarathonNext = AB, MarathonNext = FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') + i = M_MapNumber(word2[0], word2[1]); + + mapheaderinfo[num-1]->marathonnext = (INT16)i; + } else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number mapheaderinfo[num-1]->typeoflevel = (UINT32)i; else { - UINT16 tol = 0; + UINT32 tol = 0; tmp = strtok(word2,","); do { for (i = 0; TYPEOFLEVEL[i].name; i++) @@ -1870,6 +1970,12 @@ static void readlevelheader(MYFILE *f, INT32 num) } else if (fastcmp(word, "STARTRINGS")) mapheaderinfo[num-1]->startrings = (UINT16)i; + else if (fastcmp(word, "SPECIALSTAGETIME")) + mapheaderinfo[num-1]->sstimer = i; + else if (fastcmp(word, "SPECIALSTAGESPHERES")) + mapheaderinfo[num-1]->ssspheres = i; + else if (fastcmp(word, "GRAVITY")) + mapheaderinfo[num-1]->gravity = FLOAT_TO_FIXED(atof(word2)); else deh_warning("Level header %d: unknown word '%s'", num, word); } @@ -2814,7 +2920,7 @@ static actionpointer_t actionpointers[] = {{A_ThrownRing}, "A_THROWNRING"}, {{A_SetSolidSteam}, "A_SETSOLIDSTEAM"}, {{A_UnsetSolidSteam}, "A_UNSETSOLIDSTEAM"}, - {{A_SignSpin}, "S_SIGNSPIN"}, + {{A_SignSpin}, "A_SIGNSPIN"}, {{A_SignPlayer}, "A_SIGNPLAYER"}, {{A_OverlayThink}, "A_OVERLAYTHINK"}, {{A_JetChase}, "A_JETCHASE"}, @@ -2916,6 +3022,7 @@ static actionpointer_t actionpointers[] = {{A_SetRandomTics}, "A_SETRANDOMTICS"}, {{A_ChangeColorRelative}, "A_CHANGECOLORRELATIVE"}, {{A_ChangeColorAbsolute}, "A_CHANGECOLORABSOLUTE"}, + {{A_Dye}, "A_DYE"}, {{A_MoveRelative}, "A_MOVERELATIVE"}, {{A_MoveAbsolute}, "A_MOVEABSOLUTE"}, {{A_Thrust}, "A_THRUST"}, @@ -3033,6 +3140,7 @@ static actionpointer_t actionpointers[] = {{A_DragonbomberSpawn}, "A_DRAGONBOMERSPAWN"}, {{A_DragonWing}, "A_DRAGONWING"}, {{A_DragonSegment}, "A_DRAGONSEGMENT"}, + {{A_ChangeHeight}, "A_CHANGEHEIGHT"}, {{NULL}, "NONE"}, // This NULL entry must be the last in the list @@ -3123,22 +3231,20 @@ static void readframe(MYFILE *f, INT32 num) } z = 0; -#ifdef HAVE_BLUA found = LUA_SetLuaAction(&states[num], actiontocompare); if (!found) -#endif - while (actionpointers[z].name) - { - if (fastcmp(actiontocompare, actionpointers[z].name)) + while (actionpointers[z].name) { - states[num].action = actionpointers[z].action; - states[num].action.acv = actionpointers[z].action.acv; // assign - states[num].action.acp1 = actionpointers[z].action.acp1; - found = true; - break; + if (fastcmp(actiontocompare, actionpointers[z].name)) + { + states[num].action = actionpointers[z].action; + states[num].action.acv = actionpointers[z].action.acv; // assign + states[num].action.acp1 = actionpointers[z].action.acp1; + found = true; + break; + } + z++; } - z++; - } if (!found) deh_warning("Unknown action %s", actiontocompare); @@ -3889,7 +3995,26 @@ static void readmaincfg(MYFILE *f) value = atoi(word2); // used for numerical settings if (fastcmp(word, "EXECCFG")) - COM_BufAddText(va("exec %s\n", word2)); + { + if (strchr(word2, '.')) + COM_BufAddText(va("exec %s\n", word2)); + else + { + lumpnum_t lumpnum; + char newname[9]; + + strncpy(newname, word2, 8); + + newname[8] = '\0'; + + lumpnum = W_CheckNumForName(newname); + + if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0) + CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname); + else + COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); + } + } else if (fastcmp(word, "SPSTAGE_START")) { @@ -3902,7 +4027,20 @@ static void readmaincfg(MYFILE *f) else value = get_number(word2); - spstage_start = (INT16)value; + spstage_start = spmarathon_start = (INT16)value; + } + else if (fastcmp(word, "SPMARATHON_START")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + spmarathon_start = (INT16)value; } else if (fastcmp(word, "SSTAGE_START")) { @@ -3934,19 +4072,19 @@ static void readmaincfg(MYFILE *f) } else if (fastcmp(word, "REDTEAM")) { - skincolor_redteam = (UINT8)get_number(word2); + skincolor_redteam = (UINT16)get_number(word2); } else if (fastcmp(word, "BLUETEAM")) { - skincolor_blueteam = (UINT8)get_number(word2); + skincolor_blueteam = (UINT16)get_number(word2); } else if (fastcmp(word, "REDRING")) { - skincolor_redring = (UINT8)get_number(word2); + skincolor_redring = (UINT16)get_number(word2); } else if (fastcmp(word, "BLUERING")) { - skincolor_bluering = (UINT8)get_number(word2); + skincolor_bluering = (UINT16)get_number(word2); } else if (fastcmp(word, "INVULNTICS")) { @@ -3996,6 +4134,17 @@ static void readmaincfg(MYFILE *f) introtoplay = 128; introchanged = true; } + else if (fastcmp(word, "CREDITSCUTSCENE")) + { + creditscutscene = (UINT8)get_number(word2); + // range check, you morons. + if (creditscutscene > 128) + creditscutscene = 128; + } + else if (fastcmp(word, "USEBLACKROCK")) + { + useBlackRock = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); + } else if (fastcmp(word, "LOOPTITLE")) { looptitle = (value || word2[0] == 'T' || word2[0] == 'Y'); @@ -4097,13 +4246,6 @@ static void readmaincfg(MYFILE *f) titlescrollyspeed = get_number(word2); titlechanged = true; } - else if (fastcmp(word, "CREDITSCUTSCENE")) - { - creditscutscene = (UINT8)get_number(word2); - // range check, you morons. - if (creditscutscene > 128) - creditscutscene = 128; - } else if (fastcmp(word, "DISABLESPEEDADJUST")) { disableSpeedAdjust = (value || word2[0] == 'T' || word2[0] == 'Y'); @@ -4131,6 +4273,10 @@ static void readmaincfg(MYFILE *f) { maxXtraLife = (UINT8)get_number(word2); } + else if (fastcmp(word, "USECONTINUES")) + { + useContinues = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); + } else if (fastcmp(word, "GAMEDATA")) { @@ -4156,6 +4302,9 @@ static void readmaincfg(MYFILE *f) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); + strcpy(liveeventbackup, va("live%s.bkp", timeattackfolder)); + strcatbf(liveeventbackup, srb2home, PATHSEP); + gamedataadded = true; titlechanged = true; } @@ -4534,6 +4683,18 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ignorelines(f); } } + else if (fastcmp(word, "SKINCOLOR") || fastcmp(word, "COLOR")) + { + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_skincolor(word2); // find a skincolor by name + if (i < numskincolors && i >= (INT32)SKINCOLOR_FIRSTFREESLOT) + readskincolor(f, i); + else + { + deh_warning("Skincolor %d out of range (%d - %d)", i, SKINCOLOR_FIRSTFREESLOT, numskincolors-1); + ignorelines(f); + } + } else if (fastcmp(word, "SPRITE2")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number @@ -5595,10 +5756,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FANG_PINCHPATHINGSTART1", "S_FANG_PINCHPATHINGSTART2", "S_FANG_PINCHPATHING", + "S_FANG_PINCHBOUNCE0", "S_FANG_PINCHBOUNCE1", "S_FANG_PINCHBOUNCE2", "S_FANG_PINCHBOUNCE3", "S_FANG_PINCHBOUNCE4", + "S_FANG_PINCHFALL0", "S_FANG_PINCHFALL1", "S_FANG_PINCHFALL2", "S_FANG_PINCHSKID1", @@ -6210,6 +6373,14 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ROCKET", "S_LASER", + "S_LASER2", + "S_LASERFLASH", + + "S_LASERFLAME1", + "S_LASERFLAME2", + "S_LASERFLAME3", + "S_LASERFLAME4", + "S_LASERFLAME5", "S_TORPEDO", @@ -7477,7 +7648,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Got Flag Sign "S_GOTFLAG", - + // Finish flag "S_FINISHFLAG", @@ -8848,14 +9019,12 @@ static const char *const MOBJEFLAG_LIST[] = { NULL }; -#ifdef HAVE_BLUA static const char *const MAPTHINGFLAG_LIST[4] = { "EXTRA", // Extra flag for objects. "OBJECTFLIP", // Reverse gravity flag for objects. "OBJECTSPECIAL", // Special flag used with certain objects. "AMBUSH" // Deaf monsters/do not react to sound. }; -#endif static const char *const PLAYERFLAG_LIST[] = { @@ -8952,7 +9121,6 @@ static const char *const GAMETYPERULE_LIST[] = { NULL }; -#ifdef HAVE_BLUA // Linedef flags static const char *const ML_LIST[16] = { "IMPASSIBLE", @@ -8972,10 +9140,7 @@ static const char *const ML_LIST[16] = { "BOUNCY", "TFERLINE" }; -#endif -// This DOES differ from r_draw's Color_Names, unfortunately. -// Also includes Super colors static const char *COLOR_ENUMS[] = { "NONE", // SKINCOLOR_NONE, @@ -9145,7 +9310,11 @@ static const char *const POWERS_LIST[] = { //for linedef exec 427 "NOCONTROL", - "JUSTLAUNCHED", + + //for dyes + "DYE", + + "JUSTLAUNCHED" }; static const char *const HUDITEMS_LIST[] = { @@ -9209,6 +9378,7 @@ static const char *const MENUTYPES_LIST[] = { "MP_CONNECT", "MP_ROOM", "MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + "MP_SERVER_OPTIONS", // Options "OP_MAIN", @@ -9218,18 +9388,20 @@ static const char *const MENUTYPES_LIST[] = { "OP_P1MOUSE", "OP_P1JOYSTICK", "OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2 + "OP_P1CAMERA", "OP_P2CONTROLS", "OP_P2MOUSE", "OP_P2JOYSTICK", + "OP_P2CAMERA", + + "OP_PLAYSTYLE", "OP_VIDEO", "OP_VIDEOMODE", "OP_COLOR", "OP_OPENGL", "OP_OPENGL_LIGHTING", - "OP_OPENGL_FOG", - "OP_OPENGL_COLOR", "OP_SOUND", @@ -9271,11 +9443,7 @@ static const char *const MENUTYPES_LIST[] = { struct { const char *n; // has to be able to hold both fixed_t and angle_t, so drastic measure!! -#ifdef HAVE_BLUA lua_Integer v; -#else - INT64 v; -#endif } const INT_CONST[] = { // If a mod removes some variables here, // please leave the names in-tact and just set @@ -9406,7 +9574,8 @@ struct { // SKINCOLOR_ doesn't include these..! {"MAXSKINCOLORS",MAXSKINCOLORS}, - {"MAXTRANSLATIONS",MAXTRANSLATIONS}, + {"FIRSTSUPERCOLOR",FIRSTSUPERCOLOR}, + {"NUMSUPERCOLORS",NUMSUPERCOLORS}, // Precipitation {"PRECIP_NONE",PRECIP_NONE}, @@ -9457,6 +9626,7 @@ struct { {"CR_MINECART",CR_MINECART}, {"CR_ROLLOUT",CR_ROLLOUT}, {"CR_PTERABYTE",CR_PTERABYTE}, + {"CR_DUSTDEVIL",CR_DUSTDEVIL}, // Ring weapons (ringweapons_t) // Useful for A_GiveWeapon @@ -9484,6 +9654,7 @@ struct { {"SF_FASTEDGE",SF_FASTEDGE}, {"SF_MULTIABILITY",SF_MULTIABILITY}, {"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION}, + {"SF_NONIGHTSSUPER",SF_NONIGHTSSUPER}, // Dashmode constants {"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD}, @@ -9531,7 +9702,6 @@ struct { {"ME_ULTIMATE",ME_ULTIMATE}, {"ME_PERFECT",ME_PERFECT}, -#ifdef HAVE_BLUA // p_local.h constants {"FLOATSPEED",FLOATSPEED}, {"MAXSTEPMOVE",MAXSTEPMOVE}, @@ -9666,11 +9836,11 @@ struct { {"FF_CUTEXTRA",FF_CUTEXTRA}, ///< Cuts out hidden translucent pixels. {"FF_CUTLEVEL",FF_CUTLEVEL}, ///< Cuts out all hidden pixels. {"FF_CUTSPRITES",FF_CUTSPRITES}, ///< Final step in making 3D water. - {"FF_BOTHPLANES",FF_BOTHPLANES}, ///< Renders both planes all the time. + {"FF_BOTHPLANES",FF_BOTHPLANES}, ///< Render inside and outside planes. {"FF_EXTRA",FF_EXTRA}, ///< Gets cut by ::FF_CUTEXTRA. {"FF_TRANSLUCENT",FF_TRANSLUCENT}, ///< See through! {"FF_FOG",FF_FOG}, ///< Fog "brush." - {"FF_INVERTPLANES",FF_INVERTPLANES}, ///< Reverse the plane visibility rules. + {"FF_INVERTPLANES",FF_INVERTPLANES}, ///< Only render inside planes. {"FF_ALLSIDES",FF_ALLSIDES}, ///< Render inside and outside sides. {"FF_INVERTSIDES",FF_INVERTSIDES}, ///< Only render inside sides. {"FF_DOUBLESHADOW",FF_DOUBLESHADOW}, ///< Make two lightlist entries to reset light? @@ -9696,11 +9866,10 @@ struct { // Node flags {"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf. #endif -#ifdef ESLOPE + // Slope flags {"SL_NOPHYSICS",SL_NOPHYSICS}, {"SL_DYNAMIC",SL_DYNAMIC}, -#endif // Angles {"ANG1",ANG1}, @@ -9864,7 +10033,12 @@ struct { {"TC_RAINBOW",TC_RAINBOW}, {"TC_BLINK",TC_BLINK}, {"TC_DASHMODE",TC_DASHMODE}, -#endif + + // marathonmode flags + {"MA_INIT",MA_INIT}, + {"MA_RUNNING",MA_RUNNING}, + {"MA_NOCUTSCENES",MA_NOCUTSCENES}, + {"MA_INGAME",MA_INGAME}, {NULL,0} }; @@ -9909,6 +10083,26 @@ static statenum_t get_state(const char *word) return S_NULL; } +skincolornum_t get_skincolor(const char *word) +{ // Returns the value of SKINCOLOR_ enumerations + skincolornum_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("SKINCOLOR_",word,10)) + word += 10; // take off the SKINCOLOR_ + for (i = 0; i < NUMCOLORFREESLOTS; i++) { + if (!FREE_SKINCOLORS[i]) + break; + if (fastcmp(word, FREE_SKINCOLORS[i])) + return SKINCOLOR_FIRSTFREESLOT+i; + } + for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) + if (fastcmp(word, COLOR_ENUMS[i])) + return i; + deh_warning("Couldn't find skincolor named 'SKINCOLOR_%s'",word); + return SKINCOLOR_GREEN; +} + static spritenum_t get_sprite(const char *word) { // Returns the value of SPR_ enumerations spritenum_t i; @@ -10021,8 +10215,7 @@ static menutype_t get_menutype(const char *word) return MN_NONE; } -#ifndef HAVE_BLUA -static INT16 get_gametype(const char *word) +/*static INT16 get_gametype(const char *word) { // Returns the value of GT_ enumerations INT16 i; if (*word >= '0' && *word <= '9') @@ -10048,7 +10241,7 @@ static powertype_t get_power(const char *word) return i; deh_warning("Couldn't find power named 'pw_%s'",word); return pw_invulnerability; -} +}*/ /// \todo Make ANY of this completely over-the-top math craziness obey the order of operations. static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; } @@ -10076,7 +10269,7 @@ struct { }; // Returns the full word, cut at the first symbol or whitespace -static char *read_word(const char *line) +/*static char *read_word(const char *line) { // Part 1: You got the start of the word, now find the end. const char *p; @@ -10204,6 +10397,11 @@ static fixed_t find_const(const char **rword) free(word); return r; } + else if (fastncmp("SKINCOLOR_",word,10)) { + r = get_skincolor(word); + free(word); + return r; + } else if (fastncmp("MT_",word,3)) { r = get_mobjtype(word); free(word); @@ -10236,7 +10434,7 @@ static fixed_t find_const(const char **rword) free(word); return r; } - else if (fastncmp("GT_",word,4)) { + else if (fastncmp("GT_",word,3)) { r = get_gametype(word); free(word); return r; @@ -10272,17 +10470,6 @@ static fixed_t find_const(const char **rword) free(word); return r; } - else if (fastncmp("SKINCOLOR_",word,10)) { - char *p = word+10; - for (i = 0; i < MAXTRANSLATIONS; i++) - if (fastcmp(p, COLOR_ENUMS[i])) { - free(word); - return i; - } - const_warning("color",word); - free(word); - return 0; - } else if (fastncmp("GRADE_",word,6)) { char *p = word+6; @@ -10306,16 +10493,14 @@ static fixed_t find_const(const char **rword) const_warning("constant",word); free(word); return 0; -} -#endif +}*/ // Loops through every constant and operation in word and performs its calculations, returning the final value. fixed_t get_number(const char *word) { -#ifdef HAVE_BLUA return LUA_EvalMath(word); -#else - // DESPERATELY NEEDED: Order of operations support! :x + + /*// DESPERATELY NEEDED: Order of operations support! :x fixed_t i = find_const(&word); INT32 o; while(*word) { @@ -10325,8 +10510,7 @@ fixed_t get_number(const char *word) else break; } - return i; -#endif + return i;*/ } void DEH_Check(void) @@ -10346,12 +10530,11 @@ void DEH_Check(void) if (dehpowers != NUMPOWERS) I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers)); - if (dehcolors != MAXTRANSLATIONS) - I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", MAXTRANSLATIONS, sizeu1(dehcolors)); + if (dehcolors != SKINCOLOR_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors)); #endif } -#ifdef HAVE_BLUA #include "lua_script.h" #include "lua_libs.h" @@ -10456,6 +10639,22 @@ static inline int lib_freeslot(lua_State *L) if (i == NUMMOBJFREESLOTS) CONS_Alert(CONS_WARNING, "Ran out of free MobjType slots!\n"); } + else if (fastcmp(type, "SKINCOLOR")) + { + skincolornum_t i; + for (i = 0; i < NUMCOLORFREESLOTS; i++) + if (!FREE_SKINCOLORS[i]) { + CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); + FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_SKINCOLORS[i],word); + M_AddMenuColor(numskincolors++); + lua_pushinteger(L, i); + r++; + break; + } + if (i == NUMCOLORFREESLOTS) + CONS_Alert(CONS_WARNING, "Ran out of free skincolor slots!\n"); + } else if (fastcmp(type, "SPR2")) { // Search if we already have an SPR2 by that name... @@ -10787,13 +10986,20 @@ static inline int lib_getenum(lua_State *L) } else if (fastncmp("SKINCOLOR_",word,10)) { p = word+10; - for (i = 0; i < MAXTRANSLATIONS; i++) + for (i = 0; i < NUMCOLORFREESLOTS; i++) { + if (!FREE_SKINCOLORS[i]) + break; + if (fastcmp(p, FREE_SKINCOLORS[i])) { + lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i); + return 1; + } + } + for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) if (fastcmp(p, COLOR_ENUMS[i])) { lua_pushinteger(L, i); return 1; } - if (mathlib) return luaL_error(L, "skincolor '%s' could not be found.\n", word); - return 0; + return luaL_error(L, "skincolor '%s' could not be found.\n", word); } else if (fastncmp("GRADE_",word,6)) { @@ -10977,5 +11183,3 @@ void LUA_SetActionByName(void *state, const char *actiontocompare) } } } - -#endif // HAVE_BLUA diff --git a/src/dehacked.h b/src/dehacked.h index 2b34377fd..54225f36e 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -34,11 +34,9 @@ void DEH_Check(void); fixed_t get_number(const char *word); -#ifdef HAVE_BLUA boolean LUA_SetLuaAction(void *state, const char *actiontocompare); const char *LUA_GetActionName(void *action); void LUA_SetActionByName(void *state, const char *actiontocompare); -#endif extern boolean deh_loaded; diff --git a/src/djgppdos/i_system.c b/src/djgppdos/i_system.c index dae9ed16e..9f6972fa6 100644 --- a/src/djgppdos/i_system.c +++ b/src/djgppdos/i_system.c @@ -61,6 +61,8 @@ #include "../console.h" +#include "../m_menu.h" + #ifdef __GNUG__ #pragma implementation "../i_system.h" #endif @@ -555,6 +557,7 @@ void I_Error (const char *error, ...) if (demorecording) G_CheckDemoStatus(); D_QuitNetGame (); + M_FreePlayerSetupColors(); if (shutdowning) { @@ -622,6 +625,7 @@ void I_Quit (void) if (demorecording) G_CheckDemoStatus(); D_QuitNetGame (); + M_FreePlayerSetupColors(); I_ShutdownMusic(); I_ShutdownSound(); I_ShutdownCD(); diff --git a/src/djgppdos/i_video.c b/src/djgppdos/i_video.c index 02c7a842b..d2483e318 100644 --- a/src/djgppdos/i_video.c +++ b/src/djgppdos/i_video.c @@ -90,6 +90,9 @@ static unsigned long nombre = NEWTICRATE*10; static void I_BlitScreenVesa1(void); //see later void I_FinishUpdate (void) { + if (marathonmode) + SCR_DisplayMarathonInfo(); + // draw captions if enabled if (cv_closedcaptioning.value) SCR_ClosedCaptions(); @@ -339,7 +342,4 @@ void I_StartupGraphics(void) } -void I_StartupHardwareGraphics(void) -{ - // oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo y -} +void VID_StartupOpenGL(void) {} diff --git a/src/djgppdos/rdb-s.h b/src/djgppdos/rdb-s.h index b7a994fc9..2d460c935 100644 --- a/src/djgppdos/rdb-s.h +++ b/src/djgppdos/rdb-s.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// Copyright (C) 2005-2019 by Sonic Team Junior. +// Copyright (C) 2005-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/djgppdos/vid_vesa.c b/src/djgppdos/vid_vesa.c index c8ce7dae5..61ed18e4b 100644 --- a/src/djgppdos/vid_vesa.c +++ b/src/djgppdos/vid_vesa.c @@ -378,10 +378,8 @@ INT32 VID_SetMode (INT32 modenum) //, UINT8 *palette) return 1; } -void VID_CheckRenderer(void) -{ - // .............. -} +void VID_CheckRenderer(void) {} +void VID_CheckGLLoaded(rendermode_t oldrender) {} diff --git a/src/doomdata.h b/src/doomdata.h index f6e7cb584..77ed56bc2 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -208,10 +208,6 @@ typedef struct #define ZSHIFT 4 -extern const UINT8 Color_Index[MAXTRANSLATIONS-1][16]; -extern const char *Color_Names[MAXSKINCOLORS + NUMSUPERCOLORS]; -extern const UINT8 Color_Opposite[MAXSKINCOLORS - 1][2]; - #define NUMMAPS 1035 #endif // __DOOMDATA__ diff --git a/src/doomdef.h b/src/doomdef.h index a21f878ae..1f90a6f7f 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -143,16 +143,19 @@ extern char logfilename[1024]; // we use comprevision and compbranch instead. #else #define VERSION 202 // Game version -#define SUBVERSION 1 // more precise version number -#define VERSIONSTRING "v2.2.1" -#define VERSIONSTRINGW L"v2.2.1" +#define SUBVERSION 4 // more precise version number +#define VERSIONSTRING "v2.2.4" +#define VERSIONSTRINGW L"v2.2.4" // Hey! If you change this, add 1 to the MODVERSION below! // Otherwise we can't force updates! #endif +/* A custom URL protocol for server links. */ +#define SERVER_URL_PROTOCOL "srb2://" + // Does this version require an added patch file? // Comment or uncomment this as necessary. -//#define USE_PATCH_DTA +#define USE_PATCH_DTA // Use .kart extension addons //#define USE_KART @@ -210,7 +213,7 @@ extern char logfilename[1024]; // it's only for detection of the version the player is using so the MS can alert them of an update. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1". -#define MODVERSION 41 +#define MODVERSION 44 // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. // Increment MINOREXECVERSION whenever a config change is needed that does not correspond @@ -236,6 +239,20 @@ extern char logfilename[1024]; #define PLAYERSMASK (MAXPLAYERS-1) #define MAXPLAYERNAME 21 +#define COLORRAMPSIZE 16 +#define MAXCOLORNAME 32 +#define NUMCOLORFREESLOTS 1024 + +typedef struct skincolor_s +{ + char name[MAXCOLORNAME+1]; // Skincolor name + UINT8 ramp[COLORRAMPSIZE]; // Colormap ramp + UINT16 invcolor; // Signpost color + UINT8 invshade; // Signpost color shade + UINT16 chatcolor; // Chat color + boolean accessible; // Accessible by the color command + setup menu +} skincolor_t; + typedef enum { SKINCOLOR_NONE = 0, @@ -314,12 +331,10 @@ typedef enum SKINCOLOR_RASPBERRY, SKINCOLOR_ROSY, - // SKINCOLOR_? - one left before we bump up against 0x39, which isn't a HARD limit anymore but would be excessive - - MAXSKINCOLORS, + FIRSTSUPERCOLOR, // Super special awesome Super flashing colors! - SKINCOLOR_SUPERSILVER1 = MAXSKINCOLORS, + SKINCOLOR_SUPERSILVER1 = FIRSTSUPERCOLOR, SKINCOLOR_SUPERSILVER2, SKINCOLOR_SUPERSILVER3, SKINCOLOR_SUPERSILVER4, @@ -373,9 +388,17 @@ typedef enum SKINCOLOR_SUPERTAN4, SKINCOLOR_SUPERTAN5, - MAXTRANSLATIONS, - NUMSUPERCOLORS = ((MAXTRANSLATIONS - MAXSKINCOLORS)/5) -} skincolors_t; + SKINCOLOR_FIRSTFREESLOT, + SKINCOLOR_LASTFREESLOT = SKINCOLOR_FIRSTFREESLOT + NUMCOLORFREESLOTS - 1, + + MAXSKINCOLORS, + + NUMSUPERCOLORS = ((SKINCOLOR_FIRSTFREESLOT - FIRSTSUPERCOLOR)/5) +} skincolornum_t; + +extern UINT16 numskincolors; + +extern skincolor_t skincolors[MAXSKINCOLORS]; // State updates, number of tics / second. // NOTE: used to setup the timer rate, see I_StartupTimer(). @@ -455,7 +478,8 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...) FUNCDEBUG; // Things that used to be in dstrings.h #define SAVEGAMENAME "srb2sav" -char savegamename[256]; +extern char savegamename[256]; +extern char liveeventbackup[256]; // m_misc.h #ifdef GETTEXT @@ -562,15 +586,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; // None of these that are disabled in the normal build are guaranteed to work perfectly // Compile them at your own risk! -/// Kalaron/Eternity Engine slope code (SRB2CB ported) -#define ESLOPE - -#ifdef ESLOPE -/// Backwards compatibility with SRB2CB's slope linedef types. -/// \note A simple shim that prints a warning. -#define ESLOPE_TYPESHIM -#endif - /// Allows the use of devmode in multiplayer. AKA "fishcake" //#define NETGAME_DEVMODE @@ -580,9 +595,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Dumps the contents of a network save game upon consistency failure for debugging. //#define DUMPCONSISTENCY -/// Polyobject fake flat code -#define POLYOBJECTS_PLANES - /// See name of player in your crosshair #define SEENAMES @@ -605,11 +617,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// memory that never gets touched. #define ALLOW_RESETDATA -#ifndef NONET -/// Display a connection screen on join attempts. -#define CLIENT_LOADINGSCREEN -#endif - /// Experimental tweaks to analog mode. (Needs a lot of work before it's ready for primetime.) //#define REDSANALOG @@ -627,17 +634,13 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// SRB2CB itself ported this from PrBoom+ #define NEWCLIP +/// OpenGL shaders +#define GL_SHADERS + /// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink. /// \note Required for proper collision with moving sloped surfaces that have sector specials on them. #define SECTORSPECIALSAFTERTHINK -/// FINALLY some real clipping that doesn't make walls dissappear AND speeds the game up -/// (that was the original comment from SRB2CB, sadly it is a lie and actually slows game down) -/// on the bright side it fixes some weird issues with translucent walls -/// \note SRB2CB port. -/// SRB2CB itself ported this from PrBoom+ -#define NEWCLIP - /// Cache patches in Lua in a way that renderer switching will work flawlessly. //#define LUA_PATCH_SAFETY diff --git a/src/doomstat.h b/src/doomstat.h index b1266a9a3..3abaf2988 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -45,7 +45,19 @@ extern INT32 curWeather; extern INT32 cursaveslot; //extern INT16 lastmapsaved; extern INT16 lastmaploaded; -extern boolean gamecomplete; +extern UINT8 gamecomplete; + +// Extra abilities/settings for skins (combinable stuff) +typedef enum +{ + MA_RUNNING = 1, // In action + MA_INIT = 1<<1, // Initialisation + MA_NOCUTSCENES = 1<<2, // No cutscenes + MA_INGAME = 1<<3 // Timer ignores loads +} marathonmode_t; + +extern marathonmode_t marathonmode; +extern tic_t marathontime; #define maxgameovers 13 extern UINT8 numgameovers; @@ -127,7 +139,7 @@ extern INT32 displayplayer; extern INT32 secondarydisplayplayer; // for splitscreen // Maps of special importance -extern INT16 spstage_start; +extern INT16 spstage_start, spmarathon_start; extern INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; extern INT16 titlemap; @@ -145,7 +157,7 @@ extern INT32 tutorialanalog; // store cv_analog[0] user value extern boolean looptitle; // CTF colors. -extern UINT8 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering; +extern UINT16 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering; extern tic_t countdowntimer; extern boolean countdowntimeup; @@ -289,6 +301,7 @@ typedef struct UINT8 actnum; ///< Act number or 0 for none. UINT32 typeoflevel; ///< Combination of typeoflevel flags. INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end. + INT16 marathonnext; ///< See nextlevel, but for Marathon mode. Necessary to support hub worlds ala SUGOI. char keywords[33]; ///< Keywords separated by space to search for. 32 characters. char musname[7]; ///< Music track to play. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. @@ -319,6 +332,9 @@ typedef struct char selectheading[22]; ///< Level select heading. Allows for controllable grouping. UINT16 startrings; ///< Number of rings players start with. + INT32 sstimer; ///< Timer for special stages. + UINT32 ssspheres; ///< Sphere requirement in special stages. + fixed_t gravity; ///< Map-wide gravity. // Title card. char ltzzpatch[8]; ///< Zig zag patch. @@ -493,7 +509,6 @@ extern UINT16 emeralds; #define EMERALD7 64 #define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) -// yes, even in non HAVE_BLUA #define NUM_LUABANKS 16 // please only make this number go up between versions, never down. you'll break saves otherwise. also, must fit in UINT8 extern INT32 luabanks[NUM_LUABANKS]; @@ -543,7 +558,7 @@ extern recorddata_t *mainrecords[NUMMAPS]; extern UINT8 mapvisited[NUMMAPS]; // Temporary holding place for nights data for the current map -nightsdata_t ntemprecords; +extern nightsdata_t ntemprecords; extern UINT32 token; ///< Number of tokens collected in a level extern UINT32 tokenlist; ///< List of tokens collected @@ -573,9 +588,12 @@ extern UINT16 nightslinktics; extern UINT8 introtoplay; extern UINT8 creditscutscene; +extern UINT8 useBlackRock; extern UINT8 use1upSound; extern UINT8 maxXtraLife; // Max extra lives from rings +extern UINT8 useContinues; +#define continuesInSession (!multiplayer && (ultimatemode || (useContinues && !marathonmode) || (!modeattacking && !(cursaveslot > 0)))) extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations @@ -616,6 +634,19 @@ extern mapthing_t *playerstarts[MAXPLAYERS]; // Cooperative extern mapthing_t *bluectfstarts[MAXPLAYERS]; // CTF extern mapthing_t *redctfstarts[MAXPLAYERS]; // CTF +#define WAYPOINTSEQUENCESIZE 256 +#define NUMWAYPOINTSEQUENCES 256 +extern mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE]; +extern UINT16 numwaypoints[NUMWAYPOINTSEQUENCES]; + +void P_AddWaypoint(UINT8 sequence, UINT8 id, mobj_t *waypoint); +mobj_t *P_GetFirstWaypoint(UINT8 sequence); +mobj_t *P_GetLastWaypoint(UINT8 sequence); +mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap); +mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap); +mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo); +boolean P_IsDegeneratedWaypointSequence(UINT8 sequence); + // ===================================== // Internal parameters, used for engine. // ===================================== diff --git a/src/doomtype.h b/src/doomtype.h index 6365f851e..571e930e0 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index 5c0f7eb99..4a657ed19 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -16,6 +16,11 @@ tic_t I_GetTime(void) return 0; } +int I_GetTimeMicros(void) +{ + return 0; +} + void I_Sleep(void){} void I_GetEvent(void){} diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c index fafeee000..56ead3672 100644 --- a/src/dummy/i_video.c +++ b/src/dummy/i_video.c @@ -11,10 +11,10 @@ boolean allow_fullscreen = false; consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; void I_StartupGraphics(void){} -void I_StartupHardwareGraphics(void){} - void I_ShutdownGraphics(void){} +void VID_StartupOpenGL(void){} + void I_SetPalette(RGBA_t *palette) { (void)palette; @@ -40,10 +40,8 @@ INT32 VID_SetMode(INT32 modenum) return 0; } -void VID_CheckRenderer(void) -{ - // .............. -} +void VID_CheckRenderer(void) {} +void VID_CheckGLLoaded(rendermode_t oldrender) {} const char *VID_GetModeName(INT32 modenum) { diff --git a/src/endian.h b/src/endian.h index 76f3ef6e8..24d8e35cd 100644 --- a/src/endian.h +++ b/src/endian.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/f_finale.c b/src/f_finale.c index 66f963bbb..2ce8fd101 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -39,9 +39,7 @@ #include "fastcmp.h" #include "console.h" -#ifdef HAVE_BLUA #include "lua_hud.h" -#endif // Stage of animation: // 0 = text, 1 = art screen @@ -1120,9 +1118,6 @@ static const char *credits[] = { "\1Sonic Robo Blast II", "\1Credits", "", - "\1Producer", - "Rob Tisdell", - "", "\1Game Design", "Ben \"Mystic\" Geyer", "\"SSNTails\"", @@ -1153,11 +1148,13 @@ static const char *credits[] = { "", "\1Programming", "\1Assistance", + "Colette \"fickleheart\" Bordelon", "\"chi.miru\"", // helped port slope drawing code from ZDoom "Andrew \"orospakr\" Clunis", "Sally \"TehRealSalt\" Cochenour", "Gregor \"Oogaland\" Dick", "Julio \"Chaos Zero 64\" Guir", + "\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Lat'\"", // SRB2-CHAT, the chat window from Kart "Matthew \"Shuffle\" Marsalko", @@ -1176,6 +1173,7 @@ static const char *credits[] = { "\1Art", "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: "Ryan \"Blaze Hedgehog\" Bloom", + "\"ChrispyPixels\"", "Paul \"Boinciel\" Clempson", "Sally \"TehRealSalt\" Cochenour", "\"Dave Lite\"", @@ -1222,6 +1220,7 @@ static const char *credits[] = { "\"SSNTails\"", "", "\1Level Design", + "Colette \"fickleheart\" Bordelon", "Hank \"FuriousFox\" Brannock", "Matthew \"Fawfulfan\" Chapman", "Paul \"Boinciel\" Clempson", @@ -1257,6 +1256,7 @@ static const char *credits[] = { "Johnny \"Sonikku\" Wallbank", "", "\1Testing", + "Discord Community Testers", "Hank \"FuriousFox\" Brannock", "Cody \"SRB2 Playah\" Koester", "Skye \"OmegaVelocity\" Meredith", @@ -1332,10 +1332,6 @@ void F_StartCredits(void) // Just in case they're open ... somehow M_ClearMenus(true); - // Save the second we enter the credits - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) - G_SaveGame((UINT32)cursaveslot); - if (creditscutscene) { F_StartCustomCutscene(creditscutscene - 1, false, false); @@ -1531,12 +1527,6 @@ void F_StartGameEvaluation(void) // Just in case they're open ... somehow M_ClearMenus(true); - // Save the second we enter the evaluation - // We need to do this again! Remember, it's possible a mod designed skipped - // the credits sequence! - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) - G_SaveGame((UINT32)cursaveslot); - goodending = (ALL7EMERALDS(emeralds)); gameaction = ga_nothing; @@ -1553,13 +1543,20 @@ void F_GameEvaluationDrawer(void) angle_t fa; INT32 eemeralds_cur; char patchname[7] = "CEMGx0"; - const char* endingtext = (goodending ? "CONGRATULATIONS!" : "TRY AGAIN..."); + const char* endingtext; + + if (marathonmode) + endingtext = "THANKS FOR THE RUN!"; + else if (goodending) + endingtext = "CONGRATULATIONS!"; + else + endingtext = "TRY AGAIN..."; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Draw all the good crap here. - if (finalecount > 0) + if (finalecount > 0 && useBlackRock) { INT32 scale = FRACUNIT; patch_t *rockpat; @@ -1686,7 +1683,9 @@ void F_GameEvaluationTicker(void) return; } - if (!goodending) + if (!useBlackRock) + ; + else if (!goodending) { if (sparklloop) sparklloop--; @@ -1843,10 +1842,6 @@ void F_StartEnding(void) // Just in case they're open ... somehow M_ClearMenus(true); - // Save before the credits sequence. - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) - G_SaveGame((UINT32)cursaveslot); - gameaction = ga_nothing; paused = false; CON_ToggleOff(); @@ -2187,7 +2182,7 @@ void F_EndingDrawer(void) for (i = 0; i < 7; ++i) { UINT8* colormap; - skincolors_t col = SKINCOLOR_GREEN; + skincolornum_t col = SKINCOLOR_GREEN; switch (i) { case 1: @@ -2762,11 +2757,7 @@ void F_TitleScreenDrawer(void) // rei|miru: use title pics? hidepics = curhidepics; if (hidepics) -#ifdef HAVE_BLUA goto luahook; -#else - return; -#endif switch(curttmode) { @@ -3488,10 +3479,8 @@ void F_TitleScreenDrawer(void) break; } -#ifdef HAVE_BLUA luahook: LUAh_TitleHUD(); -#endif } // separate animation timer for backgrounds, since we also count @@ -3626,7 +3615,7 @@ void F_StartContinue(void) { I_Assert(!netgame && !multiplayer); - if (players[consoleplayer].continues <= 0) + if (continuesInSession && players[consoleplayer].continues <= 0) { Command_ExitGame_f(); return; @@ -3733,7 +3722,9 @@ void F_ContinueDrawer(void) } // Draw the continue markers! Show continues. - if (ncontinues > 10) + if (!continuesInSession) + ; + else if (ncontinues > 10) { if (!(continuetime & 1) || continuetime > 17) V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); @@ -3965,6 +3956,7 @@ static void F_AdvanceToNextScene(void) animtimer = pictime = cutscenes[cutnum]->scene[scenenum].picduration[picnum]; } +// See also G_AfterIntermission, the only other place which handles intra-map/ending transitions void F_EndCutScene(void) { cutsceneover = true; // do this first, just in case G_EndGame or something wants to turn it back false later diff --git a/src/f_finale.h b/src/f_finale.h index efc2de2e6..b3abf1778 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -162,7 +162,9 @@ extern wipestyleflags_t wipestyleflags; // Even my function names are borderline boolean F_ShouldColormapFade(void); boolean F_TryColormapFade(UINT8 wipecolor); +#ifndef NOWIPE void F_DecideWipeStyle(void); +#endif #define FADECOLORMAPDIV 8 #define FADECOLORMAPROWS (256/FADECOLORMAPDIV) diff --git a/src/f_wipe.c b/src/f_wipe.c index f8b24d387..01b45b0c2 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -16,6 +16,7 @@ #include "i_video.h" #include "v_video.h" +#include "r_state.h" // fadecolormap #include "r_draw.h" // transtable #include "p_pspr.h" // tr_transxxx #include "p_local.h" @@ -32,9 +33,7 @@ #include "doomstat.h" -#ifdef HAVE_BLUA #include "lua_hud.h" // level title -#endif #ifdef HWRENDER #include "hardware/hw_main.h" @@ -465,6 +464,7 @@ void F_WipeEndScreen(void) */ boolean F_ShouldColormapFade(void) { +#ifndef NOWIPE if ((wipestyleflags & (WSF_FADEIN|WSF_FADEOUT)) // only if one of those wipestyleflags are actually set && !(wipestyleflags & WSF_CROSSFADE)) // and if not crossfading { @@ -480,11 +480,13 @@ boolean F_ShouldColormapFade(void) // Menus || gamestate == GS_TIMEATTACK); } +#endif return false; } /** Decides what wipe style to use. */ +#ifndef NOWIPE void F_DecideWipeStyle(void) { // Set default wipe style @@ -494,6 +496,7 @@ void F_DecideWipeStyle(void) if (F_ShouldColormapFade()) wipestyle = WIPESTYLE_COLORMAP; } +#endif /** Attempt to run a colormap fade, provided all the conditionals were properly met. @@ -502,6 +505,7 @@ void F_DecideWipeStyle(void) */ boolean F_TryColormapFade(UINT8 wipecolor) { +#ifndef NOWIPE if (F_ShouldColormapFade()) { #ifdef HWRENDER @@ -511,6 +515,7 @@ boolean F_TryColormapFade(UINT8 wipecolor) return true; } else +#endif { F_WipeColorFill(wipecolor); return false; @@ -609,6 +614,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) tic_t F_GetWipeLength(UINT8 wipetype) { #ifdef NOWIPE + (void)wipetype; return 0; #else static char lumpname[10] = "FADEmmss"; @@ -635,6 +641,7 @@ tic_t F_GetWipeLength(UINT8 wipetype) boolean F_WipeExists(UINT8 wipetype) { #ifdef NOWIPE + (void)wipetype; return false; #else static char lumpname[10] = "FADEmm00"; diff --git a/src/filesrch.h b/src/filesrch.h index 4186271b0..dfea8979e 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -60,7 +60,7 @@ typedef enum #endif EXT_PK3, EXT_SOC, - EXT_LUA, // allowed even if not HAVE_BLUA so that we can yell on load attempt + EXT_LUA, NUM_EXT, NUM_EXT_TABLE = NUM_EXT-EXT_START, EXT_LOADED = 0x80 diff --git a/src/g_demo.c b/src/g_demo.c new file mode 100644 index 000000000..4dad85a3c --- /dev/null +++ b/src/g_demo.c @@ -0,0 +1,2526 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file g_demo.c +/// \brief Demo recording and playback + +#include "doomdef.h" +#include "console.h" +#include "d_main.h" +#include "d_player.h" +#include "d_clisrv.h" +#include "p_setup.h" +#include "i_system.h" +#include "m_random.h" +#include "p_local.h" +#include "r_draw.h" +#include "r_main.h" +#include "g_game.h" +#include "g_demo.h" +#include "m_misc.h" +#include "m_menu.h" +#include "m_argv.h" +#include "hu_stuff.h" +#include "z_zone.h" +#include "i_video.h" +#include "byteptr.h" +#include "i_joy.h" +#include "r_local.h" +#include "r_skins.h" +#include "y_inter.h" +#include "v_video.h" +#include "lua_hook.h" +#include "md5.h" // demo checksums + +boolean timingdemo; // if true, exit with report on completion +boolean nodrawers; // for comparative timing purposes +boolean noblit; // for comparative timing purposes +tic_t demostarttime; // for comparative timing purposes + +static char demoname[64]; +boolean demorecording; +boolean demoplayback; +boolean titledemo; // Title Screen demo can be cancelled by any key +static UINT8 *demobuffer = NULL; +static UINT8 *demo_p, *demotime_p; +static UINT8 *demoend; +static UINT8 demoflags; +static UINT16 demoversion; +boolean singledemo; // quit after playing a demo from cmdline +boolean demo_start; // don't start playing demo right away +boolean demosynced = true; // console warning message + +boolean metalrecording; // recording as metal sonic +mobj_t *metalplayback; +static UINT8 *metalbuffer = NULL; +static UINT8 *metal_p; +static UINT16 metalversion; + +// extra data stuff (events registered this frame while recording) +static struct { + UINT8 flags; // EZT flags + + // EZT_COLOR + UINT16 color, lastcolor; + + // EZT_SCALE + fixed_t scale, lastscale; + + // EZT_HIT + UINT16 hits; + mobj_t **hitlist; +} ghostext; + +// Your naming conventions are stupid and useless. +// There is no conflict here. +typedef struct demoghost { + UINT8 checksum[16]; + UINT8 *buffer, *p, fadein; + UINT16 color; + UINT16 version; + mobj_t oldmo, *mo; + struct demoghost *next; +} demoghost; +demoghost *ghosts = NULL; + +// +// DEMO RECORDING +// + +#define DEMOVERSION 0x000d +#define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" + +#define DF_GHOST 0x01 // This demo contains ghost data too! +#define DF_RECORDATTACK 0x02 // This demo is from record attack and contains its final completion time, score, and rings! +#define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! +#define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? +#define DF_ATTACKSHIFT 1 + +// For demos +#define ZT_FWD 0x01 +#define ZT_SIDE 0x02 +#define ZT_ANGLE 0x04 +#define ZT_BUTTONS 0x08 +#define ZT_AIMING 0x10 +#define DEMOMARKER 0x80 // demoend +#define METALDEATH 0x44 +#define METALSNICE 0x69 + +static ticcmd_t oldcmd; + +// For Metal Sonic and time attack ghosts +#define GZT_XYZ 0x01 +#define GZT_MOMXY 0x02 +#define GZT_MOMZ 0x04 +#define GZT_ANGLE 0x08 +#define GZT_FRAME 0x10 // Animation frame +#define GZT_SPR2 0x20 // Player animations +#define GZT_EXTRA 0x40 +#define GZT_FOLLOW 0x80 // Followmobj + +// GZT_EXTRA flags +#define EZT_THOK 0x01 // Spawned a thok object +#define EZT_SPIN 0x02 // Because one type of thok object apparently wasn't enough +#define EZT_REV 0x03 // And two types wasn't enough either yet +#define EZT_THOKMASK 0x03 +#define EZT_COLOR 0x04 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) +#define EZT_FLIP 0x08 // Reversed gravity +#define EZT_SCALE 0x10 // Changed size +#define EZT_HIT 0x20 // Damaged a mobj +#define EZT_SPRITE 0x40 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) +#define EZT_HEIGHT 0x80 // Changed height + +// GZT_FOLLOW flags +#define FZT_SPAWNED 0x01 // just been spawned +#define FZT_SKIN 0x02 // has skin +#define FZT_LINKDRAW 0x04 // has linkdraw (combine with spawned only) +#define FZT_COLORIZED 0x08 // colorized (ditto) +#define FZT_SCALE 0x10 // different scale to object +// spare FZT slots 0x20 to 0x80 + +static mobj_t oldmetal, oldghost; + +void G_SaveMetal(UINT8 **buffer) +{ + I_Assert(buffer != NULL && *buffer != NULL); + + WRITEUINT32(*buffer, metal_p - metalbuffer); +} + +void G_LoadMetal(UINT8 **buffer) +{ + I_Assert(buffer != NULL && *buffer != NULL); + + G_DoPlayMetal(); + metal_p = metalbuffer + READUINT32(*buffer); +} + + +void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) +{ + UINT8 ziptic; + + if (!demo_p || !demo_start) + return; + ziptic = READUINT8(demo_p); + + if (ziptic & ZT_FWD) + oldcmd.forwardmove = READSINT8(demo_p); + if (ziptic & ZT_SIDE) + oldcmd.sidemove = READSINT8(demo_p); + if (ziptic & ZT_ANGLE) + oldcmd.angleturn = READINT16(demo_p); + if (ziptic & ZT_BUTTONS) + oldcmd.buttons = (oldcmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) | (READUINT16(demo_p) & ~(BT_CAMLEFT|BT_CAMRIGHT)); + if (ziptic & ZT_AIMING) + oldcmd.aiming = READINT16(demo_p); + + G_CopyTiccmd(cmd, &oldcmd, 1); + players[playernum].angleturn = cmd->angleturn; + + if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) + { + // end of demo data stream + G_CheckDemoStatus(); + return; + } +} + +void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) +{ + char ziptic = 0; + UINT8 *ziptic_p; + (void)playernum; + + if (!demo_p) + return; + ziptic_p = demo_p++; // the ziptic, written at the end of this function + + if (cmd->forwardmove != oldcmd.forwardmove) + { + WRITEUINT8(demo_p,cmd->forwardmove); + oldcmd.forwardmove = cmd->forwardmove; + ziptic |= ZT_FWD; + } + + if (cmd->sidemove != oldcmd.sidemove) + { + WRITEUINT8(demo_p,cmd->sidemove); + oldcmd.sidemove = cmd->sidemove; + ziptic |= ZT_SIDE; + } + + if (cmd->angleturn != oldcmd.angleturn) + { + WRITEINT16(demo_p,cmd->angleturn); + oldcmd.angleturn = cmd->angleturn; + ziptic |= ZT_ANGLE; + } + + if (cmd->buttons != oldcmd.buttons) + { + WRITEUINT16(demo_p,cmd->buttons); + oldcmd.buttons = cmd->buttons; + ziptic |= ZT_BUTTONS; + } + + if (cmd->aiming != oldcmd.aiming) + { + WRITEINT16(demo_p,cmd->aiming); + oldcmd.aiming = cmd->aiming; + ziptic |= ZT_AIMING; + } + + *ziptic_p = ziptic; + + // attention here for the ticcmd size! + // latest demos with mouse aiming byte in ticcmd + if (!(demoflags & DF_GHOST) && ziptic_p > demoend - 9) + { + G_CheckDemoStatus(); // no more space + return; + } +} + +void G_GhostAddThok(void) +{ + if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) + return; + ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_THOK; +} + +void G_GhostAddSpin(void) +{ + if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) + return; + ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_SPIN; +} + +void G_GhostAddRev(void) +{ + if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) + return; + ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_REV; +} + +void G_GhostAddFlip(void) +{ + if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) + return; + ghostext.flags |= EZT_FLIP; +} + +void G_GhostAddColor(ghostcolor_t color) +{ + if (!demorecording || !(demoflags & DF_GHOST)) + return; + if (ghostext.lastcolor == (UINT16)color) + { + ghostext.flags &= ~EZT_COLOR; + return; + } + ghostext.flags |= EZT_COLOR; + ghostext.color = (UINT16)color; +} + +void G_GhostAddScale(fixed_t scale) +{ + if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) + return; + if (ghostext.lastscale == scale) + { + ghostext.flags &= ~EZT_SCALE; + return; + } + ghostext.flags |= EZT_SCALE; + ghostext.scale = scale; +} + +void G_GhostAddHit(mobj_t *victim) +{ + if (!demorecording || !(demoflags & DF_GHOST)) + return; + ghostext.flags |= EZT_HIT; + ghostext.hits++; + ghostext.hitlist = Z_Realloc(ghostext.hitlist, ghostext.hits * sizeof(mobj_t *), PU_LEVEL, NULL); + ghostext.hitlist[ghostext.hits-1] = victim; +} + +void G_WriteGhostTic(mobj_t *ghost) +{ + char ziptic = 0; + UINT8 *ziptic_p; + UINT32 i; + fixed_t height; + + if (!demo_p) + return; + if (!(demoflags & DF_GHOST)) + return; // No ghost data to write. + + ziptic_p = demo_p++; // the ziptic, written at the end of this function + + #define MAXMOM (0xFFFF<<8) + + // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. + if (abs(ghost->x-oldghost.x) > MAXMOM + || abs(ghost->y-oldghost.y) > MAXMOM + || abs(ghost->z-oldghost.z) > MAXMOM) + { + oldghost.x = ghost->x; + oldghost.y = ghost->y; + oldghost.z = ghost->z; + ziptic |= GZT_XYZ; + WRITEFIXED(demo_p,oldghost.x); + WRITEFIXED(demo_p,oldghost.y); + WRITEFIXED(demo_p,oldghost.z); + } + else + { + // For moving normally: + // Store one full byte of movement, plus one byte of fractional movement. + INT16 momx = (INT16)((ghost->x-oldghost.x)>>8); + INT16 momy = (INT16)((ghost->y-oldghost.y)>>8); + if (momx != oldghost.momx + || momy != oldghost.momy) + { + oldghost.momx = momx; + oldghost.momy = momy; + ziptic |= GZT_MOMXY; + WRITEINT16(demo_p,momx); + WRITEINT16(demo_p,momy); + } + momx = (INT16)((ghost->z-oldghost.z)>>8); + if (momx != oldghost.momz) + { + oldghost.momz = momx; + ziptic |= GZT_MOMZ; + WRITEINT16(demo_p,momx); + } + + // This SHOULD set oldghost.x/y/z to match ghost->x/y/z + // but it keeps the fractional loss of one byte, + // so it will hopefully be made up for in future tics. + oldghost.x += oldghost.momx<<8; + oldghost.y += oldghost.momy<<8; + oldghost.z += oldghost.momz<<8; + } + + #undef MAXMOM + + // Only store the 8 most relevant bits of angle + // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites + // and it does not affect this mode of movement at all anyway. + if (ghost->player && ghost->player->drawangle>>24 != oldghost.angle) + { + oldghost.angle = ghost->player->drawangle>>24; + ziptic |= GZT_ANGLE; + WRITEUINT8(demo_p,oldghost.angle); + } + + // Store the sprite frame. + if ((ghost->frame & FF_FRAMEMASK) != oldghost.frame) + { + oldghost.frame = (ghost->frame & FF_FRAMEMASK); + ziptic |= GZT_FRAME; + WRITEUINT8(demo_p,oldghost.frame); + } + + if (ghost->sprite == SPR_PLAY + && ghost->sprite2 != oldghost.sprite2) + { + oldghost.sprite2 = ghost->sprite2; + ziptic |= GZT_SPR2; + WRITEUINT8(demo_p,oldghost.sprite2); + } + + // Check for sprite set changes + if (ghost->sprite != oldghost.sprite) + { + oldghost.sprite = ghost->sprite; + ghostext.flags |= EZT_SPRITE; + } + + if ((height = FixedDiv(ghost->height, ghost->scale)) != oldghost.height) + { + oldghost.height = height; + ghostext.flags |= EZT_HEIGHT; + } + + if (ghostext.flags) + { + ziptic |= GZT_EXTRA; + + if (ghostext.color == ghostext.lastcolor) + ghostext.flags &= ~EZT_COLOR; + if (ghostext.scale == ghostext.lastscale) + ghostext.flags &= ~EZT_SCALE; + + WRITEUINT8(demo_p,ghostext.flags); + if (ghostext.flags & EZT_COLOR) + { + WRITEUINT16(demo_p,ghostext.color); + ghostext.lastcolor = ghostext.color; + } + if (ghostext.flags & EZT_SCALE) + { + WRITEFIXED(demo_p,ghostext.scale); + ghostext.lastscale = ghostext.scale; + } + if (ghostext.flags & EZT_HIT) + { + WRITEUINT16(demo_p,ghostext.hits); + for (i = 0; i < ghostext.hits; i++) + { + mobj_t *mo = ghostext.hitlist[i]; + //WRITEUINT32(demo_p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) + WRITEUINT32(demo_p,mo->type); + WRITEUINT16(demo_p,(UINT16)mo->health); + WRITEFIXED(demo_p,mo->x); + WRITEFIXED(demo_p,mo->y); + WRITEFIXED(demo_p,mo->z); + WRITEANGLE(demo_p,mo->angle); + } + Z_Free(ghostext.hitlist); + ghostext.hits = 0; + ghostext.hitlist = NULL; + } + if (ghostext.flags & EZT_SPRITE) + WRITEUINT16(demo_p,oldghost.sprite); + if (ghostext.flags & EZT_HEIGHT) + { + height >>= FRACBITS; + WRITEINT16(demo_p, height); + } + ghostext.flags = 0; + } + + if (ghost->player && ghost->player->followmobj && !(ghost->player->followmobj->sprite == SPR_NULL || (ghost->player->followmobj->flags2 & MF2_DONTDRAW))) // bloats tails runs but what can ya do + { + INT16 temp; + UINT8 *followtic_p = demo_p++; + UINT8 followtic = 0; + + ziptic |= GZT_FOLLOW; + + if (ghost->player->followmobj->skin) + followtic |= FZT_SKIN; + + if (!(oldghost.flags2 & MF2_AMBUSH)) + { + followtic |= FZT_SPAWNED; + WRITEINT16(demo_p,ghost->player->followmobj->info->height>>FRACBITS); + if (ghost->player->followmobj->flags2 & MF2_LINKDRAW) + followtic |= FZT_LINKDRAW; + if (ghost->player->followmobj->colorized) + followtic |= FZT_COLORIZED; + if (followtic & FZT_SKIN) + WRITEUINT8(demo_p,(UINT8)(((skin_t *)(ghost->player->followmobj->skin))-skins)); + oldghost.flags2 |= MF2_AMBUSH; + } + + if (ghost->player->followmobj->scale != ghost->scale) + { + followtic |= FZT_SCALE; + WRITEFIXED(demo_p,ghost->player->followmobj->scale); + } + + temp = (INT16)((ghost->player->followmobj->x-ghost->x)>>8); + WRITEINT16(demo_p,temp); + temp = (INT16)((ghost->player->followmobj->y-ghost->y)>>8); + WRITEINT16(demo_p,temp); + temp = (INT16)((ghost->player->followmobj->z-ghost->z)>>8); + WRITEINT16(demo_p,temp); + if (followtic & FZT_SKIN) + WRITEUINT8(demo_p,ghost->player->followmobj->sprite2); + WRITEUINT16(demo_p,ghost->player->followmobj->sprite); + WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK)); + WRITEUINT16(demo_p,ghost->player->followmobj->color); + + *followtic_p = followtic; + } + else + oldghost.flags2 &= ~MF2_AMBUSH; + + *ziptic_p = ziptic; + + // attention here for the ticcmd size! + // latest demos with mouse aiming byte in ticcmd + if (demo_p >= demoend - (13 + 9 + 9)) + { + G_CheckDemoStatus(); // no more space + return; + } +} + +// Uses ghost data to do consistency checks on your position. +// This fixes desynchronising demos when fighting eggman. +void G_ConsGhostTic(void) +{ + UINT8 ziptic; + UINT16 px,py,pz,gx,gy,gz; + mobj_t *testmo; + + if (!demo_p || !demo_start) + return; + if (!(demoflags & DF_GHOST)) + return; // No ghost data to use. + + testmo = players[0].mo; + + // Grab ghost data. + ziptic = READUINT8(demo_p); + if (ziptic & GZT_XYZ) + { + oldghost.x = READFIXED(demo_p); + oldghost.y = READFIXED(demo_p); + oldghost.z = READFIXED(demo_p); + } + else + { + if (ziptic & GZT_MOMXY) + { + oldghost.momx = READINT16(demo_p)<<8; + oldghost.momy = READINT16(demo_p)<<8; + } + if (ziptic & GZT_MOMZ) + oldghost.momz = READINT16(demo_p)<<8; + oldghost.x += oldghost.momx; + oldghost.y += oldghost.momy; + oldghost.z += oldghost.momz; + } + if (ziptic & GZT_ANGLE) + demo_p++; + if (ziptic & GZT_FRAME) + demo_p++; + if (ziptic & GZT_SPR2) + demo_p++; + + if (ziptic & GZT_EXTRA) + { // But wait, there's more! + UINT8 xziptic = READUINT8(demo_p); + if (xziptic & EZT_COLOR) + demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16); + if (xziptic & EZT_SCALE) + demo_p += sizeof(fixed_t); + if (xziptic & EZT_HIT) + { // Resync mob damage. + UINT16 i, count = READUINT16(demo_p); + thinker_t *th; + mobj_t *mobj; + + UINT32 type; + UINT16 health; + fixed_t x; + fixed_t y; + fixed_t z; + + for (i = 0; i < count; i++) + { + //demo_p += 4; // reserved. + type = READUINT32(demo_p); + health = READUINT16(demo_p); + x = READFIXED(demo_p); + y = READFIXED(demo_p); + z = READFIXED(demo_p); + demo_p += sizeof(angle_t); // angle, unnecessary for cons. + + mobj = NULL; + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + mobj = (mobj_t *)th; + if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z) + break; + } + if (th != &thlist[THINK_MOBJ] && mobj->health != health) // Wasn't damaged?! This is desync! Fix it! + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; + P_DamageMobj(mobj, players[0].mo, players[0].mo, 1, 0); + } + } + } + if (xziptic & EZT_SPRITE) + demo_p += sizeof(UINT16); + if (xziptic & EZT_HEIGHT) + demo_p += sizeof(INT16); + } + + if (ziptic & GZT_FOLLOW) + { // Even more... + UINT8 followtic = READUINT8(demo_p); + if (followtic & FZT_SPAWNED) + { + demo_p += sizeof(INT16); + if (followtic & FZT_SKIN) + demo_p++; + } + if (followtic & FZT_SCALE) + demo_p += sizeof(fixed_t); + demo_p += sizeof(INT16); + demo_p += sizeof(INT16); + demo_p += sizeof(INT16); + if (followtic & FZT_SKIN) + demo_p++; + demo_p += sizeof(UINT16); + demo_p++; + demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16); + } + + // Re-synchronise + px = testmo->x>>FRACBITS; + py = testmo->y>>FRACBITS; + pz = testmo->z>>FRACBITS; + gx = oldghost.x>>FRACBITS; + gy = oldghost.y>>FRACBITS; + gz = oldghost.z>>FRACBITS; + + if (px != gx || py != gy || pz != gz) + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; + + P_UnsetThingPosition(testmo); + testmo->x = oldghost.x; + testmo->y = oldghost.y; + P_SetThingPosition(testmo); + testmo->z = oldghost.z; + } + + if (*demo_p == DEMOMARKER) + { + // end of demo data stream + G_CheckDemoStatus(); + return; + } +} + +void G_GhostTicker(void) +{ + demoghost *g,*p; + for(g = ghosts, p = NULL; g; g = g->next) + { + // Skip normal demo data. + UINT8 ziptic = READUINT8(g->p); + UINT8 xziptic = 0; + if (ziptic & ZT_FWD) + g->p++; + if (ziptic & ZT_SIDE) + g->p++; + if (ziptic & ZT_ANGLE) + g->p += 2; + if (ziptic & ZT_BUTTONS) + g->p += 2; + if (ziptic & ZT_AIMING) + g->p += 2; + + // Grab ghost data. + ziptic = READUINT8(g->p); + if (ziptic & GZT_XYZ) + { + g->oldmo.x = READFIXED(g->p); + g->oldmo.y = READFIXED(g->p); + g->oldmo.z = READFIXED(g->p); + } + else + { + if (ziptic & GZT_MOMXY) + { + g->oldmo.momx = READINT16(g->p)<<8; + g->oldmo.momy = READINT16(g->p)<<8; + } + if (ziptic & GZT_MOMZ) + g->oldmo.momz = READINT16(g->p)<<8; + g->oldmo.x += g->oldmo.momx; + g->oldmo.y += g->oldmo.momy; + g->oldmo.z += g->oldmo.momz; + } + if (ziptic & GZT_ANGLE) + g->mo->angle = READUINT8(g->p)<<24; + if (ziptic & GZT_FRAME) + g->oldmo.frame = READUINT8(g->p); + if (ziptic & GZT_SPR2) + g->oldmo.sprite2 = READUINT8(g->p); + + // Update ghost + P_UnsetThingPosition(g->mo); + g->mo->x = g->oldmo.x; + g->mo->y = g->oldmo.y; + g->mo->z = g->oldmo.z; + P_SetThingPosition(g->mo); + g->mo->frame = g->oldmo.frame | tr_trans30<fadein) + { + g->mo->frame += (((--g->fadein)/6)<fadein is bad, and it's only set once, so... + g->mo->flags2 &= ~MF2_DONTDRAW; + } + g->mo->sprite2 = g->oldmo.sprite2; + + if (ziptic & GZT_EXTRA) + { // But wait, there's more! + xziptic = READUINT8(g->p); + if (xziptic & EZT_COLOR) + { + g->color = (g->version==0x000c) ? READUINT8(g->p) : READUINT16(g->p); + switch(g->color) + { + default: + case GHC_RETURNSKIN: + g->mo->skin = g->oldmo.skin; + /* FALLTHRU */ + case GHC_NORMAL: // Go back to skin color + g->mo->color = g->oldmo.color; + break; + // Handled below + case GHC_SUPER: + case GHC_INVINCIBLE: + break; + case GHC_FIREFLOWER: // Fireflower + g->mo->color = SKINCOLOR_WHITE; + break; + case GHC_NIGHTSSKIN: // not actually a colour + g->mo->skin = &skins[DEFAULTNIGHTSSKIN]; + break; + } + } + if (xziptic & EZT_FLIP) + g->mo->eflags ^= MFE_VERTICALFLIP; + if (xziptic & EZT_SCALE) + { + g->mo->destscale = READFIXED(g->p); + if (g->mo->destscale != g->mo->scale) + P_SetScale(g->mo, g->mo->destscale); + } + if (xziptic & EZT_THOKMASK) + { // Let's only spawn ONE of these per frame, thanks. + mobj_t *mobj; + UINT32 type = MT_NULL; + if (g->mo->skin) + { + skin_t *skin = (skin_t *)g->mo->skin; + switch (xziptic & EZT_THOKMASK) + { + case EZT_THOK: + type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; + break; + case EZT_SPIN: + type = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; + break; + case EZT_REV: + type = skin->revitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; + break; + } + } + if (type != MT_NULL) + { + if (type == MT_GHOST) + { + mobj = P_SpawnGhostMobj(g->mo); // does a large portion of the work for us + mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|tr_trans60<mo, 0, 0, -FixedDiv(FixedMul(g->mo->info->height, g->mo->scale) - g->mo->height,3*FRACUNIT), MT_THOK); + mobj->sprite = states[mobjinfo[type].spawnstate].sprite; + mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<color = g->mo->color; + mobj->skin = g->mo->skin; + P_SetScale(mobj, (mobj->destscale = g->mo->scale)); + + if (type == MT_THOK) // spintrail-specific modification for MT_THOK + { + mobj->frame = FF_TRANS80; + mobj->fuse = mobj->tics; + } + mobj->tics = -1; // nope. + } + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_UnsetThingPosition(mobj); + mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... + P_SetThingPosition(mobj); + if (!mobj->fuse) + mobj->fuse = 8; + P_SetTarget(&mobj->target, g->mo); + } + } + if (xziptic & EZT_HIT) + { // Spawn hit poofs for killing things! + UINT16 i, count = READUINT16(g->p), health; + UINT32 type; + fixed_t x,y,z; + angle_t angle; + mobj_t *poof; + for (i = 0; i < count; i++) + { + //g->p += 4; // reserved + type = READUINT32(g->p); + health = READUINT16(g->p); + x = READFIXED(g->p); + y = READFIXED(g->p); + z = READFIXED(g->p); + angle = READANGLE(g->p); + if (!(mobjinfo[type].flags & MF_SHOOTABLE) + || !(mobjinfo[type].flags & (MF_ENEMY|MF_MONITOR)) + || health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. + continue; + poof = P_SpawnMobj(x, y, z, MT_GHOST); + poof->angle = angle; + poof->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... + poof->health = 0; + P_SetMobjStateNF(poof, S_XPLD1); + } + } + if (xziptic & EZT_SPRITE) + g->mo->sprite = READUINT16(g->p); + if (xziptic & EZT_HEIGHT) + { + fixed_t temp = READINT16(g->p)<mo->height = FixedMul(temp, g->mo->scale); + } + } + + // Tick ghost colors (Super and Mario Invincibility flashing) + switch(g->color) + { + case GHC_SUPER: // Super (P_DoSuperStuff) + if (g->mo->skin) + { + skin_t *skin = (skin_t *)g->mo->skin; + g->mo->color = skin->supercolor; + } + else + g->mo->color = SKINCOLOR_SUPERGOLD1; + g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4); + break; + case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer) + g->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours + break; + default: + break; + } + +#define follow g->mo->tracer + if (ziptic & GZT_FOLLOW) + { // Even more... + UINT8 followtic = READUINT8(g->p); + fixed_t temp; + if (followtic & FZT_SPAWNED) + { + if (follow) + P_RemoveMobj(follow); + P_SetTarget(&follow, P_SpawnMobjFromMobj(g->mo, 0, 0, 0, MT_GHOST)); + P_SetTarget(&follow->tracer, g->mo); + follow->tics = -1; + temp = READINT16(g->p)<height = FixedMul(follow->scale, temp); + + if (followtic & FZT_LINKDRAW) + follow->flags2 |= MF2_LINKDRAW; + + if (followtic & FZT_COLORIZED) + follow->colorized = true; + + if (followtic & FZT_SKIN) + follow->skin = &skins[READUINT8(g->p)]; + } + if (follow) + { + if (followtic & FZT_SCALE) + follow->destscale = READFIXED(g->p); + else + follow->destscale = g->mo->destscale; + if (follow->destscale != follow->scale) + P_SetScale(follow, follow->destscale); + + P_UnsetThingPosition(follow); + temp = READINT16(g->p)<<8; + follow->x = g->mo->x + temp; + temp = READINT16(g->p)<<8; + follow->y = g->mo->y + temp; + temp = READINT16(g->p)<<8; + follow->z = g->mo->z + temp; + P_SetThingPosition(follow); + if (followtic & FZT_SKIN) + follow->sprite2 = READUINT8(g->p); + else + follow->sprite2 = 0; + follow->sprite = READUINT16(g->p); + follow->frame = (READUINT8(g->p)) | (g->mo->frame & FF_TRANSMASK); + follow->angle = g->mo->angle; + follow->color = (g->version==0x000c) ? READUINT8(g->p) : READUINT16(g->p); + + if (!(followtic & FZT_SPAWNED)) + { + if (xziptic & EZT_FLIP) + { + follow->flags2 ^= MF2_OBJECTFLIP; + follow->eflags ^= MFE_VERTICALFLIP; + } + } + } + } + else if (follow) + { + P_RemoveMobj(follow); + P_SetTarget(&follow, NULL); + } + // Demo ends after ghost data. + if (*g->p == DEMOMARKER) + { + g->mo->momx = g->mo->momy = g->mo->momz = 0; +#if 1 // freeze frame (maybe more useful for time attackers) + g->mo->colorized = true; + if (follow) + follow->colorized = true; +#else // dissapearing act + g->mo->fuse = TICRATE; + if (follow) + follow->fuse = TICRATE; +#endif + if (p) + p->next = g->next; + else + ghosts = g->next; + Z_Free(g); + continue; + } + p = g; +#undef follow + } +} + +void G_ReadMetalTic(mobj_t *metal) +{ + UINT8 ziptic; + UINT8 xziptic = 0; + + if (!metal_p) + return; + + if (!metal->health) + { + G_StopMetalDemo(); + return; + } + + switch (*metal_p) + { + case METALSNICE: + break; + case METALDEATH: + if (metal->tracer) + P_RemoveMobj(metal->tracer); + P_KillMobj(metal, NULL, NULL, 0); + /* FALLTHRU */ + case DEMOMARKER: + default: + // end of demo data stream + G_StopMetalDemo(); + return; + } + metal_p++; + + ziptic = READUINT8(metal_p); + + // Read changes from the tic + if (ziptic & GZT_XYZ) + { + // make sure the values are read in the right order + oldmetal.x = READFIXED(metal_p); + oldmetal.y = READFIXED(metal_p); + oldmetal.z = READFIXED(metal_p); + P_TeleportMove(metal, oldmetal.x, oldmetal.y, oldmetal.z); + oldmetal.x = metal->x; + oldmetal.y = metal->y; + oldmetal.z = metal->z; + } + else + { + if (ziptic & GZT_MOMXY) + { + oldmetal.momx = READINT16(metal_p)<<8; + oldmetal.momy = READINT16(metal_p)<<8; + } + if (ziptic & GZT_MOMZ) + oldmetal.momz = READINT16(metal_p)<<8; + oldmetal.x += oldmetal.momx; + oldmetal.y += oldmetal.momy; + oldmetal.z += oldmetal.momz; + } + if (ziptic & GZT_ANGLE) + metal->angle = READUINT8(metal_p)<<24; + if (ziptic & GZT_FRAME) + oldmetal.frame = READUINT32(metal_p); + if (ziptic & GZT_SPR2) + oldmetal.sprite2 = READUINT8(metal_p); + + // Set movement, position, and angle + // oldmetal contains where you're supposed to be. + metal->momx = oldmetal.momx; + metal->momy = oldmetal.momy; + metal->momz = oldmetal.momz; + P_UnsetThingPosition(metal); + metal->x = oldmetal.x; + metal->y = oldmetal.y; + metal->z = oldmetal.z; + P_SetThingPosition(metal); + metal->frame = oldmetal.frame; + metal->sprite2 = oldmetal.sprite2; + + if (ziptic & GZT_EXTRA) + { // But wait, there's more! + xziptic = READUINT8(metal_p); + if (xziptic & EZT_FLIP) + { + metal->eflags ^= MFE_VERTICALFLIP; + metal->flags2 ^= MF2_OBJECTFLIP; + } + if (xziptic & EZT_SCALE) + { + metal->destscale = READFIXED(metal_p); + if (metal->destscale != metal->scale) + P_SetScale(metal, metal->destscale); + } + if (xziptic & EZT_THOKMASK) + { // Let's only spawn ONE of these per frame, thanks. + mobj_t *mobj; + UINT32 type = MT_NULL; + if (metal->skin) + { + skin_t *skin = (skin_t *)metal->skin; + switch (xziptic & EZT_THOKMASK) + { + case EZT_THOK: + type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; + break; + case EZT_SPIN: + type = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; + break; + case EZT_REV: + type = skin->revitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; + break; + } + } + if (type != MT_NULL) + { + if (type == MT_GHOST) + { + mobj = P_SpawnGhostMobj(metal); // does a large portion of the work for us + } + else + { + mobj = P_SpawnMobjFromMobj(metal, 0, 0, -FixedDiv(FixedMul(metal->info->height, metal->scale) - metal->height,3*FRACUNIT), MT_THOK); + mobj->sprite = states[mobjinfo[type].spawnstate].sprite; + mobj->frame = states[mobjinfo[type].spawnstate].frame; + mobj->angle = metal->angle; + mobj->color = metal->color; + mobj->skin = metal->skin; + P_SetScale(mobj, (mobj->destscale = metal->scale)); + + if (type == MT_THOK) // spintrail-specific modification for MT_THOK + { + mobj->frame = FF_TRANS70; + mobj->fuse = mobj->tics; + } + mobj->tics = -1; // nope. + } + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_UnsetThingPosition(mobj); + mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... + P_SetThingPosition(mobj); + if (!mobj->fuse) + mobj->fuse = 8; + P_SetTarget(&mobj->target, metal); + } + } + if (xziptic & EZT_SPRITE) + metal->sprite = READUINT16(metal_p); + if (xziptic & EZT_HEIGHT) + { + fixed_t temp = READINT16(metal_p)<height = FixedMul(temp, metal->scale); + } + } + +#define follow metal->tracer + if (ziptic & GZT_FOLLOW) + { // Even more... + UINT8 followtic = READUINT8(metal_p); + fixed_t temp; + if (followtic & FZT_SPAWNED) + { + if (follow) + P_RemoveMobj(follow); + P_SetTarget(&follow, P_SpawnMobjFromMobj(metal, 0, 0, 0, MT_GHOST)); + P_SetTarget(&follow->tracer, metal); + follow->tics = -1; + temp = READINT16(metal_p)<height = FixedMul(follow->scale, temp); + + if (followtic & FZT_LINKDRAW) + follow->flags2 |= MF2_LINKDRAW; + + if (followtic & FZT_COLORIZED) + follow->colorized = true; + + if (followtic & FZT_SKIN) + follow->skin = &skins[READUINT8(metal_p)]; + } + if (follow) + { + if (followtic & FZT_SCALE) + follow->destscale = READFIXED(metal_p); + else + follow->destscale = metal->destscale; + if (follow->destscale != follow->scale) + P_SetScale(follow, follow->destscale); + + P_UnsetThingPosition(follow); + temp = READINT16(metal_p)<<8; + follow->x = metal->x + temp; + temp = READINT16(metal_p)<<8; + follow->y = metal->y + temp; + temp = READINT16(metal_p)<<8; + follow->z = metal->z + temp; + P_SetThingPosition(follow); + if (followtic & FZT_SKIN) + follow->sprite2 = READUINT8(metal_p); + else + follow->sprite2 = 0; + follow->sprite = READUINT16(metal_p); + follow->frame = READUINT32(metal_p); // NOT & FF_FRAMEMASK here, so 32 bits + follow->angle = metal->angle; + follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p); + + if (!(followtic & FZT_SPAWNED)) + { + if (xziptic & EZT_FLIP) + { + follow->flags2 ^= MF2_OBJECTFLIP; + follow->eflags ^= MFE_VERTICALFLIP; + } + } + } + } + else if (follow) + { + P_RemoveMobj(follow); + P_SetTarget(&follow, NULL); + } +#undef follow +} + +void G_WriteMetalTic(mobj_t *metal) +{ + UINT8 ziptic = 0; + UINT8 *ziptic_p; + fixed_t height; + + if (!demo_p) // demo_p will be NULL until the race start linedef executor is activated! + return; + + WRITEUINT8(demo_p, METALSNICE); + ziptic_p = demo_p++; // the ziptic, written at the end of this function + + #define MAXMOM (0xFFFF<<8) + + // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. + if (abs(metal->x-oldmetal.x) > MAXMOM + || abs(metal->y-oldmetal.y) > MAXMOM + || abs(metal->z-oldmetal.z) > MAXMOM) + { + oldmetal.x = metal->x; + oldmetal.y = metal->y; + oldmetal.z = metal->z; + ziptic |= GZT_XYZ; + WRITEFIXED(demo_p,oldmetal.x); + WRITEFIXED(demo_p,oldmetal.y); + WRITEFIXED(demo_p,oldmetal.z); + } + else + { + // For moving normally: + // Store one full byte of movement, plus one byte of fractional movement. + INT16 momx = (INT16)((metal->x-oldmetal.x)>>8); + INT16 momy = (INT16)((metal->y-oldmetal.y)>>8); + if (momx != oldmetal.momx + || momy != oldmetal.momy) + { + oldmetal.momx = momx; + oldmetal.momy = momy; + ziptic |= GZT_MOMXY; + WRITEINT16(demo_p,momx); + WRITEINT16(demo_p,momy); + } + momx = (INT16)((metal->z-oldmetal.z)>>8); + if (momx != oldmetal.momz) + { + oldmetal.momz = momx; + ziptic |= GZT_MOMZ; + WRITEINT16(demo_p,momx); + } + + // This SHOULD set oldmetal.x/y/z to match metal->x/y/z + // but it keeps the fractional loss of one byte, + // so it will hopefully be made up for in future tics. + oldmetal.x += oldmetal.momx<<8; + oldmetal.y += oldmetal.momy<<8; + oldmetal.z += oldmetal.momz<<8; + } + + #undef MAXMOM + + // Only store the 8 most relevant bits of angle + // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites + // and it does not affect movement at all anyway. + if (metal->player && metal->player->drawangle>>24 != oldmetal.angle) + { + oldmetal.angle = metal->player->drawangle>>24; + ziptic |= GZT_ANGLE; + WRITEUINT8(demo_p,oldmetal.angle); + } + + // Store the sprite frame. + if ((metal->frame & FF_FRAMEMASK) != oldmetal.frame) + { + oldmetal.frame = metal->frame; // NOT & FF_FRAMEMASK here, so 32 bits + ziptic |= GZT_FRAME; + WRITEUINT32(demo_p,oldmetal.frame); + } + + if (metal->sprite == SPR_PLAY + && metal->sprite2 != oldmetal.sprite2) + { + oldmetal.sprite2 = metal->sprite2; + ziptic |= GZT_SPR2; + WRITEUINT8(demo_p,oldmetal.sprite2); + } + + // Check for sprite set changes + if (metal->sprite != oldmetal.sprite) + { + oldmetal.sprite = metal->sprite; + ghostext.flags |= EZT_SPRITE; + } + + if ((height = FixedDiv(metal->height, metal->scale)) != oldmetal.height) + { + oldmetal.height = height; + ghostext.flags |= EZT_HEIGHT; + } + + if (ghostext.flags & ~(EZT_COLOR|EZT_HIT)) // these two aren't handled by metal ever + { + ziptic |= GZT_EXTRA; + + if (ghostext.scale == ghostext.lastscale) + ghostext.flags &= ~EZT_SCALE; + + WRITEUINT8(demo_p,ghostext.flags); + if (ghostext.flags & EZT_SCALE) + { + WRITEFIXED(demo_p,ghostext.scale); + ghostext.lastscale = ghostext.scale; + } + if (ghostext.flags & EZT_SPRITE) + WRITEUINT16(demo_p,oldmetal.sprite); + if (ghostext.flags & EZT_HEIGHT) + { + height >>= FRACBITS; + WRITEINT16(demo_p, height); + } + ghostext.flags = 0; + } + + if (metal->player && metal->player->followmobj && !(metal->player->followmobj->sprite == SPR_NULL || (metal->player->followmobj->flags2 & MF2_DONTDRAW))) + { + INT16 temp; + UINT8 *followtic_p = demo_p++; + UINT8 followtic = 0; + + ziptic |= GZT_FOLLOW; + + if (metal->player->followmobj->skin) + followtic |= FZT_SKIN; + + if (!(oldmetal.flags2 & MF2_AMBUSH)) + { + followtic |= FZT_SPAWNED; + WRITEINT16(demo_p,metal->player->followmobj->info->height>>FRACBITS); + if (metal->player->followmobj->flags2 & MF2_LINKDRAW) + followtic |= FZT_LINKDRAW; + if (metal->player->followmobj->colorized) + followtic |= FZT_COLORIZED; + if (followtic & FZT_SKIN) + WRITEUINT8(demo_p,(UINT8)(((skin_t *)(metal->player->followmobj->skin))-skins)); + oldmetal.flags2 |= MF2_AMBUSH; + } + + if (metal->player->followmobj->scale != metal->scale) + { + followtic |= FZT_SCALE; + WRITEFIXED(demo_p,metal->player->followmobj->scale); + } + + temp = (INT16)((metal->player->followmobj->x-metal->x)>>8); + WRITEINT16(demo_p,temp); + temp = (INT16)((metal->player->followmobj->y-metal->y)>>8); + WRITEINT16(demo_p,temp); + temp = (INT16)((metal->player->followmobj->z-metal->z)>>8); + WRITEINT16(demo_p,temp); + if (followtic & FZT_SKIN) + WRITEUINT8(demo_p,metal->player->followmobj->sprite2); + WRITEUINT16(demo_p,metal->player->followmobj->sprite); + WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits + WRITEUINT16(demo_p,metal->player->followmobj->color); + + *followtic_p = followtic; + } + else + oldmetal.flags2 &= ~MF2_AMBUSH; + + *ziptic_p = ziptic; + + // attention here for the ticcmd size! + // latest demos with mouse aiming byte in ticcmd + if (demo_p >= demoend - 32) + { + G_StopMetalRecording(false); // no more space + return; + } +} + +// +// G_RecordDemo +// +void G_RecordDemo(const char *name) +{ + INT32 maxsize; + + strcpy(demoname, name); + strcat(demoname, ".lmp"); + maxsize = 1024*1024; + if (M_CheckParm("-maxdemo") && M_IsNextParm()) + maxsize = atoi(M_GetNextParm()) * 1024; +// if (demobuffer) +// free(demobuffer); + demo_p = NULL; + demobuffer = malloc(maxsize); + demoend = demobuffer + maxsize; + + demorecording = true; +} + +void G_RecordMetal(void) +{ + INT32 maxsize; + maxsize = 1024*1024; + if (M_CheckParm("-maxdemo") && M_IsNextParm()) + maxsize = atoi(M_GetNextParm()) * 1024; + demo_p = NULL; + demobuffer = malloc(maxsize); + demoend = demobuffer + maxsize; + metalrecording = true; +} + +void G_BeginRecording(void) +{ + UINT8 i; + char name[MAXCOLORNAME+1]; + player_t *player = &players[consoleplayer]; + + if (demo_p) + return; + memset(name,0,sizeof(name)); + + demo_p = demobuffer; + demoflags = DF_GHOST|(modeattacking<>DF_ATTACKSHIFT) + { + case ATTACKING_NONE: // 0 + break; + case ATTACKING_RECORD: // 1 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + WRITEUINT32(demo_p,0); // score + WRITEUINT16(demo_p,0); // rings + break; + case ATTACKING_NIGHTS: // 2 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + WRITEUINT32(demo_p,0); // score + break; + default: // 3 + break; + } + + WRITEUINT32(demo_p,P_GetInitSeed()); + + // Name + for (i = 0; i < 16 && cv_playername.string[i]; i++) + name[i] = cv_playername.string[i]; + for (; i < 16; i++) + name[i] = '\0'; + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Skin + for (i = 0; i < 16 && cv_skin.string[i]; i++) + name[i] = cv_skin.string[i]; + for (; i < 16; i++) + name[i] = '\0'; + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Color + for (i = 0; i < MAXCOLORNAME && cv_playercolor.string[i]; i++) + name[i] = cv_playercolor.string[i]; + for (; i < MAXCOLORNAME; i++) + name[i] = '\0'; + M_Memcpy(demo_p,name,MAXCOLORNAME); + demo_p += MAXCOLORNAME; + + // Stats + WRITEUINT8(demo_p,player->charability); + WRITEUINT8(demo_p,player->charability2); + WRITEUINT8(demo_p,player->actionspd>>FRACBITS); + WRITEUINT8(demo_p,player->mindash>>FRACBITS); + WRITEUINT8(demo_p,player->maxdash>>FRACBITS); + WRITEUINT8(demo_p,player->normalspeed>>FRACBITS); + WRITEUINT8(demo_p,player->runspeed>>FRACBITS); + WRITEUINT8(demo_p,player->thrustfactor); + WRITEUINT8(demo_p,player->accelstart); + WRITEUINT8(demo_p,player->acceleration); + WRITEUINT8(demo_p,player->height>>FRACBITS); + WRITEUINT8(demo_p,player->spinheight>>FRACBITS); + WRITEUINT8(demo_p,player->camerascale>>FRACBITS); + WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); + + // Trying to convert it back to % causes demo desync due to precision loss. + // Don't do it. + WRITEFIXED(demo_p, player->jumpfactor); + + // And mobjtype_t is best with UINT32 too... + WRITEUINT32(demo_p, player->followitem); + + // Save pflag data - see SendWeaponPref() + { + UINT8 buf = 0; + pflags_t pflags = 0; + if (cv_flipcam.value) + { + buf |= 0x01; + pflags |= PF_FLIPCAM; + } + if (cv_analog[0].value) + { + buf |= 0x02; + pflags |= PF_ANALOGMODE; + } + if (cv_directionchar[0].value) + { + buf |= 0x04; + pflags |= PF_DIRECTIONCHAR; + } + if (cv_autobrake.value) + { + buf |= 0x08; + pflags |= PF_AUTOBRAKE; + } + if (cv_usejoystick.value) + buf |= 0x10; + CV_SetValue(&cv_showinputjoy, !!(cv_usejoystick.value)); + + WRITEUINT8(demo_p,buf); + player->pflags = pflags; + } + + // Save netvar data + CV_SaveNetVars(&demo_p); + + memset(&oldcmd,0,sizeof(oldcmd)); + memset(&oldghost,0,sizeof(oldghost)); + memset(&ghostext,0,sizeof(ghostext)); + ghostext.lastcolor = ghostext.color = GHC_NORMAL; + ghostext.lastscale = ghostext.scale = FRACUNIT; + + if (player->mo) + { + oldghost.x = player->mo->x; + oldghost.y = player->mo->y; + oldghost.z = player->mo->z; + oldghost.angle = player->mo->angle>>24; + + // preticker started us gravity flipped + if (player->mo->eflags & MFE_VERTICALFLIP) + ghostext.flags |= EZT_FLIP; + } +} + +void G_BeginMetal(void) +{ + mobj_t *mo = players[consoleplayer].mo; + +#if 0 + if (demo_p) + return; +#endif + + demo_p = demobuffer; + + // Write header. + M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12; + WRITEUINT8(demo_p,VERSION); + WRITEUINT8(demo_p,SUBVERSION); + WRITEUINT16(demo_p,DEMOVERSION); + + // demo checksum + demo_p += 16; + + M_Memcpy(demo_p, "METL", 4); demo_p += 4; + + memset(&ghostext,0,sizeof(ghostext)); + ghostext.lastscale = ghostext.scale = FRACUNIT; + + // Set up our memory. + memset(&oldmetal,0,sizeof(oldmetal)); + oldmetal.x = mo->x; + oldmetal.y = mo->y; + oldmetal.z = mo->z; + oldmetal.angle = mo->angle>>24; +} + +void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings) +{ + if (!demorecording || !demotime_p) + return; + if (demoflags & DF_RECORDATTACK) + { + WRITEUINT32(demotime_p, ptime); + WRITEUINT32(demotime_p, pscore); + WRITEUINT16(demotime_p, prings); + demotime_p = NULL; + } + else if (demoflags & DF_NIGHTSATTACK) + { + WRITEUINT32(demotime_p, ptime); + WRITEUINT32(demotime_p, pscore); + demotime_p = NULL; + } +} + +// Returns bitfield: +// 1 == new demo has lower time +// 2 == new demo has higher score +// 4 == new demo has higher rings +UINT8 G_CmpDemoTime(char *oldname, char *newname) +{ + UINT8 *buffer,*p; + UINT8 flags; + UINT32 oldtime, newtime, oldscore, newscore; + UINT16 oldrings, newrings, oldversion; + size_t bufsize ATTRUNUSED; + UINT8 c; + UINT16 s ATTRUNUSED; + UINT8 aflags = 0; + + // load the new file + FIL_DefaultExtension(newname, ".lmp"); + bufsize = FIL_ReadFile(newname, &buffer); + I_Assert(bufsize != 0); + p = buffer; + + // read demo header + I_Assert(!memcmp(p, DEMOHEADER, 12)); + p += 12; // DEMOHEADER + c = READUINT8(p); // VERSION + I_Assert(c == VERSION); + c = READUINT8(p); // SUBVERSION + I_Assert(c == SUBVERSION); + s = READUINT16(p); + I_Assert(s >= 0x000c); + p += 16; // demo checksum + I_Assert(!memcmp(p, "PLAY", 4)); + p += 4; // PLAY + p += 2; // gamemap + p += 16; // map md5 + flags = READUINT8(p); // demoflags + + aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); + I_Assert(aflags); + if (flags & DF_RECORDATTACK) + { + newtime = READUINT32(p); + newscore = READUINT32(p); + newrings = READUINT16(p); + } + else if (flags & DF_NIGHTSATTACK) + { + newtime = READUINT32(p); + newscore = READUINT32(p); + newrings = 0; + } + else // appease compiler + return 0; + + Z_Free(buffer); + + // load old file + FIL_DefaultExtension(oldname, ".lmp"); + if (!FIL_ReadFile(oldname, &buffer)) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), oldname); + return UINT8_MAX; + } + p = buffer; + + // read demo header + if (memcmp(p, DEMOHEADER, 12)) + { + CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); + Z_Free(buffer); + return UINT8_MAX; + } p += 12; // DEMOHEADER + p++; // VERSION + p++; // SUBVERSION + oldversion = READUINT16(p); + switch(oldversion) // demoversion + { + case DEMOVERSION: // latest always supported + case 0x000c: // all that changed between then and now was longer color name + break; + // too old, cannot support. + default: + CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); + Z_Free(buffer); + return UINT8_MAX; + } + p += 16; // demo checksum + if (memcmp(p, "PLAY", 4)) + { + CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); + Z_Free(buffer); + return UINT8_MAX; + } p += 4; // "PLAY" + if (oldversion <= 0x0008) + p++; // gamemap + else + p += 2; // gamemap + p += 16; // mapmd5 + flags = READUINT8(p); + if (!(flags & aflags)) + { + CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname); + Z_Free(buffer); + return UINT8_MAX; + } + if (flags & DF_RECORDATTACK) + { + oldtime = READUINT32(p); + oldscore = READUINT32(p); + oldrings = READUINT16(p); + } + else if (flags & DF_NIGHTSATTACK) + { + oldtime = READUINT32(p); + oldscore = READUINT32(p); + oldrings = 0; + } + else // appease compiler + return UINT8_MAX; + + Z_Free(buffer); + + c = 0; + if (newtime < oldtime + || (newtime == oldtime && (newscore > oldscore || newrings > oldrings))) + c |= 1; // Better time + if (newscore > oldscore + || (newscore == oldscore && newtime < oldtime)) + c |= 1<<1; // Better score + if (newrings > oldrings + || (newrings == oldrings && newtime < oldtime)) + c |= 1<<2; // Better rings + return c; +} + +// +// G_PlayDemo +// +void G_DeferedPlayDemo(const char *name) +{ + COM_BufAddText("playdemo \""); + COM_BufAddText(name); + COM_BufAddText("\"\n"); +} + +// +// Start a demo from a .LMP file or from a wad resource +// +void G_DoPlayDemo(char *defdemoname) +{ + UINT8 i; + lumpnum_t l; + char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname; + UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration,cnamelen; + pflags_t pflags; + UINT32 randseed, followitem; + fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; + char msg[1024]; + + skin[16] = '\0'; + color[MAXCOLORNAME] = '\0'; + + n = defdemoname+strlen(defdemoname); + while (*n != '/' && *n != '\\' && n != defdemoname) + n--; + if (n != defdemoname) + n++; + pdemoname = ZZ_Alloc(strlen(n)+1); + strcpy(pdemoname,n); + + // Internal if no extension, external if one exists + if (FIL_CheckExtension(defdemoname)) + { + //FIL_DefaultExtension(defdemoname, ".lmp"); + if (!FIL_ReadFile(defdemoname, &demobuffer)) + { + snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + demo_p = demobuffer; + } + // load demo resource from WAD + else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + else // it's an internal demo + demobuffer = demo_p = W_CacheLumpNum(l, PU_STATIC); + + // read demo header + gameaction = ga_nothing; + demoplayback = true; + if (memcmp(demo_p, DEMOHEADER, 12)) + { + snprintf(msg, 1024, M_GetText("%s is not a SRB2 replay file.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + demo_p += 12; // DEMOHEADER + + version = READUINT8(demo_p); + subversion = READUINT8(demo_p); + demoversion = READUINT16(demo_p); + switch(demoversion) + { + case DEMOVERSION: // latest always supported + cnamelen = MAXCOLORNAME; + break; + // all that changed between then and now was longer color name + case 0x000c: + cnamelen = 16; + break; + // too old, cannot support. + default: + snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + demo_p += 16; // demo checksum + if (memcmp(demo_p, "PLAY", 4)) + { + snprintf(msg, 1024, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + demo_p += 4; // "PLAY" + gamemap = READINT16(demo_p); + demo_p += 16; // mapmd5 + + demoflags = READUINT8(demo_p); + modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; + CON_ToggleOff(); + + hu_demoscore = 0; + hu_demotime = UINT32_MAX; + hu_demorings = 0; + + switch (modeattacking) + { + case ATTACKING_NONE: // 0 + break; + case ATTACKING_RECORD: // 1 + hu_demotime = READUINT32(demo_p); + hu_demoscore = READUINT32(demo_p); + hu_demorings = READUINT16(demo_p); + break; + case ATTACKING_NIGHTS: // 2 + hu_demotime = READUINT32(demo_p); + hu_demoscore = READUINT32(demo_p); + break; + default: // 3 + modeattacking = ATTACKING_NONE; + break; + } + + // Random seed + randseed = READUINT32(demo_p); + + // Player name + M_Memcpy(player_names[0],demo_p,16); + demo_p += 16; + + // Skin + M_Memcpy(skin,demo_p,16); + demo_p += 16; + + // Color + M_Memcpy(color,demo_p,cnamelen); + demo_p += cnamelen; + + charability = READUINT8(demo_p); + charability2 = READUINT8(demo_p); + actionspd = (fixed_t)READUINT8(demo_p)<color = players[0].skincolor; + oldghost.x = players[0].mo->x; + oldghost.y = players[0].mo->y; + oldghost.z = players[0].mo->z; + } + + // Set saved attribute values + // No cheat checking here, because even if they ARE wrong... + // it would only break the replay if we clipped them. + players[0].camerascale = camerascale; + players[0].shieldscale = shieldscale; + players[0].charability = charability; + players[0].charability2 = charability2; + players[0].actionspd = actionspd; + players[0].mindash = mindash; + players[0].maxdash = maxdash; + players[0].normalspeed = normalspeed; + players[0].runspeed = runspeed; + players[0].thrustfactor = thrustfactor; + players[0].accelstart = accelstart; + players[0].acceleration = acceleration; + players[0].height = height; + players[0].spinheight = spinheight; + players[0].jumpfactor = jumpfactor; + players[0].followitem = followitem; + players[0].pflags = pflags; + + demo_start = true; +} + +void G_AddGhost(char *defdemoname) +{ + INT32 i; + lumpnum_t l; + char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; + UINT8 cnamelen; + demoghost *gh; + UINT8 flags; + UINT8 *buffer,*p; + mapthing_t *mthing; + UINT16 count, ghostversion; + + name[16] = '\0'; + skin[16] = '\0'; + color[16] = '\0'; + + n = defdemoname+strlen(defdemoname); + while (*n != '/' && *n != '\\' && n != defdemoname) + n--; + if (n != defdemoname) + n++; + pdemoname = ZZ_Alloc(strlen(n)+1); + strcpy(pdemoname,n); + + // Internal if no extension, external if one exists + if (FIL_CheckExtension(defdemoname)) + { + //FIL_DefaultExtension(defdemoname, ".lmp"); + if (!FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL)) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname); + Z_Free(pdemoname); + return; + } + p = buffer; + } + // load demo resource from WAD + else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read lump '%s'.\n"), defdemoname); + Z_Free(pdemoname); + return; + } + else // it's an internal demo + buffer = p = W_CacheLumpNum(l, PU_LEVEL); + + // read demo header + if (memcmp(p, DEMOHEADER, 12)) + { + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } p += 12; // DEMOHEADER + p++; // VERSION + p++; // SUBVERSION + ghostversion = READUINT16(p); + switch(ghostversion) + { + case DEMOVERSION: // latest always supported + cnamelen = MAXCOLORNAME; + break; + // all that changed between then and now was longer color name + case 0x000c: + cnamelen = 16; + break; + // too old, cannot support. + default: + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + M_Memcpy(md5, p, 16); p += 16; // demo checksum + for (gh = ghosts; gh; gh = gh->next) + if (!memcmp(md5, gh->checksum, 16)) // another ghost in the game already has this checksum? + { // Don't add another one, then! + CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (MD5 was matched)\n", pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + if (memcmp(p, "PLAY", 4)) + { + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } p += 4; // "PLAY" + if (ghostversion <= 0x0008) + p++; // gamemap + else + p += 2; // gamemap + p += 16; // mapmd5 (possibly check for consistency?) + flags = READUINT8(p); + if (!(flags & DF_GHOST)) + { + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) + { + case ATTACKING_NONE: // 0 + break; + case ATTACKING_RECORD: // 1 + p += 10; // demo time, score, and rings + break; + case ATTACKING_NIGHTS: // 2 + p += 8; // demo time left, score + break; + default: // 3 + break; + } + + p += 4; // random seed + + // Player name (TODO: Display this somehow if it doesn't match cv_playername!) + M_Memcpy(name, p,16); + p += 16; + + // Skin + M_Memcpy(skin, p,16); + p += 16; + + // Color + M_Memcpy(color, p,cnamelen); + p += cnamelen; + + // Ghosts do not have a player structure to put this in. + p++; // charability + p++; // charability2 + p++; // actionspd + p++; // mindash + p++; // maxdash + p++; // normalspeed + p++; // runspeed + p++; // thrustfactor + p++; // accelstart + p++; // acceleration + p++; // height + p++; // spinheight + p++; // camerascale + p++; // shieldscale + p += 4; // jumpfactor + p += 4; // followitem + + p++; // pflag data + + // net var data + count = READUINT16(p); + while (count--) + { + p += 2; + SKIPSTRING(p); + p++; + } + + if (*p == DEMOMARKER) + { + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + + gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL); + gh->next = ghosts; + gh->buffer = buffer; + M_Memcpy(gh->checksum, md5, 16); + gh->p = p; + + ghosts = gh; + + gh->version = ghostversion; + mthing = playerstarts[0]; + I_Assert(mthing); + { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. + fixed_t z,f,c; + fixed_t offset = mthing->z << FRACBITS; + gh->mo = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST); + gh->mo->angle = FixedAngle(mthing->angle << FRACBITS); + f = gh->mo->floorz; + c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height; + if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) + { + z = c - offset; + if (z < f) + z = f; + } + else + { + z = f + offset; + if (z > c) + z = c; + } + gh->mo->z = z; + } + + gh->oldmo.x = gh->mo->x; + gh->oldmo.y = gh->mo->y; + gh->oldmo.z = gh->mo->z; + + // Set skin + gh->mo->skin = &skins[0]; + for (i = 0; i < numskins; i++) + if (!stricmp(skins[i].name,skin)) + { + gh->mo->skin = &skins[i]; + break; + } + gh->oldmo.skin = gh->mo->skin; + + // Set color + gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor; + for (i = 0; i < numskincolors; i++) + if (!stricmp(skincolors[i].name,color)) + { + gh->mo->color = (UINT16)i; + break; + } + gh->oldmo.color = gh->mo->color; + + gh->mo->state = states+S_PLAY_STND; + gh->mo->sprite = gh->mo->state->sprite; + gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK); + //gh->mo->frame = tr_trans30<mo->flags2 |= MF2_DONTDRAW; + gh->fadein = (9-3)*6; // fade from invisible to trans30 over as close to 35 tics as possible + gh->mo->tics = -1; + + CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); + Z_Free(pdemoname); +} + +// Clean up all ghosts +void G_FreeGhosts(void) +{ + while (ghosts) + { + demoghost *next = ghosts->next; + Z_Free(ghosts); + ghosts = next; + } + ghosts = NULL; +} + +// +// G_TimeDemo +// NOTE: name is a full filename for external demos +// +static INT32 restorecv_vidwait; + +void G_TimeDemo(const char *name) +{ + nodrawers = M_CheckParm("-nodraw"); + noblit = M_CheckParm("-noblit"); + restorecv_vidwait = cv_vidwait.value; + if (cv_vidwait.value) + CV_Set(&cv_vidwait, "0"); + timingdemo = true; + singletics = true; + framecount = 0; + demostarttime = I_GetTime(); + G_DeferedPlayDemo(name); +} + +void G_DoPlayMetal(void) +{ + lumpnum_t l; + mobj_t *mo = NULL; + thinker_t *th; + + // it's an internal demo + if ((l = W_CheckNumForName(va("%sMS",G_BuildMapName(gamemap)))) == LUMPERROR) + { + CONS_Alert(CONS_WARNING, M_GetText("No bot recording for this map.\n")); + return; + } + else + metalbuffer = metal_p = W_CacheLumpNum(l, PU_STATIC); + + // find metal sonic + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + if (mo->type != MT_METALSONIC_RACE) + continue; + + break; + } + if (th == &thlist[THINK_MOBJ]) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to find bot entity.\n")); + Z_Free(metalbuffer); + return; + } + + // read demo header + metal_p += 12; // DEMOHEADER + metal_p++; // VERSION + metal_p++; // SUBVERSION + metalversion = READUINT16(metal_p); + switch(metalversion) + { + case DEMOVERSION: // latest always supported + case 0x000c: // all that changed between then and now was longer color name + break; + // too old, cannot support. + default: + CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n")); + Z_Free(metalbuffer); + return; + } + metal_p += 16; // demo checksum + if (memcmp(metal_p, "METL", 4)) + { + CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, wasn't recorded in Metal format.\n")); + Z_Free(metalbuffer); + return; + } metal_p += 4; // "METL" + + // read initial tic + memset(&oldmetal,0,sizeof(oldmetal)); + oldmetal.x = mo->x; + oldmetal.y = mo->y; + oldmetal.z = mo->z; + metalplayback = mo; +} + +void G_DoneLevelLoad(void) +{ + CONS_Printf(M_GetText("Loaded level in %f sec\n"), (double)(I_GetTime() - demostarttime) / TICRATE); + framecount = 0; + demostarttime = I_GetTime(); +} + +/* +=================== += += G_CheckDemoStatus += += Called after a death or level completion to allow demos to be cleaned up += Returns true if a new demo loop action will take place +=================== +*/ + +// Writes the demo's checksum, or just random garbage if you can't do that for some reason. +static void WriteDemoChecksum(void) +{ + UINT8 *p = demobuffer+16; // checksum position +#ifdef NOMD5 + UINT8 i; + for (i = 0; i < 16; i++, p++) + *p = P_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. +#else + md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. +#endif +} + +// Stops recording a demo. +static void G_StopDemoRecording(void) +{ + boolean saved = false; + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + WriteDemoChecksum(); + saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. + free(demobuffer); + demorecording = false; + + if (modeattacking != ATTACKING_RECORD) + { + if (saved) + CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); + else + CONS_Alert(CONS_WARNING, M_GetText("Demo %s not saved\n"), demoname); + } +} + +// Stops metal sonic's demo. Separate from other functions because metal + replays can coexist +void G_StopMetalDemo(void) +{ + + // Metal Sonic finishing doesn't end the game, dammit. + Z_Free(metalbuffer); + metalbuffer = NULL; + metalplayback = NULL; + metal_p = NULL; +} + +// Stops metal sonic recording. +ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) +{ + boolean saved = false; + if (demo_p) + { + WRITEUINT8(demo_p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker + WriteDemoChecksum(); + saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. + } + free(demobuffer); + metalrecording = false; + if (saved) + I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); + I_Error("Failed to save demo!"); +} + +// Stops timing a demo. +static void G_StopTimingDemo(void) +{ + INT32 demotime; + double f1, f2; + demotime = I_GetTime() - demostarttime; + if (!demotime) + return; + G_StopDemo(); + timingdemo = false; + f1 = (double)demotime; + f2 = (double)framecount*TICRATE; + + CONS_Printf(M_GetText("timed %u gametics in %d realtics - %u frames\n%f seconds, %f avg fps\n"), + leveltime,demotime,(UINT32)framecount,f1/TICRATE,f2/f1); + + // CSV-readable timedemo results, for external parsing + if (timedemo_csv) + { + FILE *f; + const char *csvpath = va("%s"PATHSEP"%s", srb2home, "timedemo.csv"); + const char *header = "id,demoname,seconds,avgfps,leveltime,demotime,framecount,ticrate,rendermode,vidmode,vidwidth,vidheight,procbits\n"; + const char *rowformat = "\"%s\",\"%s\",%f,%f,%u,%d,%u,%u,%u,%u,%u,%u,%u\n"; + boolean headerrow = !FIL_FileExists(csvpath); + UINT8 procbits = 0; + + // Bitness + if (sizeof(void*) == 4) + procbits = 32; + else if (sizeof(void*) == 8) + procbits = 64; + + f = fopen(csvpath, "a+"); + + if (f) + { + if (headerrow) + fputs(header, f); + fprintf(f, rowformat, + timedemo_csv_id,timedemo_name,f1/TICRATE,f2/f1,leveltime,demotime,(UINT32)framecount,TICRATE,rendermode,vid.modenum,vid.width,vid.height,procbits); + fclose(f); + CONS_Printf("Timedemo results saved to '%s'\n", csvpath); + } + else + { + // Just print the CSV output to console + CON_LogMessage(header); + CONS_Printf(rowformat, + timedemo_csv_id,timedemo_name,f1/TICRATE,f2/f1,leveltime,demotime,(UINT32)framecount,TICRATE,rendermode,vid.modenum,vid.width,vid.height,procbits); + } + } + + if (restorecv_vidwait != cv_vidwait.value) + CV_SetValue(&cv_vidwait, restorecv_vidwait); + D_AdvanceDemo(); +} + +// reset engine variable set for the demos +// called from stopdemo command, map command, and g_checkdemoStatus. +void G_StopDemo(void) +{ + Z_Free(demobuffer); + demobuffer = NULL; + demoplayback = false; + titledemo = false; + timingdemo = false; + singletics = false; + + if (gamestate == GS_INTERMISSION) + Y_EndIntermission(); // cleanup + + G_SetGamestate(GS_NULL); + wipegamestate = GS_NULL; + SV_StopServer(); + SV_ResetServer(); +} + +boolean G_CheckDemoStatus(void) +{ + G_FreeGhosts(); + + // DO NOT end metal sonic demos here + + if (timingdemo) + { + G_StopTimingDemo(); + return true; + } + + if (demoplayback) + { + if (singledemo) + I_Quit(); + G_StopDemo(); + + if (modeattacking) + M_EndModeAttackRun(); + else + D_AdvanceDemo(); + + return true; + } + + if (demorecording) + { + G_StopDemoRecording(); + return true; + } + + return false; +} diff --git a/src/g_demo.h b/src/g_demo.h new file mode 100644 index 000000000..df25042c4 --- /dev/null +++ b/src/g_demo.h @@ -0,0 +1,86 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file g_demo.h +/// \brief Demo recording and playback + +#ifndef __G_DEMO__ +#define __G_DEMO__ + +#include "doomdef.h" +#include "doomstat.h" +#include "d_event.h" + +// ====================================== +// DEMO playback/recording related stuff. +// ====================================== + +// demoplaying back and demo recording +extern boolean demoplayback, titledemo, demorecording, timingdemo; +extern tic_t demostarttime; + +// Quit after playing a demo from cmdline. +extern boolean singledemo; +extern boolean demo_start; +extern boolean demosynced; + +extern mobj_t *metalplayback; + +// Only called by startup code. +void G_RecordDemo(const char *name); +void G_RecordMetal(void); +void G_BeginRecording(void); +void G_BeginMetal(void); + +// Only called by shutdown code. +void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings); +UINT8 G_CmpDemoTime(char *oldname, char *newname); + +typedef enum +{ + GHC_NORMAL = 0, + GHC_SUPER, + GHC_FIREFLOWER, + GHC_INVINCIBLE, + GHC_NIGHTSSKIN, // not actually a colour + GHC_RETURNSKIN // ditto +} ghostcolor_t; + +// Record/playback tics +void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); +void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); +void G_GhostAddThok(void); +void G_GhostAddSpin(void); +void G_GhostAddRev(void); +void G_GhostAddColor(ghostcolor_t color); +void G_GhostAddFlip(void); +void G_GhostAddScale(fixed_t scale); +void G_GhostAddHit(mobj_t *victim); +void G_WriteGhostTic(mobj_t *ghost); +void G_ConsGhostTic(void); +void G_GhostTicker(void); +void G_ReadMetalTic(mobj_t *metal); +void G_WriteMetalTic(mobj_t *metal); +void G_SaveMetal(UINT8 **buffer); +void G_LoadMetal(UINT8 **buffer); + +void G_DeferedPlayDemo(const char *demo); +void G_DoPlayDemo(char *defdemoname); +void G_TimeDemo(const char *name); +void G_AddGhost(char *defdemoname); +void G_FreeGhosts(void); +void G_DoPlayMetal(void); +void G_DoneLevelLoad(void); +void G_StopMetalDemo(void); +ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); +void G_StopDemo(void); +boolean G_CheckDemoStatus(void); + +#endif // __G_DEMO__ diff --git a/src/g_game.c b/src/g_game.c index 634d80768..c9b570044 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -27,6 +27,7 @@ #include "r_main.h" #include "s_sound.h" #include "g_game.h" +#include "g_demo.h" #include "m_cheat.h" #include "m_misc.h" #include "m_menu.h" @@ -38,18 +39,14 @@ #include "byteptr.h" #include "i_joy.h" #include "r_local.h" -#include "r_things.h" +#include "r_skins.h" #include "y_inter.h" #include "v_video.h" -#include "dehacked.h" // get_number (for ghost thok) #include "lua_hook.h" #include "b_bot.h" #include "m_cond.h" // condition sets -#include "md5.h" // demo checksums -#ifdef HAVE_BLUA #include "lua_hud.h" -#endif gameaction_t gameaction; gamestate_t gamestate = GS_NULL; @@ -57,7 +54,7 @@ UINT8 ultimatemode = false; boolean botingame; UINT8 botskin; -UINT8 botcolor; +UINT16 botcolor; JoyType_t Joystick; JoyType_t Joystick2; @@ -85,7 +82,10 @@ INT32 curWeather = PRECIP_NONE; INT32 cursaveslot = 0; // Auto-save 1p savegame slot //INT16 lastmapsaved = 0; // Last map we auto-saved at INT16 lastmaploaded = 0; // Last map the game loaded -boolean gamecomplete = false; +UINT8 gamecomplete = 0; + +marathonmode_t marathonmode = 0; +tic_t marathontime = 0; UINT8 numgameovers = 0; // for startinglives balance SINT8 startinglivesbalance[maxgameovers+1] = {3, 5, 7, 9, 12, 15, 20, 25, 30, 40, 50, 75, 99, 0x7F}; @@ -105,11 +105,6 @@ UINT8 numDemos = 0; UINT32 demoDelayTime = 15*TICRATE; UINT32 demoIdleTime = 3*TICRATE; -boolean timingdemo; // if true, exit with report on completion -boolean nodrawers; // for comparative timing purposes -boolean noblit; // for comparative timing purposes -tic_t demostarttime; // for comparative timing purposes - boolean netgame; // only true if packets are broadcast boolean multiplayer; boolean playeringame[MAXPLAYERS]; @@ -126,7 +121,7 @@ UINT32 ssspheres; // old special stage INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) -INT16 spstage_start; +INT16 spstage_start, spmarathon_start; INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; INT16 titlemap = 0; @@ -143,10 +138,10 @@ INT32 tutorialanalog = 0; // store cv_analog[0] user value boolean looptitle = false; -UINT8 skincolor_redteam = SKINCOLOR_RED; -UINT8 skincolor_blueteam = SKINCOLOR_BLUE; -UINT8 skincolor_redring = SKINCOLOR_SALMON; -UINT8 skincolor_bluering = SKINCOLOR_CORNFLOWER; +UINT16 skincolor_redteam = SKINCOLOR_RED; +UINT16 skincolor_blueteam = SKINCOLOR_BLUE; +UINT16 skincolor_redring = SKINCOLOR_SALMON; +UINT16 skincolor_bluering = SKINCOLOR_CORNFLOWER; tic_t countdowntimer = 0; boolean countdowntimeup = false; @@ -177,7 +172,7 @@ static boolean retryingmodeattack = false; UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage. UINT16 emeralds; -INT32 luabanks[NUM_LUABANKS]; // yes, even in non HAVE_BLUA +INT32 luabanks[NUM_LUABANKS]; UINT32 token; // Number of tokens collected in a level UINT32 tokenlist; // List of tokens collected boolean gottoken; // Did you get a token? Used for end of act @@ -227,9 +222,11 @@ UINT8 ammoremovaltics = 2*TICRATE; UINT8 use1upSound = 0; UINT8 maxXtraLife = 2; // Max extra lives from rings +UINT8 useContinues = 0; // Set to 1 to enable continues outside of no-save scenarioes UINT8 introtoplay; UINT8 creditscutscene; +UINT8 useBlackRock = 1; // Emerald locations mobj_t *hunt1; @@ -256,57 +253,12 @@ UINT32 timesBeaten; UINT32 timesBeatenWithEmeralds; UINT32 timesBeatenUltimate; -static char demoname[64]; -boolean demorecording; -boolean demoplayback; -boolean titledemo; // Title Screen demo can be cancelled by any key -static UINT8 *demobuffer = NULL; -static UINT8 *demo_p, *demotime_p; -static UINT8 *demoend; -static UINT8 demoflags; -static UINT16 demoversion; -boolean singledemo; // quit after playing a demo from cmdline -boolean demo_start; // don't start playing demo right away -boolean demosynced = true; // console warning message - -boolean metalrecording; // recording as metal sonic -mobj_t *metalplayback; -static UINT8 *metalbuffer = NULL; -static UINT8 *metal_p; -static UINT16 metalversion; - typedef struct joystickvector2_s { INT32 xaxis; INT32 yaxis; } joystickvector2_t; -// extra data stuff (events registered this frame while recording) -static struct { - UINT8 flags; // EZT flags - - // EZT_COLOR - UINT8 color, lastcolor; - - // EZT_SCALE - fixed_t scale, lastscale; - - // EZT_HIT - UINT16 hits; - mobj_t **hitlist; -} ghostext; - -// Your naming conventions are stupid and useless. -// There is no conflict here. -typedef struct demoghost { - UINT8 checksum[16]; - UINT8 *buffer, *p, color, fadein; - UINT16 version; - mobj_t oldmo, *mo; - struct demoghost *next; -} demoghost; -demoghost *ghosts = NULL; - boolean precache = true; // if true, load all graphics at start INT16 prevmap, nextmap; @@ -821,6 +773,8 @@ void G_SetGameModified(boolean silent) // If in record attack recording, cancel it. if (modeattacking) M_EndModeAttackRun(); + else if (marathonmode) + Command_ExitGame_f(); } /** Builds an original game map name from a map number. @@ -1044,18 +998,17 @@ static INT32 G_BasicDeadZoneCalculation(INT32 magnitude, fixed_t deadZone) { const INT32 jdeadzone = (JOYAXISRANGE * deadZone) / FRACUNIT; INT32 deadzoneAppliedValue = 0; + INT32 adjustedMagnitude = abs(magnitude); - if (jdeadzone > 0) + if (jdeadzone >= JOYAXISRANGE && adjustedMagnitude >= JOYAXISRANGE) // If the deadzone and magnitude are both 100%... + return JOYAXISRANGE; // ...return 100% input directly, to avoid dividing by 0 + else if (adjustedMagnitude > jdeadzone) // Otherwise, calculate how much the magnitude exceeds the deadzone { - if (magnitude > jdeadzone) - { - INT32 adjustedMagnitude = abs(magnitude); - adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE); + adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE); - adjustedMagnitude -= jdeadzone; + adjustedMagnitude -= jdeadzone; - deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone); - } + deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone); } return deadzoneAppliedValue; @@ -1103,8 +1056,6 @@ static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvect } } - - // // G_BuildTiccmd // Builds a ticcmd from all of the available inputs @@ -1120,6 +1071,7 @@ static fixed_t forwardmove[2] = {25<>16, 50<>16}; static fixed_t sidemove[2] = {25<>16, 50<>16}; // faster! static fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn +INT16 ticcmd_oldangleturn[2]; boolean ticcmd_centerviewdown[2]; // For simple controls, lock the camera behind the player mobj_t *ticcmd_ztargetfocus[2]; // Locking onto an object? void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) @@ -1195,7 +1147,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametyperules & GTR_TAG) && (leveltime < hidetime * TICRATE) && (player->pflags & PF_TAGIT))))) {//@TODO splitscreen player - cmd->angleturn = (INT16)(*myangle >> 16); + cmd->angleturn = ticcmd_oldangleturn[forplayer]; cmd->aiming = G_ClipAimingPitch(myaiming); return; } @@ -1416,7 +1368,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (controlstyle == CS_SIMPLE && !ticcmd_centerviewdown[forplayer] && !G_RingSlingerGametype()) { CV_SetValue(&cv_directionchar[forplayer], 2); - *myangle = player->mo->angle; + cmd->angleturn = (INT16)((player->mo->angle - *myangle) >> 16); *myaiming = 0; if (cv_cam_lockonboss[forplayer].value) @@ -1485,7 +1437,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) else if (anglediff < -maxturn) anglediff = -maxturn; - *myangle += anglediff; + cmd->angleturn = (INT16)(cmd->angleturn + (anglediff >> 16)); } } } @@ -1622,19 +1574,23 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) B_HandleFlightIndicator(player); } else if (player->bot == 2) - *myangle = localangle; // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy + // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy + cmd->angleturn = (INT16)((localangle - *myangle) >> 16); + + *myangle += (cmd->angleturn<<16); if (controlstyle == CS_LMAOGALOG) { + angle_t angle; + if (player->awayviewtics) - cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); + angle = player->awayviewmobj->angle; else - cmd->angleturn = (INT16)(thiscam->angle >> 16); + angle = thiscam->angle; + + cmd->angleturn = (INT16)((angle - (ticcmd_oldangleturn[forplayer] << 16)) >> 16); } else { - *myangle += (cmd->angleturn<<16); - cmd->angleturn = (INT16)(*myangle >> 16); - // Adjust camera angle by player input if (controlstyle == CS_SIMPLE && !forcestrafe && thiscam->chase && !turnheld[forplayer] && !ticcmd_centerviewdown[forplayer] && !player->climbing && player->powers[pw_carry] != CR_MINECART) { @@ -1644,13 +1600,17 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { fixed_t sine = FINESINE((R_PointToAngle2(0, 0, player->rmomx, player->rmomy) - localangle)>>ANGLETOFINESHIFT); fixed_t factor; + INT16 camadjust; if ((sine > 0) == (cmd->sidemove > 0)) sine = 0; // Prevent jerking right when braking from going left, or vice versa factor = min(40, FixedMul(player->speed, abs(sine))*2 / FRACUNIT); - *myangle -= cmd->sidemove * factor * camadjustfactor; + camadjust = (cmd->sidemove * factor * camadjustfactor) >> 16; + + *myangle -= camadjust << 16; + cmd->angleturn = (INT16)(cmd->angleturn - camadjust); } if (ticcmd_centerviewdown[forplayer] && (cv_cam_lockedinput[forplayer].value || (player->pflags & PF_STARTDASH))) @@ -1687,9 +1647,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { angle_t controlangle; INT32 anglediff; + INT16 camadjust; if ((cmd->forwardmove || cmd->sidemove) && !(player->pflags & PF_SPINNING)) - controlangle = (cmd->angleturn<<16) + R_PointToAngle2(0, 0, cmd->forwardmove << FRACBITS, -cmd->sidemove << FRACBITS); + controlangle = *myangle + R_PointToAngle2(0, 0, cmd->forwardmove << FRACBITS, -cmd->sidemove << FRACBITS); else controlangle = player->drawangle + drawangleoffset; @@ -1706,7 +1667,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) anglediff = FixedMul(anglediff, sine); } - *myangle += FixedMul(anglediff, camadjustfactor); + camadjust = FixedMul(anglediff, camadjustfactor) >> 16; + + *myangle += camadjust << 16; + cmd->angleturn = (INT16)(cmd->angleturn + camadjust); } } } @@ -1715,13 +1679,33 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (ssplayer == 1 && (cmd->forwardmove || cmd->sidemove || cmd->buttons) && displayplayer != consoleplayer) { -#ifdef HAVE_BLUA // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[displayplayer], true); -#endif + LUAh_ViewpointSwitch(player, &players[consoleplayer], true); displayplayer = consoleplayer; } + + cmd->angleturn = (INT16)(cmd->angleturn + ticcmd_oldangleturn[forplayer]); + ticcmd_oldangleturn[forplayer] = cmd->angleturn; +} + +ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) +{ + return M_Memcpy(dest, src, n*sizeof(*src)); +} + +ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + { + dest[i].forwardmove = src[i].forwardmove; + dest[i].sidemove = src[i].sidemove; + dest[i].angleturn = SHORT(src[i].angleturn); + dest[i].aiming = (INT16)SHORT(src[i].aiming); + dest[i].buttons = (UINT16)SHORT(src[i].buttons); + } + return dest; } // User has designated that they want @@ -1904,6 +1888,7 @@ void G_StartTitleCard(void) // void G_PreLevelTitleCard(void) { +#ifndef NOWIPE tic_t starttime = I_GetTime(); tic_t endtime = starttime + (PRELEVELTIME*NEWTICRATERATIO); tic_t nowtime = starttime; @@ -1926,6 +1911,7 @@ void G_PreLevelTitleCard(void) } if (!cv_showhud.value) wipestyleflags = WSF_CROSSFADE; +#endif } static boolean titlecardforreload = false; @@ -2049,9 +2035,7 @@ boolean G_Responder(event_t *ev) && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) { // ViewpointSwitch Lua hook. -#ifdef HAVE_BLUA UINT8 canSwitchView = 0; -#endif if (splitscreen || !netgame) displayplayer = consoleplayer; @@ -2067,14 +2051,12 @@ boolean G_Responder(event_t *ev) if (!playeringame[displayplayer]) continue; -#ifdef HAVE_BLUA // Call ViewpointSwitch hooks here. canSwitchView = LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], false); if (canSwitchView == 1) // Set viewpoint to this player break; else if (canSwitchView == 2) // Skip this player continue; -#endif if (players[displayplayer].spectator) continue; @@ -2085,7 +2067,7 @@ boolean G_Responder(event_t *ev) && players[displayplayer].ctfteam != players[consoleplayer].ctfteam) continue; } - else if (gametype == GT_HIDEANDSEEK) + else if (gametyperules & GTR_HIDEFROZEN) { if (players[consoleplayer].pflags & PF_TAGIT) continue; @@ -2203,6 +2185,10 @@ void G_Ticker(boolean run) UINT32 i; INT32 buf; + // see also SCR_DisplayMarathonInfo + if ((marathonmode & (MA_INIT|MA_INGAME)) == MA_INGAME && gamestate == GS_LEVEL) + marathontime++; + P_MapStart(); // do player reborns if needed if (gamestate == GS_LEVEL) @@ -2219,8 +2205,13 @@ void G_Ticker(boolean run) } else { - // Costs a life to retry ... unless the player in question is dead already. - if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != INFLIVES) + // Costs a life to retry ... unless the player in question is dead already, or you haven't even touched the first starpost in marathon run. + if (marathonmode && gamemap == spmarathon_start && !players[consoleplayer].starposttime) + { + marathonmode |= MA_INIT; + marathontime = 0; + } + else if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != INFLIVES) players[consoleplayer].lives -= 1; G_DoReborn(consoleplayer); @@ -2247,11 +2238,16 @@ void G_Ticker(boolean run) buf = gametic % BACKUPTICS; - // read/write demo and check turbo cheat for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) + { G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); + + players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn; + players[i].oldrelangleturn = players[i].cmd.angleturn; + players[i].cmd.angleturn = players[i].angleturn; + } } // do main actions @@ -2419,11 +2415,12 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) fixed_t height; fixed_t spinheight; INT32 exiting; + tic_t dashmode; INT16 numboxes; INT16 totalring; UINT8 laps; UINT8 mare; - UINT8 skincolor; + UINT16 skincolor; INT32 skin; UINT32 availabilities; tic_t jointime; @@ -2434,6 +2431,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) SINT8 pity; INT16 rings; INT16 spheres; + INT16 playerangleturn; + INT16 oldrelangleturn; score = players[player].score; lives = players[player].lives; @@ -2445,6 +2444,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) spectator = players[player].spectator; outofcoop = players[player].outofcoop; pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); + playerangleturn = players[player].angleturn; + oldrelangleturn = players[player].oldrelangleturn; if (!betweenmaps) pflags |= (players[player].pflags & PF_FINISHED); @@ -2453,6 +2454,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) if (!(netgame || multiplayer)) pflags |= (players[player].pflags & (PF_GODMODE|PF_NOCLIP|PF_INVIS)); + dashmode = players[player].dashmode; + numboxes = players[player].numboxes; laps = players[player].laps; totalring = players[player].totalring; @@ -2516,6 +2519,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->quittime = quittime; p->spectator = spectator; p->outofcoop = outofcoop; + p->angleturn = playerangleturn; + p->oldrelangleturn = oldrelangleturn; // save player config truth reborn p->skincolor = skincolor; @@ -2551,6 +2556,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->spinheight = spinheight; p->exiting = exiting; + p->dashmode = dashmode; + p->numboxes = numboxes; p->laps = laps; p->totalring = totalring; @@ -2611,7 +2618,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); } - if (gametype == GT_COOP) + if (gametyperules & GTR_EMERALDHUNT) P_FindEmerald(); // scan for emeralds to hunt for // If NiGHTS, find lowest mare to start with. @@ -2674,9 +2681,7 @@ void G_SpawnPlayer(INT32 playernum) P_SpawnPlayer(playernum); G_MovePlayerToSpawnOrStarpost(playernum); -#ifdef HAVE_BLUA LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :) -#endif } void G_MovePlayerToSpawnOrStarpost(INT32 playernum) @@ -2781,6 +2786,26 @@ mapthing_t *G_FindCoopStart(INT32 playernum) return NULL; } +// Find a Co-op start, or fallback into other types of starts. +static inline mapthing_t *G_FindCoopStartOrFallback(INT32 playernum) +{ + mapthing_t *spawnpoint = NULL; + if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start + && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start + spawnpoint = G_FindCTFStart(playernum); // fallback + return spawnpoint; +} + +// Find a Match start, or fallback into other types of starts. +static inline mapthing_t *G_FindMatchStartOrFallback(INT32 playernum) +{ + mapthing_t *spawnpoint = NULL; + if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start + && !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start + spawnpoint = G_FindCoopStart(playernum); // fallback + return spawnpoint; +} + mapthing_t *G_FindMapStart(INT32 playernum) { mapthing_t *spawnpoint; @@ -2788,9 +2813,22 @@ mapthing_t *G_FindMapStart(INT32 playernum) if (!playeringame[playernum]) return NULL; + // -- Spectators -- + // Order in platform gametypes: Coop->DM->CTF + // And, with deathmatch starts: DM->CTF->Coop + if (players[playernum].spectator) + { + // In platform gametypes, spawn in Co-op starts first + // Overriden by GTR_DEATHMATCHSTARTS. + if (G_PlatformGametype() && !(gametyperules & GTR_DEATHMATCHSTARTS)) + spawnpoint = G_FindCoopStartOrFallback(playernum); + else + spawnpoint = G_FindMatchStartOrFallback(playernum); + } + // -- CTF -- // Order: CTF->DM->Coop - if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam) + else if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam) { if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start @@ -2799,21 +2837,13 @@ mapthing_t *G_FindMapStart(INT32 playernum) // -- DM/Tag/CTF-spectator/etc -- // Order: DM->CTF->Coop - else if ((gametyperules & GTR_DEATHMATCHSTARTS) && !(players[playernum].pflags & PF_TAGIT)) - { - if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start - && !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start - spawnpoint = G_FindCoopStart(playernum); // fallback - } + else if (G_TagGametype() ? (!(players[playernum].pflags & PF_TAGIT)) : (gametyperules & GTR_DEATHMATCHSTARTS)) + spawnpoint = G_FindMatchStartOrFallback(playernum); // -- Other game modes -- // Order: Coop->DM->CTF else - { - if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start - && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start - spawnpoint = G_FindCTFStart(playernum); // fallback - } + spawnpoint = G_FindCoopStartOrFallback(playernum); //No spawns found. ANYWHERE. if (!spawnpoint) @@ -2899,7 +2929,7 @@ void G_DoReborn(INT32 playernum) return; } - if (countdowntimeup || (!(netgame || multiplayer) && gametype == GT_COOP)) + if (countdowntimeup || (!(netgame || multiplayer) && (gametyperules & GTR_CAMPAIGN))) resetlevel = true; else if ((G_GametypeUsesCoopLives() || G_GametypeUsesCoopStarposts()) && (netgame || multiplayer) && !G_IsSpecialStage(gamemap)) { @@ -2973,7 +3003,7 @@ void G_DoReborn(INT32 playernum) players[i].starpostnum = 0; } } - if (!countdowntimeup && (mapheaderinfo[gamemap-1]->levelflags & LF_NORELOAD)) + if (!countdowntimeup && (mapheaderinfo[gamemap-1]->levelflags & LF_NORELOAD) && !(marathonmode & MA_INIT)) { P_RespawnThings(); @@ -3030,9 +3060,7 @@ void G_DoReborn(INT32 playernum) } else { -#ifdef HAVE_BLUA LUAh_MapChange(gamemap); -#endif titlecardforreload = true; G_DoLoadLevel(true); titlecardforreload = false; @@ -3106,7 +3134,7 @@ void G_AddPlayer(INT32 playernum) p->height = mobjinfo[MT_PLAYER].height; - if (G_GametypeUsesLives() || ((netgame || multiplayer) && gametype == GT_COOP)) + if (G_GametypeUsesLives() || ((netgame || multiplayer) && (gametyperules & GTR_FRIENDLY))) p->lives = cv_startinglives.value; if ((countplayers && !notexiting) || G_IsSpecialStage(gamemap)) @@ -3155,7 +3183,7 @@ void G_ExitLevel(void) CV_SetValue(&cv_teamscramble, cv_scrambleonchange.value); } - if (!(gametyperules & GTR_CAMPAIGN)) + if (!(gametyperules & (GTR_FRIENDLY|GTR_CAMPAIGN))) CONS_Printf(M_GetText("The round has ended.\n")); // Remove CEcho text on round end. @@ -3221,7 +3249,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // Tag GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, // Hide and Seek - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_HIDEFROZEN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, // CTF GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, @@ -3566,6 +3594,16 @@ boolean G_PlatformGametype(void) return (!(gametyperules & GTR_RINGSLINGER)); } +// +// G_CoopGametype +// +// Returns true if a gametype is a Co-op gametype. +// +boolean G_CoopGametype(void) +{ + return ((gametyperules & (GTR_FRIENDLY|GTR_CAMPAIGN)) == (GTR_FRIENDLY|GTR_CAMPAIGN)); +} + // // G_TagGametype // @@ -3592,7 +3630,7 @@ boolean G_CompetitionGametype(void) * \return The typeoflevel flag to check for that gametype. * \author Graue */ -INT16 G_TOLFlag(INT32 pgametype) +UINT32 G_TOLFlag(INT32 pgametype) { if (!multiplayer) return TOL_SP; @@ -3673,6 +3711,24 @@ static void G_UpdateVisited(void) } } +static boolean CanSaveLevel(INT32 mapnum) +{ + // You can never save in a special stage. + if (G_IsSpecialStage(mapnum)) + return false; + + // If the game is complete for this save slot, then any level can save! + if (gamecomplete) + return true; + + // Be kind with Marathon Mode live event backups. + if (marathonmode) + return true; + + // Any levels that have the savegame flag can save normally. + return (mapheaderinfo[mapnum-1] && (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME)); +} + // // G_DoCompleted // @@ -3708,66 +3764,74 @@ static void G_DoCompleted(void) // nextmap is 0-based, unlike gamemap if (nextmapoverride != 0) nextmap = (INT16)(nextmapoverride-1); + else if (marathonmode && mapheaderinfo[gamemap-1]->marathonnext) + nextmap = (INT16)(mapheaderinfo[gamemap-1]->marathonnext-1); else + { nextmap = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1); - - // Remember last map for when you come out of the special stage. - if (!spec) - lastmap = nextmap; + if (marathonmode && nextmap == spmarathon_start-1) + nextmap = 1100-1; // No infinite loop for you + } // If nextmap is actually going to get used, make sure it points to // a map of the proper gametype -- skip levels that don't support // the current gametype. (Helps avoid playing boss levels in Race, // for instance). - if (!token && !spec - && (nextmap >= 0 && nextmap < NUMMAPS)) + if (!spec) { - register INT16 cm = nextmap; - INT16 tolflag = G_TOLFlag(gametype); - UINT8 visitedmap[(NUMMAPS+7)/8]; - - memset(visitedmap, 0, sizeof (visitedmap)); - - while (!mapheaderinfo[cm] || !(mapheaderinfo[cm]->typeoflevel & tolflag)) + if (nextmap >= 0 && nextmap < NUMMAPS) { - visitedmap[cm/8] |= (1<<(cm&7)); - if (!mapheaderinfo[cm]) - cm = -1; // guarantee error execution - else - cm = (INT16)(mapheaderinfo[cm]->nextlevel-1); + register INT16 cm = nextmap; + UINT32 tolflag = G_TOLFlag(gametype); + UINT8 visitedmap[(NUMMAPS+7)/8]; - if (cm >= NUMMAPS || cm < 0) // out of range (either 1100-1102 or error) + memset(visitedmap, 0, sizeof (visitedmap)); + + while (!mapheaderinfo[cm] || !(mapheaderinfo[cm]->typeoflevel & tolflag)) { - cm = nextmap; //Start the loop again so that the error checking below is executed. + visitedmap[cm/8] |= (1<<(cm&7)); + if (!mapheaderinfo[cm]) + cm = -1; // guarantee error execution + else if (marathonmode && mapheaderinfo[cm]->marathonnext) + cm = (INT16)(mapheaderinfo[cm]->marathonnext-1); + else + cm = (INT16)(mapheaderinfo[cm]->nextlevel-1); - //Make sure the map actually exists before you try to go to it! - if ((W_CheckNumForName(G_BuildMapName(cm + 1)) == LUMPERROR)) + if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) { - CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); - cm = 0; + cm = nextmap; //Start the loop again so that the error checking below is executed. + + //Make sure the map actually exists before you try to go to it! + if ((W_CheckNumForName(G_BuildMapName(cm + 1)) == LUMPERROR)) + { + CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); + cm = 0; + break; + } + } + + if (visitedmap[cm/8] & (1<<(cm&7))) // smells familiar + { + // We got stuck in a loop, came back to the map we started on + // without finding one supporting the current gametype. + // Thus, print a warning, and just use this map anyways. + CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after map %d; using map %d anyway\n"), prevmap+1, cm+1); break; } } - - if (visitedmap[cm/8] & (1<<(cm&7))) // smells familiar - { - // We got stuck in a loop, came back to the map we started on - // without finding one supporting the current gametype. - // Thus, print a warning, and just use this map anyways. - CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after map %d; using map %d anyway\n"), prevmap+1, cm+1); - break; - } + nextmap = cm; } - nextmap = cm; + + // wrap around in race + if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) + nextmap = (INT16)(spstage_start-1); + + if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1) + I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); + + lastmap = nextmap; // Remember last map for when you come out of the special stage. } - if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1) - I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); - - // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) - nextmap = (INT16)(spstage_start-1); - if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) { token--; @@ -3805,7 +3869,10 @@ static void G_DoCompleted(void) if (nextmap < NUMMAPS && !mapheaderinfo[nextmap]) P_AllocMapHeader(nextmap); - if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed)) + // If the current gametype has no intermission screen set, then don't start it. + Y_DetermineIntermissionType(); + + if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none)) { G_UpdateVisited(); G_AfterIntermission(); @@ -3816,8 +3883,32 @@ static void G_DoCompleted(void) Y_StartIntermission(); G_UpdateVisited(); } + + // do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c + if (nextmap >= 1100-1) + { + if (!gamecomplete) + gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission + if (cursaveslot > 0) + { + if (marathonmode) + { + // don't keep a backup around when the run is done! + if (FIL_FileExists(liveeventbackup)) + remove(liveeventbackup); + cursaveslot = 0; + } + else if ((!modifiedgame || savemoddata) && !(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking)) + G_SaveGame((UINT32)cursaveslot, spstage_start); + } + } + // and doing THIS here means you don't lose your progress if you close the game mid-intermission + else if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) + && (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(lastmap+1)) + G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages } +// See also F_EndCutscene, the only other place which handles intra-map/ending transitions void G_AfterIntermission(void) { Y_CleanupScreenBuffer(); @@ -3828,9 +3919,12 @@ void G_AfterIntermission(void) return; } + if (gamecomplete == 2) // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission + gamecomplete = 1; + HU_ClearCEcho(); - if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1) // Start a custom cutscene. + if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); else { @@ -3856,7 +3950,7 @@ static void G_DoWorldDone(void) { if (server) { - if (gametype == GT_COOP) + if (gametyperules & GTR_CAMPAIGN) // don't reset player between maps D_MapChange(nextmap+1, gametype, ultimatemode, false, 0, false, false); else @@ -3906,7 +4000,8 @@ static void G_DoContinued(void) I_Assert(!netgame && !multiplayer); I_Assert(pl->continues > 0); - pl->continues--; + if (pl->continues) + pl->continues--; // Reset score pl->score = 0; @@ -3970,7 +4065,7 @@ void G_EndGame(void) void G_LoadGameSettings(void) { // defaults - spstage_start = 1; + spstage_start = spmarathon_start = 1; sstage_start = 50; sstage_end = 56; // 7 special stages in vanilla SRB2 sstage_end++; // plus one weirdo @@ -4290,7 +4385,10 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) startonmapnum = mapoverride; #endif - sprintf(savename, savegamename, slot); + if (marathonmode) + strcpy(savename, liveeventbackup); + else + sprintf(savename, savegamename, slot); length = FIL_ReadFile(savename, &savebuffer); if (!length) @@ -4302,7 +4400,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) save_p = savebuffer; memset(vcheck, 0, sizeof (vcheck)); - sprintf(vcheck, "version %d", VERSION); + sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); if (strcmp((const char *)save_p, (const char *)vcheck)) { #ifdef SAVEGAME_OTHERVERSIONS @@ -4342,6 +4440,11 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) memset(&savedata, 0, sizeof(savedata)); return; } + if (marathonmode) + { + marathontime = READUINT32(save_p); + marathonmode |= READUINT8(save_p); + } // done Z_Free(savebuffer); @@ -4364,19 +4467,18 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) // G_SaveGame // Saves your game. // -void G_SaveGame(UINT32 slot) +void G_SaveGame(UINT32 slot, INT16 mapnum) { boolean saved; char savename[256] = ""; const char *backup; - sprintf(savename, savegamename, slot); + if (marathonmode) + strcpy(savename, liveeventbackup); + else + sprintf(savename, savegamename, slot); backup = va("%s",savename); - // save during evaluation or credits? game's over, folks! - if (gamestate == GS_ENDING || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) - gamecomplete = true; - gameaction = ga_nothing; { char name[VERSIONSIZE]; @@ -4390,10 +4492,15 @@ void G_SaveGame(UINT32 slot) } memset(name, 0, sizeof (name)); - sprintf(name, "version %d", VERSION); + sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION); WRITEMEM(save_p, name, VERSIONSIZE); - P_SaveGame(); + P_SaveGame(mapnum); + if (marathonmode) + { + WRITEUINT32(save_p, marathontime); + WRITEUINT8(save_p, (marathonmode & ~MA_INIT)); + } length = save_p - savebuffer; saved = FIL_WriteFile(backup, savebuffer, length); @@ -4406,7 +4513,7 @@ void G_SaveGame(UINT32 slot) if (cv_debug && saved) CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) - CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, savegamename); + CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); } #define BADSAVE goto cleanup; @@ -4419,7 +4526,10 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) char savename[255]; const char *backup; - sprintf(savename, savegamename, slot); + if (marathonmode) + strcpy(savename, liveeventbackup); + else + sprintf(savename, savegamename, slot); backup = va("%s",savename); length = FIL_ReadFile(savename, &savebuffer); @@ -4438,7 +4548,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) save_p = savebuffer; // Version check memset(vcheck, 0, sizeof (vcheck)); - sprintf(vcheck, "version %d", VERSION); + sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE save_p += VERSIONSIZE; @@ -4505,7 +4615,7 @@ cleanup: if (cv_debug && saved) CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) - CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, savegamename); + CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); Z_Free(savebuffer); save_p = savebuffer = NULL; @@ -4520,12 +4630,12 @@ cleanup: // void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS) { - UINT8 color = skins[pickedchar].prefcolor; + UINT16 color = skins[pickedchar].prefcolor; paused = false; if (demoplayback) COM_BufAddText("stopdemo\n"); - ghosts = NULL; + G_FreeGhosts(); // TODO: do we actually need to do this? // this leave the actual game if needed SV_StartSinglePlayerServer(); @@ -4643,7 +4753,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean automapactive = false; imcontinuing = false; - if ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking) // Start a custom cutscene. + if ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer); else G_DoLoadLevel(resetplayer); @@ -4674,7 +4784,7 @@ char *G_BuildMapTitle(INT32 mapnum) { size_t len = 1; const char *zonetext = NULL; - const INT32 actnum = mapheaderinfo[mapnum-1]->actnum; + const UINT8 actnum = mapheaderinfo[mapnum-1]->actnum; len += strlen(mapheaderinfo[mapnum-1]->lvlttl); if (!(mapheaderinfo[mapnum-1]->levelflags & LF_NOZONE)) @@ -4934,2432 +5044,6 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) return newmapnum; } -// -// DEMO RECORDING -// - -#define DEMOVERSION 0x000c -#define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" - -#define DF_GHOST 0x01 // This demo contains ghost data too! -#define DF_RECORDATTACK 0x02 // This demo is from record attack and contains its final completion time, score, and rings! -#define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! -#define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? -#define DF_ATTACKSHIFT 1 - -// For demos -#define ZT_FWD 0x01 -#define ZT_SIDE 0x02 -#define ZT_ANGLE 0x04 -#define ZT_BUTTONS 0x08 -#define ZT_AIMING 0x10 -#define DEMOMARKER 0x80 // demoend -#define METALDEATH 0x44 -#define METALSNICE 0x69 - -static ticcmd_t oldcmd; - -// For Metal Sonic and time attack ghosts -#define GZT_XYZ 0x01 -#define GZT_MOMXY 0x02 -#define GZT_MOMZ 0x04 -#define GZT_ANGLE 0x08 -#define GZT_FRAME 0x10 // Animation frame -#define GZT_SPR2 0x20 // Player animations -#define GZT_EXTRA 0x40 -#define GZT_FOLLOW 0x80 // Followmobj - -// GZT_EXTRA flags -#define EZT_THOK 0x01 // Spawned a thok object -#define EZT_SPIN 0x02 // Because one type of thok object apparently wasn't enough -#define EZT_REV 0x03 // And two types wasn't enough either yet -#define EZT_THOKMASK 0x03 -#define EZT_COLOR 0x04 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) -#define EZT_FLIP 0x08 // Reversed gravity -#define EZT_SCALE 0x10 // Changed size -#define EZT_HIT 0x20 // Damaged a mobj -#define EZT_SPRITE 0x40 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) -#define EZT_HEIGHT 0x80 // Changed height - -// GZT_FOLLOW flags -#define FZT_SPAWNED 0x01 // just been spawned -#define FZT_SKIN 0x02 // has skin -#define FZT_LINKDRAW 0x04 // has linkdraw (combine with spawned only) -#define FZT_COLORIZED 0x08 // colorized (ditto) -#define FZT_SCALE 0x10 // different scale to object -// spare FZT slots 0x20 to 0x80 - -static mobj_t oldmetal, oldghost; - -void G_SaveMetal(UINT8 **buffer) -{ - I_Assert(buffer != NULL && *buffer != NULL); - - WRITEUINT32(*buffer, metal_p - metalbuffer); -} - -void G_LoadMetal(UINT8 **buffer) -{ - I_Assert(buffer != NULL && *buffer != NULL); - - G_DoPlayMetal(); - metal_p = metalbuffer + READUINT32(*buffer); -} - -ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) -{ - return M_Memcpy(dest, src, n*sizeof(*src)); -} - -ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) -{ - size_t i; - for (i = 0; i < n; i++) - { - dest[i].forwardmove = src[i].forwardmove; - dest[i].sidemove = src[i].sidemove; - dest[i].angleturn = SHORT(src[i].angleturn); - dest[i].aiming = (INT16)SHORT(src[i].aiming); - dest[i].buttons = (UINT16)SHORT(src[i].buttons); - } - return dest; -} - -void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) -{ - UINT8 ziptic; - (void)playernum; - - if (!demo_p || !demo_start) - return; - ziptic = READUINT8(demo_p); - - if (ziptic & ZT_FWD) - oldcmd.forwardmove = READSINT8(demo_p); - if (ziptic & ZT_SIDE) - oldcmd.sidemove = READSINT8(demo_p); - if (ziptic & ZT_ANGLE) - oldcmd.angleturn = READINT16(demo_p); - if (ziptic & ZT_BUTTONS) - oldcmd.buttons = (oldcmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) | (READUINT16(demo_p) & ~(BT_CAMLEFT|BT_CAMRIGHT)); - if (ziptic & ZT_AIMING) - oldcmd.aiming = READINT16(demo_p); - - G_CopyTiccmd(cmd, &oldcmd, 1); - - if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) - { - // end of demo data stream - G_CheckDemoStatus(); - return; - } -} - -void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) -{ - char ziptic = 0; - UINT8 *ziptic_p; - (void)playernum; - - if (!demo_p) - return; - ziptic_p = demo_p++; // the ziptic, written at the end of this function - - if (cmd->forwardmove != oldcmd.forwardmove) - { - WRITEUINT8(demo_p,cmd->forwardmove); - oldcmd.forwardmove = cmd->forwardmove; - ziptic |= ZT_FWD; - } - - if (cmd->sidemove != oldcmd.sidemove) - { - WRITEUINT8(demo_p,cmd->sidemove); - oldcmd.sidemove = cmd->sidemove; - ziptic |= ZT_SIDE; - } - - if (cmd->angleturn != oldcmd.angleturn) - { - WRITEINT16(demo_p,cmd->angleturn); - oldcmd.angleturn = cmd->angleturn; - ziptic |= ZT_ANGLE; - } - - if (cmd->buttons != oldcmd.buttons) - { - WRITEUINT16(demo_p,cmd->buttons); - oldcmd.buttons = cmd->buttons; - ziptic |= ZT_BUTTONS; - } - - if (cmd->aiming != oldcmd.aiming) - { - WRITEINT16(demo_p,cmd->aiming); - oldcmd.aiming = cmd->aiming; - ziptic |= ZT_AIMING; - } - - *ziptic_p = ziptic; - - // attention here for the ticcmd size! - // latest demos with mouse aiming byte in ticcmd - if (!(demoflags & DF_GHOST) && ziptic_p > demoend - 9) - { - G_CheckDemoStatus(); // no more space - return; - } -} - -void G_GhostAddThok(void) -{ - if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) - return; - ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_THOK; -} - -void G_GhostAddSpin(void) -{ - if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) - return; - ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_SPIN; -} - -void G_GhostAddRev(void) -{ - if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) - return; - ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_REV; -} - -void G_GhostAddFlip(void) -{ - if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) - return; - ghostext.flags |= EZT_FLIP; -} - -void G_GhostAddColor(ghostcolor_t color) -{ - if (!demorecording || !(demoflags & DF_GHOST)) - return; - if (ghostext.lastcolor == (UINT8)color) - { - ghostext.flags &= ~EZT_COLOR; - return; - } - ghostext.flags |= EZT_COLOR; - ghostext.color = (UINT8)color; -} - -void G_GhostAddScale(fixed_t scale) -{ - if (!metalrecording && (!demorecording || !(demoflags & DF_GHOST))) - return; - if (ghostext.lastscale == scale) - { - ghostext.flags &= ~EZT_SCALE; - return; - } - ghostext.flags |= EZT_SCALE; - ghostext.scale = scale; -} - -void G_GhostAddHit(mobj_t *victim) -{ - if (!demorecording || !(demoflags & DF_GHOST)) - return; - ghostext.flags |= EZT_HIT; - ghostext.hits++; - ghostext.hitlist = Z_Realloc(ghostext.hitlist, ghostext.hits * sizeof(mobj_t *), PU_LEVEL, NULL); - ghostext.hitlist[ghostext.hits-1] = victim; -} - -void G_WriteGhostTic(mobj_t *ghost) -{ - char ziptic = 0; - UINT8 *ziptic_p; - UINT32 i; - fixed_t height; - - if (!demo_p) - return; - if (!(demoflags & DF_GHOST)) - return; // No ghost data to write. - - ziptic_p = demo_p++; // the ziptic, written at the end of this function - - #define MAXMOM (0xFFFF<<8) - - // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. - if (abs(ghost->x-oldghost.x) > MAXMOM - || abs(ghost->y-oldghost.y) > MAXMOM - || abs(ghost->z-oldghost.z) > MAXMOM) - { - oldghost.x = ghost->x; - oldghost.y = ghost->y; - oldghost.z = ghost->z; - ziptic |= GZT_XYZ; - WRITEFIXED(demo_p,oldghost.x); - WRITEFIXED(demo_p,oldghost.y); - WRITEFIXED(demo_p,oldghost.z); - } - else - { - // For moving normally: - // Store one full byte of movement, plus one byte of fractional movement. - INT16 momx = (INT16)((ghost->x-oldghost.x)>>8); - INT16 momy = (INT16)((ghost->y-oldghost.y)>>8); - if (momx != oldghost.momx - || momy != oldghost.momy) - { - oldghost.momx = momx; - oldghost.momy = momy; - ziptic |= GZT_MOMXY; - WRITEINT16(demo_p,momx); - WRITEINT16(demo_p,momy); - } - momx = (INT16)((ghost->z-oldghost.z)>>8); - if (momx != oldghost.momz) - { - oldghost.momz = momx; - ziptic |= GZT_MOMZ; - WRITEINT16(demo_p,momx); - } - - // This SHOULD set oldghost.x/y/z to match ghost->x/y/z - // but it keeps the fractional loss of one byte, - // so it will hopefully be made up for in future tics. - oldghost.x += oldghost.momx<<8; - oldghost.y += oldghost.momy<<8; - oldghost.z += oldghost.momz<<8; - } - - #undef MAXMOM - - // Only store the 8 most relevant bits of angle - // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites - // and it does not affect this mode of movement at all anyway. - if (ghost->player && ghost->player->drawangle>>24 != oldghost.angle) - { - oldghost.angle = ghost->player->drawangle>>24; - ziptic |= GZT_ANGLE; - WRITEUINT8(demo_p,oldghost.angle); - } - - // Store the sprite frame. - if ((ghost->frame & FF_FRAMEMASK) != oldghost.frame) - { - oldghost.frame = (ghost->frame & FF_FRAMEMASK); - ziptic |= GZT_FRAME; - WRITEUINT8(demo_p,oldghost.frame); - } - - if (ghost->sprite == SPR_PLAY - && ghost->sprite2 != oldghost.sprite2) - { - oldghost.sprite2 = ghost->sprite2; - ziptic |= GZT_SPR2; - WRITEUINT8(demo_p,oldghost.sprite2); - } - - // Check for sprite set changes - if (ghost->sprite != oldghost.sprite) - { - oldghost.sprite = ghost->sprite; - ghostext.flags |= EZT_SPRITE; - } - - if ((height = FixedDiv(ghost->height, ghost->scale)) != oldghost.height) - { - oldghost.height = height; - ghostext.flags |= EZT_HEIGHT; - } - - if (ghostext.flags) - { - ziptic |= GZT_EXTRA; - - if (ghostext.color == ghostext.lastcolor) - ghostext.flags &= ~EZT_COLOR; - if (ghostext.scale == ghostext.lastscale) - ghostext.flags &= ~EZT_SCALE; - - WRITEUINT8(demo_p,ghostext.flags); - if (ghostext.flags & EZT_COLOR) - { - WRITEUINT8(demo_p,ghostext.color); - ghostext.lastcolor = ghostext.color; - } - if (ghostext.flags & EZT_SCALE) - { - WRITEFIXED(demo_p,ghostext.scale); - ghostext.lastscale = ghostext.scale; - } - if (ghostext.flags & EZT_HIT) - { - WRITEUINT16(demo_p,ghostext.hits); - for (i = 0; i < ghostext.hits; i++) - { - mobj_t *mo = ghostext.hitlist[i]; - //WRITEUINT32(demo_p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) - WRITEUINT32(demo_p,mo->type); - WRITEUINT16(demo_p,(UINT16)mo->health); - WRITEFIXED(demo_p,mo->x); - WRITEFIXED(demo_p,mo->y); - WRITEFIXED(demo_p,mo->z); - WRITEANGLE(demo_p,mo->angle); - } - Z_Free(ghostext.hitlist); - ghostext.hits = 0; - ghostext.hitlist = NULL; - } - if (ghostext.flags & EZT_SPRITE) - WRITEUINT16(demo_p,oldghost.sprite); - if (ghostext.flags & EZT_HEIGHT) - { - height >>= FRACBITS; - WRITEINT16(demo_p, height); - } - ghostext.flags = 0; - } - - if (ghost->player && ghost->player->followmobj && !(ghost->player->followmobj->sprite == SPR_NULL || (ghost->player->followmobj->flags2 & MF2_DONTDRAW))) // bloats tails runs but what can ya do - { - INT16 temp; - UINT8 *followtic_p = demo_p++; - UINT8 followtic = 0; - - ziptic |= GZT_FOLLOW; - - if (ghost->player->followmobj->skin) - followtic |= FZT_SKIN; - - if (!(oldghost.flags2 & MF2_AMBUSH)) - { - followtic |= FZT_SPAWNED; - WRITEINT16(demo_p,ghost->player->followmobj->info->height>>FRACBITS); - if (ghost->player->followmobj->flags2 & MF2_LINKDRAW) - followtic |= FZT_LINKDRAW; - if (ghost->player->followmobj->colorized) - followtic |= FZT_COLORIZED; - if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,(UINT8)(((skin_t *)(ghost->player->followmobj->skin))-skins)); - oldghost.flags2 |= MF2_AMBUSH; - } - - if (ghost->player->followmobj->scale != ghost->scale) - { - followtic |= FZT_SCALE; - WRITEFIXED(demo_p,ghost->player->followmobj->scale); - } - - temp = (INT16)((ghost->player->followmobj->x-ghost->x)>>8); - WRITEINT16(demo_p,temp); - temp = (INT16)((ghost->player->followmobj->y-ghost->y)>>8); - WRITEINT16(demo_p,temp); - temp = (INT16)((ghost->player->followmobj->z-ghost->z)>>8); - WRITEINT16(demo_p,temp); - if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,ghost->player->followmobj->sprite2); - WRITEUINT16(demo_p,ghost->player->followmobj->sprite); - WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK)); - WRITEUINT8(demo_p,ghost->player->followmobj->color); - - *followtic_p = followtic; - } - else - oldghost.flags2 &= ~MF2_AMBUSH; - - *ziptic_p = ziptic; - - // attention here for the ticcmd size! - // latest demos with mouse aiming byte in ticcmd - if (demo_p >= demoend - (13 + 9 + 9)) - { - G_CheckDemoStatus(); // no more space - return; - } -} - -// Uses ghost data to do consistency checks on your position. -// This fixes desynchronising demos when fighting eggman. -void G_ConsGhostTic(void) -{ - UINT8 ziptic; - UINT16 px,py,pz,gx,gy,gz; - mobj_t *testmo; - - if (!demo_p || !demo_start) - return; - if (!(demoflags & DF_GHOST)) - return; // No ghost data to use. - - testmo = players[0].mo; - - // Grab ghost data. - ziptic = READUINT8(demo_p); - if (ziptic & GZT_XYZ) - { - oldghost.x = READFIXED(demo_p); - oldghost.y = READFIXED(demo_p); - oldghost.z = READFIXED(demo_p); - } - else - { - if (ziptic & GZT_MOMXY) - { - oldghost.momx = READINT16(demo_p)<<8; - oldghost.momy = READINT16(demo_p)<<8; - } - if (ziptic & GZT_MOMZ) - oldghost.momz = READINT16(demo_p)<<8; - oldghost.x += oldghost.momx; - oldghost.y += oldghost.momy; - oldghost.z += oldghost.momz; - } - if (ziptic & GZT_ANGLE) - demo_p++; - if (ziptic & GZT_FRAME) - demo_p++; - if (ziptic & GZT_SPR2) - demo_p++; - - if (ziptic & GZT_EXTRA) - { // But wait, there's more! - UINT8 xziptic = READUINT8(demo_p); - if (xziptic & EZT_COLOR) - demo_p++; - if (xziptic & EZT_SCALE) - demo_p += sizeof(fixed_t); - if (xziptic & EZT_HIT) - { // Resync mob damage. - UINT16 i, count = READUINT16(demo_p); - thinker_t *th; - mobj_t *mobj; - - UINT32 type; - UINT16 health; - fixed_t x; - fixed_t y; - fixed_t z; - - for (i = 0; i < count; i++) - { - //demo_p += 4; // reserved. - type = READUINT32(demo_p); - health = READUINT16(demo_p); - x = READFIXED(demo_p); - y = READFIXED(demo_p); - z = READFIXED(demo_p); - demo_p += sizeof(angle_t); // angle, unnecessary for cons. - - mobj = NULL; - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - mobj = (mobj_t *)th; - if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z) - break; - } - if (th != &thlist[THINK_MOBJ] && mobj->health != health) // Wasn't damaged?! This is desync! Fix it! - { - if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); - demosynced = false; - P_DamageMobj(mobj, players[0].mo, players[0].mo, 1, 0); - } - } - } - if (xziptic & EZT_SPRITE) - demo_p += sizeof(UINT16); - if (xziptic & EZT_HEIGHT) - demo_p += sizeof(INT16); - } - - if (ziptic & GZT_FOLLOW) - { // Even more... - UINT8 followtic = READUINT8(demo_p); - if (followtic & FZT_SPAWNED) - { - demo_p += sizeof(INT16); - if (followtic & FZT_SKIN) - demo_p++; - } - if (followtic & FZT_SCALE) - demo_p += sizeof(fixed_t); - demo_p += sizeof(INT16); - demo_p += sizeof(INT16); - demo_p += sizeof(INT16); - if (followtic & FZT_SKIN) - demo_p++; - demo_p += sizeof(UINT16); - demo_p++; - demo_p++; - } - - // Re-synchronise - px = testmo->x>>FRACBITS; - py = testmo->y>>FRACBITS; - pz = testmo->z>>FRACBITS; - gx = oldghost.x>>FRACBITS; - gy = oldghost.y>>FRACBITS; - gz = oldghost.z>>FRACBITS; - - if (px != gx || py != gy || pz != gz) - { - if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); - demosynced = false; - - P_UnsetThingPosition(testmo); - testmo->x = oldghost.x; - testmo->y = oldghost.y; - P_SetThingPosition(testmo); - testmo->z = oldghost.z; - } - - if (*demo_p == DEMOMARKER) - { - // end of demo data stream - G_CheckDemoStatus(); - return; - } -} - -void G_GhostTicker(void) -{ - demoghost *g,*p; - for(g = ghosts, p = NULL; g; g = g->next) - { - // Skip normal demo data. - UINT8 ziptic = READUINT8(g->p); - UINT8 xziptic = 0; - if (ziptic & ZT_FWD) - g->p++; - if (ziptic & ZT_SIDE) - g->p++; - if (ziptic & ZT_ANGLE) - g->p += 2; - if (ziptic & ZT_BUTTONS) - g->p += 2; - if (ziptic & ZT_AIMING) - g->p += 2; - - // Grab ghost data. - ziptic = READUINT8(g->p); - if (ziptic & GZT_XYZ) - { - g->oldmo.x = READFIXED(g->p); - g->oldmo.y = READFIXED(g->p); - g->oldmo.z = READFIXED(g->p); - } - else - { - if (ziptic & GZT_MOMXY) - { - g->oldmo.momx = READINT16(g->p)<<8; - g->oldmo.momy = READINT16(g->p)<<8; - } - if (ziptic & GZT_MOMZ) - g->oldmo.momz = READINT16(g->p)<<8; - g->oldmo.x += g->oldmo.momx; - g->oldmo.y += g->oldmo.momy; - g->oldmo.z += g->oldmo.momz; - } - if (ziptic & GZT_ANGLE) - g->mo->angle = READUINT8(g->p)<<24; - if (ziptic & GZT_FRAME) - g->oldmo.frame = READUINT8(g->p); - if (ziptic & GZT_SPR2) - g->oldmo.sprite2 = READUINT8(g->p); - - // Update ghost - P_UnsetThingPosition(g->mo); - g->mo->x = g->oldmo.x; - g->mo->y = g->oldmo.y; - g->mo->z = g->oldmo.z; - P_SetThingPosition(g->mo); - g->mo->frame = g->oldmo.frame | tr_trans30<fadein) - { - g->mo->frame += (((--g->fadein)/6)<fadein is bad, and it's only set once, so... - g->mo->flags2 &= ~MF2_DONTDRAW; - } - g->mo->sprite2 = g->oldmo.sprite2; - - if (ziptic & GZT_EXTRA) - { // But wait, there's more! - xziptic = READUINT8(g->p); - if (xziptic & EZT_COLOR) - { - g->color = READUINT8(g->p); - switch(g->color) - { - default: - case GHC_RETURNSKIN: - g->mo->skin = g->oldmo.skin; - /* FALLTHRU */ - case GHC_NORMAL: // Go back to skin color - g->mo->color = g->oldmo.color; - break; - // Handled below - case GHC_SUPER: - case GHC_INVINCIBLE: - break; - case GHC_FIREFLOWER: // Fireflower - g->mo->color = SKINCOLOR_WHITE; - break; - case GHC_NIGHTSSKIN: // not actually a colour - g->mo->skin = &skins[DEFAULTNIGHTSSKIN]; - break; - } - } - if (xziptic & EZT_FLIP) - g->mo->eflags ^= MFE_VERTICALFLIP; - if (xziptic & EZT_SCALE) - { - g->mo->destscale = READFIXED(g->p); - if (g->mo->destscale != g->mo->scale) - P_SetScale(g->mo, g->mo->destscale); - } - if (xziptic & EZT_THOKMASK) - { // Let's only spawn ONE of these per frame, thanks. - mobj_t *mobj; - INT32 type = -1; - if (g->mo->skin) - { - skin_t *skin = (skin_t *)g->mo->skin; - switch (xziptic & EZT_THOKMASK) - { - case EZT_THOK: - type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; - break; - case EZT_SPIN: - type = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; - break; - case EZT_REV: - type = skin->revitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; - break; - } - } - if (type != MT_NULL) - { - if (type == MT_GHOST) - { - mobj = P_SpawnGhostMobj(g->mo); // does a large portion of the work for us - mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|tr_trans60<mo, 0, 0, -FixedDiv(FixedMul(g->mo->info->height, g->mo->scale) - g->mo->height,3*FRACUNIT), MT_THOK); - mobj->sprite = states[mobjinfo[type].spawnstate].sprite; - mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<color = g->mo->color; - mobj->skin = g->mo->skin; - P_SetScale(mobj, (mobj->destscale = g->mo->scale)); - - if (type == MT_THOK) // spintrail-specific modification for MT_THOK - { - mobj->frame = FF_TRANS80; - mobj->fuse = mobj->tics; - } - mobj->tics = -1; // nope. - } - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_UnsetThingPosition(mobj); - mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... - P_SetThingPosition(mobj); - if (!mobj->fuse) - mobj->fuse = 8; - P_SetTarget(&mobj->target, g->mo); - } - } - if (xziptic & EZT_HIT) - { // Spawn hit poofs for killing things! - UINT16 i, count = READUINT16(g->p), health; - UINT32 type; - fixed_t x,y,z; - angle_t angle; - mobj_t *poof; - for (i = 0; i < count; i++) - { - //g->p += 4; // reserved - type = READUINT32(g->p); - health = READUINT16(g->p); - x = READFIXED(g->p); - y = READFIXED(g->p); - z = READFIXED(g->p); - angle = READANGLE(g->p); - if (!(mobjinfo[type].flags & MF_SHOOTABLE) - || !(mobjinfo[type].flags & (MF_ENEMY|MF_MONITOR)) - || health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. - continue; - poof = P_SpawnMobj(x, y, z, MT_GHOST); - poof->angle = angle; - poof->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... - poof->health = 0; - P_SetMobjStateNF(poof, S_XPLD1); - } - } - if (xziptic & EZT_SPRITE) - g->mo->sprite = READUINT16(g->p); - if (xziptic & EZT_HEIGHT) - { - fixed_t temp = READINT16(g->p)<mo->height = FixedMul(temp, g->mo->scale); - } - } - - // Tick ghost colors (Super and Mario Invincibility flashing) - switch(g->color) - { - case GHC_SUPER: // Super (P_DoSuperStuff) - if (g->mo->skin) - { - skin_t *skin = (skin_t *)g->mo->skin; - g->mo->color = skin->supercolor; - } - else - g->mo->color = SKINCOLOR_SUPERGOLD1; - g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4); - break; - case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer) - g->mo->color = (UINT8)(SKINCOLOR_RUBY + (leveltime % (MAXSKINCOLORS - SKINCOLOR_RUBY))); // Passes through all saturated colours - break; - default: - break; - } - -#define follow g->mo->tracer - if (ziptic & GZT_FOLLOW) - { // Even more... - UINT8 followtic = READUINT8(g->p); - fixed_t temp; - if (followtic & FZT_SPAWNED) - { - if (follow) - P_RemoveMobj(follow); - P_SetTarget(&follow, P_SpawnMobjFromMobj(g->mo, 0, 0, 0, MT_GHOST)); - P_SetTarget(&follow->tracer, g->mo); - follow->tics = -1; - temp = READINT16(g->p)<height = FixedMul(follow->scale, temp); - - if (followtic & FZT_LINKDRAW) - follow->flags2 |= MF2_LINKDRAW; - - if (followtic & FZT_COLORIZED) - follow->colorized = true; - - if (followtic & FZT_SKIN) - follow->skin = &skins[READUINT8(g->p)]; - } - if (follow) - { - if (followtic & FZT_SCALE) - follow->destscale = READFIXED(g->p); - else - follow->destscale = g->mo->destscale; - if (follow->destscale != follow->scale) - P_SetScale(follow, follow->destscale); - - P_UnsetThingPosition(follow); - temp = READINT16(g->p)<<8; - follow->x = g->mo->x + temp; - temp = READINT16(g->p)<<8; - follow->y = g->mo->y + temp; - temp = READINT16(g->p)<<8; - follow->z = g->mo->z + temp; - P_SetThingPosition(follow); - if (followtic & FZT_SKIN) - follow->sprite2 = READUINT8(g->p); - else - follow->sprite2 = 0; - follow->sprite = READUINT16(g->p); - follow->frame = (READUINT8(g->p)) | (g->mo->frame & FF_TRANSMASK); - follow->angle = g->mo->angle; - follow->color = READUINT8(g->p); - - if (!(followtic & FZT_SPAWNED)) - { - if (xziptic & EZT_FLIP) - { - follow->flags2 ^= MF2_OBJECTFLIP; - follow->eflags ^= MFE_VERTICALFLIP; - } - } - } - } - else if (follow) - { - P_RemoveMobj(follow); - P_SetTarget(&follow, NULL); - } - // Demo ends after ghost data. - if (*g->p == DEMOMARKER) - { - g->mo->momx = g->mo->momy = g->mo->momz = 0; -#if 1 // freeze frame (maybe more useful for time attackers) - g->mo->colorized = true; - if (follow) - follow->colorized = true; -#else // dissapearing act - g->mo->fuse = TICRATE; - if (follow) - follow->fuse = TICRATE; -#endif - if (p) - p->next = g->next; - else - ghosts = g->next; - Z_Free(g); - continue; - } - p = g; -#undef follow - } -} - -void G_ReadMetalTic(mobj_t *metal) -{ - UINT8 ziptic; - UINT8 xziptic = 0; - - if (!metal_p) - return; - - if (!metal->health) - { - G_StopMetalDemo(); - return; - } - - switch (*metal_p) - { - case METALSNICE: - break; - case METALDEATH: - if (metal->tracer) - P_RemoveMobj(metal->tracer); - P_KillMobj(metal, NULL, NULL, 0); - /* FALLTHRU */ - case DEMOMARKER: - default: - // end of demo data stream - G_StopMetalDemo(); - return; - } - metal_p++; - - ziptic = READUINT8(metal_p); - - // Read changes from the tic - if (ziptic & GZT_XYZ) - { - P_TeleportMove(metal, READFIXED(metal_p), READFIXED(metal_p), READFIXED(metal_p)); - oldmetal.x = metal->x; - oldmetal.y = metal->y; - oldmetal.z = metal->z; - } - else - { - if (ziptic & GZT_MOMXY) - { - oldmetal.momx = READINT16(metal_p)<<8; - oldmetal.momy = READINT16(metal_p)<<8; - } - if (ziptic & GZT_MOMZ) - oldmetal.momz = READINT16(metal_p)<<8; - oldmetal.x += oldmetal.momx; - oldmetal.y += oldmetal.momy; - oldmetal.z += oldmetal.momz; - } - if (ziptic & GZT_ANGLE) - metal->angle = READUINT8(metal_p)<<24; - if (ziptic & GZT_FRAME) - oldmetal.frame = READUINT32(metal_p); - if (ziptic & GZT_SPR2) - oldmetal.sprite2 = READUINT8(metal_p); - - // Set movement, position, and angle - // oldmetal contains where you're supposed to be. - metal->momx = oldmetal.momx; - metal->momy = oldmetal.momy; - metal->momz = oldmetal.momz; - P_UnsetThingPosition(metal); - metal->x = oldmetal.x; - metal->y = oldmetal.y; - metal->z = oldmetal.z; - P_SetThingPosition(metal); - metal->frame = oldmetal.frame; - metal->sprite2 = oldmetal.sprite2; - - if (ziptic & GZT_EXTRA) - { // But wait, there's more! - xziptic = READUINT8(metal_p); - if (xziptic & EZT_FLIP) - { - metal->eflags ^= MFE_VERTICALFLIP; - metal->flags2 ^= MF2_OBJECTFLIP; - } - if (xziptic & EZT_SCALE) - { - metal->destscale = READFIXED(metal_p); - if (metal->destscale != metal->scale) - P_SetScale(metal, metal->destscale); - } - if (xziptic & EZT_THOKMASK) - { // Let's only spawn ONE of these per frame, thanks. - mobj_t *mobj; - INT32 type = -1; - if (metal->skin) - { - skin_t *skin = (skin_t *)metal->skin; - switch (xziptic & EZT_THOKMASK) - { - case EZT_THOK: - type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; - break; - case EZT_SPIN: - type = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; - break; - case EZT_REV: - type = skin->revitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; - break; - } - } - if (type != MT_NULL) - { - if (type == MT_GHOST) - { - mobj = P_SpawnGhostMobj(metal); // does a large portion of the work for us - } - else - { - mobj = P_SpawnMobjFromMobj(metal, 0, 0, -FixedDiv(FixedMul(metal->info->height, metal->scale) - metal->height,3*FRACUNIT), MT_THOK); - mobj->sprite = states[mobjinfo[type].spawnstate].sprite; - mobj->frame = states[mobjinfo[type].spawnstate].frame; - mobj->angle = metal->angle; - mobj->color = metal->color; - mobj->skin = metal->skin; - P_SetScale(mobj, (mobj->destscale = metal->scale)); - - if (type == MT_THOK) // spintrail-specific modification for MT_THOK - { - mobj->frame = FF_TRANS70; - mobj->fuse = mobj->tics; - } - mobj->tics = -1; // nope. - } - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_UnsetThingPosition(mobj); - mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... - P_SetThingPosition(mobj); - if (!mobj->fuse) - mobj->fuse = 8; - P_SetTarget(&mobj->target, metal); - } - } - if (xziptic & EZT_SPRITE) - metal->sprite = READUINT16(metal_p); - if (xziptic & EZT_HEIGHT) - { - fixed_t temp = READINT16(metal_p)<height = FixedMul(temp, metal->scale); - } - } - -#define follow metal->tracer - if (ziptic & GZT_FOLLOW) - { // Even more... - UINT8 followtic = READUINT8(metal_p); - fixed_t temp; - if (followtic & FZT_SPAWNED) - { - if (follow) - P_RemoveMobj(follow); - P_SetTarget(&follow, P_SpawnMobjFromMobj(metal, 0, 0, 0, MT_GHOST)); - P_SetTarget(&follow->tracer, metal); - follow->tics = -1; - temp = READINT16(metal_p)<height = FixedMul(follow->scale, temp); - - if (followtic & FZT_LINKDRAW) - follow->flags2 |= MF2_LINKDRAW; - - if (followtic & FZT_COLORIZED) - follow->colorized = true; - - if (followtic & FZT_SKIN) - follow->skin = &skins[READUINT8(metal_p)]; - } - if (follow) - { - if (followtic & FZT_SCALE) - follow->destscale = READFIXED(metal_p); - else - follow->destscale = metal->destscale; - if (follow->destscale != follow->scale) - P_SetScale(follow, follow->destscale); - - P_UnsetThingPosition(follow); - temp = READINT16(metal_p)<<8; - follow->x = metal->x + temp; - temp = READINT16(metal_p)<<8; - follow->y = metal->y + temp; - temp = READINT16(metal_p)<<8; - follow->z = metal->z + temp; - P_SetThingPosition(follow); - if (followtic & FZT_SKIN) - follow->sprite2 = READUINT8(metal_p); - else - follow->sprite2 = 0; - follow->sprite = READUINT16(metal_p); - follow->frame = READUINT32(metal_p); // NOT & FF_FRAMEMASK here, so 32 bits - follow->angle = metal->angle; - follow->color = READUINT8(metal_p); - - if (!(followtic & FZT_SPAWNED)) - { - if (xziptic & EZT_FLIP) - { - follow->flags2 ^= MF2_OBJECTFLIP; - follow->eflags ^= MFE_VERTICALFLIP; - } - } - } - } - else if (follow) - { - P_RemoveMobj(follow); - P_SetTarget(&follow, NULL); - } -#undef follow -} - -void G_WriteMetalTic(mobj_t *metal) -{ - UINT8 ziptic = 0; - UINT8 *ziptic_p; - fixed_t height; - - if (!demo_p) // demo_p will be NULL until the race start linedef executor is activated! - return; - - WRITEUINT8(demo_p, METALSNICE); - ziptic_p = demo_p++; // the ziptic, written at the end of this function - - #define MAXMOM (0xFFFF<<8) - - // GZT_XYZ is only useful if you've moved 256 FRACUNITS or more in a single tic. - if (abs(metal->x-oldmetal.x) > MAXMOM - || abs(metal->y-oldmetal.y) > MAXMOM - || abs(metal->z-oldmetal.z) > MAXMOM) - { - oldmetal.x = metal->x; - oldmetal.y = metal->y; - oldmetal.z = metal->z; - ziptic |= GZT_XYZ; - WRITEFIXED(demo_p,oldmetal.x); - WRITEFIXED(demo_p,oldmetal.y); - WRITEFIXED(demo_p,oldmetal.z); - } - else - { - // For moving normally: - // Store one full byte of movement, plus one byte of fractional movement. - INT16 momx = (INT16)((metal->x-oldmetal.x)>>8); - INT16 momy = (INT16)((metal->y-oldmetal.y)>>8); - if (momx != oldmetal.momx - || momy != oldmetal.momy) - { - oldmetal.momx = momx; - oldmetal.momy = momy; - ziptic |= GZT_MOMXY; - WRITEINT16(demo_p,momx); - WRITEINT16(demo_p,momy); - } - momx = (INT16)((metal->z-oldmetal.z)>>8); - if (momx != oldmetal.momz) - { - oldmetal.momz = momx; - ziptic |= GZT_MOMZ; - WRITEINT16(demo_p,momx); - } - - // This SHOULD set oldmetal.x/y/z to match metal->x/y/z - // but it keeps the fractional loss of one byte, - // so it will hopefully be made up for in future tics. - oldmetal.x += oldmetal.momx<<8; - oldmetal.y += oldmetal.momy<<8; - oldmetal.z += oldmetal.momz<<8; - } - - #undef MAXMOM - - // Only store the 8 most relevant bits of angle - // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites - // and it does not affect movement at all anyway. - if (metal->player && metal->player->drawangle>>24 != oldmetal.angle) - { - oldmetal.angle = metal->player->drawangle>>24; - ziptic |= GZT_ANGLE; - WRITEUINT8(demo_p,oldmetal.angle); - } - - // Store the sprite frame. - if ((metal->frame & FF_FRAMEMASK) != oldmetal.frame) - { - oldmetal.frame = metal->frame; // NOT & FF_FRAMEMASK here, so 32 bits - ziptic |= GZT_FRAME; - WRITEUINT32(demo_p,oldmetal.frame); - } - - if (metal->sprite == SPR_PLAY - && metal->sprite2 != oldmetal.sprite2) - { - oldmetal.sprite2 = metal->sprite2; - ziptic |= GZT_SPR2; - WRITEUINT8(demo_p,oldmetal.sprite2); - } - - // Check for sprite set changes - if (metal->sprite != oldmetal.sprite) - { - oldmetal.sprite = metal->sprite; - ghostext.flags |= EZT_SPRITE; - } - - if ((height = FixedDiv(metal->height, metal->scale)) != oldmetal.height) - { - oldmetal.height = height; - ghostext.flags |= EZT_HEIGHT; - } - - if (ghostext.flags & ~(EZT_COLOR|EZT_HIT)) // these two aren't handled by metal ever - { - ziptic |= GZT_EXTRA; - - if (ghostext.scale == ghostext.lastscale) - ghostext.flags &= ~EZT_SCALE; - - WRITEUINT8(demo_p,ghostext.flags); - if (ghostext.flags & EZT_SCALE) - { - WRITEFIXED(demo_p,ghostext.scale); - ghostext.lastscale = ghostext.scale; - } - if (ghostext.flags & EZT_SPRITE) - WRITEUINT16(demo_p,oldmetal.sprite); - if (ghostext.flags & EZT_HEIGHT) - { - height >>= FRACBITS; - WRITEINT16(demo_p, height); - } - ghostext.flags = 0; - } - - if (metal->player && metal->player->followmobj && !(metal->player->followmobj->sprite == SPR_NULL || (metal->player->followmobj->flags2 & MF2_DONTDRAW))) - { - INT16 temp; - UINT8 *followtic_p = demo_p++; - UINT8 followtic = 0; - - ziptic |= GZT_FOLLOW; - - if (metal->player->followmobj->skin) - followtic |= FZT_SKIN; - - if (!(oldmetal.flags2 & MF2_AMBUSH)) - { - followtic |= FZT_SPAWNED; - WRITEINT16(demo_p,metal->player->followmobj->info->height>>FRACBITS); - if (metal->player->followmobj->flags2 & MF2_LINKDRAW) - followtic |= FZT_LINKDRAW; - if (metal->player->followmobj->colorized) - followtic |= FZT_COLORIZED; - if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,(UINT8)(((skin_t *)(metal->player->followmobj->skin))-skins)); - oldmetal.flags2 |= MF2_AMBUSH; - } - - if (metal->player->followmobj->scale != metal->scale) - { - followtic |= FZT_SCALE; - WRITEFIXED(demo_p,metal->player->followmobj->scale); - } - - temp = (INT16)((metal->player->followmobj->x-metal->x)>>8); - WRITEINT16(demo_p,temp); - temp = (INT16)((metal->player->followmobj->y-metal->y)>>8); - WRITEINT16(demo_p,temp); - temp = (INT16)((metal->player->followmobj->z-metal->z)>>8); - WRITEINT16(demo_p,temp); - if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,metal->player->followmobj->sprite2); - WRITEUINT16(demo_p,metal->player->followmobj->sprite); - WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits - WRITEUINT8(demo_p,metal->player->followmobj->color); - - *followtic_p = followtic; - } - else - oldmetal.flags2 &= ~MF2_AMBUSH; - - *ziptic_p = ziptic; - - // attention here for the ticcmd size! - // latest demos with mouse aiming byte in ticcmd - if (demo_p >= demoend - 32) - { - G_StopMetalRecording(false); // no more space - return; - } -} - -// -// G_RecordDemo -// -void G_RecordDemo(const char *name) -{ - INT32 maxsize; - - strcpy(demoname, name); - strcat(demoname, ".lmp"); - maxsize = 1024*1024; - if (M_CheckParm("-maxdemo") && M_IsNextParm()) - maxsize = atoi(M_GetNextParm()) * 1024; -// if (demobuffer) -// free(demobuffer); - demo_p = NULL; - demobuffer = malloc(maxsize); - demoend = demobuffer + maxsize; - - demorecording = true; -} - -void G_RecordMetal(void) -{ - INT32 maxsize; - maxsize = 1024*1024; - if (M_CheckParm("-maxdemo") && M_IsNextParm()) - maxsize = atoi(M_GetNextParm()) * 1024; - demo_p = NULL; - demobuffer = malloc(maxsize); - demoend = demobuffer + maxsize; - metalrecording = true; -} - -void G_BeginRecording(void) -{ - UINT8 i; - char name[16]; - player_t *player = &players[consoleplayer]; - - if (demo_p) - return; - memset(name,0,sizeof(name)); - - demo_p = demobuffer; - demoflags = DF_GHOST|(modeattacking<>DF_ATTACKSHIFT) - { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_RECORD: // 1 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - WRITEUINT32(demo_p,0); // score - WRITEUINT16(demo_p,0); // rings - break; - case ATTACKING_NIGHTS: // 2 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - WRITEUINT32(demo_p,0); // score - break; - default: // 3 - break; - } - - WRITEUINT32(demo_p,P_GetInitSeed()); - - // Name - for (i = 0; i < 16 && cv_playername.string[i]; i++) - name[i] = cv_playername.string[i]; - for (; i < 16; i++) - name[i] = '\0'; - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Skin - for (i = 0; i < 16 && cv_skin.string[i]; i++) - name[i] = cv_skin.string[i]; - for (; i < 16; i++) - name[i] = '\0'; - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Color - for (i = 0; i < 16 && cv_playercolor.string[i]; i++) - name[i] = cv_playercolor.string[i]; - for (; i < 16; i++) - name[i] = '\0'; - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Stats - WRITEUINT8(demo_p,player->charability); - WRITEUINT8(demo_p,player->charability2); - WRITEUINT8(demo_p,player->actionspd>>FRACBITS); - WRITEUINT8(demo_p,player->mindash>>FRACBITS); - WRITEUINT8(demo_p,player->maxdash>>FRACBITS); - WRITEUINT8(demo_p,player->normalspeed>>FRACBITS); - WRITEUINT8(demo_p,player->runspeed>>FRACBITS); - WRITEUINT8(demo_p,player->thrustfactor); - WRITEUINT8(demo_p,player->accelstart); - WRITEUINT8(demo_p,player->acceleration); - WRITEUINT8(demo_p,player->height>>FRACBITS); - WRITEUINT8(demo_p,player->spinheight>>FRACBITS); - WRITEUINT8(demo_p,player->camerascale>>FRACBITS); - WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); - - // Trying to convert it back to % causes demo desync due to precision loss. - // Don't do it. - WRITEFIXED(demo_p, player->jumpfactor); - - // And mobjtype_t is best with UINT32 too... - WRITEUINT32(demo_p, player->followitem); - - // Save pflag data - see SendWeaponPref() - { - UINT8 buf = 0; - pflags_t pflags = 0; - if (cv_flipcam.value) - { - buf |= 0x01; - pflags |= PF_FLIPCAM; - } - if (cv_analog[0].value) - { - buf |= 0x02; - pflags |= PF_ANALOGMODE; - } - if (cv_directionchar[0].value) - { - buf |= 0x04; - pflags |= PF_DIRECTIONCHAR; - } - if (cv_autobrake.value) - { - buf |= 0x08; - pflags |= PF_AUTOBRAKE; - } - if (cv_usejoystick.value) - buf |= 0x10; - CV_SetValue(&cv_showinputjoy, !!(cv_usejoystick.value)); - - WRITEUINT8(demo_p,buf); - player->pflags = pflags; - } - - // Save netvar data - CV_SaveNetVars(&demo_p); - - memset(&oldcmd,0,sizeof(oldcmd)); - memset(&oldghost,0,sizeof(oldghost)); - memset(&ghostext,0,sizeof(ghostext)); - ghostext.lastcolor = ghostext.color = GHC_NORMAL; - ghostext.lastscale = ghostext.scale = FRACUNIT; - - if (player->mo) - { - oldghost.x = player->mo->x; - oldghost.y = player->mo->y; - oldghost.z = player->mo->z; - oldghost.angle = player->mo->angle>>24; - - // preticker started us gravity flipped - if (player->mo->eflags & MFE_VERTICALFLIP) - ghostext.flags |= EZT_FLIP; - } -} - -void G_BeginMetal(void) -{ - mobj_t *mo = players[consoleplayer].mo; - -#if 0 - if (demo_p) - return; -#endif - - demo_p = demobuffer; - - // Write header. - M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12; - WRITEUINT8(demo_p,VERSION); - WRITEUINT8(demo_p,SUBVERSION); - WRITEUINT16(demo_p,DEMOVERSION); - - // demo checksum - demo_p += 16; - - M_Memcpy(demo_p, "METL", 4); demo_p += 4; - - memset(&ghostext,0,sizeof(ghostext)); - ghostext.lastscale = ghostext.scale = FRACUNIT; - - // Set up our memory. - memset(&oldmetal,0,sizeof(oldmetal)); - oldmetal.x = mo->x; - oldmetal.y = mo->y; - oldmetal.z = mo->z; - oldmetal.angle = mo->angle>>24; -} - -void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings) -{ - if (!demorecording || !demotime_p) - return; - if (demoflags & DF_RECORDATTACK) - { - WRITEUINT32(demotime_p, ptime); - WRITEUINT32(demotime_p, pscore); - WRITEUINT16(demotime_p, prings); - demotime_p = NULL; - } - else if (demoflags & DF_NIGHTSATTACK) - { - WRITEUINT32(demotime_p, ptime); - WRITEUINT32(demotime_p, pscore); - demotime_p = NULL; - } -} - -// Returns bitfield: -// 1 == new demo has lower time -// 2 == new demo has higher score -// 4 == new demo has higher rings -UINT8 G_CmpDemoTime(char *oldname, char *newname) -{ - UINT8 *buffer,*p; - UINT8 flags; - UINT32 oldtime, newtime, oldscore, newscore; - UINT16 oldrings, newrings, oldversion; - size_t bufsize ATTRUNUSED; - UINT8 c; - UINT16 s ATTRUNUSED; - UINT8 aflags = 0; - - // load the new file - FIL_DefaultExtension(newname, ".lmp"); - bufsize = FIL_ReadFile(newname, &buffer); - I_Assert(bufsize != 0); - p = buffer; - - // read demo header - I_Assert(!memcmp(p, DEMOHEADER, 12)); - p += 12; // DEMOHEADER - c = READUINT8(p); // VERSION - I_Assert(c == VERSION); - c = READUINT8(p); // SUBVERSION - I_Assert(c == SUBVERSION); - s = READUINT16(p); - I_Assert(s == DEMOVERSION); - p += 16; // demo checksum - I_Assert(!memcmp(p, "PLAY", 4)); - p += 4; // PLAY - p += 2; // gamemap - p += 16; // map md5 - flags = READUINT8(p); // demoflags - - aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); - I_Assert(aflags); - if (flags & DF_RECORDATTACK) - { - newtime = READUINT32(p); - newscore = READUINT32(p); - newrings = READUINT16(p); - } - else if (flags & DF_NIGHTSATTACK) - { - newtime = READUINT32(p); - newscore = READUINT32(p); - newrings = 0; - } - else // appease compiler - return 0; - - Z_Free(buffer); - - // load old file - FIL_DefaultExtension(oldname, ".lmp"); - if (!FIL_ReadFile(oldname, &buffer)) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), oldname); - return UINT8_MAX; - } - p = buffer; - - // read demo header - if (memcmp(p, DEMOHEADER, 12)) - { - CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); - Z_Free(buffer); - return UINT8_MAX; - } p += 12; // DEMOHEADER - p++; // VERSION - p++; // SUBVERSION - oldversion = READUINT16(p); - switch(oldversion) // demoversion - { - case DEMOVERSION: // latest always supported - break; - // too old, cannot support. - default: - CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); - Z_Free(buffer); - return UINT8_MAX; - } - p += 16; // demo checksum - if (memcmp(p, "PLAY", 4)) - { - CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); - Z_Free(buffer); - return UINT8_MAX; - } p += 4; // "PLAY" - if (oldversion <= 0x0008) - p++; // gamemap - else - p += 2; // gamemap - p += 16; // mapmd5 - flags = READUINT8(p); - if (!(flags & aflags)) - { - CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname); - Z_Free(buffer); - return UINT8_MAX; - } - if (flags & DF_RECORDATTACK) - { - oldtime = READUINT32(p); - oldscore = READUINT32(p); - oldrings = READUINT16(p); - } - else if (flags & DF_NIGHTSATTACK) - { - oldtime = READUINT32(p); - oldscore = READUINT32(p); - oldrings = 0; - } - else // appease compiler - return UINT8_MAX; - - Z_Free(buffer); - - c = 0; - if (newtime < oldtime - || (newtime == oldtime && (newscore > oldscore || newrings > oldrings))) - c |= 1; // Better time - if (newscore > oldscore - || (newscore == oldscore && newtime < oldtime)) - c |= 1<<1; // Better score - if (newrings > oldrings - || (newrings == oldrings && newtime < oldtime)) - c |= 1<<2; // Better rings - return c; -} - -// -// G_PlayDemo -// -void G_DeferedPlayDemo(const char *name) -{ - COM_BufAddText("playdemo \""); - COM_BufAddText(name); - COM_BufAddText("\"\n"); -} - -// -// Start a demo from a .LMP file or from a wad resource -// -void G_DoPlayDemo(char *defdemoname) -{ - UINT8 i; - lumpnum_t l; - char skin[17],color[17],*n,*pdemoname; - UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration; - pflags_t pflags; - UINT32 randseed, followitem; - fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; - char msg[1024]; - - skin[16] = '\0'; - color[16] = '\0'; - - n = defdemoname+strlen(defdemoname); - while (*n != '/' && *n != '\\' && n != defdemoname) - n--; - if (n != defdemoname) - n++; - pdemoname = ZZ_Alloc(strlen(n)+1); - strcpy(pdemoname,n); - - // Internal if no extension, external if one exists - if (FIL_CheckExtension(defdemoname)) - { - //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFile(defdemoname, &demobuffer)) - { - snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } - demo_p = demobuffer; - } - // load demo resource from WAD - else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) - { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } - else // it's an internal demo - demobuffer = demo_p = W_CacheLumpNum(l, PU_STATIC); - - // read demo header - gameaction = ga_nothing; - demoplayback = true; - if (memcmp(demo_p, DEMOHEADER, 12)) - { - snprintf(msg, 1024, M_GetText("%s is not a SRB2 replay file.\n"), pdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - M_StartMessage(msg, NULL, MM_NOTHING); - Z_Free(pdemoname); - Z_Free(demobuffer); - demoplayback = false; - titledemo = false; - return; - } - demo_p += 12; // DEMOHEADER - - version = READUINT8(demo_p); - subversion = READUINT8(demo_p); - demoversion = READUINT16(demo_p); - switch(demoversion) - { - case DEMOVERSION: // latest always supported - break; - // too old, cannot support. - default: - snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - M_StartMessage(msg, NULL, MM_NOTHING); - Z_Free(pdemoname); - Z_Free(demobuffer); - demoplayback = false; - titledemo = false; - return; - } - demo_p += 16; // demo checksum - if (memcmp(demo_p, "PLAY", 4)) - { - snprintf(msg, 1024, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - M_StartMessage(msg, NULL, MM_NOTHING); - Z_Free(pdemoname); - Z_Free(demobuffer); - demoplayback = false; - titledemo = false; - return; - } - demo_p += 4; // "PLAY" - gamemap = READINT16(demo_p); - demo_p += 16; // mapmd5 - - demoflags = READUINT8(demo_p); - modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; - CON_ToggleOff(); - - hu_demoscore = 0; - hu_demotime = UINT32_MAX; - hu_demorings = 0; - - switch (modeattacking) - { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_RECORD: // 1 - hu_demotime = READUINT32(demo_p); - hu_demoscore = READUINT32(demo_p); - hu_demorings = READUINT16(demo_p); - break; - case ATTACKING_NIGHTS: // 2 - hu_demotime = READUINT32(demo_p); - hu_demoscore = READUINT32(demo_p); - break; - default: // 3 - modeattacking = ATTACKING_NONE; - break; - } - - // Random seed - randseed = READUINT32(demo_p); - - // Player name - M_Memcpy(player_names[0],demo_p,16); - demo_p += 16; - - // Skin - M_Memcpy(skin,demo_p,16); - demo_p += 16; - - // Color - M_Memcpy(color,demo_p,16); - demo_p += 16; - - charability = READUINT8(demo_p); - charability2 = READUINT8(demo_p); - actionspd = (fixed_t)READUINT8(demo_p)<color = players[0].skincolor; - oldghost.x = players[0].mo->x; - oldghost.y = players[0].mo->y; - oldghost.z = players[0].mo->z; - } - - // Set saved attribute values - // No cheat checking here, because even if they ARE wrong... - // it would only break the replay if we clipped them. - players[0].camerascale = camerascale; - players[0].shieldscale = shieldscale; - players[0].charability = charability; - players[0].charability2 = charability2; - players[0].actionspd = actionspd; - players[0].mindash = mindash; - players[0].maxdash = maxdash; - players[0].normalspeed = normalspeed; - players[0].runspeed = runspeed; - players[0].thrustfactor = thrustfactor; - players[0].accelstart = accelstart; - players[0].acceleration = acceleration; - players[0].height = height; - players[0].spinheight = spinheight; - players[0].jumpfactor = jumpfactor; - players[0].followitem = followitem; - players[0].pflags = pflags; - - demo_start = true; -} - -void G_AddGhost(char *defdemoname) -{ - INT32 i; - lumpnum_t l; - char name[17],skin[17],color[17],*n,*pdemoname,md5[16]; - demoghost *gh; - UINT8 flags; - UINT8 *buffer,*p; - mapthing_t *mthing; - UINT16 count, ghostversion; - - name[16] = '\0'; - skin[16] = '\0'; - color[16] = '\0'; - - n = defdemoname+strlen(defdemoname); - while (*n != '/' && *n != '\\' && n != defdemoname) - n--; - if (n != defdemoname) - n++; - pdemoname = ZZ_Alloc(strlen(n)+1); - strcpy(pdemoname,n); - - // Internal if no extension, external if one exists - if (FIL_CheckExtension(defdemoname)) - { - //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL)) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname); - Z_Free(pdemoname); - return; - } - p = buffer; - } - // load demo resource from WAD - else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - Z_Free(pdemoname); - return; - } - else // it's an internal demo - buffer = p = W_CacheLumpNum(l, PU_LEVEL); - - // read demo header - if (memcmp(p, DEMOHEADER, 12)) - { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; - } p += 12; // DEMOHEADER - p++; // VERSION - p++; // SUBVERSION - ghostversion = READUINT16(p); - switch(ghostversion) - { - case DEMOVERSION: // latest always supported - break; - // too old, cannot support. - default: - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; - } - M_Memcpy(md5, p, 16); p += 16; // demo checksum - for (gh = ghosts; gh; gh = gh->next) - if (!memcmp(md5, gh->checksum, 16)) // another ghost in the game already has this checksum? - { // Don't add another one, then! - CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (MD5 was matched)\n", pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; - } - if (memcmp(p, "PLAY", 4)) - { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; - } p += 4; // "PLAY" - if (ghostversion <= 0x0008) - p++; // gamemap - else - p += 2; // gamemap - p += 16; // mapmd5 (possibly check for consistency?) - flags = READUINT8(p); - if (!(flags & DF_GHOST)) - { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; - } - switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) - { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_RECORD: // 1 - p += 10; // demo time, score, and rings - break; - case ATTACKING_NIGHTS: // 2 - p += 8; // demo time left, score - break; - default: // 3 - break; - } - - p += 4; // random seed - - // Player name (TODO: Display this somehow if it doesn't match cv_playername!) - M_Memcpy(name, p,16); - p += 16; - - // Skin - M_Memcpy(skin, p,16); - p += 16; - - // Color - M_Memcpy(color, p,16); - p += 16; - - // Ghosts do not have a player structure to put this in. - p++; // charability - p++; // charability2 - p++; // actionspd - p++; // mindash - p++; // maxdash - p++; // normalspeed - p++; // runspeed - p++; // thrustfactor - p++; // accelstart - p++; // acceleration - p++; // height - p++; // spinheight - p++; // camerascale - p++; // shieldscale - p += 4; // jumpfactor - p += 4; // followitem - - p++; // pflag data - - // net var data - count = READUINT16(p); - while (count--) - { - p += 2; - SKIPSTRING(p); - p++; - } - - if (*p == DEMOMARKER) - { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname); - Z_Free(pdemoname); - Z_Free(buffer); - return; - } - - gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL); - gh->next = ghosts; - gh->buffer = buffer; - M_Memcpy(gh->checksum, md5, 16); - gh->p = p; - - ghosts = gh; - - gh->version = ghostversion; - mthing = playerstarts[0]; - I_Assert(mthing); - { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. - fixed_t z,f,c; - fixed_t offset = mthing->z << FRACBITS; - gh->mo = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST); - gh->mo->angle = FixedAngle(mthing->angle << FRACBITS); - f = gh->mo->floorz; - c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height; - if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) - { - z = c - offset; - if (z < f) - z = f; - } - else - { - z = f + offset; - if (z > c) - z = c; - } - gh->mo->z = z; - } - - gh->oldmo.x = gh->mo->x; - gh->oldmo.y = gh->mo->y; - gh->oldmo.z = gh->mo->z; - - // Set skin - gh->mo->skin = &skins[0]; - for (i = 0; i < numskins; i++) - if (!stricmp(skins[i].name,skin)) - { - gh->mo->skin = &skins[i]; - break; - } - gh->oldmo.skin = gh->mo->skin; - - // Set color - gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor; - for (i = 0; i < MAXSKINCOLORS; i++) - if (!stricmp(Color_Names[i],color)) - { - gh->mo->color = (UINT8)i; - break; - } - gh->oldmo.color = gh->mo->color; - - gh->mo->state = states+S_PLAY_STND; - gh->mo->sprite = gh->mo->state->sprite; - gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK); - //gh->mo->frame = tr_trans30<mo->flags2 |= MF2_DONTDRAW; - gh->fadein = (9-3)*6; // fade from invisible to trans30 over as close to 35 tics as possible - gh->mo->tics = -1; - - CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); - Z_Free(pdemoname); -} - -// -// G_TimeDemo -// NOTE: name is a full filename for external demos -// -static INT32 restorecv_vidwait; - -void G_TimeDemo(const char *name) -{ - nodrawers = M_CheckParm("-nodraw"); - noblit = M_CheckParm("-noblit"); - restorecv_vidwait = cv_vidwait.value; - if (cv_vidwait.value) - CV_Set(&cv_vidwait, "0"); - timingdemo = true; - singletics = true; - framecount = 0; - demostarttime = I_GetTime(); - G_DeferedPlayDemo(name); -} - -void G_DoPlayMetal(void) -{ - lumpnum_t l; - mobj_t *mo = NULL; - thinker_t *th; - - // it's an internal demo - if ((l = W_CheckNumForName(va("%sMS",G_BuildMapName(gamemap)))) == LUMPERROR) - { - CONS_Alert(CONS_WARNING, M_GetText("No bot recording for this map.\n")); - return; - } - else - metalbuffer = metal_p = W_CacheLumpNum(l, PU_STATIC); - - // find metal sonic - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo = (mobj_t *)th; - if (mo->type != MT_METALSONIC_RACE) - continue; - - break; - } - if (th == &thlist[THINK_MOBJ]) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to find bot entity.\n")); - Z_Free(metalbuffer); - return; - } - - // read demo header - metal_p += 12; // DEMOHEADER - metal_p++; // VERSION - metal_p++; // SUBVERSION - metalversion = READUINT16(metal_p); - switch(metalversion) - { - case DEMOVERSION: // latest always supported - break; - // too old, cannot support. - default: - CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n")); - Z_Free(metalbuffer); - return; - } - metal_p += 16; // demo checksum - if (memcmp(metal_p, "METL", 4)) - { - CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, wasn't recorded in Metal format.\n")); - Z_Free(metalbuffer); - return; - } metal_p += 4; // "METL" - - // read initial tic - memset(&oldmetal,0,sizeof(oldmetal)); - oldmetal.x = mo->x; - oldmetal.y = mo->y; - oldmetal.z = mo->z; - metalplayback = mo; -} - -void G_DoneLevelLoad(void) -{ - CONS_Printf(M_GetText("Loaded level in %f sec\n"), (double)(I_GetTime() - demostarttime) / TICRATE); - framecount = 0; - demostarttime = I_GetTime(); -} - -/* -=================== -= -= G_CheckDemoStatus -= -= Called after a death or level completion to allow demos to be cleaned up -= Returns true if a new demo loop action will take place -=================== -*/ - -// Stops metal sonic's demo. Separate from other functions because metal + replays can coexist -void G_StopMetalDemo(void) -{ - - // Metal Sonic finishing doesn't end the game, dammit. - Z_Free(metalbuffer); - metalbuffer = NULL; - metalplayback = NULL; - metal_p = NULL; -} - -// Stops metal sonic recording. -ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) -{ - boolean saved = false; - if (demo_p) - { - UINT8 *p = demobuffer+16; // checksum position - if (kill) - WRITEUINT8(demo_p, METALDEATH); // add the metal death marker - else - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker -#ifdef NOMD5 - { - UINT8 i; - for (i = 0; i < 16; i++, p++) - *p = P_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. - } -#else - md5_buffer((char *)p+16, demo_p - (p+16), (void *)p); // make a checksum of everything after the checksum in the file. -#endif - saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. - } - free(demobuffer); - metalrecording = false; - if (saved) - I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); - I_Error("Failed to save demo!"); -} - -// reset engine variable set for the demos -// called from stopdemo command, map command, and g_checkdemoStatus. -void G_StopDemo(void) -{ - Z_Free(demobuffer); - demobuffer = NULL; - demoplayback = false; - titledemo = false; - timingdemo = false; - singletics = false; - - if (gamestate == GS_INTERMISSION) - Y_EndIntermission(); // cleanup - - G_SetGamestate(GS_NULL); - wipegamestate = GS_NULL; - SV_StopServer(); - SV_ResetServer(); -} - -boolean G_CheckDemoStatus(void) -{ - boolean saved; - - while (ghosts) - { - demoghost *next = ghosts->next; - Z_Free(ghosts); - ghosts = next; - } - ghosts = NULL; - - - // DO NOT end metal sonic demos here - - if (timingdemo) - { - INT32 demotime; - double f1, f2; - demotime = I_GetTime() - demostarttime; - if (!demotime) - return true; - G_StopDemo(); - timingdemo = false; - f1 = (double)demotime; - f2 = (double)framecount*TICRATE; - - CONS_Printf(M_GetText("timed %u gametics in %d realtics - %u frames\n%f seconds, %f avg fps\n"), - leveltime,demotime,(UINT32)framecount,f1/TICRATE,f2/f1); - - // CSV-readable timedemo results, for external parsing - if (timedemo_csv) - { - FILE *f; - const char *csvpath = va("%s"PATHSEP"%s", srb2home, "timedemo.csv"); - const char *header = "id,demoname,seconds,avgfps,leveltime,demotime,framecount,ticrate,rendermode,vidmode,vidwidth,vidheight,procbits\n"; - const char *rowformat = "\"%s\",\"%s\",%f,%f,%u,%d,%u,%u,%u,%u,%u,%u,%u\n"; - boolean headerrow = !FIL_FileExists(csvpath); - UINT8 procbits = 0; - - // Bitness - if (sizeof(void*) == 4) - procbits = 32; - else if (sizeof(void*) == 8) - procbits = 64; - - f = fopen(csvpath, "a+"); - - if (f) - { - if (headerrow) - fputs(header, f); - fprintf(f, rowformat, - timedemo_csv_id,timedemo_name,f1/TICRATE,f2/f1,leveltime,demotime,(UINT32)framecount,TICRATE,rendermode,vid.modenum,vid.width,vid.height,procbits); - fclose(f); - CONS_Printf("Timedemo results saved to '%s'\n", csvpath); - } - else - { - // Just print the CSV output to console - CON_LogMessage(header); - CONS_Printf(rowformat, - timedemo_csv_id,timedemo_name,f1/TICRATE,f2/f1,leveltime,demotime,(UINT32)framecount,TICRATE,rendermode,vid.modenum,vid.width,vid.height,procbits); - } - } - - if (restorecv_vidwait != cv_vidwait.value) - CV_SetValue(&cv_vidwait, restorecv_vidwait); - D_AdvanceDemo(); - return true; - } - - if (demoplayback) - { - if (singledemo) - I_Quit(); - G_StopDemo(); - - if (modeattacking) - M_EndModeAttackRun(); - else - D_AdvanceDemo(); - - return true; - } - - if (demorecording) - { - UINT8 *p = demobuffer+16; // checksum position -#ifdef NOMD5 - UINT8 i; - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - for (i = 0; i < 16; i++, p++) - *p = P_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. -#else - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. -#endif - saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. - free(demobuffer); - demorecording = false; - - if (modeattacking != ATTACKING_RECORD) - { - if (saved) - CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); - else - CONS_Alert(CONS_WARNING, M_GetText("Demo %s not saved\n"), demoname); - } - return true; - } - - return false; -} - // // G_SetGamestate // diff --git a/src/g_game.h b/src/g_game.h index a4afac163..c8abe560c 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -17,6 +17,7 @@ #include "doomdef.h" #include "doomstat.h" #include "d_event.h" +#include "g_demo.h" extern char gamedatafilename[64]; extern char timeattackfolder[64]; @@ -31,21 +32,6 @@ extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1]; extern player_t players[MAXPLAYERS]; extern boolean playeringame[MAXPLAYERS]; -// ====================================== -// DEMO playback/recording related stuff. -// ====================================== - -// demoplaying back and demo recording -extern boolean demoplayback, titledemo, demorecording, timingdemo; -extern tic_t demostarttime; - -// Quit after playing a demo from cmdline. -extern boolean singledemo; -extern boolean demo_start; -extern boolean demosynced; - -extern mobj_t *metalplayback; - // gametic at level start extern tic_t levelstarttic; @@ -107,6 +93,7 @@ typedef enum // build an internal map name MAPxx from map number const char *G_BuildMapName(INT32 map); +extern INT16 ticcmd_oldangleturn[2]; extern boolean ticcmd_centerviewdown[2]; // For simple controls, lock the camera behind the player extern mobj_t *ticcmd_ztargetfocus[2]; // Locking onto an object? void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer); @@ -173,65 +160,16 @@ void G_DoLoadLevel(boolean resetplayer); void G_StartTitleCard(void); void G_PreLevelTitleCard(void); boolean G_IsTitleCardAvailable(void); -void G_DeferedPlayDemo(const char *demo); // Can be called by the startup code or M_Responder, calls P_SetupLevel. void G_LoadGame(UINT32 slot, INT16 mapoverride); void G_SaveGameData(void); -void G_SaveGame(UINT32 slot); +void G_SaveGame(UINT32 slot, INT16 mapnum); void G_SaveGameOver(UINT32 slot, boolean modifylives); -// Only called by startup code. -void G_RecordDemo(const char *name); -void G_RecordMetal(void); -void G_BeginRecording(void); -void G_BeginMetal(void); - -// Only called by shutdown code. -void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings); -UINT8 G_CmpDemoTime(char *oldname, char *newname); - -typedef enum -{ - GHC_NORMAL = 0, - GHC_SUPER, - GHC_FIREFLOWER, - GHC_INVINCIBLE, - GHC_NIGHTSSKIN, // not actually a colour - GHC_RETURNSKIN // ditto -} ghostcolor_t; - -// Record/playback tics -void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); -void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); -void G_GhostAddThok(void); -void G_GhostAddSpin(void); -void G_GhostAddRev(void); -void G_GhostAddColor(ghostcolor_t color); -void G_GhostAddFlip(void); -void G_GhostAddScale(fixed_t scale); -void G_GhostAddHit(mobj_t *victim); -void G_WriteGhostTic(mobj_t *ghost); -void G_ConsGhostTic(void); -void G_GhostTicker(void); -void G_ReadMetalTic(mobj_t *metal); -void G_WriteMetalTic(mobj_t *metal); -void G_SaveMetal(UINT8 **buffer); -void G_LoadMetal(UINT8 **buffer); - -void G_DoPlayDemo(char *defdemoname); -void G_TimeDemo(const char *name); -void G_AddGhost(char *defdemoname); -void G_DoPlayMetal(void); -void G_DoneLevelLoad(void); -void G_StopMetalDemo(void); -ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); -void G_StopDemo(void); -boolean G_CheckDemoStatus(void); - extern UINT32 gametypedefaultrules[NUMGAMETYPES]; extern UINT32 gametypetol[NUMGAMETYPES]; extern INT16 gametyperankings[NUMGAMETYPES]; @@ -253,6 +191,7 @@ boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); boolean G_RingSlingerGametype(void); boolean G_PlatformGametype(void); +boolean G_CoopGametype(void); boolean G_TagGametype(void); boolean G_CompetitionGametype(void); boolean G_EnoughPlayersFinished(void); @@ -309,6 +248,6 @@ FUNCMATH INT32 G_TicsToCentiseconds(tic_t tics); FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); // Don't split up TOL handling -INT16 G_TOLFlag(INT32 pgametype); +UINT32 G_TOLFlag(INT32 pgametype); #endif diff --git a/src/g_input.c b/src/g_input.c index ed7bc5cb6..ecce4d83c 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/g_input.h b/src/g_input.h index f7f952d72..a7484c7ad 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/g_state.h b/src/g_state.h index e82a34935..e364c5a35 100644 --- a/src/g_state.h +++ b/src/g_state.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -57,6 +57,7 @@ extern UINT8 ultimatemode; // was sk_insane extern gameaction_t gameaction; extern boolean botingame; -extern UINT8 botskin, botcolor; +extern UINT8 botskin; +extern UINT16 botcolor; #endif //__G_STATE__ diff --git a/src/hardware/hw3dsdrv.h b/src/hardware/hw3dsdrv.h index 8811d4546..9b8670705 100644 --- a/src/hardware/hw3dsdrv.h +++ b/src/hardware/hw3dsdrv.h @@ -1,20 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 2001 by DooM Legacy Team. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw3dsdrv.h /// \brief 3D sound import/export prototypes for low-level hardware interface #ifndef __HW_3DS_DRV_H__ diff --git a/src/hardware/hw3sound.c b/src/hardware/hw3sound.c index f7c6e1da0..81f1d8e68 100644 --- a/src/hardware/hw3sound.c +++ b/src/hardware/hw3sound.c @@ -1,19 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 2001 by DooM Legacy Team. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw3sound.c /// \brief Hardware 3D sound general code #include "../doomdef.h" @@ -28,7 +21,7 @@ #include "../tables.h" #include "../sounds.h" #include "../r_main.h" -#include "../r_things.h" +#include "../r_skins.h" #include "../m_random.h" #include "../p_local.h" #include "hw3dsdrv.h" diff --git a/src/hardware/hw3sound.h b/src/hardware/hw3sound.h index a8a475b69..1796dd696 100644 --- a/src/hardware/hw3sound.h +++ b/src/hardware/hw3sound.h @@ -1,20 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 2001 by DooM Legacy Team. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw3sound.h /// \brief High-level functions of hardware 3D sound #ifndef __HW3_SOUND_H__ diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c new file mode 100644 index 000000000..5c5379f6d --- /dev/null +++ b/src/hardware/hw_batching.c @@ -0,0 +1,454 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_batching.c +/// \brief Draw call batching and related things. + +#ifdef HWRENDER +#include "hw_glob.h" +#include "hw_batching.h" +#include "../i_system.h" + +// The texture for the next polygon given to HWR_ProcessPolygon. +// Set with HWR_SetCurrentTexture. +GLMipmap_t *current_texture = NULL; + +boolean currently_batching = false; + +FOutVector* finalVertexArray = NULL;// contains subset of sorted vertices and texture coordinates to be sent to gpu +UINT32* finalVertexIndexArray = NULL;// contains indexes for glDrawElements, taking into account fan->triangles conversion +// NOTE have this alloced as 3x finalVertexArray size +int finalVertexArrayAllocSize = 65536; +//GLubyte* colorArray = NULL;// contains color data to be sent to gpu, if needed +//int colorArrayAllocSize = 65536; +// not gonna use this for now, just sort by color and change state when it changes +// later maybe when using vertex attributes if it's needed + +PolygonArrayEntry* polygonArray = NULL;// contains the polygon data from DrawPolygon, waiting to be processed +int polygonArraySize = 0; +UINT32* polygonIndexArray = NULL;// contains sorting pointers for polygonArray +int polygonArrayAllocSize = 65536; + +FOutVector* unsortedVertexArray = NULL;// contains unsorted vertices and texture coordinates from DrawPolygon +int unsortedVertexArraySize = 0; +int unsortedVertexArrayAllocSize = 65536; + +// Enables batching mode. HWR_ProcessPolygon will collect polygons instead of passing them directly to the rendering backend. +// Call HWR_RenderBatches to render all the collected geometry. +void HWR_StartBatching(void) +{ + if (currently_batching) + I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); + + // init arrays if that has not been done yet + if (!finalVertexArray) + { + finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); + finalVertexIndexArray = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); + polygonArray = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); + polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); + unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); + } + + currently_batching = true; +} + +// This replaces the direct calls to pfnSetTexture in cases where batching is available. +// The texture selection is saved for the next HWR_ProcessPolygon call. +// Doing this was easier than getting a texture pointer to HWR_ProcessPolygon. +void HWR_SetCurrentTexture(GLMipmap_t *texture) +{ + if (currently_batching) + { + current_texture = texture; + } + else + { + HWD.pfnSetTexture(texture); + } +} + +// If batching is enabled, this function collects the polygon data and the chosen texture +// for later use in HWR_RenderBatches. Otherwise the rendering backend is used to +// render the polygon immediately. +void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial) +{ + if (currently_batching) + { + if (!pSurf) + I_Error("Got a null FSurfaceInfo in batching");// nulls should not come in the stuff that batching currently applies to + if (polygonArraySize == polygonArrayAllocSize) + { + PolygonArrayEntry* new_array; + // ran out of space, make new array double the size + polygonArrayAllocSize *= 2; + new_array = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); + memcpy(new_array, polygonArray, polygonArraySize * sizeof(PolygonArrayEntry)); + free(polygonArray); + polygonArray = new_array; + // also need to redo the index array, dont need to copy it though + free(polygonIndexArray); + polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); + } + + while (unsortedVertexArraySize + (int)iNumPts > unsortedVertexArrayAllocSize) + { + FOutVector* new_array; + // need more space for vertices in unsortedVertexArray + unsortedVertexArrayAllocSize *= 2; + new_array = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); + memcpy(new_array, unsortedVertexArray, unsortedVertexArraySize * sizeof(FOutVector)); + free(unsortedVertexArray); + unsortedVertexArray = new_array; + } + + // add the polygon data to the arrays + + polygonArray[polygonArraySize].surf = *pSurf; + polygonArray[polygonArraySize].vertsIndex = unsortedVertexArraySize; + polygonArray[polygonArraySize].numVerts = iNumPts; + polygonArray[polygonArraySize].polyFlags = PolyFlags; + polygonArray[polygonArraySize].texture = current_texture; + polygonArray[polygonArraySize].shader = shader; + polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; + polygonArraySize++; + + memcpy(&unsortedVertexArray[unsortedVertexArraySize], pOutVerts, iNumPts * sizeof(FOutVector)); + unsortedVertexArraySize += iNumPts; + } + else + { + if (shader) + HWD.pfnSetShader(shader); + HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags); + } +} + +static int comparePolygons(const void *p1, const void *p2) +{ + unsigned int index1 = *(const unsigned int*)p1; + unsigned int index2 = *(const unsigned int*)p2; + PolygonArrayEntry* poly1 = &polygonArray[index1]; + PolygonArrayEntry* poly2 = &polygonArray[index2]; + int diff; + INT64 diff64; + + int shader1 = poly1->shader; + int shader2 = poly2->shader; + // make skywalls and horizon lines first in order + if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) + shader1 = -1; + if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) + shader2 = -1; + diff = shader1 - shader2; + if (diff != 0) return diff; + + // skywalls and horizon lines must retain their order for horizon lines to work + if (shader1 == -1 && shader2 == -1) + return index1 - index2; + + diff64 = poly1->texture - poly2->texture; + if (diff64 != 0) return diff64; + + diff = poly1->polyFlags - poly2->polyFlags; + if (diff != 0) return diff; + + diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + diff64 = poly1->surf.TintColor.rgba - poly2->surf.TintColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + diff64 = poly1->surf.FadeColor.rgba - poly2->surf.FadeColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + + diff = poly1->surf.LightInfo.light_level - poly2->surf.LightInfo.light_level; + if (diff != 0) return diff; + diff = poly1->surf.LightInfo.fade_start - poly2->surf.LightInfo.fade_start; + if (diff != 0) return diff; + diff = poly1->surf.LightInfo.fade_end - poly2->surf.LightInfo.fade_end; + return diff; +} + +static int comparePolygonsNoShaders(const void *p1, const void *p2) +{ + unsigned int index1 = *(const unsigned int*)p1; + unsigned int index2 = *(const unsigned int*)p2; + PolygonArrayEntry* poly1 = &polygonArray[index1]; + PolygonArrayEntry* poly2 = &polygonArray[index2]; + int diff; + INT64 diff64; + + GLMipmap_t *texture1 = poly1->texture; + GLMipmap_t *texture2 = poly2->texture; + if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) + texture1 = NULL; + if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) + texture2 = NULL; + diff64 = texture1 - texture2; + if (diff64 != 0) return diff64; + + // skywalls and horizon lines must retain their order for horizon lines to work + if (texture1 == NULL && texture2 == NULL) + return index1 - index2; + + diff = poly1->polyFlags - poly2->polyFlags; + if (diff != 0) return diff; + + diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + + return 0; +} + +// This function organizes the geometry collected by HWR_ProcessPolygon calls into batches and uses +// the rendering backend to draw them. +void HWR_RenderBatches(void) +{ + int finalVertexWritePos = 0;// position in finalVertexArray + int finalIndexWritePos = 0;// position in finalVertexIndexArray + + int polygonReadPos = 0;// position in polygonIndexArray + + int currentShader; + int nextShader = 0; + GLMipmap_t *currentTexture; + GLMipmap_t *nextTexture = NULL; + FBITFIELD currentPolyFlags = 0; + FBITFIELD nextPolyFlags = 0; + FSurfaceInfo currentSurfaceInfo; + FSurfaceInfo nextSurfaceInfo; + + int i; + + if (!currently_batching) + I_Error("HWR_RenderBatches called without starting batching"); + + nextSurfaceInfo.LightInfo.fade_end = 0; + nextSurfaceInfo.LightInfo.fade_start = 0; + nextSurfaceInfo.LightInfo.light_level = 0; + + currently_batching = false;// no longer collecting batches + if (!polygonArraySize) + { + rs_hw_numpolys = rs_hw_numcalls = rs_hw_numshaders = rs_hw_numtextures = rs_hw_numpolyflags = rs_hw_numcolors = 0; + return;// nothing to draw + } + // init stats vars + rs_hw_numpolys = polygonArraySize; + rs_hw_numcalls = rs_hw_numverts = 0; + rs_hw_numshaders = rs_hw_numtextures = rs_hw_numpolyflags = rs_hw_numcolors = 1; + // init polygonIndexArray + for (i = 0; i < polygonArraySize; i++) + { + polygonIndexArray[i] = i; + } + + // sort polygons + rs_hw_batchsorttime = I_GetTimeMicros(); + if (cv_grshaders.value && gr_shadersavailable) + qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); + else + qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); + rs_hw_batchsorttime = I_GetTimeMicros() - rs_hw_batchsorttime; + // sort order + // 1. shader + // 2. texture + // 3. polyflags + // 4. colors + light level + // not sure about what order of the last 2 should be, or if it even matters + + rs_hw_batchdrawtime = I_GetTimeMicros(); + + currentShader = polygonArray[polygonIndexArray[0]].shader; + currentTexture = polygonArray[polygonIndexArray[0]].texture; + currentPolyFlags = polygonArray[polygonIndexArray[0]].polyFlags; + currentSurfaceInfo = polygonArray[polygonIndexArray[0]].surf; + // For now, will sort and track the colors. Vertex attributes could be used instead of uniforms + // and a color array could replace the color calls. + + // set state for first batch + + if (cv_grshaders.value && gr_shadersavailable) + { + HWD.pfnSetShader(currentShader); + } + + if (currentPolyFlags & PF_NoTexture) + currentTexture = NULL; + else + HWD.pfnSetTexture(currentTexture); + + while (1)// note: remember handling notexture polyflag as having texture number 0 (also in comparePolygons) + { + int firstIndex; + int lastIndex; + + boolean stopFlag = false; + boolean changeState = false; + boolean changeShader = false; + boolean changeTexture = false; + boolean changePolyFlags = false; + boolean changeSurfaceInfo = false; + + // steps: + // write vertices + // check for changes or end, otherwise go back to writing + // changes will affect the next vars and the change bools + // end could set flag for stopping + // execute draw call + // could check ending flag here + // change states according to next vars and change bools, updating the current vars and reseting the bools + // reset write pos + // repeat loop + + int index = polygonIndexArray[polygonReadPos++]; + int numVerts = polygonArray[index].numVerts; + // before writing, check if there is enough room + // using 'while' instead of 'if' here makes sure that there will *always* be enough room. + // probably never will this loop run more than once though + while (finalVertexWritePos + numVerts > finalVertexArrayAllocSize) + { + FOutVector* new_array; + unsigned int* new_index_array; + finalVertexArrayAllocSize *= 2; + new_array = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); + memcpy(new_array, finalVertexArray, finalVertexWritePos * sizeof(FOutVector)); + free(finalVertexArray); + finalVertexArray = new_array; + // also increase size of index array, 3x of vertex array since + // going from fans to triangles increases vertex count to 3x + new_index_array = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); + memcpy(new_index_array, finalVertexIndexArray, finalIndexWritePos * sizeof(UINT32)); + free(finalVertexIndexArray); + finalVertexIndexArray = new_index_array; + } + // write the vertices of the polygon + memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[polygonArray[index].vertsIndex], + numVerts * sizeof(FOutVector)); + // write the indexes, pointing to the fan vertexes but in triangles format + firstIndex = finalVertexWritePos; + lastIndex = finalVertexWritePos + numVerts; + finalVertexWritePos += 2; + while (finalVertexWritePos < lastIndex) + { + finalVertexIndexArray[finalIndexWritePos++] = firstIndex; + finalVertexIndexArray[finalIndexWritePos++] = finalVertexWritePos - 1; + finalVertexIndexArray[finalIndexWritePos++] = finalVertexWritePos++; + } + + if (polygonReadPos >= polygonArraySize) + { + stopFlag = true; + } + else + { + // check if a state change is required, set the change bools and next vars + int nextIndex = polygonIndexArray[polygonReadPos]; + nextShader = polygonArray[nextIndex].shader; + nextTexture = polygonArray[nextIndex].texture; + nextPolyFlags = polygonArray[nextIndex].polyFlags; + nextSurfaceInfo = polygonArray[nextIndex].surf; + if (nextPolyFlags & PF_NoTexture) + nextTexture = 0; + if (currentShader != nextShader && cv_grshaders.value && gr_shadersavailable) + { + changeState = true; + changeShader = true; + } + if (currentTexture != nextTexture) + { + changeState = true; + changeTexture = true; + } + if (currentPolyFlags != nextPolyFlags) + { + changeState = true; + changePolyFlags = true; + } + if (cv_grshaders.value && gr_shadersavailable) + { + if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || + currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || + currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || + currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || + currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || + currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end) + { + changeState = true; + changeSurfaceInfo = true; + } + } + else + { + if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba) + { + changeState = true; + changeSurfaceInfo = true; + } + } + } + + if (changeState || stopFlag) + { + // execute draw call + HWD.pfnDrawIndexedTriangles(¤tSurfaceInfo, finalVertexArray, finalIndexWritePos, currentPolyFlags, finalVertexIndexArray); + // update stats + rs_hw_numcalls++; + rs_hw_numverts += finalIndexWritePos; + // reset write positions + finalVertexWritePos = 0; + finalIndexWritePos = 0; + } + else continue; + + // if we're here then either its time to stop or time to change state + if (stopFlag) break; + + // change state according to change bools and next vars, update current vars and reset bools + if (changeShader) + { + HWD.pfnSetShader(nextShader); + currentShader = nextShader; + changeShader = false; + + rs_hw_numshaders++; + } + if (changeTexture) + { + // texture should be already ready for use from calls to SetTexture during batch collection + HWD.pfnSetTexture(nextTexture); + currentTexture = nextTexture; + changeTexture = false; + + rs_hw_numtextures++; + } + if (changePolyFlags) + { + currentPolyFlags = nextPolyFlags; + changePolyFlags = false; + + rs_hw_numpolyflags++; + } + if (changeSurfaceInfo) + { + currentSurfaceInfo = nextSurfaceInfo; + changeSurfaceInfo = false; + + rs_hw_numcolors++; + } + // and that should be it? + } + // reset the arrays (set sizes to 0) + polygonArraySize = 0; + unsortedVertexArraySize = 0; + + rs_hw_batchdrawtime = I_GetTimeMicros() - rs_hw_batchdrawtime; +} + + +#endif // HWRENDER diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h new file mode 100644 index 000000000..7c108a4bd --- /dev/null +++ b/src/hardware/hw_batching.h @@ -0,0 +1,37 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_batching.h +/// \brief Draw call batching and related things. + +#ifndef __HWR_BATCHING_H__ +#define __HWR_BATCHING_H__ + +#include "hw_defs.h" +#include "hw_data.h" +#include "hw_drv.h" + +typedef struct +{ + FSurfaceInfo surf;// surf also has its own polyflags for some reason, but it seems unused + unsigned int vertsIndex;// location of verts in unsortedVertexArray + FUINT numVerts; + FBITFIELD polyFlags; + GLMipmap_t *texture; + int shader; + // this tells batching that the plane belongs to a horizon line and must be drawn in correct order with the skywalls + boolean horizonSpecial; +} PolygonArrayEntry; + +void HWR_StartBatching(void); +void HWR_SetCurrentTexture(GLMipmap_t *texture); +void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial); +void HWR_RenderBatches(void); + +#endif diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 6f3dd9fbd..6987e9d01 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -1,19 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_bsp.c /// \brief convert SRB2 map #include "../doomdef.h" @@ -887,12 +880,10 @@ static void AdjustSegs(void) float distv1,distv2,tmp; nearv1 = nearv2 = MYMAX; -#ifdef POLYOBJECTS // Don't touch polyobject segs. We'll compensate // for this when we go about drawing them. if (lseg->polyseg) continue; -#endif if (p) { for (j = 0; j < p->numpts; j++) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index ccffc8a49..ab9a50dd5 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -1,20 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_cache.c /// \brief load and convert graphics to the hardware format #include "../doomdef.h" @@ -22,6 +15,7 @@ #ifdef HWRENDER #include "hw_glob.h" #include "hw_drv.h" +#include "hw_batching.h" #include "../doomstat.h" //gamemode #include "../i_video.h" //rendermode @@ -33,9 +27,6 @@ #include "../r_patch.h" #include "../p_setup.h" -// Values set after a call to HWR_ResizeBlock() -static INT32 blocksize, blockwidth, blockheight; - INT32 patchformat = GR_TEXFMT_AP_88; // use alpha for holes INT32 textureformat = GR_TEXFMT_P_8; // use chromakey for hole @@ -234,11 +225,11 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, if (mipmap->colormap) texel = mipmap->colormap[texel]; - // transparent pixel - if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX) + // If the mipmap is chromakeyed, check if the texel's color + // is equivalent to the chroma key's color index. + alpha = 0xff; + if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)) alpha = 0x00; - else - alpha = 0xff; // hope compiler will get this switch out of the loops (dreams...) // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?) @@ -308,13 +299,13 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, if (pwidth <= 0 || pheight <= 0) return; - ncols = (pwidth * pblockwidth) / pwidth; + ncols = pwidth; // source advance xfrac = 0; - xfracstep = (pwidth << FRACBITS) / pblockwidth; - yfracstep = (pheight << FRACBITS) / pblockheight; - scale_y = (pblockheight << FRACBITS) / pheight; + xfracstep = FRACUNIT; + yfracstep = FRACUNIT; + scale_y = FRACUNIT; bpp = format2bpp[mipmap->grInfo.format]; @@ -322,7 +313,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp); // NOTE: should this actually be pblockwidth*bpp? - blockmodulo = blockwidth*bpp; + blockmodulo = pblockwidth*bpp; // Draw each column to the block cache for (; ncols--; block += bpp, xfrac += xfracstep) @@ -415,7 +406,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp); // NOTE: should this actually be pblockwidth*bpp? - blockmodulo = blockwidth*bpp; + blockmodulo = pblockwidth*bpp; // Draw each column to the block cache for (block += col*bpp; ncols--; block += bpp, xfrac += xfracstep) @@ -433,142 +424,12 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, } } - -// resize the patch to be 3dfx compliant -// set : blocksize = blockwidth * blockheight (no bpp used) -// blockwidth -// blockheight -//note : 8bit (1 byte per pixel) palettized format -static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, - GrTexInfo *grInfo) -{ -#ifdef GLIDE_API_COMPATIBILITY - // Build the full textures from patches. - static const GrLOD_t gr_lods[9] = - { - GR_LOD_LOG2_256, - GR_LOD_LOG2_128, - GR_LOD_LOG2_64, - GR_LOD_LOG2_32, - GR_LOD_LOG2_16, - GR_LOD_LOG2_8, - GR_LOD_LOG2_4, - GR_LOD_LOG2_2, - GR_LOD_LOG2_1 - }; - - typedef struct - { - GrAspectRatio_t aspect; - float max_s; - float max_t; - } booring_aspect_t; - - static const booring_aspect_t gr_aspects[8] = - { - {GR_ASPECT_LOG2_1x1, 255, 255}, - {GR_ASPECT_LOG2_2x1, 255, 127}, - {GR_ASPECT_LOG2_4x1, 255, 63}, - {GR_ASPECT_LOG2_8x1, 255, 31}, - - {GR_ASPECT_LOG2_1x1, 255, 255}, - {GR_ASPECT_LOG2_1x2, 127, 255}, - {GR_ASPECT_LOG2_1x4, 63, 255}, - {GR_ASPECT_LOG2_1x8, 31, 255} - }; - - INT32 j,k; - INT32 max,min; -#else - (void)grInfo; -#endif - - // find a power of 2 width/height - if (cv_grrounddown.value) - { - blockwidth = 256; - while (originalwidth < blockwidth) - blockwidth >>= 1; - if (blockwidth < 1) - I_Error("3D GenerateTexture : too small"); - - blockheight = 256; - while (originalheight < blockheight) - blockheight >>= 1; - if (blockheight < 1) - I_Error("3D GenerateTexture : too small"); - } - else - { -#ifdef GLIDE_API_COMPATIBILITY - //size up to nearest power of 2 - blockwidth = 1; - while (blockwidth < originalwidth) - blockwidth <<= 1; - // scale down the original graphics to fit in 256 - if (blockwidth > 2048) - blockwidth = 2048; - //I_Error("3D GenerateTexture : too big"); - - //size up to nearest power of 2 - blockheight = 1; - while (blockheight < originalheight) - blockheight <<= 1; - // scale down the original graphics to fit in 256 - if (blockheight > 2048) - blockheight = 2048; - //I_Error("3D GenerateTexture : too big"); -#else - blockwidth = originalwidth; - blockheight = originalheight; -#endif - } - - // do the boring LOD stuff.. blech! -#ifdef GLIDE_API_COMPATIBILITY - if (blockwidth >= blockheight) - { - max = blockwidth; - min = blockheight; - } - else - { - max = blockheight; - min = blockwidth; - } - - for (k = 2048, j = 0; k > max; j++) - k>>=1; - grInfo->smallLodLog2 = gr_lods[j]; - grInfo->largeLodLog2 = gr_lods[j]; - - for (k = max, j = 0; k > min && j < 4; j++) - k>>=1; - // aspect ratio too small for 3Dfx (eg: 8x128 is 1x16 : use 1x8) - if (j == 4) - { - j = 3; - //CONS_Debug(DBG_RENDER, "HWR_ResizeBlock : bad aspect ratio %dx%d\n", blockwidth,blockheight); - if (blockwidth < blockheight) - blockwidth = max>>3; - else - blockheight = max>>3; - } - if (blockwidth < blockheight) - j += 4; - grInfo->aspectRatioLog2 = gr_aspects[j].aspect; -#endif - - blocksize = blockwidth * blockheight; - - //CONS_Debug(DBG_RENDER, "Width is %d, Height is %d\n", blockwidth, blockheight); -} - static UINT8 *MakeBlock(GLMipmap_t *grMipmap) { UINT8 *block; INT32 bpp, i; UINT16 bu16 = ((0x00 <<8) | HWR_PATCHES_CHROMAKEY_COLORINDEX); + INT32 blocksize = (grMipmap->width * grMipmap->height); bpp = format2bpp[grMipmap->grInfo.format]; block = Z_Malloc(blocksize*bpp, PU_HWRCACHE, &(grMipmap->grInfo.data)); @@ -599,6 +460,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) texpatch_t *patch; patch_t *realpatch; UINT8 *pdata; + INT32 blockwidth, blockheight, blocksize; INT32 i; boolean skyspecial = false; //poor hack for Legacy large skies.. @@ -619,11 +481,13 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) else grtex->mipmap.flags = TF_CHROMAKEYED | TF_WRAPXY; - HWR_ResizeBlock (texture->width, texture->height, &grtex->mipmap.grInfo); - grtex->mipmap.width = (UINT16)blockwidth; - grtex->mipmap.height = (UINT16)blockheight; + grtex->mipmap.width = (UINT16)texture->width; + grtex->mipmap.height = (UINT16)texture->height; grtex->mipmap.grInfo.format = textureformat; + blockwidth = texture->width; + blockheight = texture->height; + blocksize = (blockwidth * blockheight); block = MakeBlock(&grtex->mipmap); if (skyspecial) //Hurdler: not efficient, but better than holes in the sky (and it's done only at level loading) @@ -692,8 +556,6 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) // patch may be NULL if grMipmap has been initialised already and makebitmap is false void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap) { - INT32 newwidth, newheight; - #ifndef NO_PNG_LUMPS // lump is a png so convert it size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum); @@ -712,51 +574,32 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm grPatch->leftoffset = SHORT(patch->leftoffset); grPatch->topoffset = SHORT(patch->topoffset); - // find the good 3dfx size (boring spec) - HWR_ResizeBlock (SHORT(patch->width), SHORT(patch->height), &grMipmap->grInfo); - grMipmap->width = (UINT16)blockwidth; - grMipmap->height = (UINT16)blockheight; + grMipmap->width = grMipmap->height = 1; + while (grMipmap->width < grPatch->width) grMipmap->width <<= 1; + while (grMipmap->height < grPatch->height) grMipmap->height <<= 1; // no wrap around, no chroma key grMipmap->flags = 0; // setup the texture info grMipmap->grInfo.format = patchformat; - } - else - { - blockwidth = grMipmap->width; - blockheight = grMipmap->height; - blocksize = blockwidth * blockheight; + + //grPatch->max_s = grPatch->max_t = 1.0f; + grPatch->max_s = (float)grPatch->width / (float)grMipmap->width; + grPatch->max_t = (float)grPatch->height / (float)grMipmap->height; } Z_Free(grMipmap->grInfo.data); grMipmap->grInfo.data = NULL; - // if rounddown, rounddown patches as well as textures - if (cv_grrounddown.value) - { - newwidth = blockwidth; - newheight = blockheight; - } - else - { - // no rounddown, do not size up patches, so they don't look 'scaled' - newwidth = min(grPatch->width, blockwidth); - newheight = min(grPatch->height, blockheight); - } - if (makebitmap) { MakeBlock(grMipmap); HWR_DrawPatchInCache(grMipmap, - newwidth, newheight, + grMipmap->width, grMipmap->height, grPatch->width, grPatch->height, patch); } - - grPatch->max_s = (float)newwidth / (float)blockwidth; - grPatch->max_t = (float)newheight / (float)blockheight; } @@ -896,8 +739,11 @@ GLTexture_t *HWR_GetTexture(INT32 tex) if (!grtex->mipmap.grInfo.data && !grtex->mipmap.downloaded) HWR_GenerateTexture(tex, grtex); - // Tell the hardware driver to bind the current texture to the flat's mipmap - HWD.pfnSetTexture(&grtex->mipmap); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grtex->mipmap.downloaded) + HWD.pfnSetTexture(&grtex->mipmap); + + HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. Z_ChangeTag(grtex->mipmap.grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -910,11 +756,6 @@ static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) size_t size, pflatsize; // setup the texture info -#ifdef GLIDE_API_COMPATIBILITY - grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; - grMipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_64; - grMipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; -#endif grMipmap->grInfo.format = GR_TEXFMT_P_8; grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; @@ -957,15 +798,7 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) { UINT8 *flat; - if (needpatchflush) - W_FlushCachedPatches(); - // setup the texture info -#ifdef GLIDE_API_COMPATIBILITY - grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; - grMipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_64; - grMipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; -#endif grMipmap->grInfo.format = GR_TEXFMT_P_8; grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; @@ -985,14 +818,15 @@ void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum) if (flatlumpnum == LUMPERROR) return; - if (needpatchflush) - W_FlushCachedPatches(); - grmip = HWR_GetCachedGLPatch(flatlumpnum)->mipmap; if (!grmip->downloaded && !grmip->grInfo.data) HWR_CacheFlat(grmip, flatlumpnum); - HWD.pfnSetTexture(grmip); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grmip->downloaded) + HWD.pfnSetTexture(grmip); + + HWR_SetCurrentTexture(grmip); // The system-memory data can be purged now. Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -1026,14 +860,17 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) if (!grtex->mipmap.grInfo.data && !grtex->mipmap.downloaded) HWR_CacheTextureAsFlat(&grtex->mipmap, texturenum); - // Tell the hardware driver to bind the current texture to the flat's mipmap - HWD.pfnSetTexture(&grtex->mipmap); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grtex->mipmap.downloaded) + HWD.pfnSetTexture(&grtex->mipmap); + + HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. Z_ChangeTag(grtex->mipmap.grInfo.data, PU_HWRCACHE_UNLOCKED); } else // set no texture - HWD.pfnSetTexture(NULL); + HWR_SetCurrentTexture(NULL); } // @@ -1055,7 +892,11 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) Z_Free(patch); } - HWD.pfnSetTexture(grmip); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grmip->downloaded) + HWD.pfnSetTexture(grmip); + + HWR_SetCurrentTexture(grmip); // The system-memory data can be purged now. Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -1066,9 +907,6 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) // -----------------+ void HWR_GetPatch(GLPatch_t *gpatch) { - if (needpatchflush) - W_FlushCachedPatches(); - // is it in hardware cache if (!gpatch->mipmap->downloaded && !gpatch->mipmap->grInfo.data) { @@ -1085,7 +923,11 @@ void HWR_GetPatch(GLPatch_t *gpatch) Z_Free(ptr); } - HWD.pfnSetTexture(gpatch->mipmap); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!gpatch->mipmap->downloaded) + HWD.pfnSetTexture(gpatch->mipmap); + + HWR_SetCurrentTexture(gpatch->mipmap); // The system-memory patch data can be purged now. Z_ChangeTag(gpatch->mipmap->grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -1099,9 +941,6 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) { GLMipmap_t *grmip, *newmip; - if (needpatchflush) - W_FlushCachedPatches(); - if (colormap == colormaps || colormap == NULL) { // Load the default (green) color in doom cache (temporary?) AND hardware cache @@ -1225,19 +1064,12 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig // -----------------+ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) { - GLPatch_t *grpatch; - - if (needpatchflush) - W_FlushCachedPatches(); - - grpatch = HWR_GetCachedGLPatch(lumpnum); - + GLPatch_t *grpatch = HWR_GetCachedGLPatch(lumpnum); if (!grpatch->mipmap->downloaded && !grpatch->mipmap->grInfo.data) { pic_t *pic; UINT8 *block; size_t len; - INT32 newwidth, newheight; pic = W_CacheLumpNum(lumpnum, PU_CACHE); grpatch->width = SHORT(pic->width); @@ -1247,10 +1079,8 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) grpatch->leftoffset = 0; grpatch->topoffset = 0; - // find the good 3dfx size (boring spec) - HWR_ResizeBlock (grpatch->width, grpatch->height, &grpatch->mipmap->grInfo); - grpatch->mipmap->width = (UINT16)blockwidth; - grpatch->mipmap->height = (UINT16)blockheight; + grpatch->mipmap->width = (UINT16)grpatch->width; + grpatch->mipmap->height = (UINT16)grpatch->height; if (pic->mode == PALETTE) grpatch->mipmap->grInfo.format = textureformat; // can be set by driver @@ -1262,30 +1092,16 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) // allocate block block = MakeBlock(grpatch->mipmap); - // if rounddown, rounddown patches as well as textures - if (cv_grrounddown.value) - { - newwidth = blockwidth; - newheight = blockheight; - } - else - { - // no rounddown, do not size up patches, so they don't look 'scaled' - newwidth = min(SHORT(pic->width),blockwidth); - newheight = min(SHORT(pic->height),blockheight); - } - - - if (grpatch->width == blockwidth && - grpatch->height == blockheight && + if (grpatch->width == SHORT(pic->width) && + grpatch->height == SHORT(pic->height) && format2bpp[grpatch->mipmap->grInfo.format] == format2bpp[picmode2GR[pic->mode]]) { // no conversion needed M_Memcpy(grpatch->mipmap->grInfo.data, pic->data,len); } else - HWR_DrawPicInCache(block, newwidth, newheight, - blockwidth*format2bpp[grpatch->mipmap->grInfo.format], + HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height), + SHORT(pic->width)*format2bpp[grpatch->mipmap->grInfo.format], pic, format2bpp[grpatch->mipmap->grInfo.format]); @@ -1293,8 +1109,7 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED); grpatch->mipmap->flags = 0; - grpatch->max_s = (float)newwidth / (float)blockwidth; - grpatch->max_t = (float)newheight / (float)blockheight; + grpatch->max_s = grpatch->max_t = 1.0f; } HWD.pfnSetTexture(grpatch->mipmap); //CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grpatch->mipmap.grInfo.data, grpatch->mipmap.downloaded); @@ -1330,7 +1145,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 { INT32 i,j; fixed_t posx, posy, stepx, stepy; - UINT8 *block = mipmap->grInfo.data; // places the data directly into here, it already has the space allocated from HWR_ResizeBlock + UINT8 *block = mipmap->grInfo.data; // places the data directly into here UINT8 *flat; UINT8 *dest, *src, texel; RGBA_t col; @@ -1345,7 +1160,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 for (j = 0; j < pblockheight; j++) { posx = 0; - dest = &block[j*blockwidth]; // 1bpp + dest = &block[j*(mipmap->width)]; // 1bpp src = &flat[(posy>>FRACBITS)*SHORT(fmwidth)]; for (i = 0; i < pblockwidth;i++) { @@ -1399,14 +1214,12 @@ static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum) } // Thankfully, this will still work for this scenario - HWR_ResizeBlock(fmwidth, fmheight, &grMipmap->grInfo); - - grMipmap->width = blockwidth; - grMipmap->height = blockheight; + grMipmap->width = fmwidth; + grMipmap->height = fmheight; MakeBlock(grMipmap); - HWR_DrawFadeMaskInCache(grMipmap, blockwidth, blockheight, fademasklumpnum, fmwidth, fmheight); + HWR_DrawFadeMaskInCache(grMipmap, fmwidth, fmheight, fademasklumpnum, fmwidth, fmheight); // I DO need to convert this because it isn't power of 2 and we need the alpha } @@ -1414,13 +1227,7 @@ static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum) void HWR_GetFadeMask(lumpnum_t fademasklumpnum) { - GLMipmap_t *grmip; - - if (needpatchflush) - W_FlushCachedPatches(); - - grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; - + GLMipmap_t *grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; if (!grmip->downloaded && !grmip->grInfo.data) HWR_CacheFadeMask(grmip, fademasklumpnum); diff --git a/src/hardware/hw_clip.c b/src/hardware/hw_clip.c index a63527083..86e0c58d2 100644 --- a/src/hardware/hw_clip.c +++ b/src/hardware/hw_clip.c @@ -78,8 +78,8 @@ #include "r_opengl/r_opengl.h" #ifdef HAVE_SPHEREFRUSTRUM -static GLfloat viewMatrix[16]; -static GLfloat projMatrix[16]; +static GLdouble viewMatrix[16]; +static GLdouble projMatrix[16]; float frustum[6][4]; #endif @@ -320,12 +320,12 @@ void gld_clipper_Clear(void) #define RMUL (1.6f/1.333333f) -angle_t gld_FrustumAngle(void) +angle_t gld_FrustumAngle(angle_t tiltangle) { double floatangle; angle_t a1; - float tilt = (float)fabs(((double)(int)aimingangle) / ANG1); + float tilt = (float)fabs(((double)(int)tiltangle) / ANG1); // NEWCLIP TODO: SRB2CBTODO: make a global render_fov for this function @@ -339,7 +339,7 @@ angle_t gld_FrustumAngle(void) } // If the pitch is larger than this you can look all around at a FOV of 90 - if (abs((signed)aimingangle) > 46 * ANG1) + if (abs((signed)tiltangle) > 46 * ANG1) return 0xffffffff; // ok, this is a gross hack that barely works... @@ -352,7 +352,7 @@ angle_t gld_FrustumAngle(void) } // SRB2CB I don't think used any of this stuff, let's disable for now since SRB2 probably doesn't want it either -// compiler complains about (p)glGetDoublev anyway, in case anyone wants this +// compiler complains about (p)glGetFloatv anyway, in case anyone wants this // only r_opengl.c can use the base gl funcs as it turns out, that's a problem for whoever wants sphere frustum checks // btw to renable define HAVE_SPHEREFRUSTRUM in hw_clip.h #ifdef HAVE_SPHEREFRUSTRUM @@ -381,7 +381,7 @@ void gld_FrustrumSetup(void) float t; float clip[16]; - pglGeFloatv(GL_PROJECTION_MATRIX, projMatrix); + pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); pglGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix); clip[0] = CALCMATRIX(0, 0, 1, 4, 2, 8, 3, 12); diff --git a/src/hardware/hw_clip.h b/src/hardware/hw_clip.h index 3ba26e5e5..27a2ed1ef 100644 --- a/src/hardware/hw_clip.h +++ b/src/hardware/hw_clip.h @@ -17,7 +17,7 @@ boolean gld_clipper_SafeCheckRange(angle_t startAngle, angle_t endAngle); void gld_clipper_SafeAddClipRange(angle_t startangle, angle_t endangle); void gld_clipper_Clear(void); -angle_t gld_FrustumAngle(void); +angle_t gld_FrustumAngle(angle_t tiltangle); #ifdef HAVE_SPHEREFRUSTRUM void gld_FrustrumSetup(void); boolean gld_SphereInFrustum(float x, float y, float z, float radius); diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index ef57426a4..686d522a0 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -1,21 +1,14 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file -/// \brief defines structures and exports for the standard 3D driver DLL used by Doom Legacy +/// \file hw_data.h +/// \brief defines structures and exports for the hardware interface used by Sonic Robo Blast 2 #ifndef _HWR_DATA_ #define _HWR_DATA_ diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 95882b03e..715c45ef3 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -1,24 +1,19 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_defs.h /// \brief 3D hardware renderer definitions #ifndef _HWR_DEFS_ #define _HWR_DEFS_ #include "../doomtype.h" +#include "../r_defs.h" #define ZCLIP_PLANE 4.0f // Used for the actual game drawing #define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures @@ -82,16 +77,18 @@ typedef struct // Simple 3D vector typedef struct FVector { - FLOAT x,y,z; + FLOAT x,y,z; } FVector; -// 3D model vector (coords + texture coords) -typedef struct -{ - //FVector Point; - FLOAT x,y,z; - FLOAT s,t,w; // texture coordinates -} v3d_t, wallVert3D; +// ====================== +// wallVert3D +// ---------------------- +// :crab: IS GONE! :crab: +// ====================== + +// ----------- +// structures +// ----------- //Hurdler: Transform (coords + angles) //BP: transform order : scale(rotation_x(rotation_y(translation(v)))) @@ -123,15 +120,16 @@ typedef struct #ifdef USE_FTRANSFORM_MIRROR boolean mirror; // SRB2Kart: Encore Mode #endif + boolean shearing; // 14042019 + float viewaiming; // 17052019 } FTransform; // Transformed vector, as passed to HWR API typedef struct { FLOAT x,y,z; - FUINT argb; // flat-shaded color - FLOAT sow; // s texture ordinate (s over w) - FLOAT tow; // t texture ordinate (t over w) + FLOAT s; // s texture ordinate (s over w) + FLOAT t; // t texture ordinate (t over w) } FOutVector; @@ -162,10 +160,10 @@ enum EPolyFlags PF_Invisible = 0x00000400, // Disable write to color buffer PF_Decal = 0x00000800, // Enable polygon offset PF_Modulated = 0x00001000, // Modulation (multiply output with constant ARGB) - // When set, pass the color constant into the FSurfaceInfo -> FlatColor + // When set, pass the color constant into the FSurfaceInfo -> PolyColor PF_NoTexture = 0x00002000, // Use the small white texture PF_Corona = 0x00004000, // Tell the rendrer we are drawing a corona - PF_Unused = 0x00008000, // Unused + PF_Ripple = 0x00008000, // Water shader effect PF_RemoveYWrap = 0x00010000, // Force clamp texture on Y PF_ForceWrapX = 0x00020000, // Force repeat texture on X PF_ForceWrapY = 0x00040000, // Force repeat texture on Y @@ -178,7 +176,6 @@ enum EPolyFlags enum ESurfFlags { SF_DYNLIGHT = 0x00000001, - }; enum ETextureFlags @@ -190,38 +187,36 @@ enum ETextureFlags TF_TRANSPARENT = 0x00000040, // texture with some alpha == 0 }; -#ifdef TODO -struct FTextureInfo -{ - FUINT Width; // Pixels - FUINT Height; // Pixels - FUBYTE *TextureData; // Image data - FUINT Format; // FORMAT_RGB, ALPHA ... - FBITFIELD Flags; // Flags to tell driver about texture (see ETextureFlags) - void DriverExtra; // (OpenGL texture object nr, ...) - // chromakey enabled,... - - struct FTextureInfo *Next; // Manage list of downloaded textures. -}; -#else typedef struct GLMipmap_s FTextureInfo; -#endif + +// jimita 14032019 +struct FLightInfo +{ + FUINT light_level; + FUINT fade_start; + FUINT fade_end; +}; +typedef struct FLightInfo FLightInfo; // Description of a renderable surface struct FSurfaceInfo { - FUINT PolyFlags; // Surface flags -- UNUSED YET -- - RGBA_t FlatColor; // Flat-shaded color used with PF_Modulated mode + FUINT PolyFlags; + RGBA_t PolyColor; + RGBA_t TintColor; + RGBA_t FadeColor; + FLightInfo LightInfo; // jimita 14032019 }; typedef struct FSurfaceInfo FSurfaceInfo; +#define GL_DEFAULTMIX 0x00000000 +#define GL_DEFAULTFOG 0xFF000000 + //Hurdler: added for backward compatibility enum hwdsetspecialstate { HWD_SET_MODEL_LIGHTING = 1, - HWD_SET_FOG_MODE, - HWD_SET_FOG_COLOR, - HWD_SET_FOG_DENSITY, + HWD_SET_SHADERS, HWD_SET_TEXTUREFILTERMODE, HWD_SET_TEXTUREANISOTROPICMODE, HWD_NUMSTATE @@ -229,6 +224,15 @@ enum hwdsetspecialstate typedef enum hwdsetspecialstate hwdspecialstate_t; +// Lactozilla: Shader info +// Generally set at the start of the frame. +enum hwdshaderinfo +{ + HWD_SHADERINFO_LEVELTIME = 1, +}; + +typedef enum hwdshaderinfo hwdshaderinfo_t; + enum hwdfiltermode { HWD_SET_TEXTUREFILTER_POINTSAMPLED, diff --git a/src/hardware/hw_dll.h b/src/hardware/hw_dll.h index 3fa5852d8..d22c8c312 100644 --- a/src/hardware/hw_dll.h +++ b/src/hardware/hw_dll.h @@ -1,19 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- +// Copyright (C) 2005 by Sonic Team Junior. // -// Copyright (C) 2005 by SRB2 Jr. Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_dll.h /// \brief Win32 DLL and Shared Objects API definitions #ifndef __HWR_DLL_H__ @@ -54,8 +47,6 @@ #endif #endif -typedef void (*I_Error_t) (const char *error, ...) FUNCIERROR; - // ========================================================================== // MATHS // ========================================================================== @@ -63,7 +54,7 @@ typedef void (*I_Error_t) (const char *error, ...) FUNCIERROR; // Constants #define DEGREE (0.017453292519943295769236907684883l) // 2*PI/360 -void DBG_Printf(const char *lpFmt, ...) /*FUNCPRINTF*/; +void GL_DBG_Printf(const char *format, ...) /*FUNCPRINTF*/; #ifdef _WINDOWS BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 598a635aa..3d20cd9b0 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -1,19 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_draw.c /// \brief miscellaneous drawing (mainly 2d) #ifdef __GNUC__ @@ -23,6 +17,7 @@ #include "../doomdef.h" #ifdef HWRENDER +#include "hw_main.h" #include "hw_glob.h" #include "hw_drv.h" @@ -43,9 +38,6 @@ #define O_BINARY 0 #endif -float gr_patch_scalex; -float gr_patch_scaley; - #if defined(_MSC_VER) #pragma pack(1) #endif @@ -65,9 +57,6 @@ typedef struct #if defined(_MSC_VER) #pragma pack() #endif -typedef UINT8 GLRGB[3]; - -#define BLENDMODE PF_Translucent static UINT8 softwaretranstogl[11] = { 0, 25, 51, 76,102,127,153,178,204,229,255}; static UINT8 softwaretranstogl_hi[11] = { 0, 51,102,153,204,255,255,255,255,255,255}; @@ -121,12 +110,12 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = gpatch->max_s; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = gpatch->max_s; + v[0].t = v[1].t = 0.0f; + v[2].t = v[3].t = gpatch->max_t; - flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; + flags = PF_Translucent|PF_NoDepthTest; if (option & V_WRAPX) flags |= PF_ForceWrapX; @@ -291,7 +280,7 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) { // Need to temporarily cache the real patch to get the colour of the top left pixel - patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); + patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); if (!column->topdelta) { @@ -356,19 +345,19 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (option & V_FLIP) { - v[0].sow = v[3].sow = gpatch->max_s; - v[2].sow = v[1].sow = 0.0f; + v[0].s = v[3].s = gpatch->max_s; + v[2].s = v[1].s = 0.0f; } else { - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = gpatch->max_s; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = gpatch->max_s; } - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; + v[0].t = v[1].t = 0.0f; + v[2].t = v[3].t = gpatch->max_t; - flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; + flags = PF_Translucent|PF_NoDepthTest; if (option & V_WRAPX) flags |= PF_ForceWrapX; @@ -379,11 +368,11 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (alphalevel) { FSurfaceInfo Surf; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - if (alphalevel == 13) Surf.FlatColor.s.alpha = softwaretranstogl_lo[st_translucency]; - else if (alphalevel == 14) Surf.FlatColor.s.alpha = softwaretranstogl[st_translucency]; - else if (alphalevel == 15) Surf.FlatColor.s.alpha = softwaretranstogl_hi[st_translucency]; - else Surf.FlatColor.s.alpha = softwaretranstogl[10-alphalevel]; + Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; + if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; + else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; + else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } @@ -450,7 +439,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) { // Need to temporarily cache the real patch to get the colour of the top left pixel - patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); + patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); if (!column->topdelta) { @@ -514,19 +503,19 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = ((sx )/(float)SHORT(gpatch->width) )*gpatch->max_s; + v[0].s = v[3].s = ((sx )/(float)SHORT(gpatch->width) )*gpatch->max_s; if (sx + w > SHORT(gpatch->width)) - v[2].sow = v[1].sow = gpatch->max_s; + v[2].s = v[1].s = gpatch->max_s; else - v[2].sow = v[1].sow = ((sx+w)/(float)SHORT(gpatch->width) )*gpatch->max_s; + v[2].s = v[1].s = ((sx+w)/(float)SHORT(gpatch->width) )*gpatch->max_s; - v[0].tow = v[1].tow = ((sy )/(float)SHORT(gpatch->height))*gpatch->max_t; + v[0].t = v[1].t = ((sy )/(float)SHORT(gpatch->height))*gpatch->max_t; if (sy + h > SHORT(gpatch->height)) - v[2].tow = v[3].tow = gpatch->max_t; + v[2].t = v[3].t = gpatch->max_t; else - v[2].tow = v[3].tow = ((sy+h)/(float)SHORT(gpatch->height))*gpatch->max_t; + v[2].t = v[3].t = ((sy+h)/(float)SHORT(gpatch->height))*gpatch->max_t; - flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; + flags = PF_Translucent|PF_NoDepthTest; if (option & V_WRAPX) flags |= PF_ForceWrapX; @@ -537,11 +526,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal if (alphalevel) { FSurfaceInfo Surf; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - if (alphalevel == 13) Surf.FlatColor.s.alpha = softwaretranstogl_lo[st_translucency]; - else if (alphalevel == 14) Surf.FlatColor.s.alpha = softwaretranstogl[st_translucency]; - else if (alphalevel == 15) Surf.FlatColor.s.alpha = softwaretranstogl_hi[st_translucency]; - else Surf.FlatColor.s.alpha = softwaretranstogl[10-alphalevel]; + Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; + if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; + else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; + else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } @@ -569,10 +558,10 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0; - v[2].sow = v[1].sow = patch->max_s; - v[0].tow = v[1].tow = 0; - v[2].tow = v[3].tow = patch->max_t; + v[0].s = v[3].s = 0; + v[2].s = v[1].s = patch->max_s; + v[0].t = v[1].t = 0; + v[2].t = v[3].t = patch->max_t; //Hurdler: Boris, the same comment as above... but maybe for pics @@ -581,7 +570,7 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) // But then, the question is: why not 0 instead of PF_Masked ? // or maybe PF_Environment ??? (like what I said above) // BP: PF_Environment don't change anything ! and 0 is undifined - HWD.pfnDrawPolygon(NULL, v, 4, BLENDMODE | PF_NoDepthTest | PF_Clip | PF_NoZClip); + HWD.pfnDrawPolygon(NULL, v, 4, PF_Translucent | PF_NoDepthTest | PF_Clip | PF_NoZClip); } // ========================================================================== @@ -644,10 +633,10 @@ void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; // flat is 64x64 lod and texture offsets are [0.0, 1.0] - v[0].sow = v[3].sow = (float)((x & flatflag)/dflatsize); - v[2].sow = v[1].sow = (float)(v[0].sow + w/dflatsize); - v[0].tow = v[1].tow = (float)((y & flatflag)/dflatsize); - v[2].tow = v[3].tow = (float)(v[0].tow + h/dflatsize); + v[0].s = v[3].s = (float)((x & flatflag)/dflatsize); + v[2].s = v[1].s = (float)(v[0].s + w/dflatsize); + v[0].t = v[1].t = (float)((y & flatflag)/dflatsize); + v[2].t = v[3].t = (float)(v[0].t + h/dflatsize); HWR_LiterallyGetFlat(flatlumpnum); @@ -679,20 +668,20 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) v[2].y = v[3].y = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = 1.0f; - v[0].tow = v[1].tow = 1.0f; - v[2].tow = v[3].tow = 0.0f; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = 1.0f; + v[0].t = v[1].t = 1.0f; + v[2].t = v[3].t = 0.0f; if (color & 0xFF00) // Do COLORMAP fade. { - Surf.FlatColor.rgba = UINT2RGBA(0x01010160); - Surf.FlatColor.s.alpha = (strength*8); + Surf.PolyColor.rgba = UINT2RGBA(0x01010160); + Surf.PolyColor.s.alpha = (strength*8); } else // Do TRANSMAP** fade. { - Surf.FlatColor.rgba = V_GetColor(color).rgba; - Surf.FlatColor.s.alpha = softwaretranstogl[strength]; + Surf.PolyColor.rgba = V_GetColor(color).rgba; + Surf.PolyColor.s.alpha = softwaretranstogl[strength]; } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -850,24 +839,22 @@ void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 ac v[0].y = v[1].y = fy; v[2].y = v[3].y = fy - fh; - //Hurdler: do we still use this argb color? if not, we should remove it - v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = 1.0f; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = 1.0f; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = 1.0f; + v[0].t = v[1].t = 0.0f; + v[2].t = v[3].t = 1.0f; if (actualcolor & 0xFF00) // Do COLORMAP fade. { - Surf.FlatColor.rgba = UINT2RGBA(0x01010160); - Surf.FlatColor.s.alpha = (strength*8); + Surf.PolyColor.rgba = UINT2RGBA(0x01010160); + Surf.PolyColor.s.alpha = (strength*8); } else // Do TRANSMAP** fade. { - Surf.FlatColor.rgba = V_GetColor(actualcolor).rgba; - Surf.FlatColor.s.alpha = softwaretranstogl[strength]; + Surf.PolyColor.rgba = V_GetColor(actualcolor).rgba; + Surf.PolyColor.s.alpha = softwaretranstogl[strength]; } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -888,13 +875,13 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height) v[2].y = v[3].y = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = 1.0f; - v[0].tow = v[1].tow = 1.0f; - v[2].tow = v[3].tow = 0.0f; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = 1.0f; + v[0].t = v[1].t = 1.0f; + v[2].t = v[3].t = 0.0f; - Surf.FlatColor.rgba = UINT2RGBA(color); - Surf.FlatColor.s.alpha = 0x80; + Surf.PolyColor.rgba = UINT2RGBA(color); + Surf.PolyColor.s.alpha = 0x80; HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -904,7 +891,11 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight) { FOutVector v[4]; FSurfaceInfo Surf; - INT32 height = (boxheight * 4) + (boxheight/2)*5; // 4 lines of space plus gaps between and some leeway + INT32 height; + if (boxheight < 0) + height = -boxheight; + else + height = (boxheight * 4) + (boxheight/2)*5; // 4 lines of space plus gaps between and some leeway // setup some neat-o translucency effect @@ -914,13 +905,13 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight) v[2].y = v[3].y = -1.0f+((height<<1)/(float)vid.height); v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = 1.0f; - v[0].tow = v[1].tow = 1.0f; - v[2].tow = v[3].tow = 0.0f; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = 1.0f; + v[0].t = v[1].t = 1.0f; + v[2].t = v[3].t = 0.0f; - Surf.FlatColor.rgba = UINT2RGBA(color); - Surf.FlatColor.s.alpha = (color == 0 ? 0xC0 : 0x80); // make black darker, like software + Surf.PolyColor.rgba = UINT2RGBA(color); + Surf.PolyColor.s.alpha = (color == 0 ? 0xC0 : 0x80); // make black darker, like software HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -1232,17 +1223,15 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 v[0].y = v[1].y = fy; v[2].y = v[3].y = fy - fh; - //Hurdler: do we still use this argb color? if not, we should remove it - v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = 1.0f; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = 1.0f; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = 1.0f; + v[0].t = v[1].t = 0.0f; + v[2].t = v[3].t = 1.0f; - Surf.FlatColor.rgba = UINT2RGBA(actualcolor); - Surf.FlatColor.s.alpha = 0x80; + Surf.PolyColor.rgba = UINT2RGBA(actualcolor); + Surf.PolyColor.s.alpha = 0x80; HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -1412,16 +1401,14 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) v[0].y = v[1].y = fy; v[2].y = v[3].y = fy - fh; - //Hurdler: do we still use this argb color? if not, we should remove it - v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = 1.0f; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = 1.0f; + v[0].s = v[3].s = 0.0f; + v[2].s = v[1].s = 1.0f; + v[0].t = v[1].t = 0.0f; + v[2].t = v[3].t = 1.0f; - Surf.FlatColor = V_GetColor(color); + Surf.PolyColor = V_GetColor(color); HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_NoTexture|PF_NoDepthTest); diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 3314fb015..2e4ea10cc 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -1,20 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_drv.h /// \brief imports/exports for the 3D hardware low-level interface API #ifndef __HWR_DRV_H__ @@ -32,7 +25,7 @@ // STANDARD DLL EXPORTS // ========================================================================== -EXPORT boolean HWRAPI(Init) (I_Error_t ErrorFunction); +EXPORT boolean HWRAPI(Init) (void); #ifndef HAVE_SDL EXPORT void HWRAPI(Shutdown) (void); #endif @@ -43,10 +36,12 @@ EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal); 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(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, UINT32 *IndexArray); 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); +EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -55,14 +50,11 @@ EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); //Hurdler: added for new development -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 *color); +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); -EXPORT INT32 HWRAPI(GetRenderVersion) (void); -#define SCREENVERTS 10 -EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); EXPORT void HWRAPI(FlushScreenTextures) (void); EXPORT void HWRAPI(StartScreenWipe) (void); EXPORT void HWRAPI(EndScreenWipe) (void); @@ -71,6 +63,20 @@ EXPORT void HWRAPI(DrawIntermissionBG) (void); EXPORT void HWRAPI(MakeScreenTexture) (void); EXPORT void HWRAPI(MakeScreenFinalTexture) (void); EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); + +#define SCREENVERTS 10 +EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); + +// jimita +EXPORT boolean HWRAPI(LoadShaders) (void); +EXPORT void HWRAPI(KillShaders) (void); +EXPORT void HWRAPI(SetShader) (int shader); +EXPORT void HWRAPI(UnSetShader) (void); + +EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); +EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment); +EXPORT boolean HWRAPI(InitCustomShaders) (void); + // ========================================================================== // HWR DRIVER OBJECT, FOR CLIENT PROGRAM // ========================================================================== @@ -84,10 +90,12 @@ struct hwdriver_s FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; + DrawIndexedTriangles pfnDrawIndexedTriangles; RenderSkyDome pfnRenderSkyDome; SetBlend pfnSetBlend; ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; + UpdateTexture pfnUpdateTexture; ReadRect pfnReadRect; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; @@ -96,7 +104,6 @@ struct hwdriver_s CreateModelVBOs pfnCreateModelVBOs; SetTransform pfnSetTransform; GetTextureUsed pfnGetTextureUsed; - GetRenderVersion pfnGetRenderVersion; #ifdef _WINDOWS GetModeList pfnGetModeList; #endif @@ -112,13 +119,19 @@ struct hwdriver_s MakeScreenTexture pfnMakeScreenTexture; MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; + + LoadShaders pfnLoadShaders; + KillShaders pfnKillShaders; + SetShader pfnSetShader; + UnSetShader pfnUnSetShader; + + SetShaderInfo pfnSetShaderInfo; + LoadCustomShader pfnLoadCustomShader; + InitCustomShaders pfnInitCustomShaders; }; extern struct hwdriver_s hwdriver; -//Hurdler: 16/10/99: added for OpenGL gamma correction -//extern RGBA_t gamma_correction; - #define HWD hwdriver #endif //not defined _CREATE_DLL_ diff --git a/src/hardware/hw_glide.h b/src/hardware/hw_glide.h index bf91229ef..d0eeebaeb 100644 --- a/src/hardware/hw_glide.h +++ b/src/hardware/hw_glide.h @@ -1,19 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_glide.h /// \brief Declaration needed by Glide renderer /// !!! To be replaced by our own def in the future !!! @@ -25,26 +18,6 @@ typedef unsigned long FxU32; typedef long FxI32; -typedef FxI32 GrAspectRatio_t; -#define GR_ASPECT_LOG2_8x1 3 /* 8W x 1H */ -#define GR_ASPECT_LOG2_4x1 2 /* 4W x 1H */ -#define GR_ASPECT_LOG2_2x1 1 /* 2W x 1H */ -#define GR_ASPECT_LOG2_1x1 0 /* 1W x 1H */ -#define GR_ASPECT_LOG2_1x2 -1 /* 1W x 2H */ -#define GR_ASPECT_LOG2_1x4 -2 /* 1W x 4H */ -#define GR_ASPECT_LOG2_1x8 -3 /* 1W x 8H */ - -typedef FxI32 GrLOD_t; -#define GR_LOD_LOG2_256 0x8 -#define GR_LOD_LOG2_128 0x7 -#define GR_LOD_LOG2_64 0x6 -#define GR_LOD_LOG2_32 0x5 -#define GR_LOD_LOG2_16 0x4 -#define GR_LOD_LOG2_8 0x3 -#define GR_LOD_LOG2_4 0x2 -#define GR_LOD_LOG2_2 0x1 -#define GR_LOD_LOG2_1 0x0 - typedef FxI32 GrTextureFormat_t; #define GR_TEXFMT_ALPHA_8 0x2 /* (0..0xFF) alpha */ #define GR_TEXFMT_INTENSITY_8 0x3 /* (0..0xFF) intensity */ @@ -59,11 +32,6 @@ typedef FxI32 GrTextureFormat_t; typedef struct { -#ifdef GLIDE_API_COMPATIBILITY - GrLOD_t smallLodLog2; - GrLOD_t largeLodLog2; - GrAspectRatio_t aspectRatioLog2; -#endif GrTextureFormat_t format; void *data; } GrTexInfo; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index a2bf79817..d8ea7c7a3 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -1,20 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_glob.h /// \brief globals (shared data & code) for hw_ modules #ifndef _HWR_GLOB_H_ @@ -68,9 +61,6 @@ typedef struct // equivalent of the software renderer's vissprites typedef struct gr_vissprite_s { - // Doubly linked list - struct gr_vissprite_s *prev; - struct gr_vissprite_s *next; float x1, x2; float tz, ty; //lumpnum_t patchlumpnum; @@ -118,11 +108,6 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum); // -------- // hw_draw.c // -------- -extern float gr_patch_scalex; -extern float gr_patch_scaley; - -extern consvar_t cv_grrounddown; // on/off - extern INT32 patchformat; extern INT32 textureformat; diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index c5af8d6d3..b2139d5ee 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -1,19 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_light.c /// \brief Corona/Dynamic/Static lighting add on by Hurdler /// !!! Under construction !!! @@ -298,6 +292,8 @@ light_t *t_lspr[NUMSPRITES] = // Projectiles &lspr[NOLIGHT], // SPR_MISL + &lspr[SMALLREDBALL_L], // SPR_LASR + &lspr[REDSHINE_L], // SPR_LASF &lspr[NOLIGHT], // SPR_TORP &lspr[NOLIGHT], // SPR_ENRG &lspr[NOLIGHT], // SPR_MINE @@ -877,19 +873,19 @@ void HWR_WallLighting(FOutVector *wlVerts) #endif for (i = 0; i < 4; i++) { - wlVerts[i].sow = (float)(0.5f + d[i]*s); - wlVerts[i].tow = (float)(0.5f + (wlVerts[i].y-LIGHT_POS(j).y)*s*1.2f); + wlVerts[i].s = (float)(0.5f + d[i]*s); + wlVerts[i].t = (float)(0.5f + (wlVerts[i].y-LIGHT_POS(j).y)*s*1.2f); } HWR_SetLight(); - Surf.FlatColor.rgba = LONG(dynlights->p_lspr[j]->dynamic_color); + Surf.PolyColor.rgba = LONG(dynlights->p_lspr[j]->dynamic_color); #ifdef DL_HIGH_QUALITY - Surf.FlatColor.s.alpha = (UINT8)((1-dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha); + Surf.PolyColor.s.alpha = (UINT8)((1-dist_p2d/DL_SQRRADIUS(j))*Surf.PolyColor.s.alpha); #endif // next state is null so fade out with alpha if (dynlights->mo[j]->state->nextstate == S_NULL) - Surf.FlatColor.s.alpha = (UINT8)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha); + Surf.PolyColor.s.alpha = (UINT8)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.PolyColor.s.alpha); HWD.pfnDrawPolygon (&Surf, wlVerts, 4, LIGHTMAPFLAGS); @@ -946,19 +942,19 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts) #endif for (i = 0; i < nrClipVerts; i++) { - clVerts[i].sow = 0.5f + (clVerts[i].x-LIGHT_POS(j).x)*s; - clVerts[i].tow = 0.5f + (clVerts[i].z-LIGHT_POS(j).z)*s*1.2f; + clVerts[i].s = 0.5f + (clVerts[i].x-LIGHT_POS(j).x)*s; + clVerts[i].t = 0.5f + (clVerts[i].z-LIGHT_POS(j).z)*s*1.2f; } HWR_SetLight(); - Surf.FlatColor.rgba = LONG(dynlights->p_lspr[j]->dynamic_color); + Surf.PolyColor.rgba = LONG(dynlights->p_lspr[j]->dynamic_color); #ifdef DL_HIGH_QUALITY - Surf.FlatColor.s.alpha = (unsigned char)((1 - dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha); + Surf.PolyColor.s.alpha = (unsigned char)((1 - dist_p2d/DL_SQRRADIUS(j))*Surf.PolyColor.s.alpha); #endif // next state is null so fade out with alpha if ((dynlights->mo[j]->state->nextstate == S_NULL)) - Surf.FlatColor.s.alpha = (unsigned char)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha); + Surf.PolyColor.s.alpha = (unsigned char)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.PolyColor.s.alpha); HWD.pfnDrawPolygon (&Surf, clVerts, nrClipVerts, LIGHTMAPFLAGS); @@ -1025,11 +1021,11 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gr_vissprite_t *spr) // more realistique corona ! if (cz >= 255*8+250) return; - Surf.FlatColor.rgba = p_lspr->corona_color; + Surf.PolyColor.rgba = p_lspr->corona_color; if (cz > 250.0f) - Surf.FlatColor.s.alpha = 0xff-((int)cz-250)/8; + Surf.PolyColor.s.alpha = 0xff-((int)cz-250)/8; else - Surf.FlatColor.s.alpha = 0xff; + Surf.PolyColor.s.alpha = 0xff; // do not be hide by sprite of the light itself ! cz = cz - 2.0f; @@ -1041,19 +1037,19 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gr_vissprite_t *spr) // car comme l'offset est minime sa ce voit pas ! light[0].x = cx-size; light[0].z = cz; light[0].y = cy-size*1.33f+p_lspr->light_yoffset; - light[0].sow = 0.0f; light[0].tow = 0.0f; + light[0].s = 0.0f; light[0].t = 0.0f; light[1].x = cx+size; light[1].z = cz; light[1].y = cy-size*1.33f+p_lspr->light_yoffset; - light[1].sow = 1.0f; light[1].tow = 0.0f; + light[1].s = 1.0f; light[1].t = 0.0f; light[2].x = cx+size; light[2].z = cz; light[2].y = cy+size*1.33f+p_lspr->light_yoffset; - light[2].sow = 1.0f; light[2].tow = 1.0f; + light[2].s = 1.0f; light[2].t = 1.0f; light[3].x = cx-size; light[3].z = cz; light[3].y = cy+size*1.33f+p_lspr->light_yoffset; - light[3].sow = 0.0f; light[3].tow = 1.0f; + light[3].s = 0.0f; light[3].t = 1.0f; HWR_GetPic(coronalumpnum); /// \todo use different coronas @@ -1099,11 +1095,11 @@ void HWR_DrawCoronas(void) // more realistique corona ! if (cz >= 255*8+250) continue; - Surf.FlatColor.rgba = p_lspr->corona_color; + Surf.PolyColor.rgba = p_lspr->corona_color; if (cz > 250.0f) - Surf.FlatColor.s.alpha = (UINT8)(0xff-(UINT8)(((int)cz-250)/8)); + Surf.PolyColor.s.alpha = (UINT8)(0xff-(UINT8)(((int)cz-250)/8)); else - Surf.FlatColor.s.alpha = 0xff; + Surf.PolyColor.s.alpha = 0xff; switch (p_lspr->type) { @@ -1111,7 +1107,7 @@ void HWR_DrawCoronas(void) size = p_lspr->corona_radius * ((cz+120.0f)/950.0f); // d'ou vienne ces constante ? break; case ROCKET_SPR: - Surf.FlatColor.s.alpha = (UINT8)((M_RandomByte()>>1)&0xff); + Surf.PolyColor.s.alpha = (UINT8)((M_RandomByte()>>1)&0xff); // don't need a break case CORONA_SPR: size = p_lspr->corona_radius * ((cz+60.0f)/100.0f); // d'ou vienne ces constante ? @@ -1131,19 +1127,19 @@ void HWR_DrawCoronas(void) light[0].x = cx-size; light[0].z = cz; light[0].y = cy-size*1.33f; - light[0].sow = 0.0f; light[0].tow = 0.0f; + light[0].s = 0.0f; light[0].t = 0.0f; light[1].x = cx+size; light[1].z = cz; light[1].y = cy-size*1.33f; - light[1].sow = 1.0f; light[1].tow = 0.0f; + light[1].s = 1.0f; light[1].t = 0.0f; light[2].x = cx+size; light[2].z = cz; light[2].y = cy+size*1.33f; - light[2].sow = 1.0f; light[2].tow = 1.0f; + light[2].s = 1.0f; light[2].t = 1.0f; light[3].x = cx-size; light[3].z = cz; light[3].y = cy+size*1.33f; - light[3].sow = 0.0f; light[3].tow = 1.0f; + light[3].s = 0.0f; light[3].t = 1.0f; HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Clip | PF_NoDepthTest | PF_Corona); } @@ -1252,11 +1248,6 @@ static void HWR_SetLight(void) lightmappatch.height = 128; lightmappatch.mipmap->width = 128; lightmappatch.mipmap->height = 128; -#ifdef GLIDE_API_COMPATIBILITY - lightmappatch.mipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_128; - lightmappatch.mipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_128; - lightmappatch.mipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; -#endif lightmappatch.mipmap->flags = 0; //TF_WRAPXY; // DEBUG: view the overdraw ! } HWD.pfnSetTexture(lightmappatch.mipmap); diff --git a/src/hardware/hw_light.h b/src/hardware/hw_light.h index 2733cc698..3b12f9c87 100644 --- a/src/hardware/hw_light.h +++ b/src/hardware/hw_light.h @@ -1,19 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_light.h /// \brief Dynamic lighting & coronas add on by Hurdler #ifndef _HW_LIGHTS_ diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index efed9b602..455985ddf 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1,19 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_main.c /// \brief hardware renderer, using the standard HardWareRender driver DLL for SRB2 #include @@ -24,6 +18,7 @@ #include "hw_glob.h" #include "hw_light.h" #include "hw_drv.h" +#include "hw_batching.h" #include "../i_video.h" // for rendermode == render_glide #include "../v_video.h" @@ -42,9 +37,7 @@ #include "../m_cheat.h" #include "../f_finale.h" #include "../r_things.h" // R_GetShadowZ -#ifdef ESLOPE #include "../p_slopes.h" -#endif #include "hw_md2.h" #ifdef NEWCLIP @@ -53,7 +46,6 @@ #define R_FAKEFLOORS #define HWPRECIP -#define SORTING //#define POLYSKY // ========================================================================== @@ -72,175 +64,12 @@ static void HWR_ProjectSprite(mobj_t *thing); static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); #endif -#ifdef SORTING -void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, - INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); +void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap); -#else -static void HWR_Add3DWater(levelflat_t *levelflat, extrasubsector_t *xsub, fixed_t fixedheight, - INT32 lightlevel, INT32 alpha, sector_t *FOFSector); -static void HWR_Render3DWater(void); -static void HWR_RenderTransparentWalls(void); -#endif -static void HWR_FoggingOn(void); -static UINT32 atohex(const char *s); boolean drawsky = true; -/* - * lookuptable for lightvalues - * calculated as follow: - * floatlight = (1.0-exp((light^3)*gamma)) / (1.0-exp(1.0*gamma)); - * gamma=-0,2;-2,0;-4,0;-6,0;-8,0 - * light = 0,0 .. 1,0 - */ -static const float lighttable[5][256] = -{ - { - 0.00000f,0.00000f,0.00000f,0.00000f,0.00000f,0.00001f,0.00001f,0.00002f,0.00003f,0.00004f, - 0.00006f,0.00008f,0.00010f,0.00013f,0.00017f,0.00020f,0.00025f,0.00030f,0.00035f,0.00041f, - 0.00048f,0.00056f,0.00064f,0.00073f,0.00083f,0.00094f,0.00106f,0.00119f,0.00132f,0.00147f, - 0.00163f,0.00180f,0.00198f,0.00217f,0.00237f,0.00259f,0.00281f,0.00305f,0.00331f,0.00358f, - 0.00386f,0.00416f,0.00447f,0.00479f,0.00514f,0.00550f,0.00587f,0.00626f,0.00667f,0.00710f, - 0.00754f,0.00800f,0.00848f,0.00898f,0.00950f,0.01003f,0.01059f,0.01117f,0.01177f,0.01239f, - 0.01303f,0.01369f,0.01437f,0.01508f,0.01581f,0.01656f,0.01734f,0.01814f,0.01896f,0.01981f, - 0.02069f,0.02159f,0.02251f,0.02346f,0.02444f,0.02544f,0.02647f,0.02753f,0.02862f,0.02973f, - 0.03088f,0.03205f,0.03325f,0.03448f,0.03575f,0.03704f,0.03836f,0.03971f,0.04110f,0.04252f, - 0.04396f,0.04545f,0.04696f,0.04851f,0.05009f,0.05171f,0.05336f,0.05504f,0.05676f,0.05852f, - 0.06031f,0.06214f,0.06400f,0.06590f,0.06784f,0.06981f,0.07183f,0.07388f,0.07597f,0.07810f, - 0.08027f,0.08248f,0.08473f,0.08702f,0.08935f,0.09172f,0.09414f,0.09659f,0.09909f,0.10163f, - 0.10421f,0.10684f,0.10951f,0.11223f,0.11499f,0.11779f,0.12064f,0.12354f,0.12648f,0.12946f, - 0.13250f,0.13558f,0.13871f,0.14188f,0.14511f,0.14838f,0.15170f,0.15507f,0.15850f,0.16197f, - 0.16549f,0.16906f,0.17268f,0.17635f,0.18008f,0.18386f,0.18769f,0.19157f,0.19551f,0.19950f, - 0.20354f,0.20764f,0.21179f,0.21600f,0.22026f,0.22458f,0.22896f,0.23339f,0.23788f,0.24242f, - 0.24702f,0.25168f,0.25640f,0.26118f,0.26602f,0.27091f,0.27587f,0.28089f,0.28596f,0.29110f, - 0.29630f,0.30156f,0.30688f,0.31226f,0.31771f,0.32322f,0.32879f,0.33443f,0.34013f,0.34589f, - 0.35172f,0.35761f,0.36357f,0.36960f,0.37569f,0.38185f,0.38808f,0.39437f,0.40073f,0.40716f, - 0.41366f,0.42022f,0.42686f,0.43356f,0.44034f,0.44718f,0.45410f,0.46108f,0.46814f,0.47527f, - 0.48247f,0.48974f,0.49709f,0.50451f,0.51200f,0.51957f,0.52721f,0.53492f,0.54271f,0.55058f, - 0.55852f,0.56654f,0.57463f,0.58280f,0.59105f,0.59937f,0.60777f,0.61625f,0.62481f,0.63345f, - 0.64217f,0.65096f,0.65984f,0.66880f,0.67783f,0.68695f,0.69615f,0.70544f,0.71480f,0.72425f, - 0.73378f,0.74339f,0.75308f,0.76286f,0.77273f,0.78268f,0.79271f,0.80283f,0.81304f,0.82333f, - 0.83371f,0.84417f,0.85472f,0.86536f,0.87609f,0.88691f,0.89781f,0.90880f,0.91989f,0.93106f, - 0.94232f,0.95368f,0.96512f,0.97665f,0.98828f,1.00000f - }, - { - 0.00000f,0.00000f,0.00000f,0.00000f,0.00001f,0.00002f,0.00003f,0.00005f,0.00007f,0.00010f, - 0.00014f,0.00019f,0.00024f,0.00031f,0.00038f,0.00047f,0.00057f,0.00069f,0.00081f,0.00096f, - 0.00112f,0.00129f,0.00148f,0.00170f,0.00193f,0.00218f,0.00245f,0.00274f,0.00306f,0.00340f, - 0.00376f,0.00415f,0.00456f,0.00500f,0.00547f,0.00597f,0.00649f,0.00704f,0.00763f,0.00825f, - 0.00889f,0.00957f,0.01029f,0.01104f,0.01182f,0.01264f,0.01350f,0.01439f,0.01532f,0.01630f, - 0.01731f,0.01836f,0.01945f,0.02058f,0.02176f,0.02298f,0.02424f,0.02555f,0.02690f,0.02830f, - 0.02974f,0.03123f,0.03277f,0.03436f,0.03600f,0.03768f,0.03942f,0.04120f,0.04304f,0.04493f, - 0.04687f,0.04886f,0.05091f,0.05301f,0.05517f,0.05738f,0.05964f,0.06196f,0.06434f,0.06677f, - 0.06926f,0.07181f,0.07441f,0.07707f,0.07979f,0.08257f,0.08541f,0.08831f,0.09126f,0.09428f, - 0.09735f,0.10048f,0.10368f,0.10693f,0.11025f,0.11362f,0.11706f,0.12056f,0.12411f,0.12773f, - 0.13141f,0.13515f,0.13895f,0.14281f,0.14673f,0.15072f,0.15476f,0.15886f,0.16303f,0.16725f, - 0.17153f,0.17587f,0.18028f,0.18474f,0.18926f,0.19383f,0.19847f,0.20316f,0.20791f,0.21272f, - 0.21759f,0.22251f,0.22748f,0.23251f,0.23760f,0.24274f,0.24793f,0.25318f,0.25848f,0.26383f, - 0.26923f,0.27468f,0.28018f,0.28573f,0.29133f,0.29697f,0.30266f,0.30840f,0.31418f,0.32001f, - 0.32588f,0.33179f,0.33774f,0.34374f,0.34977f,0.35585f,0.36196f,0.36810f,0.37428f,0.38050f, - 0.38675f,0.39304f,0.39935f,0.40570f,0.41207f,0.41847f,0.42490f,0.43136f,0.43784f,0.44434f, - 0.45087f,0.45741f,0.46398f,0.47057f,0.47717f,0.48379f,0.49042f,0.49707f,0.50373f,0.51041f, - 0.51709f,0.52378f,0.53048f,0.53718f,0.54389f,0.55061f,0.55732f,0.56404f,0.57075f,0.57747f, - 0.58418f,0.59089f,0.59759f,0.60429f,0.61097f,0.61765f,0.62432f,0.63098f,0.63762f,0.64425f, - 0.65086f,0.65746f,0.66404f,0.67060f,0.67714f,0.68365f,0.69015f,0.69662f,0.70307f,0.70948f, - 0.71588f,0.72224f,0.72857f,0.73488f,0.74115f,0.74739f,0.75359f,0.75976f,0.76589f,0.77199f, - 0.77805f,0.78407f,0.79005f,0.79599f,0.80189f,0.80774f,0.81355f,0.81932f,0.82504f,0.83072f, - 0.83635f,0.84194f,0.84747f,0.85296f,0.85840f,0.86378f,0.86912f,0.87441f,0.87964f,0.88482f, - 0.88995f,0.89503f,0.90005f,0.90502f,0.90993f,0.91479f,0.91959f,0.92434f,0.92903f,0.93366f, - 0.93824f,0.94276f,0.94723f,0.95163f,0.95598f,0.96027f,0.96451f,0.96868f,0.97280f,0.97686f, - 0.98086f,0.98481f,0.98869f,0.99252f,0.99629f,1.00000f - }, - { - 0.00000f,0.00000f,0.00000f,0.00001f,0.00002f,0.00003f,0.00005f,0.00008f,0.00013f,0.00018f, - 0.00025f,0.00033f,0.00042f,0.00054f,0.00067f,0.00083f,0.00101f,0.00121f,0.00143f,0.00168f, - 0.00196f,0.00227f,0.00261f,0.00299f,0.00339f,0.00383f,0.00431f,0.00483f,0.00538f,0.00598f, - 0.00661f,0.00729f,0.00802f,0.00879f,0.00961f,0.01048f,0.01140f,0.01237f,0.01340f,0.01447f, - 0.01561f,0.01680f,0.01804f,0.01935f,0.02072f,0.02215f,0.02364f,0.02520f,0.02682f,0.02850f, - 0.03026f,0.03208f,0.03397f,0.03594f,0.03797f,0.04007f,0.04225f,0.04451f,0.04684f,0.04924f, - 0.05172f,0.05428f,0.05691f,0.05963f,0.06242f,0.06530f,0.06825f,0.07129f,0.07441f,0.07761f, - 0.08089f,0.08426f,0.08771f,0.09125f,0.09487f,0.09857f,0.10236f,0.10623f,0.11019f,0.11423f, - 0.11836f,0.12257f,0.12687f,0.13125f,0.13571f,0.14027f,0.14490f,0.14962f,0.15442f,0.15931f, - 0.16427f,0.16932f,0.17445f,0.17966f,0.18496f,0.19033f,0.19578f,0.20130f,0.20691f,0.21259f, - 0.21834f,0.22417f,0.23007f,0.23605f,0.24209f,0.24820f,0.25438f,0.26063f,0.26694f,0.27332f, - 0.27976f,0.28626f,0.29282f,0.29944f,0.30611f,0.31284f,0.31962f,0.32646f,0.33334f,0.34027f, - 0.34724f,0.35426f,0.36132f,0.36842f,0.37556f,0.38273f,0.38994f,0.39718f,0.40445f,0.41174f, - 0.41907f,0.42641f,0.43378f,0.44116f,0.44856f,0.45598f,0.46340f,0.47084f,0.47828f,0.48573f, - 0.49319f,0.50064f,0.50809f,0.51554f,0.52298f,0.53042f,0.53784f,0.54525f,0.55265f,0.56002f, - 0.56738f,0.57472f,0.58203f,0.58932f,0.59658f,0.60381f,0.61101f,0.61817f,0.62529f,0.63238f, - 0.63943f,0.64643f,0.65339f,0.66031f,0.66717f,0.67399f,0.68075f,0.68746f,0.69412f,0.70072f, - 0.70726f,0.71375f,0.72017f,0.72653f,0.73282f,0.73905f,0.74522f,0.75131f,0.75734f,0.76330f, - 0.76918f,0.77500f,0.78074f,0.78640f,0.79199f,0.79751f,0.80295f,0.80831f,0.81359f,0.81880f, - 0.82393f,0.82898f,0.83394f,0.83883f,0.84364f,0.84836f,0.85301f,0.85758f,0.86206f,0.86646f, - 0.87078f,0.87502f,0.87918f,0.88326f,0.88726f,0.89118f,0.89501f,0.89877f,0.90245f,0.90605f, - 0.90957f,0.91301f,0.91638f,0.91966f,0.92288f,0.92601f,0.92908f,0.93206f,0.93498f,0.93782f, - 0.94059f,0.94329f,0.94592f,0.94848f,0.95097f,0.95339f,0.95575f,0.95804f,0.96027f,0.96244f, - 0.96454f,0.96658f,0.96856f,0.97049f,0.97235f,0.97416f,0.97591f,0.97760f,0.97924f,0.98083f, - 0.98237f,0.98386f,0.98530f,0.98669f,0.98803f,0.98933f,0.99058f,0.99179f,0.99295f,0.99408f, - 0.99516f,0.99620f,0.99721f,0.99817f,0.99910f,1.00000f - }, - { - 0.00000f,0.00000f,0.00000f,0.00001f,0.00002f,0.00005f,0.00008f,0.00012f,0.00019f,0.00026f, - 0.00036f,0.00048f,0.00063f,0.00080f,0.00099f,0.00122f,0.00148f,0.00178f,0.00211f,0.00249f, - 0.00290f,0.00335f,0.00386f,0.00440f,0.00500f,0.00565f,0.00636f,0.00711f,0.00793f,0.00881f, - 0.00975f,0.01075f,0.01182f,0.01295f,0.01416f,0.01543f,0.01678f,0.01821f,0.01971f,0.02129f, - 0.02295f,0.02469f,0.02652f,0.02843f,0.03043f,0.03252f,0.03469f,0.03696f,0.03933f,0.04178f, - 0.04433f,0.04698f,0.04973f,0.05258f,0.05552f,0.05857f,0.06172f,0.06498f,0.06834f,0.07180f, - 0.07537f,0.07905f,0.08283f,0.08672f,0.09072f,0.09483f,0.09905f,0.10337f,0.10781f,0.11236f, - 0.11701f,0.12178f,0.12665f,0.13163f,0.13673f,0.14193f,0.14724f,0.15265f,0.15817f,0.16380f, - 0.16954f,0.17538f,0.18132f,0.18737f,0.19351f,0.19976f,0.20610f,0.21255f,0.21908f,0.22572f, - 0.23244f,0.23926f,0.24616f,0.25316f,0.26023f,0.26739f,0.27464f,0.28196f,0.28935f,0.29683f, - 0.30437f,0.31198f,0.31966f,0.32740f,0.33521f,0.34307f,0.35099f,0.35896f,0.36699f,0.37506f, - 0.38317f,0.39133f,0.39952f,0.40775f,0.41601f,0.42429f,0.43261f,0.44094f,0.44929f,0.45766f, - 0.46604f,0.47443f,0.48283f,0.49122f,0.49962f,0.50801f,0.51639f,0.52476f,0.53312f,0.54146f, - 0.54978f,0.55807f,0.56633f,0.57457f,0.58277f,0.59093f,0.59905f,0.60713f,0.61516f,0.62314f, - 0.63107f,0.63895f,0.64676f,0.65452f,0.66221f,0.66984f,0.67739f,0.68488f,0.69229f,0.69963f, - 0.70689f,0.71407f,0.72117f,0.72818f,0.73511f,0.74195f,0.74870f,0.75536f,0.76192f,0.76839f, - 0.77477f,0.78105f,0.78723f,0.79331f,0.79930f,0.80518f,0.81096f,0.81664f,0.82221f,0.82768f, - 0.83305f,0.83832f,0.84347f,0.84853f,0.85348f,0.85832f,0.86306f,0.86770f,0.87223f,0.87666f, - 0.88098f,0.88521f,0.88933f,0.89334f,0.89726f,0.90108f,0.90480f,0.90842f,0.91194f,0.91537f, - 0.91870f,0.92193f,0.92508f,0.92813f,0.93109f,0.93396f,0.93675f,0.93945f,0.94206f,0.94459f, - 0.94704f,0.94941f,0.95169f,0.95391f,0.95604f,0.95810f,0.96009f,0.96201f,0.96386f,0.96564f, - 0.96735f,0.96900f,0.97059f,0.97212f,0.97358f,0.97499f,0.97634f,0.97764f,0.97888f,0.98007f, - 0.98122f,0.98231f,0.98336f,0.98436f,0.98531f,0.98623f,0.98710f,0.98793f,0.98873f,0.98949f, - 0.99021f,0.99090f,0.99155f,0.99218f,0.99277f,0.99333f,0.99387f,0.99437f,0.99486f,0.99531f, - 0.99575f,0.99616f,0.99654f,0.99691f,0.99726f,0.99759f,0.99790f,0.99819f,0.99847f,0.99873f, - 0.99897f,0.99920f,0.99942f,0.99963f,0.99982f,1.00000f - }, - { - 0.00000f,0.00000f,0.00000f,0.00001f,0.00003f,0.00006f,0.00010f,0.00017f,0.00025f,0.00035f, - 0.00048f,0.00064f,0.00083f,0.00106f,0.00132f,0.00163f,0.00197f,0.00237f,0.00281f,0.00330f, - 0.00385f,0.00446f,0.00513f,0.00585f,0.00665f,0.00751f,0.00845f,0.00945f,0.01054f,0.01170f, - 0.01295f,0.01428f,0.01569f,0.01719f,0.01879f,0.02048f,0.02227f,0.02415f,0.02614f,0.02822f, - 0.03042f,0.03272f,0.03513f,0.03765f,0.04028f,0.04303f,0.04589f,0.04887f,0.05198f,0.05520f, - 0.05855f,0.06202f,0.06561f,0.06933f,0.07318f,0.07716f,0.08127f,0.08550f,0.08987f,0.09437f, - 0.09900f,0.10376f,0.10866f,0.11369f,0.11884f,0.12414f,0.12956f,0.13512f,0.14080f,0.14662f, - 0.15257f,0.15865f,0.16485f,0.17118f,0.17764f,0.18423f,0.19093f,0.19776f,0.20471f,0.21177f, - 0.21895f,0.22625f,0.23365f,0.24117f,0.24879f,0.25652f,0.26435f,0.27228f,0.28030f,0.28842f, - 0.29662f,0.30492f,0.31329f,0.32175f,0.33028f,0.33889f,0.34756f,0.35630f,0.36510f,0.37396f, - 0.38287f,0.39183f,0.40084f,0.40989f,0.41897f,0.42809f,0.43723f,0.44640f,0.45559f,0.46479f, - 0.47401f,0.48323f,0.49245f,0.50167f,0.51088f,0.52008f,0.52927f,0.53843f,0.54757f,0.55668f, - 0.56575f,0.57479f,0.58379f,0.59274f,0.60164f,0.61048f,0.61927f,0.62799f,0.63665f,0.64524f, - 0.65376f,0.66220f,0.67056f,0.67883f,0.68702f,0.69511f,0.70312f,0.71103f,0.71884f,0.72655f, - 0.73415f,0.74165f,0.74904f,0.75632f,0.76348f,0.77053f,0.77747f,0.78428f,0.79098f,0.79756f, - 0.80401f,0.81035f,0.81655f,0.82264f,0.82859f,0.83443f,0.84013f,0.84571f,0.85117f,0.85649f, - 0.86169f,0.86677f,0.87172f,0.87654f,0.88124f,0.88581f,0.89026f,0.89459f,0.89880f,0.90289f, - 0.90686f,0.91071f,0.91445f,0.91807f,0.92157f,0.92497f,0.92826f,0.93143f,0.93450f,0.93747f, - 0.94034f,0.94310f,0.94577f,0.94833f,0.95081f,0.95319f,0.95548f,0.95768f,0.95980f,0.96183f, - 0.96378f,0.96565f,0.96744f,0.96916f,0.97081f,0.97238f,0.97388f,0.97532f,0.97669f,0.97801f, - 0.97926f,0.98045f,0.98158f,0.98266f,0.98369f,0.98467f,0.98560f,0.98648f,0.98732f,0.98811f, - 0.98886f,0.98958f,0.99025f,0.99089f,0.99149f,0.99206f,0.99260f,0.99311f,0.99359f,0.99404f, - 0.99446f,0.99486f,0.99523f,0.99559f,0.99592f,0.99623f,0.99652f,0.99679f,0.99705f,0.99729f, - 0.99751f,0.99772f,0.99792f,0.99810f,0.99827f,0.99843f,0.99857f,0.99871f,0.99884f,0.99896f, - 0.99907f,0.99917f,0.99926f,0.99935f,0.99943f,0.99951f,0.99958f,0.99964f,0.99970f,0.99975f, - 0.99980f,0.99985f,0.99989f,0.99993f,0.99997f,1.00000f - } -}; - -#define gld_CalcLightLevel(lightlevel) (lighttable[1][max(min((lightlevel),255),0)]) - // ========================================================================== // VIEW GLOBALS // ========================================================================== @@ -313,153 +142,199 @@ static float gr_viewsin, gr_viewcos; static float gr_viewludsin, gr_viewludcos; // look up down kik test static float gr_fovlud; +static angle_t gr_aimingangle; +static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); + +// Render stats +int rs_hw_nodesorttime = 0; +int rs_hw_nodedrawtime = 0; +int rs_hw_spritesorttime = 0; +int rs_hw_spritedrawtime = 0; + +// Render stats for batching +int rs_hw_numpolys = 0; +int rs_hw_numverts = 0; +int rs_hw_numcalls = 0; +int rs_hw_numshaders = 0; +int rs_hw_numtextures = 0; +int rs_hw_numpolyflags = 0; +int rs_hw_numcolors = 0; +int rs_hw_batchsorttime = 0; +int rs_hw_batchdrawtime = 0; + +boolean gr_shadersavailable = true; + + // ========================================================================== -// LIGHT stuffs +// Lighting // ========================================================================== -static UINT8 lightleveltonumlut[256]; - -// added to SRB2's sector lightlevel to make things a bit brighter (sprites/walls/planes) -FUNCMATH UINT8 LightLevelToLum(INT32 l) +void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap) { - return (UINT8)(255*gld_CalcLightLevel(l)); + RGBA_t poly_color, tint_color, fade_color; + + poly_color.rgba = 0xFFFFFFFF; + tint_color.rgba = (colormap != NULL) ? (UINT32)colormap->rgba : GL_DEFAULTMIX; + fade_color.rgba = (colormap != NULL) ? (UINT32)colormap->fadergba : GL_DEFAULTFOG; + + // Crappy backup coloring if you can't do shaders + if (!cv_grshaders.value || !gr_shadersavailable) + { + // be careful, this may get negative for high lightlevel values. + float tint_alpha, fade_alpha; + float red, green, blue; + + red = (float)poly_color.s.red; + green = (float)poly_color.s.green; + blue = (float)poly_color.s.blue; + + // 48 is just an arbritrary value that looked relatively okay. + tint_alpha = (float)(sqrt(tint_color.s.alpha) * 48) / 255.0f; + + // 8 is roughly the brightness of the "close" color in Software, and 16 the brightness of the "far" color. + // 8 is too bright for dark levels, and 16 is too dark for bright levels. + // 12 is the compromise value. It doesn't look especially good anywhere, but it's the most balanced. + // (Also, as far as I can tell, fade_color's alpha is actually not used in Software, so we only use light level.) + fade_alpha = (float)(sqrt(255-light_level) * 12) / 255.0f; + + // Clamp the alpha values + tint_alpha = min(max(tint_alpha, 0.0f), 1.0f); + fade_alpha = min(max(fade_alpha, 0.0f), 1.0f); + + red = (tint_color.s.red * tint_alpha) + (red * (1.0f - tint_alpha)); + green = (tint_color.s.green * tint_alpha) + (green * (1.0f - tint_alpha)); + blue = (tint_color.s.blue * tint_alpha) + (blue * (1.0f - tint_alpha)); + + red = (fade_color.s.red * fade_alpha) + (red * (1.0f - fade_alpha)); + green = (fade_color.s.green * fade_alpha) + (green * (1.0f - fade_alpha)); + blue = (fade_color.s.blue * fade_alpha) + (blue * (1.0f - fade_alpha)); + + poly_color.s.red = (UINT8)red; + poly_color.s.green = (UINT8)green; + poly_color.s.blue = (UINT8)blue; + } + + Surface->PolyColor.rgba = poly_color.rgba; + Surface->TintColor.rgba = tint_color.rgba; + Surface->FadeColor.rgba = fade_color.rgba; + Surface->LightInfo.light_level = light_level; + Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0; + Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31; } -static inline void InitLumLut(void) -{ - INT32 i, k = 0; - for (i = 0; i < 256; i++) - { - if (i > 128) - k += 2; - else - k = 1; - lightleveltonumlut[i] = (UINT8)(k); - } -} - -//#define FOGFACTOR 300 //was 600 >> Covered by cv_grfogdensity -#define NORMALFOG 0x00000000 -#define FADEFOG 0x19000000 -#define CALCFOGDENSITY(x) ((float)((5220.0f*(1.0f/((x)/41.0f+1.0f)))-(5220.0f*(1.0f/(255.0f/41.0f+1.0f))))) // Approximate fog calculation based off of software walls -#define CALCFOGDENSITYFLOOR(x) ((float)((40227.0f*(1.0f/((x)/11.0f+1.0f)))-(40227.0f*(1.0f/(255.0f/11.0f+1.0f))))) // Approximate fog calculation based off of software floors -#define CALCLIGHT(x,y) ((float)(x)*((y)/255.0f)) -UINT32 HWR_Lighting(INT32 light, UINT32 color, UINT32 fadecolor, boolean fogblockpoly, boolean plane) -{ - RGBA_t realcolor, fogcolor, surfcolor; - INT32 alpha, fogalpha; - - (void)fogblockpoly; - - // Don't go out of bounds - if (light < 0) - light = 0; - else if (light > 255) - light = 255; - - realcolor.rgba = color; - fogcolor.rgba = fadecolor; - - alpha = (realcolor.s.alpha*255)/25; - fogalpha = (fogcolor.s.alpha*255)/25; - - if (cv_grfog.value && cv_grsoftwarefog.value) // Only do this when fog is on, software fog mode is on, and the poly is not from a fog block - { - // Modulate the colors by alpha. - realcolor.s.red = (UINT8)(CALCLIGHT(alpha,realcolor.s.red)); - realcolor.s.green = (UINT8)(CALCLIGHT(alpha,realcolor.s.green)); - realcolor.s.blue = (UINT8)(CALCLIGHT(alpha,realcolor.s.blue)); - - // Set the surface colors and further modulate the colors by light. - surfcolor.s.red = (UINT8)(CALCLIGHT((0xFF-alpha),255)+CALCLIGHT(realcolor.s.red,255)); - surfcolor.s.green = (UINT8)(CALCLIGHT((0xFF-alpha),255)+CALCLIGHT(realcolor.s.green,255)); - surfcolor.s.blue = (UINT8)(CALCLIGHT((0xFF-alpha),255)+CALCLIGHT(realcolor.s.blue,255)); - surfcolor.s.alpha = 0xFF; - - // Modulate the colors by alpha. - fogcolor.s.red = (UINT8)(CALCLIGHT(fogalpha,fogcolor.s.red)); - fogcolor.s.green = (UINT8)(CALCLIGHT(fogalpha,fogcolor.s.green)); - fogcolor.s.blue = (UINT8)(CALCLIGHT(fogalpha,fogcolor.s.blue)); - } - else - { - // Modulate the colors by alpha. - realcolor.s.red = (UINT8)(CALCLIGHT(alpha,realcolor.s.red)); - realcolor.s.green = (UINT8)(CALCLIGHT(alpha,realcolor.s.green)); - realcolor.s.blue = (UINT8)(CALCLIGHT(alpha,realcolor.s.blue)); - - // Set the surface colors and further modulate the colors by light. - surfcolor.s.red = (UINT8)(CALCLIGHT((0xFF-alpha),light)+CALCLIGHT(realcolor.s.red,light)); - surfcolor.s.green = (UINT8)(CALCLIGHT((0xFF-alpha),light)+CALCLIGHT(realcolor.s.green,light)); - surfcolor.s.blue = (UINT8)(CALCLIGHT((0xFF-alpha),light)+CALCLIGHT(realcolor.s.blue,light)); - - // Modulate the colors by alpha. - fogcolor.s.red = (UINT8)(CALCLIGHT(fogalpha,fogcolor.s.red)); - fogcolor.s.green = (UINT8)(CALCLIGHT(fogalpha,fogcolor.s.green)); - fogcolor.s.blue = (UINT8)(CALCLIGHT(fogalpha,fogcolor.s.blue)); - - // Set the surface colors and further modulate the colors by light. - surfcolor.s.red = surfcolor.s.red+((UINT8)(CALCLIGHT((0xFF-fogalpha),(255-light))+CALCLIGHT(fogcolor.s.red,(255-light)))); - surfcolor.s.green = surfcolor.s.green+((UINT8)(CALCLIGHT((0xFF-fogalpha),(255-light))+CALCLIGHT(fogcolor.s.green,(255-light)))); - surfcolor.s.blue = surfcolor.s.blue+((UINT8)(CALCLIGHT((0xFF-fogalpha),(255-light))+CALCLIGHT(fogcolor.s.blue,(255-light)))); - surfcolor.s.alpha = 0xFF; - } - - if(cv_grfog.value) - { - if (cv_grsoftwarefog.value) - { - fogcolor.s.red = (UINT8)((CALCLIGHT(fogcolor.s.red,(255-light)))+(CALCLIGHT(realcolor.s.red,light))); - fogcolor.s.green = (UINT8)((CALCLIGHT(fogcolor.s.green,(255-light)))+(CALCLIGHT(realcolor.s.green,light))); - fogcolor.s.blue = (UINT8)((CALCLIGHT(fogcolor.s.blue,(255-light)))+(CALCLIGHT(realcolor.s.blue,light))); - - // Set the fog options. - if (cv_grsoftwarefog.value == 1 && plane) // With floors, software draws them way darker for their distance - HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, (INT32)(CALCFOGDENSITYFLOOR(light))); - else // everything else is drawn like walls - HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, (INT32)(CALCFOGDENSITY(light))); - } - else - { - fogcolor.s.red = (UINT8)((CALCLIGHT(fogcolor.s.red,(255-light)))+(CALCLIGHT(realcolor.s.red,light))); - fogcolor.s.green = (UINT8)((CALCLIGHT(fogcolor.s.green,(255-light)))+(CALCLIGHT(realcolor.s.green,light))); - fogcolor.s.blue = (UINT8)((CALCLIGHT(fogcolor.s.blue,(255-light)))+(CALCLIGHT(realcolor.s.blue,light))); - - fogalpha = (UINT8)((CALCLIGHT(fogalpha,(255-light)))+(CALCLIGHT(alpha,light))); - - // Set the fog options. - light = (UINT8)(CALCLIGHT(light,(255-fogalpha))); - HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, (INT32)(cv_grfogdensity.value-(cv_grfogdensity.value*(float)light/255.0f))); - } - - HWD.pfnSetSpecialState(HWD_SET_FOG_COLOR, (fogcolor.s.red*0x10000)+(fogcolor.s.green*0x100)+fogcolor.s.blue); - HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 1); - } - return surfcolor.rgba; -} - - -static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this can work +UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work { RGBA_t realcolor, surfcolor; INT32 alpha; - // Don't go out of bounds - if (light < 0) - light = 0; - else if (light > 255) - light = 255; + realcolor.rgba = (colormap != NULL) ? colormap->rgba : GL_DEFAULTMIX; - realcolor.rgba = color; + if (cv_grshaders.value && gr_shadersavailable) + { + surfcolor.s.alpha = (255 - light); + } + else + { + light = light - (255 - light); - alpha = (realcolor.s.alpha*255)/25; + // Don't go out of bounds + if (light < 0) + light = 0; + else if (light > 255) + light = 255; - // at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255 - surfcolor.s.alpha = (alpha*light)/(2*256)+255-light; + alpha = (realcolor.s.alpha*255)/25; + + // at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255 + surfcolor.s.alpha = (alpha*light) / (2*256) + 255-light; + } return surfcolor.s.alpha; } +static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y) +{ + INT16 finallight = lightnum; + + if (cv_grfakecontrast.value != 0) + { + const UINT8 contrast = 8; + fixed_t extralight = 0; + + if (cv_grfakecontrast.value == 2) // Smooth setting + { + extralight = (-(contrast<> FRACBITS; + } + else + { + if (v1y == v2y) + extralight = -contrast; + else if (v1x == v2x) + extralight = contrast; + } + + if (extralight != 0) + { + finallight += extralight; + + if (finallight < 0) + finallight = 0; + if (finallight > 255) + finallight = 255; + } + } + + return (FUINT)finallight; +} + +static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta) +{ + INT16 finallight = lightnum; + + if (cv_grfakecontrast.value != 0 && cv_grslopecontrast.value != 0) + { + const UINT8 contrast = 8; + fixed_t extralight = 0; + + if (cv_grfakecontrast.value == 2) // Smooth setting + { + fixed_t dirmul = abs(FixedDiv(AngleFixed(dir) - (180<> FRACBITS; + } + else + { + dir = ((dir + ANGLE_45) / ANGLE_90) * ANGLE_90; + + if (dir == ANGLE_180) + extralight = -contrast; + else if (dir == 0) + extralight = contrast; + + if (delta >= FRACUNIT/2) + extralight *= 2; + } + + if (extralight != 0) + { + finallight += extralight; + + if (finallight < 0) + finallight = 0; + if (finallight > 255) + finallight = 255; + } + } + + return (FUINT)finallight; +} + // ========================================================================== // FLOOR/CEILING GENERATION FROM SUBSECTORS // ========================================================================== @@ -469,8 +344,7 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this c // -----------------+ // HWR_RenderPlane : Render a floor or ceiling convex polygon // -----------------+ -static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, - FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, boolean fogplane, extracolormap_t *planecolormap) +static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap) { polyvertex_t * pv; float height; //constant y for all points on the convex flat polygon @@ -486,20 +360,17 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is angle_t angle = 0; FSurfaceInfo Surf; fixed_t tempxsow, tempytow; -#ifdef ESLOPE pslope_t *slope = NULL; -#endif static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; - (void)sector; ///@TODO remove shitty unused variable + int shader; // no convex poly were generated for this subsector if (!xsub->planepoly) return; -#ifdef ESLOPE // Get the slope pointer to simplify future code if (FOFsector) { @@ -518,8 +389,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is // Set fixedheight to the slope's height from our viewpoint, if we have a slope if (slope) - fixedheight = P_GetZAt(slope, viewx, viewy); -#endif + fixedheight = P_GetSlopeZAt(slope, viewx, viewy); height = FIXED_TO_FLOAT(fixedheight); @@ -529,13 +399,6 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is if (nrPlaneVerts < 3) //not even a triangle ? return; - // This check is so inconsistent between functions, it hurts. - if (nrPlaneVerts > INT16_MAX) // FIXME: exceeds plVerts size - { - CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, INT16_MAX); - return; - } - // Allocate plane-vertex buffer if we need to if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts) { @@ -586,15 +449,13 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is } } else // set no texture - HWD.pfnSetTexture(NULL); + HWR_SetCurrentTexture(NULL); // reference point for flat texture coord for each vertex around the polygon flatxref = (float)(((fixed_t)pv->x & (~flatflag)) / fflatwidth); flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatheight); // transform - v3d = planeVerts; - if (FOFsector != NULL) { if (!isceiling) // it's a floor @@ -626,9 +487,18 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is } } + if (angle) // Only needs to be done if there's an altered angle { - angle = InvAngle(angle)>>ANGLETOFINESHIFT; + + angle = (InvAngle(angle)+ANGLE_180)>>ANGLETOFINESHIFT; + + // This needs to be done so that it scrolls in a different direction after rotation like software + /*tempxsow = FLOAT_TO_FIXED(scrollx); + tempytow = FLOAT_TO_FIXED(scrolly); + scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); + scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));*/ + // This needs to be done so everything aligns after rotation // It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does tempxsow = FLOAT_TO_FIXED(flatxref); @@ -637,112 +507,138 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); } - for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++) - { - // Hurdler: add scrolling texture on floor/ceiling - if (texflat) - { - v3d->sow = (float)(pv->x / fflatwidth) + scrollx; - v3d->tow = -(float)(pv->y / fflatheight) + scrolly; - } - else - { - v3d->sow = (float)((pv->x / fflatwidth) - flatxref + scrollx); - v3d->tow = (float)(flatyref - (pv->y / fflatheight) + scrolly); - } +#define SETUP3DVERT(vert, vx, vy) {\ + /* Hurdler: add scrolling texture on floor/ceiling */\ + if (texflat)\ + {\ + vert->s = (float)((vx) / fflatwidth) + scrollx;\ + vert->t = -(float)((vy) / fflatheight) + scrolly;\ + }\ + else\ + {\ + vert->s = (float)(((vx) / fflatwidth) - flatxref + scrollx);\ + vert->t = (float)(flatyref - ((vy) / fflatheight) + scrolly);\ + }\ +\ + /* Need to rotate before translate */\ + if (angle) /* Only needs to be done if there's an altered angle */\ + {\ + tempxsow = FLOAT_TO_FIXED(vert->s);\ + tempytow = FLOAT_TO_FIXED(vert->t);\ + if (texflat)\ + tempytow = -tempytow;\ + vert->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));\ + vert->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));\ + }\ +\ + vert->x = (vx);\ + vert->y = height;\ + vert->z = (vy);\ +\ + if (slope)\ + {\ + fixedheight = P_GetSlopeZAt(slope, FLOAT_TO_FIXED((vx)), FLOAT_TO_FIXED((vy)));\ + vert->y = FIXED_TO_FLOAT(fixedheight);\ + }\ +} - // Need to rotate before translate - if (angle) // Only needs to be done if there's an altered angle - { - tempxsow = FLOAT_TO_FIXED(v3d->sow); - tempytow = FLOAT_TO_FIXED(v3d->tow); - if (texflat) - tempytow = -tempytow; - v3d->sow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - v3d->tow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); - } + for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++) + SETUP3DVERT(v3d, pv->x, pv->y); - //v3d->sow = (float)(v3d->sow - flatxref + scrollx); - //v3d->tow = (float)(flatyref - v3d->tow + scrolly); + if (slope) + lightlevel = HWR_CalcSlopeLight(lightlevel, R_PointToAngle2(0, 0, slope->normal.x, slope->normal.y), abs(slope->zdelta)); - v3d->x = pv->x; - v3d->y = height; - v3d->z = pv->y; - -#ifdef ESLOPE - if (slope) - { - fixedheight = P_GetZAt(slope, FLOAT_TO_FIXED(pv->x), FLOAT_TO_FIXED(pv->y)); - v3d->y = FIXED_TO_FLOAT(fixedheight); - } -#endif - } - - // only useful for flat coloured triangles - //Surf.FlatColor = 0xff804020; - - // use different light tables - // for horizontal / vertical / diagonal - // note: try to get the same visual feel as the original - Surf.FlatColor.s.red = Surf.FlatColor.s.green = - Surf.FlatColor.s.blue = LightLevelToLum(lightlevel); // Don't take from the frontsector, or the game will crash - -#if 0 // no colormap test - // colormap test - if (gr_frontsector) - { - sector_t *psector = gr_frontsector; - -#ifdef ESLOPE - if (slope) - fixedheight = P_GetZAt(slope, psector->soundorg.x, psector->soundorg.y); -#endif - - if (psector->ffloors) - { - ffloor_t *caster = psector->lightlist[R_GetPlaneLight(psector, fixedheight, false)].caster; - psector = caster ? §ors[caster->secnum] : psector; - - if (caster) - { - lightlevel = psector->lightlevel; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = LightLevelToLum(lightlevel); - } - } - if (psector->extra_colormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel,psector->extra_colormap->rgba,psector->extra_colormap->fadergba, false, true); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel,NORMALFOG,FADEFOG, false, true); - } - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel,NORMALFOG,FADEFOG, false, true); - -#endif // NOPE - - if (planecolormap) - { - if (fogplane) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, planecolormap->rgba, planecolormap->fadergba, true, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, planecolormap->rgba, planecolormap->fadergba, false, true); - } - else - { - if (fogplane) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, true, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, true); - } + HWR_Lighting(&Surf, lightlevel, planecolormap); if (PolyFlags & (PF_Translucent|PF_Fog)) { - Surf.FlatColor.s.alpha = (UINT8)alpha; - PolyFlags |= PF_Modulated|PF_Clip; + Surf.PolyColor.s.alpha = (UINT8)alpha; + PolyFlags |= PF_Modulated; } else - PolyFlags |= PF_Masked|PF_Modulated|PF_Clip; + PolyFlags |= PF_Masked|PF_Modulated; - HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags); + if (PolyFlags & PF_Fog) + shader = 6; // fog shader + else if (PolyFlags & PF_Ripple) + shader = 5; // water shader + else + shader = 1; // floor shader + + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false); + + if (subsector) + { + // Horizon lines + FOutVector horizonpts[6]; + float dist, vx, vy; + float x1, y1, xd, yd; + UINT8 numplanes, j; + vertex_t v; // For determining the closest distance from the line to the camera, to split render planes for minimum distortion; + + const float renderdist = 27000.0f; // How far out to properly render the plane + const float farrenderdist = 32768.0f; // From here, raise plane to horizon level to fill in the line with some texture distortion + + seg_t *line = &segs[subsector->firstline]; + + for (i = 0; i < subsector->numlines; i++, line++) + { + if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0) + { + P_ClosestPointOnLine(viewx, viewy, line->linedef, &v); + dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y)); + + x1 = ((polyvertex_t *)line->pv1)->x; + y1 = ((polyvertex_t *)line->pv1)->y; + xd = ((polyvertex_t *)line->pv2)->x - x1; + yd = ((polyvertex_t *)line->pv2)->y - y1; + + // Based on the seg length and the distance from the line, split horizon into multiple poly sets to reduce distortion + dist = sqrtf((xd*xd) + (yd*yd)) / dist / 16.0f; + if (dist > 100.0f) + numplanes = 100; + else + numplanes = (UINT8)dist + 1; + + for (j = 0; j < numplanes; j++) + { + // Left side + vx = x1 + xd * j / numplanes; + vy = y1 + yd * j / numplanes; + SETUP3DVERT((&horizonpts[1]), vx, vy); + + dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2)); + vx = (vx - gr_viewx) * renderdist / dist + gr_viewx; + vy = (vy - gr_viewy) * renderdist / dist + gr_viewy; + SETUP3DVERT((&horizonpts[0]), vx, vy); + + // Right side + vx = x1 + xd * (j+1) / numplanes; + vy = y1 + yd * (j+1) / numplanes; + SETUP3DVERT((&horizonpts[2]), vx, vy); + + dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2)); + vx = (vx - gr_viewx) * renderdist / dist + gr_viewx; + vy = (vy - gr_viewy) * renderdist / dist + gr_viewy; + SETUP3DVERT((&horizonpts[3]), vx, vy); + + // Horizon fills + vx = (horizonpts[0].x - gr_viewx) * farrenderdist / renderdist + gr_viewx; + vy = (horizonpts[0].z - gr_viewy) * farrenderdist / renderdist + gr_viewy; + SETUP3DVERT((&horizonpts[5]), vx, vy); + horizonpts[5].y = gr_viewz; + + vx = (horizonpts[3].x - gr_viewx) * farrenderdist / renderdist + gr_viewx; + vy = (horizonpts[3].z - gr_viewy) * farrenderdist / renderdist + gr_viewy; + SETUP3DVERT((&horizonpts[4]), vx, vy); + horizonpts[4].y = gr_viewz; + + // Draw + HWR_ProcessPolygon(&Surf, horizonpts, 6, PolyFlags, shader, true); + } + } + } + } #ifdef ALAM_LIGHTING // add here code for dynamic lighting on planes @@ -783,8 +679,8 @@ static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight) v3d = planeVerts; for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++) { - v3d->sow = 0.0f; - v3d->tow = 0.0f; + v3d->s = 0.0f; + v3d->t = 0.0f; v3d->x = pv->x; v3d->y = height; v3d->z = pv->y; @@ -807,13 +703,10 @@ static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight) #ifdef WALLSPLATS static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) { - FOutVector trVerts[4], *wv; - wallVert3D wallVerts[4]; - wallVert3D *pwallVerts; + FOutVector wallVerts[4]; wallsplat_t *splat; GLPatch_t *gpatch; fixed_t i; - FSurfaceInfo pSurf2; // seg bbox fixed_t segbbox[4]; @@ -851,141 +744,64 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) wallVerts[3].s = wallVerts[3].t = wallVerts[2].s = wallVerts[0].t = 0.0f; wallVerts[1].s = wallVerts[1].t = wallVerts[2].t = wallVerts[0].s = 1.0f; - // transform - wv = trVerts; - pwallVerts = wallVerts; - for (i = 0; i < 4; i++,wv++,pwallVerts++) - { - wv->x = pwallVerts->x; - wv->z = pwallVerts->z; - wv->y = pwallVerts->y; - - // Kalaron: TOW and SOW needed to be switched - wv->sow = pwallVerts->t; - wv->tow = pwallVerts->s; - } - M_Memcpy(&pSurf2,pSurf,sizeof (FSurfaceInfo)); switch (splat->flags & SPLATDRAWMODE_MASK) { case SPLATDRAWMODE_OPAQUE : - pSurf2.FlatColor.s.alpha = 0xff; + pSurf.PolyColor.s.alpha = 0xff; i = PF_Translucent; break; case SPLATDRAWMODE_TRANS : - pSurf2.FlatColor.s.alpha = 128; + pSurf.PolyColor.s.alpha = 128; i = PF_Translucent; break; case SPLATDRAWMODE_SHADE : - pSurf2.FlatColor.s.alpha = 0xff; + pSurf.PolyColor.s.alpha = 0xff; i = PF_Substractive; break; } - HWD.pfnDrawPolygon(&pSurf2, trVerts, 4, i|PF_Modulated|PF_Clip|PF_Decal); + HWD.pfnSetShader(2); // wall shader + HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal); } } #endif -// ========================================================================== -// WALL GENERATION FROM SUBSECTOR SEGS -// ========================================================================== - - FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) { switch (transtablenum) { - case tr_trans10 : pSurf->FlatColor.s.alpha = 0xe6;return PF_Translucent; - case tr_trans20 : pSurf->FlatColor.s.alpha = 0xcc;return PF_Translucent; - case tr_trans30 : pSurf->FlatColor.s.alpha = 0xb3;return PF_Translucent; - case tr_trans40 : pSurf->FlatColor.s.alpha = 0x99;return PF_Translucent; - case tr_trans50 : pSurf->FlatColor.s.alpha = 0x80;return PF_Translucent; - case tr_trans60 : pSurf->FlatColor.s.alpha = 0x66;return PF_Translucent; - case tr_trans70 : pSurf->FlatColor.s.alpha = 0x4c;return PF_Translucent; - case tr_trans80 : pSurf->FlatColor.s.alpha = 0x33;return PF_Translucent; - case tr_trans90 : pSurf->FlatColor.s.alpha = 0x19;return PF_Translucent; + case tr_trans10 : pSurf->PolyColor.s.alpha = 0xe6;return PF_Translucent; + case tr_trans20 : pSurf->PolyColor.s.alpha = 0xcc;return PF_Translucent; + case tr_trans30 : pSurf->PolyColor.s.alpha = 0xb3;return PF_Translucent; + case tr_trans40 : pSurf->PolyColor.s.alpha = 0x99;return PF_Translucent; + case tr_trans50 : pSurf->PolyColor.s.alpha = 0x80;return PF_Translucent; + case tr_trans60 : pSurf->PolyColor.s.alpha = 0x66;return PF_Translucent; + case tr_trans70 : pSurf->PolyColor.s.alpha = 0x4c;return PF_Translucent; + case tr_trans80 : pSurf->PolyColor.s.alpha = 0x33;return PF_Translucent; + case tr_trans90 : pSurf->PolyColor.s.alpha = 0x19;return PF_Translucent; } return PF_Translucent; } -// v1,v2 : the start & end vertices along the original wall segment, that may have been -// clipped so that only a visible portion of the wall seg is drawn. -// floorheight, ceilingheight : depend on wall upper/lower/middle, comes from the sectors. +static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap); -static void HWR_AddTransparentWall(wallVert3D *wallVerts, FSurfaceInfo * pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap); +// ========================================================================== +// Wall generation from subsector segs +// ========================================================================== -// -----------------+ -// HWR_ProjectWall : -// -----------------+ -/* - wallVerts order is : - 3--2 - | /| - |/ | - 0--1 -*/ -static void HWR_ProjectWall(wallVert3D * wallVerts, - FSurfaceInfo * pSurf, - FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) +// +// HWR_ProjectWall +// +static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { - FOutVector trVerts[4]; - FOutVector *wv; + HWR_Lighting(pSurf, lightlevel, wallcolormap); - // transform - wv = trVerts; - // it sounds really stupid to do this conversion with the new T&L code - // we should directly put the right information in the right structure - // wallVerts3D seems ok, doesn't need FOutVector - // also remove the light copy - - // More messy to unwrap, but it's also quicker, uses less memory. - wv->sow = wallVerts->s; - wv->tow = wallVerts->t; - wv->x = wallVerts->x; - wv->y = wallVerts->y; - wv->z = wallVerts->z; - wv++; wallVerts++; - wv->sow = wallVerts->s; - wv->tow = wallVerts->t; - wv->x = wallVerts->x; - wv->y = wallVerts->y; - wv->z = wallVerts->z; - wv++; wallVerts++; - wv->sow = wallVerts->s; - wv->tow = wallVerts->t; - wv->x = wallVerts->x; - wv->y = wallVerts->y; - wv->z = wallVerts->z; - wv++; wallVerts++; - wv->sow = wallVerts->s; - wv->tow = wallVerts->t; - wv->x = wallVerts->x; - wv->y = wallVerts->y; - wv->z = wallVerts->z; - - if (wallcolormap) - { - pSurf->FlatColor.rgba = HWR_Lighting(lightlevel, wallcolormap->rgba, wallcolormap->fadergba, false, false); - } - else - { - pSurf->FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); - } - - HWD.pfnDrawPolygon(pSurf, trVerts, 4, blendmode|PF_Modulated|PF_Occlude|PF_Clip); + HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, 2, false); // wall shader #ifdef WALLSPLATS if (gr_curline->linedef->splats && cv_splats.value) HWR_DrawSegsSplats(pSurf); #endif -#ifdef ALAM_LIGHTING - //Hurdler: TDOD: do static lighting using gr_curline->lm - HWR_WallLighting(trVerts); - - //Hurdler: for better dynamic light in dark area, we should draw the light first - // and then the wall all that with the right blending func - //HWD.pfnDrawPolygon(pSurf, trVerts, 4, PF_Additive|PF_Modulated|PF_Occlude|PF_Clip); -#endif } // ========================================================================== @@ -1027,38 +843,10 @@ static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2) } #endif -static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y) -{ - INT16 finallight = lightnum; - - if (cv_grfakecontrast.value != 0) - { - const UINT8 contrast = 8; - fixed_t extralight = 0; - - if (v1y == v2y) - extralight = -contrast; - else if (v1x == v2x) - extralight = contrast; - - if (extralight != 0) - { - finallight += extralight; - - if (finallight < 0) - finallight = 0; - if (finallight > 255) - finallight = 255; - } - } - - return (FUINT)finallight; -} - // // HWR_SplitWall // -static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor) +static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor) { /* SoM: split up and light walls according to the lightlist. This may also include leaving out parts @@ -1068,15 +856,13 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, float pegt, pegb, pegmul; float height = 0.0f, bheight = 0.0f; -#ifdef ESLOPE float endrealtop, endrealbot, endtop, endbot; float endpegt, endpegb, endpegmul; float endheight = 0.0f, endbheight = 0.0f; - // compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly - // use this as a temp var to store P_GetZAt's return value each time + // compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly + // use this as a temp var to store P_GetSlopeZAt's return value each time fixed_t temp; -#endif fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x); fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo @@ -1085,7 +871,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, INT32 solid, i; lightlist_t * list = sector->lightlist; - const UINT8 alpha = Surf->FlatColor.s.alpha; + const UINT8 alpha = Surf->PolyColor.s.alpha; FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y); extracolormap_t *colormap = NULL; @@ -1095,23 +881,17 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, pegb = wallVerts[0].t; pegmul = (pegb - pegt) / (top - bot); -#ifdef ESLOPE endrealtop = endtop = wallVerts[2].y; endrealbot = endbot = wallVerts[1].y; endpegt = wallVerts[2].t; endpegb = wallVerts[1].t; endpegmul = (endpegb - endpegt) / (endtop - endbot); -#endif for (i = 0; i < sector->numlights; i++) { -#ifdef ESLOPE - if (endtop < endrealbot) -#endif - if (top < realbot) + if (endtop < endrealbot && top < realbot) return; - // There's a compiler warning here if this comment isn't here because of indentation if (!(list[i].flags & FF_NOSHADE)) { if (pfloor && (pfloor->flags & FF_FOG)) @@ -1143,80 +923,40 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, else solid = false; -#ifdef ESLOPE - if (list[i].slope) - { - temp = P_GetZAt(list[i].slope, v1x, v1y); - height = FIXED_TO_FLOAT(temp); - temp = P_GetZAt(list[i].slope, v2x, v2y); - endheight = FIXED_TO_FLOAT(temp); - } - else - height = endheight = FIXED_TO_FLOAT(list[i].height); + temp = P_GetLightZAt(&list[i], v1x, v1y); + height = FIXED_TO_FLOAT(temp); + temp = P_GetLightZAt(&list[i], v2x, v2y); + endheight = FIXED_TO_FLOAT(temp); if (solid) { - if (*list[i].caster->b_slope) - { - temp = P_GetZAt(*list[i].caster->b_slope, v1x, v1y); - bheight = FIXED_TO_FLOAT(temp); - temp = P_GetZAt(*list[i].caster->b_slope, v2x, v2y); - endbheight = FIXED_TO_FLOAT(temp); - } - else - bheight = endbheight = FIXED_TO_FLOAT(*list[i].caster->bottomheight); + temp = P_GetFFloorBottomZAt(list[i].caster, v1x, v1y); + bheight = FIXED_TO_FLOAT(temp); + temp = P_GetFFloorBottomZAt(list[i].caster, v2x, v2y); + endbheight = FIXED_TO_FLOAT(temp); } -#else - height = FIXED_TO_FLOAT(list[i].height); - if (solid) - bheight = FIXED_TO_FLOAT(*list[i].caster->bottomheight); -#endif -#ifdef ESLOPE - if (endheight >= endtop) -#endif - if (height >= top) + if (endheight >= endtop && height >= top) { if (solid && top > bheight) top = bheight; -#ifdef ESLOPE if (solid && endtop > endbheight) endtop = endbheight; -#endif } -#ifdef ESLOPE if (i + 1 < sector->numlights) { - if (list[i+1].slope) - { - temp = P_GetZAt(list[i+1].slope, v1x, v1y); - bheight = FIXED_TO_FLOAT(temp); - temp = P_GetZAt(list[i+1].slope, v2x, v2y); - endbheight = FIXED_TO_FLOAT(temp); - } - else - bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height); + temp = P_GetLightZAt(&list[i+1], v1x, v1y); + bheight = FIXED_TO_FLOAT(temp); + temp = P_GetLightZAt(&list[i+1], v2x, v2y); + endbheight = FIXED_TO_FLOAT(temp); } else { bheight = realbot; endbheight = endrealbot; } -#else - if (i + 1 < sector->numlights) - { - bheight = FIXED_TO_FLOAT(list[i+1].height); - } - else - { - bheight = realbot; - } -#endif -#ifdef ESLOPE - if (endbheight >= endtop) -#endif - if (bheight >= top) + if (endbheight >= endtop && bheight >= top) continue; //Found a break; @@ -1225,15 +965,13 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, if (bot < realbot) bot = realbot; -#ifdef ESLOPE endbot = endbheight; if (endbot < endrealbot) endbot = endrealbot; -#endif - Surf->FlatColor.s.alpha = alpha; -#ifdef ESLOPE + Surf->PolyColor.s.alpha = alpha; + wallVerts[3].t = pegt + ((realtop - top) * pegmul); wallVerts[2].t = endpegt + ((endrealtop - endtop) * endpegmul); wallVerts[0].t = pegt + ((realtop - bot) * pegmul); @@ -1244,14 +982,6 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[2].y = endtop; wallVerts[0].y = bot; wallVerts[1].y = endbot; -#else - wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul); - wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul); - - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = top; - wallVerts[0].y = wallVerts[1].y = bot; -#endif if (cutflag & FF_FOG) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap); @@ -1261,22 +991,16 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); top = bot; -#ifdef ESLOPE endtop = endbot; -#endif } bot = realbot; -#ifdef ESLOPE endbot = endrealbot; - if (endtop <= endrealbot) -#endif - if (top <= realbot) + if (endtop <= endrealbot && top <= realbot) return; - Surf->FlatColor.s.alpha = alpha; + Surf->PolyColor.s.alpha = alpha; -#ifdef ESLOPE wallVerts[3].t = pegt + ((realtop - top) * pegmul); wallVerts[2].t = endpegt + ((endrealtop - endtop) * endpegmul); wallVerts[0].t = pegt + ((realtop - bot) * pegmul); @@ -1287,14 +1011,6 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[2].y = endtop; wallVerts[0].y = bot; wallVerts[1].y = endbot; -#else - wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul); - wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul); - - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = top; - wallVerts[0].y = wallVerts[1].y = bot; -#endif if (cutflag & FF_FOG) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap); @@ -1306,62 +1022,49 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, // HWR_DrawSkyWall // Draw walls into the depth buffer so that anything behind is culled properly -static void HWR_DrawSkyWall(wallVert3D *wallVerts, FSurfaceInfo *Surf) +static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) { - HWD.pfnSetTexture(NULL); + HWR_SetCurrentTexture(NULL); // no texture wallVerts[3].t = wallVerts[2].t = 0; wallVerts[0].t = wallVerts[1].t = 0; wallVerts[0].s = wallVerts[3].s = 0; wallVerts[2].s = wallVerts[1].s = 0; // this no longer sets top/bottom coords, this should be done before caling the function - HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_Clip|PF_NoTexture, 255, NULL); + HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL); // PF_Invisible so it's not drawn into the colour buffer // PF_NoTexture for no texture // PF_Occlude is set in HWR_ProjectWall to draw into the depth buffer } // -// HWR_StoreWallRange +// HWR_ProcessSeg // A portion or all of a wall segment will be drawn, from startfrac to endfrac, // where 0 is the start of the segment, 1 the end of the segment // Anything between means the wall segment has been clipped with solidsegs, // reducing wall overdraw to a minimum // -#ifdef NEWCLIP static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom -#else -static void HWR_StoreWallRange(double startfrac, double endfrac) -#endif { - wallVert3D wallVerts[4]; + FOutVector wallVerts[4]; v2d_t vs, ve; // start, end vertices of 2d line (view from above) fixed_t worldtop, worldbottom; fixed_t worldhigh = 0, worldlow = 0; -#ifdef ESLOPE fixed_t worldtopslope, worldbottomslope; fixed_t worldhighslope = 0, worldlowslope = 0; fixed_t v1x, v1y, v2x, v2y; -#endif GLTexture_t *grTex = NULL; float cliplow = 0.0f, cliphigh = 0.0f; INT32 gr_midtexture; fixed_t h, l; // 3D sides and 2s middle textures -#ifdef ESLOPE fixed_t hS, lS; -#endif FUINT lightnum = 0; // shut up compiler extracolormap_t *colormap; FSurfaceInfo Surf; -#ifndef NEWCLIP - if (startfrac > endfrac) - return; -#endif - gr_sidedef = gr_curline->sidedef; gr_linedef = gr_curline->linedef; @@ -1370,27 +1073,17 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) ve.x = ((polyvertex_t *)gr_curline->pv2)->x; ve.y = ((polyvertex_t *)gr_curline->pv2)->y; -#ifdef ESLOPE v1x = FLOAT_TO_FIXED(vs.x); v1y = FLOAT_TO_FIXED(vs.y); v2x = FLOAT_TO_FIXED(ve.x); v2y = FLOAT_TO_FIXED(ve.y); -#endif -#ifdef ESLOPE #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, v1x, v1y); \ - end2 = P_GetZAt(slope, v2x, v2y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, v1x, v1y, normalheight); \ + end2 = P_GetZAt(slope, v2x, v2y, normalheight); SLOPEPARAMS(gr_frontsector->c_slope, worldtop, worldtopslope, gr_frontsector->ceilingheight) SLOPEPARAMS(gr_frontsector->f_slope, worldbottom, worldbottomslope, gr_frontsector->floorheight) -#else - worldtop = gr_frontsector->ceilingheight; - worldbottom = gr_frontsector->floorheight; -#endif // remember vertices ordering // 3--2 @@ -1403,35 +1096,19 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[0].z = wallVerts[3].z = vs.y; wallVerts[2].x = wallVerts[1].x = ve.x; wallVerts[2].z = wallVerts[1].z = ve.y; - wallVerts[0].w = wallVerts[1].w = wallVerts[2].w = wallVerts[3].w = 1.0f; + // x offset the texture { - // x offset the texture fixed_t texturehpeg = gr_sidedef->textureoffset + gr_curline->offset; - -#ifndef NEWCLIP - // clip texture s start/end coords with solidsegs - if (startfrac > 0.0f && startfrac < 1.0f) - cliplow = (float)(texturehpeg + (gr_curline->flength*FRACUNIT) * startfrac); - else -#endif - cliplow = (float)texturehpeg; - -#ifndef NEWCLIP - if (endfrac > 0.0f && endfrac < 1.0f) - cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT) * endfrac); - else -#endif - cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT)); + cliplow = (float)texturehpeg; + cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT)); } lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); colormap = gr_frontsector->extra_colormap; if (gr_frontsector) - { - Surf.FlatColor.s.alpha = 255; - } + Surf.PolyColor.s.alpha = 255; if (gr_backsector) { @@ -1440,14 +1117,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) boolean bothceilingssky = false; // turned on if both back and front ceilings are sky boolean bothfloorssky = false; // likewise, but for floors -#ifdef ESLOPE SLOPEPARAMS(gr_backsector->c_slope, worldhigh, worldhighslope, gr_backsector->ceilingheight) SLOPEPARAMS(gr_backsector->f_slope, worldlow, worldlowslope, gr_backsector->floorheight) #undef SLOPEPARAMS -#else - worldhigh = gr_backsector->ceilingheight; - worldlow = gr_backsector->floorheight; -#endif // hack to allow height changes in outdoor areas // This is what gets rid of the upper textures if there should be sky @@ -1470,12 +1142,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture); // check TOP TEXTURE - if (( -#ifdef ESLOPE - worldhighslope < worldtopslope || -#endif - worldhigh < worldtop - ) && gr_toptexture) + if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gr_toptexture) { { fixed_t texturevpegtop; // top @@ -1485,15 +1152,10 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) // PEGGING if (gr_linedef->flags & ML_DONTPEGTOP) texturevpegtop = 0; -#ifdef ESLOPE else if (gr_linedef->flags & ML_EFFECT1) texturevpegtop = worldhigh + textureheight[gr_sidedef->toptexture] - worldtop; else texturevpegtop = gr_backsector->ceilingheight + textureheight[gr_sidedef->toptexture] - gr_frontsector->ceilingheight; -#else - else - texturevpegtop = worldhigh + textureheight[gr_sidedef->toptexture] - worldtop; -#endif texturevpegtop += gr_sidedef->rowoffset; @@ -1505,7 +1167,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; -#ifdef ESLOPE // Adjust t value for sloped walls if (!(gr_linedef->flags & ML_EFFECT1)) { @@ -1528,19 +1189,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[3].t = wallVerts[0].t - (worldtop - worldhigh) * grTex->scaleY; wallVerts[2].t = wallVerts[1].t - (worldtopslope - worldhighslope) * grTex->scaleY; } -#endif } // set top/bottom coords -#ifdef ESLOPE wallVerts[3].y = FIXED_TO_FLOAT(worldtop); wallVerts[0].y = FIXED_TO_FLOAT(worldhigh); wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope); wallVerts[1].y = FIXED_TO_FLOAT(worldhighslope); -#else - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldtop); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldhigh); -#endif if (gr_frontsector->numlights) HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTLEVEL, NULL); @@ -1552,9 +1207,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) // check BOTTOM TEXTURE if (( -#ifdef ESLOPE worldlowslope > worldbottomslope || -#endif worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!! { { @@ -1563,19 +1216,12 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) grTex = HWR_GetTexture(gr_bottomtexture); // PEGGING -#ifdef ESLOPE if (!(gr_linedef->flags & ML_DONTPEGBOTTOM)) texturevpegbottom = 0; else if (gr_linedef->flags & ML_EFFECT1) texturevpegbottom = worldbottom - worldlow; else texturevpegbottom = gr_frontsector->floorheight - gr_backsector->floorheight; -#else - if (gr_linedef->flags & ML_DONTPEGBOTTOM) - texturevpegbottom = worldbottom - worldlow; - else - texturevpegbottom = 0; -#endif texturevpegbottom += gr_sidedef->rowoffset; @@ -1587,7 +1233,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; -#ifdef ESLOPE // Adjust t value for sloped walls if (!(gr_linedef->flags & ML_EFFECT1)) { @@ -1610,19 +1255,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[0].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY; wallVerts[1].t = (texturevpegbottom + worldlowslope - worldbottomslope) * grTex->scaleY; } -#endif } // set top/bottom coords -#ifdef ESLOPE wallVerts[3].y = FIXED_TO_FLOAT(worldlow); wallVerts[0].y = FIXED_TO_FLOAT(worldbottom); wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope); wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope); -#else - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldlow); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldbottom); -#endif if (gr_frontsector->numlights) HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTLEVEL, NULL); @@ -1680,7 +1319,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) // heights of the polygon, and h & l, are the final (clipped) // poly coords. -#ifdef POLYOBJECTS // NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to, // you must use the linedef's backsector to be correct // From CB @@ -1690,18 +1328,11 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) popenbottom = back->floorheight; } else -#endif { -#ifdef ESLOPE popentop = min(worldtop, worldhigh); popenbottom = max(worldbottom, worldlow); -#else - popentop = min(front->ceilingheight, back->ceilingheight); - popenbottom = max(front->floorheight, back->floorheight); -#endif } -#ifdef ESLOPE if (gr_linedef->flags & ML_EFFECT2) { if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) @@ -1716,9 +1347,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } } else if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) -#else - if (gr_linedef->flags & ML_DONTPEGBOTTOM) -#endif { polybottom = popenbottom + gr_sidedef->rowoffset; polytop = polybottom + textureheight[gr_midtexture]*repeats; @@ -1729,7 +1357,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) polybottom = polytop - textureheight[gr_midtexture]*repeats; } // CB -#ifdef POLYOBJECTS // NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to, // you must use the linedef's backsector to be correct if (gr_curline->polyseg) @@ -1737,7 +1364,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) lowcut = polybottom; highcut = polytop; } -#endif else { // The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector @@ -1750,11 +1376,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { // PEGGING -#ifdef ESLOPE if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) -#else - if (gr_linedef->flags & ML_DONTPEGBOTTOM) -#endif texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom; else texturevpeg = polytop - h; @@ -1773,7 +1395,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h); wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l); -#ifdef ESLOPE // Correct to account for slopes { fixed_t midtextureslant; @@ -1816,7 +1437,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[2].y = FIXED_TO_FLOAT(h); wallVerts[1].y = FIXED_TO_FLOAT(l); } -#endif // set alpha for transparent walls (new boom and legacy linedef types) // ooops ! this do not work at all because render order we should render it in backtofront order @@ -1873,18 +1493,16 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) break; } -#ifdef POLYOBJECTS if (gr_curline->polyseg && gr_curline->polyseg->translucency > 0) { if (gr_curline->polyseg->translucency >= NUMTRANSMAPS) // wall not drawn { - Surf.FlatColor.s.alpha = 0x00; // This shouldn't draw anything regardless of blendmode + Surf.PolyColor.s.alpha = 0x00; // This shouldn't draw anything regardless of blendmode blendmode = PF_Masked; } else blendmode = HWR_TranstableToAlpha(gr_curline->polyseg->translucency, &Surf); } -#endif if (gr_frontsector->numlights) { @@ -1899,16 +1517,8 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap); - - // If there is a colormap change, remove it. -/* if (!(Surf.FlatColor.s.red + Surf.FlatColor.s.green + Surf.FlatColor.s.blue == Surf.FlatColor.s.red/3) - { - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.rgba = 0xffffffff; - }*/ } -#if 1 // Sky culling // No longer so much a mess as before! if (!gr_curline->polyseg) // Don't do it for polyobjects @@ -1918,12 +1528,8 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (gr_backsector->ceilingpic != skyflatnum) // don't cull if back sector is also sky { wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space -#ifdef ESLOPE wallVerts[0].y = FIXED_TO_FLOAT(worldtop); wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope); -#else - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop); -#endif HWR_DrawSkyWall(wallVerts, &Surf); } } @@ -1932,34 +1538,26 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { if (gr_backsector->floorpic != skyflatnum) // don't cull if back sector is also sky { -#ifdef ESLOPE wallVerts[3].y = FIXED_TO_FLOAT(worldbottom); wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope); -#else - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldbottom); -#endif wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space HWR_DrawSkyWall(wallVerts, &Surf); } } } -#endif } else { // Single sided line... Deal only with the middletexture (if one exists) gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture); - if (gr_midtexture && gr_linedef->special != HORIZONSPECIAL) // Ignore horizon line for OGL + if (gr_midtexture && gr_linedef->special != 41) // (Ignore horizon line for OGL) { { fixed_t texturevpeg; // PEGGING -#ifdef ESLOPE if ((gr_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2)) texturevpeg = gr_frontsector->floorheight + textureheight[gr_sidedef->midtexture] - gr_frontsector->ceilingheight + gr_sidedef->rowoffset; - else -#endif - if (gr_linedef->flags & ML_DONTPEGBOTTOM) + else if (gr_linedef->flags & ML_DONTPEGBOTTOM) texturevpeg = worldbottom + textureheight[gr_sidedef->midtexture] - worldtop + gr_sidedef->rowoffset; else // top of texture at top @@ -1972,7 +1570,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; -#ifdef ESLOPE // Texture correction for slopes if (gr_linedef->flags & ML_EFFECT2) { wallVerts[3].t += (gr_frontsector->ceilingheight - worldtop) * grTex->scaleY; @@ -1986,19 +1583,14 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[0].t = wallVerts[3].t - (worldbottom-worldtop) * grTex->scaleY; wallVerts[1].t = wallVerts[2].t - (worldbottomslope-worldtopslope) * grTex->scaleY; } -#endif } -#ifdef ESLOPE + //Set textures properly on single sided walls that are sloped wallVerts[3].y = FIXED_TO_FLOAT(worldtop); wallVerts[0].y = FIXED_TO_FLOAT(worldbottom); wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope); wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope); -#else - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldtop); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldbottom); -#endif + // I don't think that solid walls can use translucent linedef types... if (gr_frontsector->numlights) HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL); @@ -2016,22 +1608,14 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (gr_frontsector->ceilingpic == skyflatnum) // It's a single-sided line with sky for its sector { wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space -#ifdef ESLOPE wallVerts[0].y = FIXED_TO_FLOAT(worldtop); wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope); -#else - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop); -#endif HWR_DrawSkyWall(wallVerts, &Surf); } if (gr_frontsector->floorpic == skyflatnum) { -#ifdef ESLOPE wallVerts[3].y = FIXED_TO_FLOAT(worldbottom); wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope); -#else - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldbottom); -#endif wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space HWR_DrawSkyWall(wallVerts, &Surf); } @@ -2040,7 +1624,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) //Hurdler: 3d-floors test -#ifdef R_FAKEFLOORS if (gr_frontsector && gr_backsector && gr_frontsector->tag != gr_backsector->tag && (gr_backsector->ffloors || gr_frontsector->ffloors)) { ffloor_t * rover; @@ -2058,7 +1641,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { for (rover = gr_backsector->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES) || (rover->flags & FF_INVERTSIDES)) + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES)) + continue; + if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES) continue; if (*rover->topheight < lowcut || *rover->bottomheight > highcut) continue; @@ -2072,11 +1657,10 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture); } -#ifdef ESLOPE - h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight; - hS = *rover->t_slope ? P_GetZAt(*rover->t_slope, v2x, v2y) : *rover->topheight; - l = *rover->b_slope ? P_GetZAt(*rover->b_slope, v1x, v1y) : *rover->bottomheight; - lS = *rover->b_slope ? P_GetZAt(*rover->b_slope, v2x, v2y) : *rover->bottomheight; + h = P_GetFFloorTopZAt (rover, v1x, v1y); + hS = P_GetFFloorTopZAt (rover, v2x, v2y); + l = P_GetFFloorBottomZAt(rover, v1x, v1y); + lS = P_GetFFloorBottomZAt(rover, v2x, v2y); if (!(*rover->t_slope) && !gr_frontsector->c_slope && !gr_backsector->c_slope && h > highcut) h = hS = highcut; if (!(*rover->b_slope) && !gr_frontsector->f_slope && !gr_backsector->f_slope && l < lowcut) @@ -2089,19 +1673,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[2].y = FIXED_TO_FLOAT(hS); wallVerts[0].y = FIXED_TO_FLOAT(l); wallVerts[1].y = FIXED_TO_FLOAT(lS); -#else - h = *rover->topheight; - l = *rover->bottomheight; - if (h > highcut) - h = highcut; - if (l < lowcut) - l = lowcut; - //Hurdler: HW code starts here - //FIXME: check if peging is correct - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l); -#endif if (rover->flags & FF_FOG) { wallVerts[3].t = wallVerts[2].t = 0; @@ -2113,9 +1684,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { fixed_t texturevpeg; boolean attachtobottom = false; -#ifdef ESLOPE boolean slopeskew = false; // skew FOF walls with slopes? -#endif // Wow, how was this missing from OpenGL for so long? // ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software @@ -2124,22 +1693,17 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { texturevpeg = sides[newline->sidenum[0]].rowoffset; attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM); -#ifdef ESLOPE slopeskew = !!(newline->flags & ML_DONTPEGTOP); -#endif } else { texturevpeg = sides[rover->master->sidenum[0]].rowoffset; attachtobottom = !!(gr_linedef->flags & ML_DONTPEGBOTTOM); -#ifdef ESLOPE slopeskew = !!(rover->master->flags & ML_DONTPEGTOP); -#endif } grTex = HWR_GetTexture(texnum); -#ifdef ESLOPE if (!slopeskew) // no skewing { if (attachtobottom) @@ -2164,12 +1728,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[2].t = wallVerts[1].t - (hS - lS) * grTex->scaleY; } } -#else - if (attachtobottom) - texturevpeg -= *rover->topheight - *rover->bottomheight; - wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; -#endif wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; @@ -2183,15 +1741,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); colormap = rover->master->frontsector->extra_colormap; - if (rover->master->frontsector->extra_colormap) - { - - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba); - } - else - { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG); - } + Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); if (gr_frontsector->numlights) HWR_SplitWall(gr_frontsector, wallVerts, 0, &Surf, rover->flags, rover); @@ -2205,7 +1755,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { blendmode = PF_Translucent; - Surf.FlatColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; + Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; } if (gr_frontsector->numlights) @@ -2225,7 +1775,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { for (rover = gr_frontsector->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_ALLSIDES)) + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES)) + continue; + if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) continue; if (*rover->topheight < lowcut || *rover->bottomheight > highcut) continue; @@ -2238,11 +1790,10 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) newline = rover->master->frontsector->lines[0] + linenum; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture); } -#ifdef ESLOPE //backsides - h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight; - hS = *rover->t_slope ? P_GetZAt(*rover->t_slope, v2x, v2y) : *rover->topheight; - l = *rover->b_slope ? P_GetZAt(*rover->b_slope, v1x, v1y) : *rover->bottomheight; - lS = *rover->b_slope ? P_GetZAt(*rover->b_slope, v2x, v2y) : *rover->bottomheight; + h = P_GetFFloorTopZAt (rover, v1x, v1y); + hS = P_GetFFloorTopZAt (rover, v2x, v2y); + l = P_GetFFloorBottomZAt(rover, v1x, v1y); + lS = P_GetFFloorBottomZAt(rover, v2x, v2y); if (!(*rover->t_slope) && !gr_frontsector->c_slope && !gr_backsector->c_slope && h > highcut) h = hS = highcut; if (!(*rover->b_slope) && !gr_frontsector->f_slope && !gr_backsector->f_slope && l < lowcut) @@ -2255,19 +1806,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) wallVerts[2].y = FIXED_TO_FLOAT(hS); wallVerts[0].y = FIXED_TO_FLOAT(l); wallVerts[1].y = FIXED_TO_FLOAT(lS); -#else - h = *rover->topheight; - l = *rover->bottomheight; - if (h > highcut) - h = highcut; - if (l < lowcut) - l = lowcut; - //Hurdler: HW code starts here - //FIXME: check if peging is correct - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l); -#endif if (rover->flags & FF_FOG) { wallVerts[3].t = wallVerts[2].t = 0; @@ -2303,14 +1841,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); colormap = rover->master->frontsector->extra_colormap; - if (rover->master->frontsector->extra_colormap) - { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba); - } - else - { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG); - } + Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); if (gr_backsector->numlights) HWR_SplitWall(gr_backsector, wallVerts, 0, &Surf, rover->flags, rover); @@ -2324,7 +1855,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { blendmode = PF_Translucent; - Surf.FlatColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; + Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; } if (gr_backsector->numlights) @@ -2340,7 +1871,6 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } } } -#endif //Hurdler: end of 3d-floors test } @@ -2365,7 +1895,6 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks // GZDoom method of sloped line clipping -#ifdef ESLOPE if (afrontsector->f_slope || afrontsector->c_slope || abacksector->f_slope || abacksector->c_slope) { fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t @@ -2374,25 +1903,21 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks v2x = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->x); v2y = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->y); #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, v1x, v1y); \ - end2 = P_GetZAt(slope, v2x, v2y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, v1x, v1y, normalheight); \ + end2 = P_GetZAt(slope, v2x, v2y, normalheight); - SLOPEPARAMS(afrontsector->f_slope, frontf1, frontf2, afrontsector->floorheight) + SLOPEPARAMS(afrontsector->f_slope, frontf1, frontf2, afrontsector-> floorheight) SLOPEPARAMS(afrontsector->c_slope, frontc1, frontc2, afrontsector->ceilingheight) - SLOPEPARAMS( abacksector->f_slope, backf1, backf2, abacksector->floorheight) - SLOPEPARAMS( abacksector->c_slope, backc1, backc2, abacksector->ceilingheight) + SLOPEPARAMS( abacksector->f_slope, backf1, backf2, abacksector-> floorheight) + SLOPEPARAMS( abacksector->c_slope, backc1, backc2, abacksector->ceilingheight) #undef SLOPEPARAMS } else -#endif { - frontf1 = frontf2 = afrontsector->floorheight; + frontf1 = frontf2 = afrontsector-> floorheight; frontc1 = frontc2 = afrontsector->ceilingheight; - backf1 = backf2 = abacksector->floorheight; - backc1 = backc2 = abacksector->ceilingheight; + backf1 = backf2 = abacksector-> floorheight; + backc1 = backc2 = abacksector->ceilingheight; } // properly render skies (consider door "open" if both ceilings are sky) // same for floors @@ -2744,10 +2269,8 @@ static void HWR_AddLine(seg_t * line) static sector_t tempsec; fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t -#ifdef POLYOBJECTS if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES)) return; -#endif gr_curline = line; @@ -2874,13 +2397,10 @@ static void HWR_AddLine(seg_t * line) if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then { - if ( -#ifdef POLYOBJECTS - !line->polyseg && -#endif - !line->sidedef->midtexture - && ((!gr_frontsector->ffloors && !gr_backsector->ffloors) - || (gr_frontsector->tag == gr_backsector->tag))) + if (!line->polyseg && + !line->sidedef->midtexture + && ((!gr_frontsector->ffloors && !gr_backsector->ffloors) + || (gr_frontsector->tag == gr_backsector->tag))) return; // line is empty, don't even bother // treat like wide open window instead HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D @@ -2916,35 +2436,28 @@ static void HWR_AddLine(seg_t * line) if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then { - if ( -#ifdef POLYOBJECTS - !line->polyseg && -#endif - !line->sidedef->midtexture - && ((!gr_frontsector->ffloors && !gr_backsector->ffloors) - || (gr_frontsector->tag == gr_backsector->tag))) + if (!line->polyseg && + !line->sidedef->midtexture + && ((!gr_frontsector->ffloors && !gr_backsector->ffloors) + || (gr_frontsector->tag == gr_backsector->tag))) return; // line is empty, don't even bother goto clippass; // treat like wide open window instead } -#ifdef ESLOPE if (gr_frontsector->f_slope || gr_frontsector->c_slope || gr_backsector->f_slope || gr_backsector->c_slope) { fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, v1x, v1y); \ - end2 = P_GetZAt(slope, v2x, v2y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, v1x, v1y, normalheight); \ + end2 = P_GetZAt(slope, v2x, v2y, normalheight); - SLOPEPARAMS(gr_frontsector->f_slope, frontf1, frontf2, gr_frontsector->floorheight) + SLOPEPARAMS(gr_frontsector->f_slope, frontf1, frontf2, gr_frontsector-> floorheight) SLOPEPARAMS(gr_frontsector->c_slope, frontc1, frontc2, gr_frontsector->ceilingheight) - SLOPEPARAMS( gr_backsector->f_slope, backf1, backf2, gr_backsector->floorheight) - SLOPEPARAMS( gr_backsector->c_slope, backc1, backc2, gr_backsector->ceilingheight) + SLOPEPARAMS( gr_backsector->f_slope, backf1, backf2, gr_backsector-> floorheight) + SLOPEPARAMS( gr_backsector->c_slope, backc1, backc2, gr_backsector->ceilingheight) #undef SLOPEPARAMS // if both ceilings are skies, consider it always "open" // same for floors @@ -2973,7 +2486,6 @@ static void HWR_AddLine(seg_t * line) goto clippass; } else -#endif { // if both ceilings are skies, consider it always "open" // same for floors @@ -3116,8 +2628,6 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord) #endif } -#ifdef POLYOBJECTS - // // HWR_AddPolyObjectSegs // @@ -3160,7 +2670,6 @@ static inline void HWR_AddPolyObjectSegs(void) Z_Free(gr_fakeline); } -#ifdef POLYOBJECTS_PLANES static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, FBITFIELD blendmode, UINT8 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap) @@ -3176,7 +2685,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; FSurfaceInfo Surf; - fixed_t tempxsow, tempytow; + fixed_t tempxs, tempyt; size_t nrPlaneVerts; static FOutVector *planeVerts = NULL; @@ -3245,7 +2754,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, } } else // set no texture - HWD.pfnSetTexture(NULL); + HWR_SetCurrentTexture(NULL); // reference point for flat texture coord for each vertex around the polygon flatxref = (float)((polysector->origVerts[0].x & (~flatflag)) / fflatwidth); @@ -3288,17 +2797,17 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, if (angle) // Only needs to be done if there's an altered angle { // This needs to be done so that it scrolls in a different direction after rotation like software - tempxsow = FLOAT_TO_FIXED(scrollx); - tempytow = FLOAT_TO_FIXED(scrolly); - scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); + tempxs = FLOAT_TO_FIXED(scrollx); + tempyt = FLOAT_TO_FIXED(scrolly); + scrollx = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle)))); + scrolly = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle)))); // This needs to be done so everything aligns after rotation // It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does - tempxsow = FLOAT_TO_FIXED(flatxref); - tempytow = FLOAT_TO_FIXED(flatyref); - flatxref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); + tempxs = FLOAT_TO_FIXED(flatxref); + tempyt = FLOAT_TO_FIXED(flatyref); + flatxref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle)))); + flatyref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle)))); } for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++) @@ -3307,24 +2816,24 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, // Means the flat is offset based on the original vertex locations if (texflat) { - v3d->sow = (float)(FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) + scrollx; - v3d->tow = -(float)(FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly; + v3d->s = (float)(FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) + scrollx; + v3d->t = -(float)(FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly; } else { - v3d->sow = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) - flatxref + scrollx); - v3d->tow = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly); + v3d->s = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) - flatxref + scrollx); + v3d->t = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly); } // Need to rotate before translate if (angle) // Only needs to be done if there's an altered angle { - tempxsow = FLOAT_TO_FIXED(v3d->sow); - tempytow = FLOAT_TO_FIXED(v3d->tow); + tempxs = FLOAT_TO_FIXED(v3d->s); + tempyt = FLOAT_TO_FIXED(v3d->t); if (texflat) - tempytow = -tempytow; - v3d->sow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - v3d->tow = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle)))); + tempyt = -tempyt; + v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle)))); + v3d->t = (FIXED_TO_FLOAT(-FixedMul(tempxs, FINESINE(angle)) - FixedMul(tempyt, FINECOSINE(angle)))); } v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x); @@ -3333,20 +2842,17 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, } - if (planecolormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, planecolormap->rgba, planecolormap->fadergba, false, true); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, true); + HWR_Lighting(&Surf, lightlevel, planecolormap); if (blendmode & PF_Translucent) { - Surf.FlatColor.s.alpha = (UINT8)alpha; + Surf.PolyColor.s.alpha = (UINT8)alpha; blendmode |= PF_Modulated|PF_Occlude|PF_Clip; } else blendmode |= PF_Masked|PF_Modulated|PF_Clip; - HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode); + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, 1, false); // floor shader } static void HWR_AddPolyObjectPlanes(void) @@ -3380,7 +2886,7 @@ static void HWR_AddPolyObjectPlanes(void) memset(&Surf, 0x00, sizeof(Surf)); blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); HWR_AddTransparentPolyobjectFloor(&levelflats[polyobjsector->floorpic], po_ptrs[i], false, polyobjsector->floorheight, - (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.FlatColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); } else { @@ -3403,7 +2909,7 @@ static void HWR_AddPolyObjectPlanes(void) memset(&Surf, 0x00, sizeof(Surf)); blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); HWR_AddTransparentPolyobjectFloor(&levelflats[polyobjsector->ceilingpic], po_ptrs[i], true, polyobjsector->ceilingheight, - (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.FlatColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); } else { @@ -3415,8 +2921,6 @@ static void HWR_AddPolyObjectPlanes(void) } } } -#endif -#endif // -----------------+ // HWR_Subsector : Determine floor/ceiling planes. @@ -3508,22 +3012,10 @@ static void HWR_Subsector(size_t num) } else { - cullFloorHeight = locFloorHeight = gr_frontsector->floorheight; - cullCeilingHeight = locCeilingHeight = gr_frontsector->ceilingheight; - -#ifdef ESLOPE - if (gr_frontsector->f_slope) - { - cullFloorHeight = P_GetZAt(gr_frontsector->f_slope, viewx, viewy); - locFloorHeight = P_GetZAt(gr_frontsector->f_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); - } - - if (gr_frontsector->c_slope) - { - cullCeilingHeight = P_GetZAt(gr_frontsector->c_slope, viewx, viewy); - locCeilingHeight = P_GetZAt(gr_frontsector->c_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); - } -#endif + cullFloorHeight = P_GetSectorFloorZAt (gr_frontsector, viewx, viewy); + cullCeilingHeight = P_GetSectorCeilingZAt(gr_frontsector, viewx, viewy); + locFloorHeight = P_GetSectorFloorZAt (gr_frontsector, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); + locCeilingHeight = P_GetSectorCeilingZAt(gr_frontsector, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); } // ----- end special tricks ----- @@ -3561,11 +3053,11 @@ static void HWR_Subsector(size_t num) if (sub->validcount != validcount) { HWR_GetLevelFlat(&levelflats[gr_frontsector->floorpic]); - HWR_RenderPlane(gr_frontsector, &extrasubsectors[num], false, + HWR_RenderPlane(sub, &extrasubsectors[num], false, // Hack to make things continue to work around slopes. locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight, // We now return you to your regularly scheduled rendering. - PF_Occlude, floorlightlevel, &levelflats[gr_frontsector->floorpic], NULL, 255, false, floorcolormap); + PF_Occlude, floorlightlevel, &levelflats[gr_frontsector->floorpic], NULL, 255, floorcolormap); } } else @@ -3583,11 +3075,11 @@ static void HWR_Subsector(size_t num) if (sub->validcount != validcount) { HWR_GetLevelFlat(&levelflats[gr_frontsector->ceilingpic]); - HWR_RenderPlane(NULL, &extrasubsectors[num], true, + HWR_RenderPlane(sub, &extrasubsectors[num], true, // Hack to make things continue to work around slopes. locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight, // We now return you to your regularly scheduled rendering. - PF_Occlude, ceilinglightlevel, &levelflats[gr_frontsector->ceilingpic], NULL, 255, false, ceilingcolormap); + PF_Occlude, ceilinglightlevel, &levelflats[gr_frontsector->ceilingpic], NULL, 255, ceilingcolormap); } } else @@ -3615,15 +3107,8 @@ static void HWR_Subsector(size_t num) fixed_t cullHeight, centerHeight; // bottom plane -#ifdef ESLOPE - if (*rover->b_slope) - { - cullHeight = P_GetZAt(*rover->b_slope, viewx, viewy); - centerHeight = P_GetZAt(*rover->b_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); - } - else -#endif - cullHeight = centerHeight = *rover->bottomheight; + cullHeight = P_GetFFloorBottomZAt(rover, viewx, viewy); + centerHeight = P_GetFFloorBottomZAt(rover, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES)) continue; @@ -3632,7 +3117,7 @@ static void HWR_Subsector(size_t num) if (centerHeight <= locCeilingHeight && centerHeight >= locFloorHeight && - ((dup_viewz < cullHeight && !(rover->flags & FF_INVERTPLANES)) || + ((dup_viewz < cullHeight && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) || (dup_viewz > cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { if (rover->flags & FF_FOG) @@ -3640,13 +3125,9 @@ static void HWR_Subsector(size_t num) UINT8 alpha; light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); + alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap); - if (rover->master->frontsector->extra_colormap) - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba); - else - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG); - - HWR_AddTransparentFloor(NULL, + HWR_AddTransparentFloor(0, &extrasubsectors[num], false, *rover->bottomheight, @@ -3657,45 +3138,31 @@ static void HWR_Subsector(size_t num) else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient { light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); -#ifndef SORTING - HWR_Add3DWater(&levelflats[*rover->bottompic], - &extrasubsectors[num], - *rover->bottomheight, - *gr_frontsector->lightlist[light].lightlevel, - rover->alpha-1, rover->master->frontsector); -#else + HWR_AddTransparentFloor(&levelflats[*rover->bottompic], &extrasubsectors[num], false, *rover->bottomheight, *gr_frontsector->lightlist[light].lightlevel, - rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent, + rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, false, *gr_frontsector->lightlist[light].extra_colormap); -#endif } else { HWR_GetLevelFlat(&levelflats[*rover->bottompic]); light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); - HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic], - rover->master->frontsector, 255, false, *gr_frontsector->lightlist[light].extra_colormap); + HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic], + rover->master->frontsector, 255, *gr_frontsector->lightlist[light].extra_colormap); } } // top plane -#ifdef ESLOPE - if (*rover->t_slope) - { - cullHeight = P_GetZAt(*rover->t_slope, viewx, viewy); - centerHeight = P_GetZAt(*rover->t_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); - } - else -#endif - cullHeight = centerHeight = *rover->topheight; + cullHeight = P_GetFFloorTopZAt(rover, viewx, viewy); + centerHeight = P_GetFFloorTopZAt(rover, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y); if (centerHeight >= locFloorHeight && centerHeight <= locCeilingHeight && - ((dup_viewz > cullHeight && !(rover->flags & FF_INVERTPLANES)) || + ((dup_viewz > cullHeight && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) || (dup_viewz < cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { if (rover->flags & FF_FOG) @@ -3703,13 +3170,9 @@ static void HWR_Subsector(size_t num) UINT8 alpha; light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); + alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap); - if (rover->master->frontsector->extra_colormap) - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba); - else - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG); - - HWR_AddTransparentFloor(NULL, + HWR_AddTransparentFloor(0, &extrasubsectors[num], true, *rover->topheight, @@ -3720,29 +3183,21 @@ static void HWR_Subsector(size_t num) else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); -#ifndef SORTING - HWR_Add3DWater(&levelflats[*rover->toppic], - &extrasubsectors[num], - *rover->topheight, - *gr_frontsector->lightlist[light].lightlevel, - rover->alpha-1, rover->master->frontsector); -#else + HWR_AddTransparentFloor(&levelflats[*rover->toppic], &extrasubsectors[num], true, *rover->topheight, *gr_frontsector->lightlist[light].lightlevel, - rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent, + rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, false, *gr_frontsector->lightlist[light].extra_colormap); -#endif - } else { HWR_GetLevelFlat(&levelflats[*rover->toppic]); light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); - HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic], - rover->master->frontsector, 255, false, *gr_frontsector->lightlist[light].extra_colormap); + HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic], + rover->master->frontsector, 255, *gr_frontsector->lightlist[light].extra_colormap); } } } @@ -3750,7 +3205,6 @@ static void HWR_Subsector(size_t num) #endif #endif //doplanes -#ifdef POLYOBJECTS // Draw all the polyobjects in this subsector if (sub->polyList) { @@ -3765,21 +3219,21 @@ static void HWR_Subsector(size_t num) po = (polyobj_t *)(po->link.next); } + // for render stats + rs_numpolyobjects += numpolys; + // Sort polyobjects R_SortPolyObjects(sub); // Draw polyobject lines. HWR_AddPolyObjectSegs(); -#ifdef POLYOBJECTS_PLANES if (sub->validcount != validcount) // This validcount situation seems to let us know that the floors have already been drawn. { // Draw polyobject planes HWR_AddPolyObjectPlanes(); } -#endif } -#endif // Hurder ici se passe les choses INT32�essantes! // on vient de tracer le sol et le plafond @@ -3802,14 +3256,8 @@ static void HWR_Subsector(size_t num) while (count--) { - if (!line->glseg -#ifdef POLYOBJECTS - && !line->polyseg // ignore segs that belong to polyobjects -#endif - ) - { + if (!line->glseg && !line->polyseg) // ignore segs that belong to polyobjects HWR_AddLine(line); - } line++; } } @@ -3879,6 +3327,8 @@ static void HWR_RenderBSPNode(INT32 bspnum) // Decide which side the view point is on INT32 side; + + rs_numbspcalls++; // Found a subsector? if (bspnum & NF_SUBSECTOR) @@ -4091,29 +3541,29 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v return false; } -static void HWR_DrawDropShadow(mobj_t *thing, gr_vissprite_t *spr, fixed_t scale) +static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) { GLPatch_t *gpatch; FOutVector shadowVerts[4]; FSurfaceInfo sSurf; float fscale; float fx; float fy; float offset; - UINT8 lightlevel = 255; extracolormap_t *colormap = NULL; UINT8 i; + SINT8 flip = P_MobjFlip(thing); INT32 light; fixed_t scalemul; UINT16 alpha; fixed_t floordiff; - fixed_t floorz; + fixed_t groundz; fixed_t slopez; - pslope_t *floorslope; + pslope_t *groundslope; - floorz = R_GetShadowZ(thing, &floorslope); + groundz = R_GetShadowZ(thing, &groundslope); - //if (abs(floorz - gr_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes + //if (abs(groundz - gr_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes - floordiff = abs(thing->z - floorz); + floordiff = abs((flip < 0 ? thing->height : 0) + thing->z - groundz); alpha = floordiff / (4*FRACUNIT) + 75; if (alpha >= 255) return; @@ -4124,7 +3574,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, gr_vissprite_t *spr, fixed_t scale HWR_GetPatch(gpatch); scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); + scalemul = FixedMul(scalemul, (thing->radius*2) / SHORT(gpatch->height)); fscale = FIXED_TO_FLOAT(scalemul); fx = FIXED_TO_FLOAT(thing->x); @@ -4136,81 +3586,64 @@ static void HWR_DrawDropShadow(mobj_t *thing, gr_vissprite_t *spr, fixed_t scale // 0--1 if (thing && fabsf(fscale - 1.0f) > 1.0E-36f) - offset = (gpatch->height/2) * fscale; + offset = (SHORT(gpatch->height)/2) * fscale; else - offset = (float)(gpatch->height/2); + offset = (float)(SHORT(gpatch->height)/2); - shadowVerts[0].x = shadowVerts[3].x = fx - offset; - shadowVerts[2].x = shadowVerts[1].x = fx + offset; - shadowVerts[0].z = shadowVerts[1].z = fy - offset; - shadowVerts[3].z = shadowVerts[2].z = fy + offset; + shadowVerts[2].x = shadowVerts[3].x = fx + offset; + shadowVerts[1].x = shadowVerts[0].x = fx - offset; + shadowVerts[1].z = shadowVerts[2].z = fy - offset; + shadowVerts[0].z = shadowVerts[3].z = fy + offset; - if (floorslope) + for (i = 0; i < 4; i++) + { + float oldx = shadowVerts[i].x; + float oldy = shadowVerts[i].z; + shadowVerts[i].x = fx + ((oldx - fx) * gr_viewcos) - ((oldy - fy) * gr_viewsin); + shadowVerts[i].z = fy + ((oldx - fx) * gr_viewsin) + ((oldy - fy) * gr_viewcos); + } + + if (groundslope) { for (i = 0; i < 4; i++) { - slopez = P_GetZAt(floorslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z)); - shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + 0.05f; + slopez = P_GetSlopeZAt(groundslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z)); + shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + flip * 0.05f; } } else { for (i = 0; i < 4; i++) - shadowVerts[i].y = FIXED_TO_FLOAT(floorz) + 0.05f; + shadowVerts[i].y = FIXED_TO_FLOAT(groundz) + flip * 0.05f; } - if (spr->flip) - { - shadowVerts[0].sow = shadowVerts[3].sow = gpatch->max_s; - shadowVerts[2].sow = shadowVerts[1].sow = 0; - } - else - { - shadowVerts[0].sow = shadowVerts[3].sow = 0; - shadowVerts[2].sow = shadowVerts[1].sow = gpatch->max_s; - } + shadowVerts[0].s = shadowVerts[3].s = 0; + shadowVerts[2].s = shadowVerts[1].s = gpatch->max_s; - // flip the texture coords (look familiar?) - if (spr->vflip) - { - shadowVerts[3].tow = shadowVerts[2].tow = gpatch->max_t; - shadowVerts[0].tow = shadowVerts[1].tow = 0; - } - else - { - shadowVerts[3].tow = shadowVerts[2].tow = 0; - shadowVerts[0].tow = shadowVerts[1].tow = gpatch->max_t; - } + shadowVerts[3].t = shadowVerts[2].t = 0; + shadowVerts[0].t = shadowVerts[1].t = gpatch->max_t; if (thing->subsector->sector->numlights) { - light = R_GetPlaneLight(thing->subsector->sector, floorz, false); // Always use the light at the top instead of whatever I was doing before - - lightlevel = *thing->subsector->sector->lightlist[light].lightlevel; + light = R_GetPlaneLight(thing->subsector->sector, groundz, false); // Always use the light at the top instead of whatever I was doing before if (*thing->subsector->sector->lightlist[light].extra_colormap) colormap = *thing->subsector->sector->lightlist[light].extra_colormap; } else { - lightlevel = thing->subsector->sector->lightlevel; - if (thing->subsector->sector->extra_colormap) colormap = thing->subsector->sector->extra_colormap; } - if (colormap) - sSurf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); - else - sSurf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + HWR_Lighting(&sSurf, 0, colormap); + sSurf.PolyColor.s.alpha = alpha; - sSurf.FlatColor.s.alpha = alpha; - - HWD.pfnDrawPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip); + HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip, 3, false); // sprite shader } // This is expecting a pointer to an array containing 4 wallVerts for a sprite -static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts) +static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts, const boolean precip) { if (cv_grspritebillboarding.value && spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE) @@ -4218,7 +3651,7 @@ static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts { float basey = FIXED_TO_FLOAT(spr->mobj->z); float lowy = wallVerts[0].y; - if (P_MobjFlip(spr->mobj) == -1) + if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip { basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height); } @@ -4258,18 +3691,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) INT32 i; float realtop, realbot, top, bot; - float towtop, towbot, towmult; + float ttop, tbot, tmult; float bheight; float realheight, heightmult; const sector_t *sector = spr->mobj->subsector->sector; const lightlist_t *list = sector->lightlist; -#ifdef ESLOPE float endrealtop, endrealbot, endtop, endbot; float endbheight; float endrealheight; fixed_t temp; fixed_t v1x, v1y, v2x, v2y; -#endif this_scale = FIXED_TO_FLOAT(spr->mobj->scale); @@ -4301,25 +3732,25 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (spr->flip) { - baseWallVerts[0].sow = baseWallVerts[3].sow = gpatch->max_s; - baseWallVerts[2].sow = baseWallVerts[1].sow = 0; + baseWallVerts[0].s = baseWallVerts[3].s = gpatch->max_s; + baseWallVerts[2].s = baseWallVerts[1].s = 0; } else { - baseWallVerts[0].sow = baseWallVerts[3].sow = 0; - baseWallVerts[2].sow = baseWallVerts[1].sow = gpatch->max_s; + baseWallVerts[0].s = baseWallVerts[3].s = 0; + baseWallVerts[2].s = baseWallVerts[1].s = gpatch->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - baseWallVerts[3].tow = baseWallVerts[2].tow = gpatch->max_t; - baseWallVerts[0].tow = baseWallVerts[1].tow = 0; + baseWallVerts[3].t = baseWallVerts[2].t = gpatch->max_t; + baseWallVerts[0].t = baseWallVerts[1].t = 0; } else { - baseWallVerts[3].tow = baseWallVerts[2].tow = 0; - baseWallVerts[0].tow = baseWallVerts[1].tow = gpatch->max_t; + baseWallVerts[3].t = baseWallVerts[2].t = 0; + baseWallVerts[0].t = baseWallVerts[1].t = gpatch->max_t; } // if it has a dispoffset, push it a little towards the camera @@ -4333,18 +3764,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) } // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, baseWallVerts); + HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); realtop = top = baseWallVerts[3].y; realbot = bot = baseWallVerts[0].y; - towtop = baseWallVerts[3].tow; - towbot = baseWallVerts[0].tow; - towmult = (towbot - towtop) / (top - bot); + ttop = baseWallVerts[3].t; + tbot = baseWallVerts[0].t; + tmult = (tbot - ttop) / (top - bot); -#ifdef ESLOPE endrealtop = endtop = baseWallVerts[2].y; endrealbot = endbot = baseWallVerts[1].y; -#endif // copy the contents of baseWallVerts into the drawn wallVerts array // baseWallVerts is used to know the final shape to easily get the vertex @@ -4353,12 +3782,12 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (!cv_translucency.value) // translucency disabled { - Surf.FlatColor.s.alpha = 0xFF; + Surf.PolyColor.s.alpha = 0xFF; blend = PF_Translucent|PF_Occlude; } else if (spr->mobj->flags2 & MF2_SHADOW) { - Surf.FlatColor.s.alpha = 0x40; + Surf.PolyColor.s.alpha = 0x40; blend = PF_Translucent; } else if (spr->mobj->frame & FF_TRANSMASK) @@ -4369,11 +3798,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) // work properly under glide nor with fogcolor to ffffff :( // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before - Surf.FlatColor.s.alpha = 0xFF; + Surf.PolyColor.s.alpha = 0xFF; blend = PF_Translucent|PF_Occlude; } - alpha = Surf.FlatColor.s.alpha; + alpha = Surf.PolyColor.s.alpha; // Start with the lightlevel and colormap from the top of the sprite lightlevel = *list[sector->numlights - 1].lightlevel; @@ -4384,75 +3813,45 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (spr->mobj->frame & FF_FULLBRIGHT) lightlevel = 255; -#ifdef ESLOPE for (i = 1; i < sector->numlights; i++) { - fixed_t h = sector->lightlist[i].slope ? P_GetZAt(sector->lightlist[i].slope, spr->mobj->x, spr->mobj->y) - : sector->lightlist[i].height; + fixed_t h = P_GetLightZAt(§or->lightlist[i], spr->mobj->x, spr->mobj->y); if (h <= temp) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *list[i-1].lightlevel; + lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel; colormap = *list[i-1].extra_colormap; break; } } -#else - i = R_GetPlaneLight(sector, temp, false); - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *list[i].lightlevel; - colormap = *list[i].extra_colormap; -#endif for (i = 0; i < sector->numlights; i++) { -#ifdef ESLOPE - if (endtop < endrealbot) -#endif - if (top < realbot) + if (endtop < endrealbot && top < realbot) return; // even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *list[i].lightlevel; + lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel; colormap = *list[i].extra_colormap; } -#ifdef ESLOPE if (i + 1 < sector->numlights) { - if (list[i+1].slope) - { - temp = P_GetZAt(list[i+1].slope, v1x, v1y); - bheight = FIXED_TO_FLOAT(temp); - temp = P_GetZAt(list[i+1].slope, v2x, v2y); - endbheight = FIXED_TO_FLOAT(temp); - } - else - bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height); + temp = P_GetLightZAt(&list[i+1], v1x, v1y); + bheight = FIXED_TO_FLOAT(temp); + temp = P_GetLightZAt(&list[i+1], v2x, v2y); + endbheight = FIXED_TO_FLOAT(temp); } else { bheight = realbot; endbheight = endrealbot; } -#else - if (i + 1 < sector->numlights) - { - bheight = FIXED_TO_FLOAT(list[i+1].height); - } - else - { - bheight = realbot; - } -#endif -#ifdef ESLOPE - if (endbheight >= endtop) -#endif - if (bheight >= top) + if (endbheight >= endtop && bheight >= top) continue; bot = bheight; @@ -4460,18 +3859,15 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (bot < realbot) bot = realbot; -#ifdef ESLOPE endbot = endbheight; if (endbot < endrealbot) endbot = endrealbot; -#endif -#ifdef ESLOPE - wallVerts[3].tow = towtop + ((realtop - top) * towmult); - wallVerts[2].tow = towtop + ((endrealtop - endtop) * towmult); - wallVerts[0].tow = towtop + ((realtop - bot) * towmult); - wallVerts[1].tow = towtop + ((endrealtop - endbot) * towmult); + wallVerts[3].t = ttop + ((realtop - top) * tmult); + wallVerts[2].t = ttop + ((endrealtop - endtop) * tmult); + wallVerts[0].t = ttop + ((realtop - bot) * tmult); + wallVerts[1].t = ttop + ((endrealtop - endbot) * tmult); wallVerts[3].y = top; wallVerts[2].y = endtop; @@ -4501,83 +3897,38 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; } -#else - wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult); - wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult); - wallVerts[2].y = wallVerts[3].y = top; - wallVerts[0].y = wallVerts[1].y = bot; + HWR_Lighting(&Surf, lightlevel, colormap); - // The x and y only need to be adjusted in the case that it's not a papersprite - if (cv_grspritebillboarding.value - && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)) - { - // Get the x and z of the vertices so billboarding draws correctly - realheight = realbot - realtop; - heightmult = (realtop - top) / realheight; - wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult; - wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult; - wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; - wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; + Surf.PolyColor.s.alpha = alpha; - heightmult = (realtop - bot) / realheight; - wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult; - wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult; - wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; - wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; - } -#endif - - if (colormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); - - Surf.FlatColor.s.alpha = alpha; - - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader top = bot; -#ifdef ESLOPE endtop = endbot; -#endif } bot = realbot; -#ifdef ESLOPE endbot = endrealbot; - if (endtop <= endrealbot) -#endif - if (top <= realbot) + if (endtop <= endrealbot && top <= realbot) return; // If we're ever down here, somehow the above loop hasn't draw all the light levels of sprite -#ifdef ESLOPE - wallVerts[3].tow = towtop + ((realtop - top) * towmult); - wallVerts[2].tow = towtop + ((endrealtop - endtop) * towmult); - wallVerts[0].tow = towtop + ((realtop - bot) * towmult); - wallVerts[1].tow = towtop + ((endrealtop - endbot) * towmult); + wallVerts[3].t = ttop + ((realtop - top) * tmult); + wallVerts[2].t = ttop + ((endrealtop - endtop) * tmult); + wallVerts[0].t = ttop + ((realtop - bot) * tmult); + wallVerts[1].t = ttop + ((endrealtop - endbot) * tmult); wallVerts[3].y = top; wallVerts[2].y = endtop; wallVerts[0].y = bot; wallVerts[1].y = endbot; -#else - wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult); - wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult); - wallVerts[2].y = wallVerts[3].y = top; - wallVerts[0].y = wallVerts[1].y = bot; -#endif + HWR_Lighting(&Surf, lightlevel, colormap); - if (colormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + Surf.PolyColor.s.alpha = alpha; - Surf.FlatColor.s.alpha = alpha; - - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader } // -----------------+ @@ -4647,21 +3998,21 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) if (spr->flip) { - wallVerts[0].sow = wallVerts[3].sow = gpatch->max_s; - wallVerts[2].sow = wallVerts[1].sow = 0; + wallVerts[0].s = wallVerts[3].s = gpatch->max_s; + wallVerts[2].s = wallVerts[1].s = 0; }else{ - wallVerts[0].sow = wallVerts[3].sow = 0; - wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; + wallVerts[0].s = wallVerts[3].s = 0; + wallVerts[2].s = wallVerts[1].s = gpatch->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - wallVerts[3].tow = wallVerts[2].tow = gpatch->max_t; - wallVerts[0].tow = wallVerts[1].tow = 0; + wallVerts[3].t = wallVerts[2].t = gpatch->max_t; + wallVerts[0].t = wallVerts[1].t = 0; }else{ - wallVerts[3].tow = wallVerts[2].tow = 0; - wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; + wallVerts[3].t = wallVerts[2].t = 0; + wallVerts[0].t = wallVerts[1].t = gpatch->max_t; } // cache the patch in the graphics card memory @@ -4680,7 +4031,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) } // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, wallVerts); + HWR_RotateSpritePolyToAim(spr, wallVerts, false); // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components @@ -4693,24 +4044,21 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) extracolormap_t *colormap = sector->extra_colormap; if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = sector->lightlevel; + lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; - if (colormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + HWR_Lighting(&Surf, lightlevel, colormap); } { FBITFIELD blend = 0; if (!cv_translucency.value) // translucency disabled { - Surf.FlatColor.s.alpha = 0xFF; + Surf.PolyColor.s.alpha = 0xFF; blend = PF_Translucent|PF_Occlude; } else if (spr->mobj->flags2 & MF2_SHADOW) { - Surf.FlatColor.s.alpha = 0x40; + Surf.PolyColor.s.alpha = 0x40; blend = PF_Translucent; } else if (spr->mobj->frame & FF_TRANSMASK) @@ -4721,11 +4069,11 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // work properly under glide nor with fogcolor to ffffff :( // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before - Surf.FlatColor.s.alpha = 0xFF; + Surf.PolyColor.s.alpha = 0xFF; blend = PF_Translucent|PF_Occlude; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader } } @@ -4764,13 +4112,13 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) wallVerts[1].z = wallVerts[2].z = spr->z2; // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, wallVerts); + HWR_RotateSpritePolyToAim(spr, wallVerts, true); - wallVerts[0].sow = wallVerts[3].sow = 0; - wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; + wallVerts[0].s = wallVerts[3].s = 0; + wallVerts[2].s = wallVerts[1].s = gpatch->max_s; - wallVerts[3].tow = wallVerts[2].tow = 0; - wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; + wallVerts[3].t = wallVerts[2].t = 0; + wallVerts[0].t = wallVerts[1].t = gpatch->max_t; // cache the patch in the graphics card memory //12/12/99: Hurdler: same comment as above (for md2) @@ -4790,7 +4138,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *sector->lightlist[light].lightlevel; + lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; if (*sector->lightlist[light].extra_colormap) colormap = *sector->lightlist[light].extra_colormap; @@ -4798,21 +4146,18 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) else { if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = sector->lightlevel; + lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; if (sector->extra_colormap) colormap = sector->extra_colormap; } - if (colormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + HWR_Lighting(&Surf, lightlevel, colormap); } if (spr->mobj->flags2 & MF2_SHADOW) { - Surf.FlatColor.s.alpha = 0x40; + Surf.PolyColor.s.alpha = 0x40; blend = PF_Translucent; } else if (spr->mobj->frame & FF_TRANSMASK) @@ -4823,121 +4168,67 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) // work properly under glide nor with fogcolor to ffffff :( // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before - Surf.FlatColor.s.alpha = 0xFF; + Surf.PolyColor.s.alpha = 0xFF; blend = PF_Translucent|PF_Occlude; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader } #endif // -------------------------------------------------------------------------- // Sort vissprites by distance // -------------------------------------------------------------------------- -static gr_vissprite_t gr_vsprsortedhead; +gr_vissprite_t* gr_vsprorder[MAXVISSPRITES]; -static void HWR_SortVisSprites(void) +// Note: For more correct transparency the transparent sprites would need to be +// sorted and drawn together with transparent surfaces. +static int CompareVisSprites(const void *p1, const void *p2) { - UINT32 i; - gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst; - gr_vissprite_t *best = NULL; - gr_vissprite_t unsorted; - float bestdist = 0.0f; - INT32 bestdispoffset = 0; - - if (!gr_visspritecount) - return; - - dsfirst = HWR_GetVisSprite(0); - - for (i = 0, dsnext = dsfirst, ds = NULL; i < gr_visspritecount; i++) - { - dsprev = ds; - ds = dsnext; - if (i < gr_visspritecount - 1) dsnext = HWR_GetVisSprite(i + 1); - - ds->next = dsnext; - ds->prev = dsprev; - } - - // Fix first and last. ds still points to the last one after the loop - dsfirst->prev = &unsorted; - unsorted.next = dsfirst; - if (ds) - ds->next = &unsorted; - unsorted.prev = ds; - - // pull the vissprites out by scale - gr_vsprsortedhead.next = gr_vsprsortedhead.prev = &gr_vsprsortedhead; - for (i = 0; i < gr_visspritecount; i++) - { - best = NULL; - for (ds = unsorted.next; ds != &unsorted; ds = ds->next) - { - if (!best || ds->tz > bestdist) - { - bestdist = ds->tz; - bestdispoffset = ds->dispoffset; - best = ds; - } - // order visprites of same scale by dispoffset, smallest first - else if (fabsf(ds->tz - bestdist) < 1.0E-36f && ds->dispoffset < bestdispoffset) - { - bestdispoffset = ds->dispoffset; - best = ds; - } - } - if (best) - { - best->next->prev = best->prev; - best->prev->next = best->next; - best->next = &gr_vsprsortedhead; - best->prev = gr_vsprsortedhead.prev; - } - gr_vsprsortedhead.prev->next = best; - gr_vsprsortedhead.prev = best; - } - + gr_vissprite_t* spr1 = *(gr_vissprite_t*const*)p1; + gr_vissprite_t* spr2 = *(gr_vissprite_t*const*)p2; + int idiff; + float fdiff; + + // Make transparent sprites last. Comment from the previous sort implementation: // Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the // mix and they want to be translucent. So let's place all the translucent sprites and MD2's AFTER // everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine. // We just need to move all translucent ones to the end in order // TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that - best = gr_vsprsortedhead.next; + int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK); + int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK); + idiff = transparency1 - transparency2; + if (idiff != 0) return idiff; + + fdiff = spr2->tz - spr1->tz; // this order seems correct when checking with apitrace. Back to front. + if (fabsf(fdiff) < 1.0E-36f) + return spr1->dispoffset - spr2->dispoffset; // smallest dispoffset first if sprites are at (almost) same location. + else if (fdiff > 0) + return 1; + else + return -1; +} + +static void HWR_SortVisSprites(void) +{ + UINT32 i; for (i = 0; i < gr_visspritecount; i++) { - if ((best->mobj->flags2 & MF2_SHADOW) || (best->mobj->frame & FF_TRANSMASK)) - { - if (best == gr_vsprsortedhead.next) - { - gr_vsprsortedhead.next = best->next; - } - best->prev->next = best->next; - best->next->prev = best->prev; - best->prev = gr_vsprsortedhead.prev; - gr_vsprsortedhead.prev->next = best; - gr_vsprsortedhead.prev = best; - ds = best; - best = best->next; - ds->next = &gr_vsprsortedhead; - } - else - best = best->next; + gr_vsprorder[i] = HWR_GetVisSprite(i); } + qsort(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites); } // A drawnode is something that points to a 3D floor, 3D side, or masked // middle texture. This is used for sorting with sprites. typedef struct { - wallVert3D wallVerts[4]; + FOutVector wallVerts[4]; FSurfaceInfo Surf; INT32 texnum; FBITFIELD blend; INT32 drawcount; -#ifndef SORTING - fixed_t fixedheight; -#endif boolean fogwall; INT32 lightlevel; extracolormap_t *wallcolormap; // Doing the lighting in HWR_RenderWall now for correct fog after sorting @@ -4946,7 +4237,7 @@ typedef struct static wallinfo_t *wallinfo = NULL; static size_t numwalls = 0; // a list of transparent walls to be drawn -static void HWR_RenderWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap); +void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap); #define MAX_TRANSPARENTWALL 256 @@ -4985,9 +4276,6 @@ typedef struct static size_t numpolyplanes = 0; // a list of transparent poyobject floors to be drawn static polyplaneinfo_t *polyplaneinfo = NULL; -#ifndef SORTING -size_t numfloors = 0; -#else //Hurdler: 3D water sutffs typedef struct gr_drawnode_s { @@ -5005,8 +4293,7 @@ static INT32 drawcount = 0; #define MAX_TRANSPARENTFLOOR 512 // This will likely turn into a copy of HWR_Add3DWater and replace it. -void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, - fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap) +void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap) { static size_t allocedplanes = 0; @@ -5037,8 +4324,7 @@ void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boo // Adding this for now until I can create extrasubsector info for polyobjects // When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane -void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, - fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap) +void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap) { static size_t allocedpolyplanes = 0; @@ -5065,28 +4351,68 @@ void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polyse numpolyplanes++; } +// putting sortindex and sortnode here so the comparator function can see them +gr_drawnode_t *sortnode; +size_t *sortindex; + +static int CompareDrawNodes(const void *p1, const void *p2) +{ + size_t n1 = *(const size_t*)p1; + size_t n2 = *(const size_t*)p2; + INT32 v1 = 0; + INT32 v2 = 0; + INT32 diff; + if (sortnode[n1].plane) + v1 = sortnode[n1].plane->drawcount; + else if (sortnode[n1].polyplane) + v1 = sortnode[n1].polyplane->drawcount; + else if (sortnode[n1].wall) + v1 = sortnode[n1].wall->drawcount; + else I_Error("CompareDrawNodes: n1 unknown"); + + if (sortnode[n2].plane) + v2 = sortnode[n2].plane->drawcount; + else if (sortnode[n2].polyplane) + v2 = sortnode[n2].polyplane->drawcount; + else if (sortnode[n2].wall) + v2 = sortnode[n2].wall->drawcount; + else I_Error("CompareDrawNodes: n2 unknown"); + + diff = v2 - v1; + if (diff == 0) I_Error("CompareDrawNodes: diff is zero"); + return diff; +} + +static int CompareDrawNodePlanes(const void *p1, const void *p2) +{ + size_t n1 = *(const size_t*)p1; + size_t n2 = *(const size_t*)p2; + if (!sortnode[n1].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n1)"); + if (!sortnode[n2].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n2)"); + return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz); +} + // // HWR_CreateDrawNodes // Creates and sorts a list of drawnodes for the scene being rendered. static void HWR_CreateDrawNodes(void) { - UINT32 i = 0, p = 0, prev = 0, loop; - const fixed_t pviewz = dup_viewz; + UINT32 i = 0, p = 0; + size_t run_start = 0; // Dump EVERYTHING into a huge drawnode list. Then we'll sort it! // Could this be optimized into _AddTransparentWall/_AddTransparentPlane? // Hell yes! But sort algorithm must be modified to use a linked list. - gr_drawnode_t *sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes) - + (sizeof(polyplaneinfo_t)*numpolyplanes) - + (sizeof(wallinfo_t)*numwalls) - ,PU_STATIC, NULL); + sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes) + + (sizeof(polyplaneinfo_t)*numpolyplanes) + + (sizeof(wallinfo_t)*numwalls) + ,PU_STATIC, NULL); // todo: // However, in reality we shouldn't be re-copying and shifting all this information // that is already lying around. This should all be in some sort of linked list or lists. - size_t *sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL); - - // If true, swap the draw order. - boolean shift = false; + sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL); + + rs_hw_nodesorttime = I_GetTimeMicros(); for (i = 0; i < numplanes; i++, p++) { @@ -5105,110 +4431,50 @@ static void HWR_CreateDrawNodes(void) sortnode[p].wall = &wallinfo[i]; sortindex[p] = p; } + + rs_numdrawnodes = p; // p is the number of stuff to sort - // Add the 3D floors, thicksides, and masked textures... - // Instead of going through drawsegs, we need to iterate - // through the lists of masked textures and - // translucent ffloors being drawn. + // sort the list based on the value of the 'drawcount' member of the drawnodes. + qsort(sortindex, p, sizeof(size_t), CompareDrawNodes); - // This is a bubble sort! Wahoo! - - // Stuff is sorted: - // sortnode[sortindex[0]] = farthest away - // sortnode[sortindex[p-1]] = closest - // "i" should be closer. "prev" should be further. - // The lower drawcount is, the further it is from the screen. - - for (loop = 0; loop < p; loop++) + // an additional pass is needed to correct the order of consecutive planes in the list. + // for each consecutive run of planes in the list, sort that run based on plane height and view height. + while (run_start < p-1)// p-1 because a 1 plane run at the end of the list does not count { - for (i = 1; i < p; i++) + // locate run start + if (sortnode[sortindex[run_start]].plane) { - prev = i-1; - if (sortnode[sortindex[i]].plane) + // found it, now look for run end + size_t run_end;// (inclusive) + for (i = run_start+1; i < p; i++)// size_t and UINT32 being used mixed here... shouldnt break anything though.. { - // What are we comparing it with? - if (sortnode[sortindex[prev]].plane) - { - // Plane (i) is further away than plane (prev) - if (ABS(sortnode[sortindex[i]].plane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].plane->fixedheight - pviewz)) - shift = true; - } - if (sortnode[sortindex[prev]].polyplane) - { - // Plane (i) is further away than polyplane (prev) - if (ABS(sortnode[sortindex[i]].plane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].polyplane->fixedheight - pviewz)) - shift = true; - } - else if (sortnode[sortindex[prev]].wall) - { - // Plane (i) is further than wall (prev) - if (sortnode[sortindex[i]].plane->drawcount > sortnode[sortindex[prev]].wall->drawcount) - shift = true; - } + if (!sortnode[sortindex[i]].plane) break; } - else if (sortnode[sortindex[i]].polyplane) + run_end = i-1; + if (run_end > run_start)// if there are multiple consecutive planes, not just one { - // What are we comparing it with? - if (sortnode[sortindex[prev]].plane) - { - // Plane (i) is further away than plane (prev) - if (ABS(sortnode[sortindex[i]].polyplane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].plane->fixedheight - pviewz)) - shift = true; - } - if (sortnode[sortindex[prev]].polyplane) - { - // Plane (i) is further away than polyplane (prev) - if (ABS(sortnode[sortindex[i]].polyplane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].polyplane->fixedheight - pviewz)) - shift = true; - } - else if (sortnode[sortindex[prev]].wall) - { - // Plane (i) is further than wall (prev) - if (sortnode[sortindex[i]].polyplane->drawcount > sortnode[sortindex[prev]].wall->drawcount) - shift = true; - } - } - else if (sortnode[sortindex[i]].wall) - { - // What are we comparing it with? - if (sortnode[sortindex[prev]].plane) - { - // Wall (i) is further than plane(prev) - if (sortnode[sortindex[i]].wall->drawcount > sortnode[sortindex[prev]].plane->drawcount) - shift = true; - } - if (sortnode[sortindex[prev]].polyplane) - { - // Wall (i) is further than polyplane(prev) - if (sortnode[sortindex[i]].wall->drawcount > sortnode[sortindex[prev]].polyplane->drawcount) - shift = true; - } - else if (sortnode[sortindex[prev]].wall) - { - // Wall (i) is further than wall (prev) - if (sortnode[sortindex[i]].wall->drawcount > sortnode[sortindex[prev]].wall->drawcount) - shift = true; - } + // consecutive run of planes found, now sort it + qsort(sortindex + run_start, run_end - run_start + 1, sizeof(size_t), CompareDrawNodePlanes); } + run_start = run_end + 1;// continue looking for runs coming right after this one + } + else + { + // this wasnt the run start, try next one + run_start++; + } + } - if (shift) - { - size_t temp; + rs_hw_nodesorttime = I_GetTimeMicros() - rs_hw_nodesorttime; + + rs_hw_nodedrawtime = I_GetTimeMicros(); - temp = sortindex[prev]; - sortindex[prev] = sortindex[i]; - sortindex[i] = temp; - - shift = false; - } - - } //i++ - } // loop++ - - HWD.pfnSetTransform(&atransform); // Okay! Let's draw it all! Woo! + HWD.pfnSetTransform(&atransform); + HWD.pfnSetShader(0); + for (i = 0; i < p; i++) { if (sortnode[sortindex[i]].plane) @@ -5219,7 +4485,7 @@ static void HWR_CreateDrawNodes(void) if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture)) HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat); HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel, - sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->fogplane, sortnode[sortindex[i]].plane->planecolormap); + sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->planecolormap); } else if (sortnode[sortindex[i]].polyplane) { @@ -5239,6 +4505,8 @@ static void HWR_CreateDrawNodes(void) sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap); } } + + rs_hw_nodedrawtime = I_GetTimeMicros() - rs_hw_nodedrawtime; numwalls = 0; numplanes = 0; @@ -5249,60 +4517,53 @@ static void HWR_CreateDrawNodes(void) Z_Free(sortindex); } -#endif - // -------------------------------------------------------------------------- // Draw all vissprites // -------------------------------------------------------------------------- -#ifdef SORTING + // added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other static void HWR_DrawSprites(void) { - if (gr_visspritecount > 0) + UINT32 i; + HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_grmodellighting.value); + for (i = 0; i < gr_visspritecount; i++) { - gr_vissprite_t *spr; - - // draw all vissprites back to front - for (spr = gr_vsprsortedhead.next; - spr != &gr_vsprsortedhead; - spr = spr->next) - { + gr_vissprite_t *spr = gr_vsprorder[i]; #ifdef HWPRECIP - if (spr->precip) - HWR_DrawPrecipitationSprite(spr); - else + if (spr->precip) + HWR_DrawPrecipitationSprite(spr); + else #endif + { + if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value) { - if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value) - { - HWR_DrawDropShadow(spr->mobj, spr, spr->mobj->shadowscale); - } + HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale); + } - if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - { - if (!cv_grmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) - HWR_DrawSprite(spr); - else - { - if (!HWR_DrawModel(spr)) - HWR_DrawSprite(spr); - } - } + if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + { + if (!cv_grmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) + HWR_DrawSprite(spr); else { - if (!cv_grmodels.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) + if (!HWR_DrawModel(spr)) + HWR_DrawSprite(spr); + } + } + else + { + if (!cv_grmodels.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) + HWR_DrawSprite(spr); + else + { + if (!HWR_DrawModel(spr)) HWR_DrawSprite(spr); - else - { - if (!HWR_DrawModel(spr)) - HWR_DrawSprite(spr); - } } } } } + HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, 0); } -#endif // -------------------------------------------------------------------------- // HWR_AddSprites @@ -5514,10 +4775,10 @@ static void HWR_ProjectSprite(mobj_t *thing) rotsprite = sprframe->rotsprite.patch[rot][rollangle]; if (rotsprite != NULL) { - spr_width = rotsprite->width << FRACBITS; - spr_height = rotsprite->height << FRACBITS; - spr_offset = rotsprite->leftoffset << FRACBITS; - spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_width = SHORT(rotsprite->width) << FRACBITS; + spr_height = SHORT(rotsprite->height) << FRACBITS; + spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS; + spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS; // flip -> rotate, not rotate -> flip flip = 0; } @@ -5796,7 +5057,7 @@ static void HWR_DrawSkyBackground(player_t *player) //04/01/2000: Hurdler: added for T&L // It should replace all other gr_viewxxx when finished - dometransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + HWR_SetTransformAiming(&dometransform, player, false); dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); if (*type == postimg_flip) @@ -5857,8 +5118,8 @@ static void HWR_DrawSkyBackground(player_t *player) 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) + v[0].s = v[3].s = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left + v[2].s = v[1].s = v[0].s + (1.0f/dimensionmultiply); // right (or left + 1.0f) // use +angle and -1.0f above instead if you wanted old backwards behavior // Y @@ -5876,13 +5137,13 @@ static void HWR_DrawSkyBackground(player_t *player) 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) + v[3].t = v[2].t = -(0.5f-(0.5f/dimensionmultiply)); // top + v[0].t = v[1].t = v[3].t - (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) + v[0].t = v[1].t = -(0.5f-(0.5f/dimensionmultiply)); // bottom + v[3].t = v[2].t = v[0].t - (1.0f/dimensionmultiply); // top (or bottom - 1.0f) } angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; @@ -5890,16 +5151,18 @@ static void HWR_DrawSkyBackground(player_t *player) 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); + v[3].t = v[2].t += ((float) angle / angleturn); + v[0].t = v[1].t += ((float) angle / angleturn); } else { - v[3].tow = v[2].tow -= ((float) angle / angleturn); - v[0].tow = v[1].tow -= ((float) angle / angleturn); + v[3].t = v[2].t -= ((float) angle / angleturn); + v[0].t = v[1].t -= ((float) angle / angleturn); } + HWD.pfnSetShader(7); // sky shader HWD.pfnDrawPolygon(NULL, v, 4, 0); + HWD.pfnSetShader(0); } } @@ -5963,6 +5226,28 @@ void HWR_SetViewSize(void) HWD.pfnFlushScreenTextures(); } +// Set view aiming, for the sky dome, the skybox, +// and the normal view, all with a single function. +static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox) +{ + // 1 = always on + // 2 = chasecam only + if (cv_grshearing.value == 1 || (cv_grshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))) + { + fixed_t fixedaiming = AIMINGTODY(aimingangle); + trans->viewaiming = FIXED_TO_FLOAT(fixedaiming); + trans->shearing = true; + gr_aimingangle = 0; + } + else + { + trans->shearing = false; + gr_aimingangle = aimingangle; + } + + trans->anglex = (float)(gr_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); +} + // ========================================================================== // Same as rendering the player view, but from the skybox object // ========================================================================== @@ -6015,16 +5300,16 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) gr_viewsin = FIXED_TO_FLOAT(viewsin); gr_viewcos = FIXED_TO_FLOAT(viewcos); - gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(aimingangle>>ANGLETOFINESHIFT)); - gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(aimingangle>>ANGLETOFINESHIFT)); - //04/01/2000: Hurdler: added for T&L // It should replace all other gr_viewxxx when finished memset(&atransform, 0x00, sizeof(FTransform)); - atransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + HWR_SetTransformAiming(&atransform, player, true); atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gr_aimingangle>>ANGLETOFINESHIFT)); + gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(gr_aimingangle>>ANGLETOFINESHIFT)); + if (*type == postimg_flip) atransform.flip = true; else @@ -6036,6 +5321,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) atransform.scalex = 1; atransform.scaley = (float)vid.width/vid.height; atransform.scalez = 1; + atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails if (player->viewrollangle != 0) @@ -6051,14 +5337,6 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) //------------------------------------------------------------------------ HWR_ClearView(); -if (0) -{ // I don't think this is ever used. - if (cv_grfog.value) - HWR_FoggingOn(); // First of all, turn it on, set the default user settings too - else - HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); // Turn it off -} - if (drawsky) HWR_DrawSkyBackground(player); @@ -6067,13 +5345,12 @@ if (0) HWR_ClearSprites(); -#ifdef SORTING drawcount = 0; -#endif + #ifdef NEWCLIP if (rendermode == render_opengl) { - angle_t a1 = gld_FrustumAngle(); + angle_t a1 = gld_FrustumAngle(gr_aimingangle); gld_clipper_Clear(); gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1); #ifdef HAVE_SPHEREFRUSTRUM @@ -6088,8 +5365,15 @@ if (0) // Actually it only works on Walls and Planes HWD.pfnSetTransform(&atransform); + // Reset the shader state. + HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value); + HWD.pfnSetShader(0); + validcount++; + if (cv_grbatching.value) + HWR_StartBatching(); + HWR_RenderBSPNode((INT32)numnodes-1); #ifndef NEWCLIP @@ -6100,14 +5384,14 @@ if (0) viewangle = localaiming2; // Handle stuff when you are looking farther up or down. - if ((aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT)) + if ((gr_aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT)) { dup_viewangle += ANGLE_90; HWR_ClearClipSegs(); HWR_RenderBSPNode((INT32)numnodes-1); //left dup_viewangle += ANGLE_90; - if (((INT32)aimingangle > ANGLE_45 || (INT32)aimingangle<-ANGLE_45)) + if (((INT32)gr_aimingangle > ANGLE_45 || (INT32)gr_aimingangle<-ANGLE_45)) { HWR_ClearClipSegs(); HWR_RenderBSPNode((INT32)numnodes-1); //back @@ -6121,6 +5405,9 @@ if (0) } #endif + if (cv_grbatching.value) + HWR_RenderBatches(); + // Check for new console commands. NetUpdate(); @@ -6131,39 +5418,21 @@ if (0) #endif // Draw MD2 and sprites -#ifdef SORTING HWR_SortVisSprites(); -#endif - -#ifdef SORTING HWR_DrawSprites(); -#endif + #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? HWR_DrawCoronas(); #endif -#ifdef SORTING if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything { HWR_CreateDrawNodes(); } -#else - if (numfloors || numwalls) - { - HWD.pfnSetTransform(&atransform); - if (numfloors) - HWR_Render3DWater(); - if (numwalls) - HWR_RenderTransparentWalls(); - } -#endif HWD.pfnSetTransform(NULL); - - // put it off for menus etc - if (cv_grfog.value) - HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); + HWD.pfnUnSetShader(); // Check for new console commands. NetUpdate(); @@ -6195,6 +5464,9 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) ClearColor.blue = 0.0f; ClearColor.alpha = 1.0f; + if (cv_grshaders.value) + HWD.pfnSetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime. + if (viewnumber == 0) // Only do it if it's the first screen being rendered HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. @@ -6241,16 +5513,16 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) gr_viewsin = FIXED_TO_FLOAT(viewsin); gr_viewcos = FIXED_TO_FLOAT(viewcos); - gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(aimingangle>>ANGLETOFINESHIFT)); - gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(aimingangle>>ANGLETOFINESHIFT)); - //04/01/2000: Hurdler: added for T&L // It should replace all other gr_viewxxx when finished memset(&atransform, 0x00, sizeof(FTransform)); - atransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + HWR_SetTransformAiming(&atransform, player, false); atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gr_aimingangle>>ANGLETOFINESHIFT)); + gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(gr_aimingangle>>ANGLETOFINESHIFT)); + if (*type == postimg_flip) atransform.flip = true; else @@ -6262,6 +5534,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) atransform.scalex = 1; atransform.scaley = (float)vid.width/vid.height; atransform.scalez = 1; + atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails if (player->viewrollangle != 0) @@ -6277,14 +5550,6 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) //------------------------------------------------------------------------ HWR_ClearView(); // Clears the depth buffer and resets the view I believe -if (0) -{ // I don't think this is ever used. - if (cv_grfog.value) - HWR_FoggingOn(); // First of all, turn it on, set the default user settings too - else - HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); // Turn it off -} - if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox HWR_DrawSkyBackground(player); @@ -6293,13 +5558,12 @@ if (0) HWR_ClearSprites(); -#ifdef SORTING drawcount = 0; -#endif + #ifdef NEWCLIP if (rendermode == render_opengl) { - angle_t a1 = gld_FrustumAngle(); + angle_t a1 = gld_FrustumAngle(gr_aimingangle); gld_clipper_Clear(); gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1); #ifdef HAVE_SPHEREFRUSTRUM @@ -6314,8 +5578,19 @@ if (0) // Actually it only works on Walls and Planes HWD.pfnSetTransform(&atransform); + // Reset the shader state. + HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value); + HWD.pfnSetShader(0); + + rs_numbspcalls = 0; + rs_numpolyobjects = 0; + rs_bsptime = I_GetTimeMicros(); + validcount++; + if (cv_grbatching.value) + HWR_StartBatching(); + HWR_RenderBSPNode((INT32)numnodes-1); #ifndef NEWCLIP @@ -6326,14 +5601,14 @@ if (0) viewangle = localaiming2; // Handle stuff when you are looking farther up or down. - if ((aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT)) + if ((gr_aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT)) { dup_viewangle += ANGLE_90; HWR_ClearClipSegs(); HWR_RenderBSPNode((INT32)numnodes-1); //left dup_viewangle += ANGLE_90; - if (((INT32)aimingangle > ANGLE_45 || (INT32)aimingangle<-ANGLE_45)) + if (((INT32)gr_aimingangle > ANGLE_45 || (INT32)gr_aimingangle<-ANGLE_45)) { HWR_ClearClipSegs(); HWR_RenderBSPNode((INT32)numnodes-1); //back @@ -6347,6 +5622,11 @@ if (0) } #endif + rs_bsptime = I_GetTimeMicros() - rs_bsptime; + + if (cv_grbatching.value) + HWR_RenderBatches(); + // Check for new console commands. NetUpdate(); @@ -6357,39 +5637,29 @@ if (0) #endif // Draw MD2 and sprites -#ifdef SORTING + rs_numsprites = gr_visspritecount; + rs_hw_spritesorttime = I_GetTimeMicros(); HWR_SortVisSprites(); -#endif - -#ifdef SORTING + rs_hw_spritesorttime = I_GetTimeMicros() - rs_hw_spritesorttime; + rs_hw_spritedrawtime = I_GetTimeMicros(); HWR_DrawSprites(); -#endif + rs_hw_spritedrawtime = I_GetTimeMicros() - rs_hw_spritedrawtime; + #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? HWR_DrawCoronas(); #endif -#ifdef SORTING + rs_numdrawnodes = 0; + rs_hw_nodesorttime = 0; + rs_hw_nodedrawtime = 0; if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything { HWR_CreateDrawNodes(); } -#else - if (numfloors || numpolyplanes || numwalls) - { - HWD.pfnSetTransform(&atransform); - if (numfloors) - HWR_Render3DWater(); - if (numwalls) - HWR_RenderTransparentWalls(); - } -#endif HWD.pfnSetTransform(NULL); - - // put it off for menus etc - if (cv_grfog.value) - HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); + HWD.pfnUnSetShader(); HWR_DoPostProcessor(player); @@ -6401,60 +5671,16 @@ if (0) HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); } -// ========================================================================== -// FOG -// ========================================================================== - -/// \author faB - -static UINT32 atohex(const char *s) -{ - INT32 iCol; - const char *sCol; - char cCol; - INT32 i; - - if (strlen(s)<6) - return 0; - - iCol = 0; - sCol = s; - for (i = 0; i < 6; i++, sCol++) - { - iCol <<= 4; - cCol = *sCol; - if (cCol >= '0' && cCol <= '9') - iCol |= cCol - '0'; - else - { - if (cCol >= 'F') - cCol -= 'a' - 'A'; - if (cCol >= 'A' && cCol <= 'F') - iCol = iCol | (cCol - 'A' + 10); - } - } - //CONS_Debug(DBG_RENDER, "col %x\n", iCol); - return iCol; -} - -static void HWR_FoggingOn(void) -{ - HWD.pfnSetSpecialState(HWD_SET_FOG_COLOR, atohex(cv_grfogcolor.string)); - HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value); - HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 1); -} - // ========================================================================== // 3D ENGINE COMMANDS // ========================================================================== -static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}}; static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; +static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; +static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; -static void CV_grmodellighting_OnChange(void); static void CV_grfiltermode_OnChange(void); static void CV_granisotropic_OnChange(void); -static void CV_grfogdensity_OnChange(void); static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, @@ -6464,10 +5690,8 @@ static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA {0, NULL}}; CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; +consvar_t cv_grshaders = {"gr_shaders", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grsoftwarefog = {"gr_softwarefog", "Off", CV_SAVE, grsoftwarefog_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #ifdef ALAM_LIGHTING consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -6478,15 +5702,13 @@ consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL, 0, consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_grmodellighting_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grshearing = {"gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grfakecontrast = {"gr_fakecontrast", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - -consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsigned, - CV_grfogdensity_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, grfiltermode_cons_t, CV_grfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -6496,17 +5718,7 @@ consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotro consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static void CV_grmodellighting_OnChange(void) -{ - if (rendermode == render_opengl) - HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_grmodellighting.value); -} - -static void CV_grfogdensity_OnChange(void) -{ - if (rendermode == render_opengl) - HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value); -} +consvar_t cv_grbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static void CV_grfiltermode_OnChange(void) { @@ -6525,11 +5737,6 @@ void HWR_AddCommands(void) { CV_RegisterVar(&cv_fovchange); - CV_RegisterVar(&cv_grfogdensity); - CV_RegisterVar(&cv_grfogcolor); - CV_RegisterVar(&cv_grfog); - CV_RegisterVar(&cv_grsoftwarefog); - #ifdef ALAM_LIGHTING CV_RegisterVar(&cv_grstaticlighting); CV_RegisterVar(&cv_grdynamiclighting); @@ -6544,11 +5751,15 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_grskydome); CV_RegisterVar(&cv_grspritebillboarding); CV_RegisterVar(&cv_grfakecontrast); + CV_RegisterVar(&cv_grshearing); + CV_RegisterVar(&cv_grshaders); CV_RegisterVar(&cv_grfiltermode); - CV_RegisterVar(&cv_grrounddown); CV_RegisterVar(&cv_grcorrecttricks); CV_RegisterVar(&cv_grsolvetjoin); + + CV_RegisterVar(&cv_renderstats); + CV_RegisterVar(&cv_grbatching); #ifndef NEWCLIP CV_RegisterVar(&cv_grclipwalls); @@ -6573,17 +5784,12 @@ void HWR_Startup(void) { static boolean startupdone = false; - // setup GLPatch_t scaling - gr_patch_scalex = (float)(1.0f / vid.width); - gr_patch_scaley = (float)(1.0f / vid.height); - - // initalze light lut translation - InitLumLut(); - // do this once if (!startupdone) { + INT32 i; CONS_Printf("HWR_Startup()...\n"); + HWR_InitPolyPool(); HWR_AddSessionCommands(); HWR_InitTextureCache(); @@ -6591,6 +5797,12 @@ void HWR_Startup(void) #ifdef ALAM_LIGHTING HWR_InitLight(); #endif + + // read every custom shader + for (i = 0; i < numwadfiles; i++) + HWR_ReadShaders(i, (wadfiles[i]->type == RET_PK3)); + if (!HWR_LoadShaders()) + gr_shadersavailable = false; } if (rendermode == render_opengl) @@ -6605,8 +5817,6 @@ void HWR_Startup(void) void HWR_Switch(void) { // Set special states from CVARs - HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_grmodellighting.value); - HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value); HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value); HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value); } @@ -6619,7 +5829,6 @@ void HWR_Shutdown(void) CONS_Printf("HWR_Shutdown()\n"); HWR_FreeExtraSubsectors(); HWR_FreePolyPool(); - HWR_FreeMipmapCache(); HWR_FreeTextureCache(); HWD.pfnFlushScreenTextures(); } @@ -6647,106 +5856,7 @@ void transform(float *cx, float *cy, float *cz) *cx *= gr_fovlud; } - -//Hurdler: 3D Water stuff -#ifndef SORTING - -#define MAX_3DWATER 512 - -static void HWR_Add3DWater(levelflat_t *levelflat, extrasubsector_t *xsub, - fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector) -{ - static size_t allocedplanes = 0; - - // Force realloc if buffer has been freed - if (!planeinfo) - allocedplanes = 0; - - if (allocedplanes < numfloors + 1) - { - allocedplanes += MAX_3DWATER; - Z_Realloc(planeinfo, allocedplanes * sizeof (*planeinfo), PU_LEVEL, &planeinfo); - } - planeinfo[numfloors].fixedheight = fixedheight; - planeinfo[numfloors].lightlevel = lightlevel; - planeinfo[numfloors].levelflat = levelflat; - planeinfo[numfloors].xsub = xsub; - planeinfo[numfloors].alpha = alpha; - planeinfo[numfloors].FOFSector = FOFSector; - numfloors++; -} - -#define DIST_PLANE(i) ABS(planeinfo[(i)].fixedheight-dup_viewz) - -static void HWR_QuickSortPlane(INT32 start, INT32 finish) -{ - INT32 left = start; - INT32 right = finish; - INT32 starterval = (INT32)((right+left)/2); //pick a starter - - planeinfo_t temp; - - //'sort of sort' the two halves of the data list about starterval - while (right > left); - { - while (DIST_PLANE(left) < DIST_PLANE(starterval)) left++; //attempt to find a bigger value on the left - while (DIST_PLANE(right) > DIST_PLANE(starterval)) right--; //attempt to find a smaller value on the right - - if (left < right) //if we haven't gone too far - { - //switch them - M_Memcpy(&temp, &planeinfo[left], sizeof (planeinfo_t)); - M_Memcpy(&planeinfo[left], &planeinfo[right], sizeof (planeinfo_t)); - M_Memcpy(&planeinfo[right], &temp, sizeof (planeinfo_t)); - //move the bounds - left++; - right--; - } - } - - if (start < right) HWR_QuickSortPlane(start, right); - if (left < finish) HWR_QuickSortPlane(left, finish); -} - -static void HWR_Render3DWater(void) -{ - size_t i; - - //bubble sort 3D Water for correct alpha blending - { - boolean permut = true; - while (permut) - { - size_t j; - for (j = 0, permut= false; j < numfloors-1; j++) - { - if (ABS(planeinfo[j].fixedheight-dup_viewz) < ABS(planeinfo[j+1].fixedheight-dup_viewz)) - { - planeinfo_t temp; - M_Memcpy(&temp, &planeinfo[j+1], sizeof (planeinfo_t)); - M_Memcpy(&planeinfo[j+1], &planeinfo[j], sizeof (planeinfo_t)); - M_Memcpy(&planeinfo[j], &temp, sizeof (planeinfo_t)); - permut = true; - } - } - } - } -#if 0 //thanks epat, but it's goes looping forever on CTF map Silver Cascade Zone - HWR_QuickSortPlane(0, numplanes-1); -#endif - - gr_frontsector = NULL; //Hurdler: gr_fronsector is no longer valid - for (i = 0; i < numfloors; i++) - { - HWR_GetLevelFlat(planeinfo[i].levelflat); - HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].isceiling, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].levelflat, - planeinfo[i].FOFSector, planeinfo[i].alpha, planeinfo[i].fogplane, planeinfo[i].planecolormap); - } - numfloors = 0; -} -#endif - -static void HWR_AddTransparentWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap) +void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap) { static size_t allocedwalls = 0; @@ -6764,103 +5874,43 @@ static void HWR_AddTransparentWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, I M_Memcpy(&wallinfo[numwalls].Surf, pSurf, sizeof (FSurfaceInfo)); wallinfo[numwalls].texnum = texnum; wallinfo[numwalls].blend = blend; -#ifdef SORTING wallinfo[numwalls].drawcount = drawcount++; -#endif wallinfo[numwalls].fogwall = fogwall; wallinfo[numwalls].lightlevel = lightlevel; wallinfo[numwalls].wallcolormap = wallcolormap; numwalls++; } -#ifndef SORTING -static void HWR_RenderTransparentWalls(void) +void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap) { - size_t i; + FBITFIELD blendmode = blend; + UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha - /*{ // sorting is disbale for now, do it! - INT32 permut = 1; - while (permut) - { - INT32 j; - for (j = 0, permut = 0; j < numwalls-1; j++) - { - if (ABS(wallinfo[j].fixedheight-dup_viewz) < ABS(wallinfo[j+1].fixedheight-dup_viewz)) - { - wallinfo_t temp; - M_Memcpy(&temp, &wallinfo[j+1], sizeof (wallinfo_t)); - M_Memcpy(&wallinfo[j+1], &wallinfo[j], sizeof (wallinfo_t)); - M_Memcpy(&wallinfo[j], &temp, sizeof (wallinfo_t)); - permut = 1; - } - } - } - }*/ - - for (i = 0; i < numwalls; i++) - { - HWR_GetTexture(wallinfo[i].texnum); - HWR_RenderWall(wallinfo[i].wallVerts, &wallinfo[i].Surf, wallinfo[i].blend, wallinfo[i].wall->fogwall, wallinfo[i].wall->lightlevel, wallinfo[i].wall->wallcolormap); - } - numwalls = 0; -} -#endif - -static void HWR_RenderWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap) -{ - FOutVector trVerts[4]; - UINT8 i; - FOutVector *wv; - UINT8 alpha; - - // transform - wv = trVerts; - // it sounds really stupid to do this conversion with the new T&L code - // we should directly put the right information in the right structure - // wallVerts3D seems ok, doesn't need FOutVector - // also remove the light copy - for (i = 0; i < 4; i++, wv++, wallVerts++) - { - wv->sow = wallVerts->s; - wv->tow = wallVerts->t; - wv->x = wallVerts->x; - wv->y = wallVerts->y; - wv->z = wallVerts->z; - } - - alpha = pSurf->FlatColor.s.alpha; // retain the alpha + int shader; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting - if (wallcolormap) - { - if (fogwall) - pSurf->FlatColor.rgba = HWR_Lighting(lightlevel, wallcolormap->rgba, wallcolormap->fadergba, true, false); - else - pSurf->FlatColor.rgba = HWR_Lighting(lightlevel, wallcolormap->rgba, wallcolormap->fadergba, false, false); - } - else - { - if (fogwall) - pSurf->FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, true, false); - else - pSurf->FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); - } + HWR_Lighting(pSurf, lightlevel, wallcolormap); - pSurf->FlatColor.s.alpha = alpha; // put the alpha back after lighting + pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting + + shader = 2; // wall shader if (blend & PF_Environment) - HWD.pfnDrawPolygon(pSurf, trVerts, 4, blend|PF_Modulated|PF_Clip|PF_Occlude); // PF_Occlude must be used for solid objects - else - HWD.pfnDrawPolygon(pSurf, trVerts, 4, blend|PF_Modulated|PF_Clip); // No PF_Occlude means overlapping (incorrect) transparency + blendmode |= PF_Occlude; // PF_Occlude must be used for solid objects + + if (fogwall) + { + blendmode |= PF_Fog; + shader = 6; // fog shader + } + + blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency + + HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false); #ifdef WALLSPLATS if (gr_curline->linedef->splats && cv_splats.value) HWR_DrawSegsSplats(pSurf); - -#ifdef ALAM_LIGHTING - //Hurdler: TODO: do static lighting using gr_curline->lm - HWR_WallLighting(trVerts); -#endif #endif } @@ -6873,6 +5923,8 @@ void HWR_DoPostProcessor(player_t *player) { postimg_t *type; + HWD.pfnUnSetShader(); + if (splitscreen && player == &players[secondarydisplayplayer]) type = &postimgtype2; else @@ -6892,13 +5944,13 @@ void HWR_DoPostProcessor(player_t *player) // This won't change if the flash palettes are changed unfortunately, but it works for its purpose if (player->flashpal == PAL_NUKE) { - Surf.FlatColor.s.red = 0xff; - Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0x7F; // The nuke palette is kind of pink-ish + Surf.PolyColor.s.red = 0xff; + Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0x7F; // The nuke palette is kind of pink-ish } else - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; + Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; - Surf.FlatColor.s.alpha = 0xc0; // match software mode + Surf.PolyColor.s.alpha = 0xc0; // match software mode HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest|PF_Clip|PF_NoZClip); } @@ -6945,7 +5997,8 @@ void HWR_DoPostProcessor(player_t *player) } } HWD.pfnPostImgRedraw(v); - disStart += 1; + if (!(paused || P_AutoPause())) + disStart += 1; // Capture the screen again for screen waving on the intermission if(gamestate != GS_INTERMISSION) @@ -7032,4 +6085,161 @@ void HWR_DrawScreenFinalTexture(int width, int height) HWD.pfnDrawScreenFinalTexture(width, height); } +// jimita 18032019 +typedef struct +{ + char type[16]; + INT32 id; +} shaderxlat_t; + +static inline UINT16 HWR_CheckShader(UINT16 wadnum) +{ + UINT16 i; + lumpinfo_t *lump_p; + + lump_p = wadfiles[wadnum]->lumpinfo; + for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name, "SHADERS", 7) == 0) + return i; + + return INT16_MAX; +} + +boolean HWR_LoadShaders(void) +{ + return HWD.pfnInitCustomShaders(); +} + +void HWR_ReadShaders(UINT16 wadnum, boolean PK3) +{ + UINT16 lump; + char *shaderdef, *line; + char *stoken; + char *value; + size_t size; + int linenum = 1; + int shadertype = 0; + int i; + + #define SHADER_TYPES 7 + shaderxlat_t shaderxlat[SHADER_TYPES] = + { + {"Flat", 1}, + {"WallTexture", 2}, + {"Sprite", 3}, + {"Model", 4}, + {"WaterRipple", 5}, + {"Fog", 6}, + {"Sky", 7}, + }; + + lump = HWR_CheckShader(wadnum); + if (lump == INT16_MAX) + return; + + shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + line = Z_Malloc(size+1, PU_STATIC, NULL); + M_Memcpy(line, shaderdef, size); + line[size] = '\0'; + + stoken = strtok(line, "\r\n "); + while (stoken) + { + if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#'))// skip comments + { + stoken = strtok(NULL, "\r\n"); + goto skip_field; + } + + if (!stricmp(stoken, "GLSL")) + { + value = strtok(NULL, "\r\n "); + if (!value) + { + CONS_Alert(CONS_WARNING, "HWR_ReadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + stoken = strtok(NULL, "\r\n"); // skip end of line + goto skip_lump; + } + + if (!stricmp(value, "VERTEX")) + shadertype = 1; + else if (!stricmp(value, "FRAGMENT")) + shadertype = 2; + +skip_lump: + stoken = strtok(NULL, "\r\n "); + linenum++; + } + else + { + value = strtok(NULL, "\r\n= "); + if (!value) + { + CONS_Alert(CONS_WARNING, "HWR_ReadShaders: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + stoken = strtok(NULL, "\r\n"); // skip end of line + goto skip_field; + } + + if (!shadertype) + { + CONS_Alert(CONS_ERROR, "HWR_ReadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + Z_Free(line); + return; + } + + for (i = 0; i < SHADER_TYPES; i++) + { + if (!stricmp(shaderxlat[i].type, stoken)) + { + size_t shader_size; + char *shader_source; + char *shader_lumpname; + UINT16 shader_lumpnum; + + if (PK3) + { + shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL); + strcpy(shader_lumpname, "Shaders/sh_"); + strcat(shader_lumpname, value); + shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0); + } + else + { + shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL); + strcpy(shader_lumpname, "SH_"); + strcat(shader_lumpname, value); + shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0); + } + + if (shader_lumpnum == INT16_MAX) + { + CONS_Alert(CONS_ERROR, "HWR_ReadShaders: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum); + Z_Free(shader_lumpname); + continue; + } + + shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum); + shader_source = Z_Malloc(shader_size, PU_STATIC, NULL); + W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source); + + HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2)); + + Z_Free(shader_source); + Z_Free(shader_lumpname); + } + } + +skip_field: + stoken = strtok(NULL, "\r\n= "); + linenum++; + } + } + + Z_Free(line); + return; +} + #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index ec5362194..21bd7ddb3 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -1,20 +1,13 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hw_main.h /// \brief 3D render mode functions #ifndef __HWR_MAIN_H__ @@ -73,8 +66,11 @@ void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); // This stuff is put here so MD2's can use them -UINT32 HWR_Lighting(INT32 light, UINT32 color, UINT32 fadecolor, boolean fogblockpoly, boolean plane); -FUNCMATH UINT8 LightLevelToLum(INT32 l); +void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap); +UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work + +void HWR_ReadShaders(UINT16 wadnum, boolean PK3); +boolean HWR_LoadShaders(void); extern CV_PossibleValue_t granisotropicmode_cons_t[]; @@ -84,21 +80,23 @@ extern consvar_t cv_grstaticlighting; extern consvar_t cv_grcoronas; extern consvar_t cv_grcoronasize; #endif + +extern consvar_t cv_grshaders; extern consvar_t cv_grmodels; extern consvar_t cv_grmodelinterpolation; extern consvar_t cv_grmodellighting; -extern consvar_t cv_grfog; -extern consvar_t cv_grfogcolor; -extern consvar_t cv_grfogdensity; -extern consvar_t cv_grsoftwarefog; extern consvar_t cv_grfiltermode; extern consvar_t cv_granisotropicmode; extern consvar_t cv_grcorrecttricks; extern consvar_t cv_fovchange; extern consvar_t cv_grsolvetjoin; +extern consvar_t cv_grshearing; extern consvar_t cv_grspritebillboarding; extern consvar_t cv_grskydome; extern consvar_t cv_grfakecontrast; +extern consvar_t cv_grslopecontrast; + +extern consvar_t cv_grbatching; extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowy; @@ -108,4 +106,24 @@ extern float gr_viewwindowx, gr_basewindowcentery; extern fixed_t *hwbbox; extern FTransform atransform; + +// Render stats +extern int rs_hw_nodesorttime; +extern int rs_hw_nodedrawtime; +extern int rs_hw_spritesorttime; +extern int rs_hw_spritedrawtime; + +// Render stats for batching +extern int rs_hw_numpolys; +extern int rs_hw_numverts; +extern int rs_hw_numcalls; +extern int rs_hw_numshaders; +extern int rs_hw_numtextures; +extern int rs_hw_numpolyflags; +extern int rs_hw_numcolors; +extern int rs_hw_batchsorttime; +extern int rs_hw_batchdrawtime; + +extern boolean gr_shadersavailable; + #endif diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 5c3cd40a6..68b426f0c 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1,23 +1,16 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file -/// \brief MD2 Handling +/// \file hw_md2.c +/// \brief 3D Model Handling /// Inspired from md2.c by Mete Ciragan (mete@swissquake.ch) - #ifdef __GNUC__ #include #endif @@ -382,7 +375,10 @@ static void md2_loadTexture(md2_t *model) #endif grpatch->mipmap->grInfo.format = PCX_Load(filename, &w, &h, grpatch); if (grpatch->mipmap->grInfo.format == 0) + { + model->notexturefile = true; // mark it so its not searched for again repeatedly return; + } grpatch->mipmap->downloaded = 0; grpatch->mipmap->flags = 0; @@ -400,13 +396,6 @@ static void md2_loadTexture(md2_t *model) V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); image++; } - -#ifdef GLIDE_API_COMPATIBILITY - // not correct! - grpatch->mipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_256; - grpatch->mipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_256; - grpatch->mipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; -#endif } HWD.pfnSetTexture(grpatch->mipmap); } @@ -444,6 +433,7 @@ static void md2_loadBlendTexture(md2_t *model) grpatch->mipmap->grInfo.format = PCX_Load(filename, &w, &h, grpatch); if (grpatch->mipmap->grInfo.format == 0) { + model->noblendfile = true; // mark it so its not searched for again repeatedly Z_Free(filename); return; } @@ -455,13 +445,6 @@ static void md2_loadBlendTexture(md2_t *model) grpatch->height = (INT16)h; grpatch->mipmap->width = (UINT16)w; grpatch->mipmap->height = (UINT16)h; - -#ifdef GLIDE_API_COMPATIBILITY - // not correct! - grpatch->mipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_256; - grpatch->mipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_256; - grpatch->mipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; -#endif } HWD.pfnSetTexture(grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary @@ -486,6 +469,8 @@ void HWR_InitModels(void) md2_playermodels[s].scale = -1.0f; md2_playermodels[s].model = NULL; md2_playermodels[s].grpatch = NULL; + md2_playermodels[s].notexturefile = false; + md2_playermodels[s].noblendfile = false; md2_playermodels[s].skin = -1; md2_playermodels[s].notfound = true; md2_playermodels[s].error = false; @@ -495,6 +480,8 @@ void HWR_InitModels(void) md2_models[i].scale = -1.0f; md2_models[i].model = NULL; md2_models[i].grpatch = NULL; + md2_models[i].notexturefile = false; + md2_models[i].noblendfile = false; md2_models[i].skin = -1; md2_models[i].notfound = true; md2_models[i].error = false; @@ -677,12 +664,12 @@ spritemodelfound: #define SETBRIGHTNESS(brightness,r,g,b) \ brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000)) -static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color) +static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolornum_t color) { UINT16 w = gpatch->width, h = gpatch->height; UINT32 size = w*h; RGBA_t *image, *blendimage, *cur, blendcolor; - UINT8 translation[16]; // First the color index + UINT16 translation[16]; // First the color index UINT8 cutoff[16]; // Brightness cutoff before using the next color UINT8 translen = 0; UINT8 i; @@ -718,16 +705,16 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, if (skinnum == TC_METALSONIC) color = SKINCOLOR_COBALT; - if (color != SKINCOLOR_NONE) + if (color != SKINCOLOR_NONE && color < numskincolors) { UINT8 numdupes = 1; - translation[translen] = Color_Index[color-1][0]; + translation[translen] = skincolors[color].ramp[0]; cutoff[translen] = 255; for (i = 1; i < 16; i++) { - if (translation[translen] == Color_Index[color-1][i]) + if (translation[translen] == skincolors[color].ramp[i]) { numdupes++; continue; @@ -741,7 +728,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, numdupes = 1; translen++; - translation[translen] = (UINT8)Color_Index[color-1][i]; + translation[translen] = (UINT16)skincolors[color].ramp[i]; } translen++; @@ -949,11 +936,19 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, blendcolor = V_GetColor(translation[firsti]); + if (secondi >= translen) + mul = 0; + if (mul > 0) // If it's 0, then we only need the first color. { - if (secondi >= translen) // blend to black +#if 0 + if (secondi >= translen) + { + // blend to black nextcolor = V_GetColor(31); + } else +#endif nextcolor = V_GetColor(translation[secondi]); // Find difference between points @@ -1043,7 +1038,7 @@ skippixel: #undef SETBRIGHTNESS -static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolors_t color) +static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolornum_t color) { // mostly copied from HWR_GetMappedPatch, hence the similarities and comment GLMipmap_t *grmip, *newmip; @@ -1188,15 +1183,14 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t boolean HWR_DrawModel(gr_vissprite_t *spr) { - FSurfaceInfo Surf; + md2_t *md2; char filename[64]; INT32 frame = 0; INT32 nextFrame = -1; UINT8 spr2 = 0; FTransform p; - md2_t *md2; - UINT8 color[4]; + FSurfaceInfo Surf; if (!cv_grmodels.value) return false; @@ -1221,7 +1215,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *sector->lightlist[light].lightlevel; + lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; if (*sector->lightlist[light].extra_colormap) colormap = *sector->lightlist[light].extra_colormap; @@ -1229,19 +1223,16 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) else { if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = sector->lightlevel; + lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; if (sector->extra_colormap) colormap = sector->extra_colormap; } - if (colormap) - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); - else - Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + HWR_Lighting(&Surf, lightlevel, colormap); } else - Surf.FlatColor.rgba = 0xFFFFFFFF; + Surf.PolyColor.rgba = 0xFFFFFFFF; // Look at HWR_ProjectSprite for more { @@ -1263,11 +1254,11 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) //durs = tics; if (spr->mobj->flags2 & MF2_SHADOW) - Surf.FlatColor.s.alpha = 0x40; + Surf.PolyColor.s.alpha = 0x40; else if (spr->mobj->frame & FF_TRANSMASK) HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else - Surf.FlatColor.s.alpha = 0xFF; + Surf.PolyColor.s.alpha = 0xFF; // dont forget to enabled the depth test because we can't do this like // before: polygons models are not sorted @@ -1315,12 +1306,14 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy gpatch = md2->grpatch; - if (!gpatch || !gpatch->mipmap->grInfo.format || !gpatch->mipmap->downloaded) + if (!gpatch || ((!gpatch->mipmap->grInfo.format || !gpatch->mipmap->downloaded) && !md2->notexturefile)) md2_loadTexture(md2); gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... if ((gpatch && gpatch->mipmap->grInfo.format) // don't load the blend texture if the base texture isn't available - && (!md2->blendgrpatch || !((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded)) + && (!md2->blendgrpatch + || ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded) + && !md2->noblendfile))) md2_loadBlendTexture(md2); if (gpatch && gpatch->mipmap->grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture @@ -1336,7 +1329,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) else skinnum = TC_BOSS; } - else if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE) + else if ((skincolornum_t)spr->mobj->color != SKINCOLOR_NONE) { if (spr->mobj->colorized) skinnum = TC_RAINBOW; @@ -1356,7 +1349,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) } // Translation or skin number found - HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color); + HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); } else { @@ -1478,7 +1471,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) // rotation pivot p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2); - p.centery = FIXED_TO_FLOAT(spr->mobj->height/2); + p.centery = FIXED_TO_FLOAT(spr->mobj->height/(flip ? -2 : 2)); // rotation axis if (sprinfo->available) @@ -1490,6 +1483,9 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) p.rollflip = 1; else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left p.rollflip = -1; + + if (flip) + p.rollflip *= -1; } p.anglex = 0.0f; @@ -1509,11 +1505,6 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) } #endif - color[0] = Surf.FlatColor.s.red; - color[1] = Surf.FlatColor.s.green; - color[2] = Surf.FlatColor.s.blue; - color[3] = Surf.FlatColor.s.alpha; - // SRB2CBTODO: MD2 scaling support finalscale *= FIXED_TO_FLOAT(spr->mobj->scale); @@ -1522,7 +1513,8 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) p.mirror = atransform.mirror; // from Kart #endif - HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, color); + HWD.pfnSetShader(4); // model shader + HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, &Surf); } return true; diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 3bbe30053..42a9d7c63 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -1,21 +1,14 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// // Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file -/// \brief MD2 Handling +/// \file hw_md2.h +/// \brief 3D Model Handling /// Inspired from md2.h by Mete Ciragan (mete@swissquake.ch) #ifndef _HW_MD2_H_ @@ -35,7 +28,9 @@ typedef struct float offset; model_t *model; void *grpatch; + boolean notexturefile; // true if texture file was not found void *blendgrpatch; + boolean noblendfile; // true if blend texture file was not found boolean notfound; INT32 skin; boolean error; diff --git a/src/hardware/hw_trick.c b/src/hardware/hw_trick.c index 97d86b944..82d81b5b2 100644 --- a/src/hardware/hw_trick.c +++ b/src/hardware/hw_trick.c @@ -610,10 +610,8 @@ static boolean isCeilingFloating(sector_t *thisSector) if (!adjSector) // assume floating sectors have surrounding sectors return false; -#ifdef ESLOPE if (adjSector->c_slope) // Don't bother with slopes return false; -#endif if (!refSector) { @@ -663,10 +661,8 @@ static boolean isFloorFloating(sector_t *thisSector) if (!adjSector) // assume floating sectors have surrounding sectors return false; -#ifdef ESLOPE if (adjSector->f_slope) // Don't bother with slopes return false; -#endif if (!refSector) { diff --git a/src/hardware/hws_data.h b/src/hardware/hws_data.h index b890d976b..a8607ac67 100644 --- a/src/hardware/hws_data.h +++ b/src/hardware/hws_data.h @@ -1,19 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- +// Copyright (C) 2005 by Sonic Team Junior. // -// Copyright (C) 2005 by SRB2 Jr. Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file hws_data.h /// \brief 3D sound definitions #ifndef __HWS_DATA_H__ diff --git a/src/hardware/r_opengl/ogl_win.c b/src/hardware/r_opengl/ogl_win.c index e4a71734b..c9bf60144 100644 --- a/src/hardware/r_opengl/ogl_win.c +++ b/src/hardware/r_opengl/ogl_win.c @@ -206,7 +206,7 @@ int SetupPixelFormat(INT32 WantColorBits, INT32 WantStencilBits, INT32 WantDepth if (iLastPFD) { - DBG_Printf("WARNING : SetPixelFormat() called twise not supported by all drivers !\n"); + GL_DBG_Printf("WARNING : SetPixelFormat() called twise not supported by all drivers !\n"); } // set the pixel format only if different than the current @@ -215,17 +215,17 @@ int SetupPixelFormat(INT32 WantColorBits, INT32 WantStencilBits, INT32 WantDepth else iLastPFD = iPFD; - DBG_Printf("SetupPixelFormat() - %d ColorBits - %d StencilBits - %d DepthBits\n", + GL_DBG_Printf("SetupPixelFormat() - %d ColorBits - %d StencilBits - %d DepthBits\n", WantColorBits, WantStencilBits, WantDepthBits); nPixelFormat = ChoosePixelFormat(hDC, &pfd); if (nPixelFormat == 0) - DBG_Printf("ChoosePixelFormat() FAILED\n"); + GL_DBG_Printf("ChoosePixelFormat() FAILED\n"); if (SetPixelFormat(hDC, nPixelFormat, &pfd) == 0) { - DBG_Printf("SetPixelFormat() FAILED\n"); + GL_DBG_Printf("SetPixelFormat() FAILED\n"); return 0; } @@ -243,7 +243,7 @@ static INT32 WINAPI SetRes(viddef_t *lvid, vmode_t *pcurrentmode) BOOL WantFullScreen = !(lvid->u.windowed); //(lvid->u.windowed ? 0 : CDS_FULLSCREEN); UNREFERENCED_PARAMETER(pcurrentmode); - DBG_Printf ("SetMode(): %dx%d %d bits (%s)\n", + GL_DBG_Printf ("SetMode(): %dx%d %d bits (%s)\n", lvid->width, lvid->height, lvid->bpp*8, WantFullScreen ? "fullscreen" : "windowed"); @@ -301,7 +301,7 @@ static INT32 WINAPI SetRes(viddef_t *lvid, vmode_t *pcurrentmode) hDC = GetDC(hWnd); if (!hDC) { - DBG_Printf("GetDC() FAILED\n"); + GL_DBG_Printf("GetDC() FAILED\n"); return 0; } @@ -321,12 +321,12 @@ static INT32 WINAPI SetRes(viddef_t *lvid, vmode_t *pcurrentmode) hGLRC = pwglCreateContext(hDC); if (!hGLRC) { - DBG_Printf("pwglCreateContext() FAILED\n"); + GL_DBG_Printf("pwglCreateContext() FAILED\n"); return 0; } if (!pwglMakeCurrent(hDC, hGLRC)) { - DBG_Printf("wglMakeCurrent() FAILED\n"); + GL_DBG_Printf("wglMakeCurrent() FAILED\n"); return 0; } } @@ -337,15 +337,15 @@ static INT32 WINAPI SetRes(viddef_t *lvid, vmode_t *pcurrentmode) //BP: why don't we make it earlier ? //Hurdler: we cannot do that before intialising gl context renderer = (LPCSTR)pglGetString(GL_RENDERER); - DBG_Printf("Vendor : %s\n", pglGetString(GL_VENDOR)); - DBG_Printf("Renderer : %s\n", renderer); - DBG_Printf("Version : %s\n", pglGetString(GL_VERSION)); - DBG_Printf("Extensions : %s\n", gl_extensions); + GL_DBG_Printf("Vendor : %s\n", pglGetString(GL_VENDOR)); + GL_DBG_Printf("Renderer : %s\n", renderer); + GL_DBG_Printf("Version : %s\n", pglGetString(GL_VERSION)); + GL_DBG_Printf("Extensions : %s\n", gl_extensions); // BP: disable advenced feature that don't work on somes hardware // Hurdler: Now works on G400 with bios 1.6 and certified drivers 6.04 if (strstr(renderer, "810")) oglflags |= GLF_NOZBUFREAD; - DBG_Printf("oglflags : 0x%X\n", oglflags); + GL_DBG_Printf("oglflags : 0x%X\n", oglflags); #ifdef USE_WGL_SWAP if (isExtAvailable("WGL_EXT_swap_control",gl_extensions)) @@ -386,7 +386,7 @@ static INT32 WINAPI SetRes(viddef_t *lvid, vmode_t *pcurrentmode) // -----------------+ static void UnSetRes(void) { - DBG_Printf("UnSetRes()\n"); + GL_DBG_Printf("UnSetRes()\n"); pwglMakeCurrent(hDC, NULL); pwglDeleteContext(hGLRC); @@ -437,7 +437,7 @@ EXPORT void HWRAPI(GetModeList) (vmode_t** pvidmodes, INT32 *numvidmodes) video_modes[iMode].misc = 0; video_modes[iMode].name = malloc(12 * sizeof (CHAR)); sprintf(video_modes[iMode].name, "%dx%d", (INT32)Tmp.dmPelsWidth, (INT32)Tmp.dmPelsHeight); - DBG_Printf ("Mode: %s\n", video_modes[iMode].name); + GL_DBG_Printf ("Mode: %s\n", video_modes[iMode].name); video_modes[iMode].width = Tmp.dmPelsWidth; video_modes[iMode].height = Tmp.dmPelsHeight; video_modes[iMode].bytesperpixel = Tmp.dmBitsPerPel/8; @@ -474,7 +474,7 @@ EXPORT void HWRAPI(GetModeList) (vmode_t** pvidmodes, INT32 *numvidmodes) HDC bpphdc; INT32 iBitsPerPel; - DBG_Printf ("HWRAPI GetModeList()\n"); + GL_DBG_Printf ("HWRAPI GetModeList()\n"); bpphdc = GetDC(NULL); // on obtient le bpp actuel iBitsPerPel = GetDeviceCaps(bpphdc, BITSPIXEL); @@ -490,7 +490,7 @@ EXPORT void HWRAPI(GetModeList) (vmode_t** pvidmodes, INT32 *numvidmodes) video_modes[i].misc = 0; video_modes[i].name = malloc(12 * sizeof (CHAR)); sprintf(video_modes[i].name, "%dx%d", res[i][0], res[i][1]); - DBG_Printf ("Mode: %s\n", video_modes[i].name); + GL_DBG_Printf ("Mode: %s\n", video_modes[i].name); video_modes[i].width = res[i][0]; video_modes[i].height = res[i][1]; video_modes[i].bytesperpixel = iBitsPerPel/8; @@ -511,9 +511,9 @@ EXPORT void HWRAPI(Shutdown) (void) #ifdef DEBUG_TO_FILE long nb_centiemes; - DBG_Printf ("HWRAPI Shutdown()\n"); + GL_DBG_Printf ("HWRAPI Shutdown()\n"); nb_centiemes = ((clock()-my_clock)*100)/CLOCKS_PER_SEC; - DBG_Printf("Nb frames: %li; Nb sec: %2.2f -> %2.1f fps\n", + GL_DBG_Printf("Nb frames: %li; Nb sec: %2.2f -> %2.1f fps\n", nb_frames, nb_centiemes/100.0f, (100*nb_frames)/(double)nb_centiemes); #endif @@ -530,7 +530,7 @@ EXPORT void HWRAPI(Shutdown) (void) } FreeLibrary(GLU32); FreeLibrary(OGL32); - DBG_Printf ("HWRAPI Shutdown(DONE)\n"); + GL_DBG_Printf ("HWRAPI Shutdown(DONE)\n"); } // -----------------+ @@ -543,7 +543,7 @@ EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl) #else UNREFERENCED_PARAMETER(waitvbl); #endif - // DBG_Printf ("FinishUpdate()\n"); + // GL_DBG_Printf ("FinishUpdate()\n"); #ifdef DEBUG_TO_FILE if ((++nb_frames)==2) // on ne commence pas � la premi�re frame my_clock = clock(); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index a3ed3c8d2..41ec703bc 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1,20 +1,12 @@ -// Emacs style mode select -*- C++ -*- +// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- +// Copyright (C) 1998-2020 by Sonic Team Junior. // -// Copyright (C) 1998-2019 by Sonic Team Junior. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file +/// \file r_opengl.c /// \brief OpenGL API for Sonic Robo Blast 2 #if defined (_WIN32) @@ -49,8 +41,7 @@ static const GLubyte white[4] = { 255, 255, 255, 255 }; // ========================================================================== // With OpenGL 1.1+, the first texture should be 1 -#define NOTEXTURE_NUM 1 // small white texture -#define FIRST_TEX_AVAIL (NOTEXTURE_NUM + 1) +static GLuint NOTEXTURE_NUM = 0; #define N_PI_DEMI (M_PIl/2.0f) //(1.5707963268f) @@ -63,17 +54,12 @@ static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE; // ************************************************************************** -static GLuint NextTexAvail = FIRST_TEX_AVAIL; static GLuint tex_downloaded = 0; static GLfloat fov = 90.0f; -#if 0 -static GLuint pal_col = 0; -static FRGBAFloat const_pal_col; -#endif static FBITFIELD CurrentPolyFlags; -static FTextureInfo* gr_cachetail = NULL; -static FTextureInfo* gr_cachehead = NULL; +static FTextureInfo *gr_cachetail = NULL; +static FTextureInfo *gr_cachehead = NULL; RGBA_t myPaletteData[256]; GLint screen_width = 0; // used by Draw2DLine() @@ -85,32 +71,29 @@ static GLboolean MipMap = GL_FALSE; static GLint min_filter = GL_LINEAR; static GLint mag_filter = GL_LINEAR; static GLint anisotropic_filter = 0; -static boolean model_lighting = true; +static boolean model_lighting = false; +const GLubyte *gl_version = NULL; +const GLubyte *gl_renderer = NULL; const GLubyte *gl_extensions = NULL; //Hurdler: 04/10/2000: added for the kick ass coronas as Boris wanted;-) -static GLfloat modelMatrix[16]; -static GLfloat projMatrix[16]; -static GLint viewport[4]; +static GLfloat modelMatrix[16]; +static GLfloat projMatrix[16]; +static GLint viewport[4]; -// Yay for arbitrary numbers! NextTexAvail is buggy for some reason. // Sryder: NextTexAvail is broken for these because palette changes or changes to the texture filter or antialiasing // flush all of the stored textures, leaving them unavailable at times such as between levels // These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs // can know when the textures aren't there, as textures are always considered resident in their virtual memory -// TODO: Store them in a more normal way -#define SCRTEX_SCREENTEXTURE 4294967295U -#define SCRTEX_STARTSCREENWIPE 4294967294U -#define SCRTEX_ENDSCREENWIPE 4294967293U -#define SCRTEX_FINALSCREENTEXTURE 4294967292U static GLuint screentexture = 0; static GLuint startScreenWipe = 0; static GLuint endScreenWipe = 0; static GLuint finalScreenTexture = 0; -#if 0 -GLuint screentexture = FIRST_TEX_AVAIL; -#endif + +// Lactozilla: Set shader programs and uniforms +static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); +static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { @@ -148,31 +131,82 @@ static const GLfloat byte2float[256] = { 0.972549f, 0.976471f, 0.980392f, 0.984314f, 0.988235f, 0.992157f, 0.996078f, 1.000000f }; -float byteasfloat(UINT8 fbyte) -{ - return (float)(byte2float[fbyte]*2.0f); -} - -static I_Error_t I_Error_GL = NULL; - // -----------------+ -// DBG_Printf : Output error messages to debug log if DEBUG_TO_FILE is defined, +// GL_DBG_Printf : Output debug messages to debug log if DEBUG_TO_FILE is defined, // : else do nothing // Returns : // -----------------+ -FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) + +#ifdef DEBUG_TO_FILE +FILE *gllogstream; +#endif + +FUNCPRINTF void GL_DBG_Printf(const char *format, ...) { #ifdef DEBUG_TO_FILE - char str[4096] = ""; + char str[4096] = ""; va_list arglist; - va_start (arglist, lpFmt); - vsnprintf (str, 4096, lpFmt, arglist); - va_end (arglist); - if (gllogstream) - fwrite(str, strlen(str), 1, gllogstream); + if (!gllogstream) + gllogstream = fopen("ogllog.txt", "w"); + + va_start(arglist, format); + vsnprintf(str, 4096, format, arglist); + va_end(arglist); + + fwrite(str, strlen(str), 1, gllogstream); #else - (void)lpFmt; + (void)format; +#endif +} + +// -----------------+ +// GL_MSG_Warning : Raises a warning. +// : +// Returns : +// -----------------+ + +static void GL_MSG_Warning(const char *format, ...) +{ + char str[4096] = ""; + va_list arglist; + + va_start(arglist, format); + vsnprintf(str, 4096, format, arglist); + va_end(arglist); + +#ifdef HAVE_SDL + CONS_Alert(CONS_WARNING, "%s", str); +#endif +#ifdef DEBUG_TO_FILE + if (!gllogstream) + gllogstream = fopen("ogllog.txt", "w"); + fwrite(str, strlen(str), 1, gllogstream); +#endif +} + +// -----------------+ +// GL_MSG_Error : Raises an error. +// : +// Returns : +// -----------------+ + +static void GL_MSG_Error(const char *format, ...) +{ + char str[4096] = ""; + va_list arglist; + + va_start(arglist, format); + vsnprintf(str, 4096, format, arglist); + va_end(arglist); + +#ifdef HAVE_SDL + CONS_Alert(CONS_ERROR, "%s", str); +#endif +#ifdef DEBUG_TO_FILE + if (!gllogstream) + gllogstream = fopen("ogllog.txt", "w"); + fwrite(str, strlen(str), 1, gllogstream); #endif } @@ -227,6 +261,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) #define pglLightfv glLightfv #define pglLightModelfv glLightModelfv #define pglMaterialfv glMaterialfv +#define pglMateriali glMateriali /* Raster functions */ #define pglPixelStorei glPixelStorei @@ -236,13 +271,11 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) #define pglTexEnvi glTexEnvi #define pglTexParameteri glTexParameteri #define pglTexImage2D glTexImage2D - -/* Fog */ -#define pglFogf glFogf -#define pglFogfv glFogfv +#define pglTexSubImage2D glTexSubImage2D /* 1.1 functions */ /* texture objects */ //GL_EXT_texture_object +#define pglGenTextures glGenTextures #define pglDeleteTextures glDeleteTextures #define pglBindTexture glBindTexture /* texture mapping */ //GL_EXT_copy_texture @@ -255,7 +288,6 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) /* Miscellaneous */ typedef void (APIENTRY * PFNglClearColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); static PFNglClearColor pglClearColor; -//glClear typedef void (APIENTRY * PFNglColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); static PFNglColorMask pglColorMask; typedef void (APIENTRY * PFNglAlphaFunc) (GLenum func, GLclampf ref); @@ -274,8 +306,6 @@ typedef void (APIENTRY * PFNglDisable) (GLenum cap); static PFNglDisable pglDisable; typedef void (APIENTRY * PFNglGetFloatv) (GLenum pname, GLfloat *params); static PFNglGetFloatv pglGetFloatv; -//glGetIntegerv -//glGetString /* Depth Buffer */ typedef void (APIENTRY * PFNglClearDepth) (GLclampd depth); @@ -336,6 +366,8 @@ typedef void (APIENTRY * PFNglLightModelfv) (GLenum pname, GLfloat *params); static PFNglLightModelfv pglLightModelfv; typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *params); static PFNglMaterialfv pglMaterialfv; +typedef void (APIENTRY * PFNglMateriali) (GLint face, GLenum pname, GLint param); +static PFNglMateriali pglMateriali; /* Raster functions */ typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param); @@ -350,15 +382,13 @@ typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint static PFNglTexParameteri pglTexParameteri; typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); static PFNglTexImage2D pglTexImage2D; - -/* Fog */ -typedef void (APIENTRY * PFNglFogf) (GLenum pname, GLfloat param); -static PFNglFogf pglFogf; -typedef void (APIENTRY * PFNglFogfv) (GLenum pname, const GLfloat *params); -static PFNglFogfv pglFogfv; +typedef void (APIENTRY * PFNglTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static PFNglTexSubImage2D pglTexSubImage2D; /* 1.1 functions */ /* texture objects */ //GL_EXT_texture_object +typedef void (APIENTRY * PFNglGenTextures) (GLsizei n, const GLuint *textures); +static PFNglGenTextures pglGenTextures; typedef void (APIENTRY * PFNglDeleteTextures) (GLsizei n, const GLuint *textures); static PFNglDeleteTextures pglDeleteTextures; typedef void (APIENTRY * PFNglBindTexture) (GLenum target, GLuint texture); @@ -429,7 +459,7 @@ boolean SetupGLfunc(void) func = GetGLFunc(#proc); \ if (!func) \ { \ - DBG_Printf("failed to get OpenGL function: %s", #proc); \ + GL_MSG_Warning("failed to get OpenGL function: %s", #proc); \ } \ GETOPENGLFUNC(pglClearColor, glClearColor) @@ -447,22 +477,23 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglGetIntegerv, glGetIntegerv) GETOPENGLFUNC(pglGetString, glGetString) - GETOPENGLFUNC(pglClearDepth , glClearDepth) - GETOPENGLFUNC(pglDepthFunc , glDepthFunc) - GETOPENGLFUNC(pglDepthMask , glDepthMask) - GETOPENGLFUNC(pglDepthRange , glDepthRange) + GETOPENGLFUNC(pglClearDepth, glClearDepth) + GETOPENGLFUNC(pglDepthFunc, glDepthFunc) + GETOPENGLFUNC(pglDepthMask, glDepthMask) + GETOPENGLFUNC(pglDepthRange, glDepthRange) - GETOPENGLFUNC(pglMatrixMode , glMatrixMode) - GETOPENGLFUNC(pglViewport , glViewport) - GETOPENGLFUNC(pglPushMatrix , glPushMatrix) - GETOPENGLFUNC(pglPopMatrix , glPopMatrix) - GETOPENGLFUNC(pglLoadIdentity , glLoadIdentity) - GETOPENGLFUNC(pglMultMatrixf , glMultMatrixf) - GETOPENGLFUNC(pglRotatef , glRotatef) - GETOPENGLFUNC(pglScalef , glScalef) - GETOPENGLFUNC(pglTranslatef , glTranslatef) + GETOPENGLFUNC(pglMatrixMode, glMatrixMode) + GETOPENGLFUNC(pglViewport, glViewport) + GETOPENGLFUNC(pglPushMatrix, glPushMatrix) + GETOPENGLFUNC(pglPopMatrix, glPopMatrix) + GETOPENGLFUNC(pglLoadIdentity, glLoadIdentity) + GETOPENGLFUNC(pglMultMatrixf, glMultMatrixf) + GETOPENGLFUNC(pglRotatef, glRotatef) + GETOPENGLFUNC(pglScalef, glScalef) + GETOPENGLFUNC(pglTranslatef, glTranslatef) GETOPENGLFUNC(pglColor4ubv, glColor4ubv) + GETOPENGLFUNC(pglVertexPointer, glVertexPointer) GETOPENGLFUNC(pglNormalPointer, glNormalPointer) GETOPENGLFUNC(pglTexCoordPointer, glTexCoordPointer) @@ -472,38 +503,329 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglEnableClientState, glEnableClientState) GETOPENGLFUNC(pglDisableClientState, glDisableClientState) - GETOPENGLFUNC(pglShadeModel , glShadeModel) + GETOPENGLFUNC(pglShadeModel, glShadeModel) GETOPENGLFUNC(pglLightfv, glLightfv) - GETOPENGLFUNC(pglLightModelfv , glLightModelfv) - GETOPENGLFUNC(pglMaterialfv , glMaterialfv) + GETOPENGLFUNC(pglLightModelfv, glLightModelfv) + GETOPENGLFUNC(pglMaterialfv, glMaterialfv) + GETOPENGLFUNC(pglMateriali, glMateriali) - GETOPENGLFUNC(pglPixelStorei , glPixelStorei) - GETOPENGLFUNC(pglReadPixels , glReadPixels) + GETOPENGLFUNC(pglPixelStorei, glPixelStorei) + GETOPENGLFUNC(pglReadPixels, glReadPixels) - GETOPENGLFUNC(pglTexEnvi , glTexEnvi) - GETOPENGLFUNC(pglTexParameteri , glTexParameteri) - GETOPENGLFUNC(pglTexImage2D , glTexImage2D) + GETOPENGLFUNC(pglTexEnvi, glTexEnvi) + GETOPENGLFUNC(pglTexParameteri, glTexParameteri) + GETOPENGLFUNC(pglTexImage2D, glTexImage2D) + GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) - GETOPENGLFUNC(pglFogf , glFogf) - GETOPENGLFUNC(pglFogfv , glFogfv) + GETOPENGLFUNC(pglGenTextures, glGenTextures) + GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures) + GETOPENGLFUNC(pglBindTexture, glBindTexture) - GETOPENGLFUNC(pglDeleteTextures , glDeleteTextures) - GETOPENGLFUNC(pglBindTexture , glBindTexture) - - GETOPENGLFUNC(pglCopyTexImage2D , glCopyTexImage2D) - GETOPENGLFUNC(pglCopyTexSubImage2D , glCopyTexSubImage2D) + GETOPENGLFUNC(pglCopyTexImage2D, glCopyTexImage2D) + GETOPENGLFUNC(pglCopyTexSubImage2D, glCopyTexSubImage2D) #undef GETOPENGLFUNC - pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps"); - #endif return true; } -// This has to be done after the context is created so the version number can be obtained -// This is stupid -- even some of the oldest usable OpenGL hardware today supports 1.3-level featureset. -boolean SetupGLFunc13(void) +static boolean gl_allowshaders = false; +static boolean gl_shadersenabled = false; + +#ifdef GL_SHADERS +typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum); +typedef void (APIENTRY *PFNglShaderSource) (GLuint, GLsizei, const GLchar**, GLint*); +typedef void (APIENTRY *PFNglCompileShader) (GLuint); +typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*); +typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*); +typedef void (APIENTRY *PFNglDeleteShader) (GLuint); +typedef GLuint (APIENTRY *PFNglCreateProgram) (void); +typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint); +typedef void (APIENTRY *PFNglLinkProgram) (GLuint); +typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); +typedef void (APIENTRY *PFNglUseProgram) (GLuint); +typedef void (APIENTRY *PFNglUniform1i) (GLint, GLint); +typedef void (APIENTRY *PFNglUniform1f) (GLint, GLfloat); +typedef void (APIENTRY *PFNglUniform2f) (GLint, GLfloat, GLfloat); +typedef void (APIENTRY *PFNglUniform3f) (GLint, GLfloat, GLfloat, GLfloat); +typedef void (APIENTRY *PFNglUniform4f) (GLint, GLfloat, GLfloat, GLfloat, GLfloat); +typedef void (APIENTRY *PFNglUniform1fv) (GLint, GLsizei, const GLfloat*); +typedef void (APIENTRY *PFNglUniform2fv) (GLint, GLsizei, const GLfloat*); +typedef void (APIENTRY *PFNglUniform3fv) (GLint, GLsizei, const GLfloat*); +typedef GLint (APIENTRY *PFNglGetUniformLocation) (GLuint, const GLchar*); + +static PFNglCreateShader pglCreateShader; +static PFNglShaderSource pglShaderSource; +static PFNglCompileShader pglCompileShader; +static PFNglGetShaderiv pglGetShaderiv; +static PFNglGetShaderInfoLog pglGetShaderInfoLog; +static PFNglDeleteShader pglDeleteShader; +static PFNglCreateProgram pglCreateProgram; +static PFNglAttachShader pglAttachShader; +static PFNglLinkProgram pglLinkProgram; +static PFNglGetProgramiv pglGetProgramiv; +static PFNglUseProgram pglUseProgram; +static PFNglUniform1i pglUniform1i; +static PFNglUniform1f pglUniform1f; +static PFNglUniform2f pglUniform2f; +static PFNglUniform3f pglUniform3f; +static PFNglUniform4f pglUniform4f; +static PFNglUniform1fv pglUniform1fv; +static PFNglUniform2fv pglUniform2fv; +static PFNglUniform3fv pglUniform3fv; +static PFNglGetUniformLocation pglGetUniformLocation; + +#define MAXSHADERS 16 +#define MAXSHADERPROGRAMS 16 + +// 18032019 +static char *gl_customvertexshaders[MAXSHADERS]; +static char *gl_customfragmentshaders[MAXSHADERS]; +static GLuint gl_currentshaderprogram = 0; +static boolean gl_shaderprogramchanged = true; + +// 13062019 +typedef enum +{ + // lighting + gluniform_poly_color, + gluniform_tint_color, + gluniform_fade_color, + gluniform_lighting, + gluniform_fade_start, + gluniform_fade_end, + + // misc. (custom shaders) + gluniform_leveltime, + + gluniform_max, +} gluniform_t; + +typedef struct gl_shaderprogram_s +{ + GLuint program; + boolean custom; + GLint uniforms[gluniform_max+1]; +} gl_shaderprogram_t; +static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; + +// Shader info +static INT32 shader_leveltime = 0; + +// ======================== +// Fragment shader macros +// ======================== + +// +// GLSL Software fragment shader +// + +#define GLSL_DOOM_COLORMAP \ + "float R_DoomColormap(float light, float z)\n" \ + "{\n" \ + "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ + "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ + "float startmap = (15.0 - lightnum) * 4.0;\n" \ + "float scale = 160.0 / (lightz + 1.0);\n" \ + "return startmap - scale * 0.5;\n" \ + "}\n" + +#define GLSL_DOOM_LIGHT_EQUATION \ + "float R_DoomLightingEquation(float light)\n" \ + "{\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ + "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ + "}\n" + +#define GLSL_SOFTWARE_TINT_EQUATION \ + "if (tint_color.a > 0.0) {\n" \ + "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \ + "float strength = sqrt(9.0 * tint_color.a);\n" \ + "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \ + "}\n" + +#define GLSL_SOFTWARE_FADE_EQUATION \ + "float darkness = R_DoomLightingEquation(lighting);\n" \ + "if (fade_start != 0.0 || fade_end != 31.0) {\n" \ + "float fs = fade_start / 31.0;\n" \ + "float fe = fade_end / 31.0;\n" \ + "float fd = fe - fs;\n" \ + "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \ + "}\n" \ + "final_color = mix(final_color, fade_color, darkness);\n" + +#define GLSL_SOFTWARE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Water surface shader +// +// Mostly guesstimated, rather than the rest being built off Software science. +// Still needs to distort things underneath/around the water... +// + +#define GLSL_WATER_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + "uniform float leveltime;\n" \ + "const float freq = 0.025;\n" \ + "const float amp = 0.025;\n" \ + "const float speed = 2.0;\n" \ + "const float pi = 3.14159;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ + "float a = -pi * (z * freq) + (leveltime * speed);\n" \ + "float sdistort = sin(a) * amp;\n" \ + "float cdistort = cos(a) * amp;\n" \ + "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Fog block shader +// +// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha +// + +#define GLSL_FOG_FRAGMENT_SHADER \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 base_color = gl_Color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// GLSL generic fragment shader +// + +#define GLSL_DEFAULT_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +static const char *fragment_shaders[] = { + // Default fragment shader + GLSL_DEFAULT_FRAGMENT_SHADER, + + // Floor fragment shader + GLSL_SOFTWARE_FRAGMENT_SHADER, + + // Wall fragment shader + GLSL_SOFTWARE_FRAGMENT_SHADER, + + // Sprite fragment shader + GLSL_SOFTWARE_FRAGMENT_SHADER, + + // Model fragment shader + GLSL_SOFTWARE_FRAGMENT_SHADER, + + // Water fragment shader + GLSL_WATER_FRAGMENT_SHADER, + + // Fog fragment shader + GLSL_FOG_FRAGMENT_SHADER, + + // Sky fragment shader + "uniform sampler2D tex;\n" + "void main(void) {\n" + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" + "}\0", + + NULL, +}; + +// ====================== +// Vertex shader macros +// ====================== + +// +// GLSL generic vertex shader +// + +#define GLSL_DEFAULT_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +static const char *vertex_shaders[] = { + // Default vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Floor vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Wall vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Sprite vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Model vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Water vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Fog vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + // Sky vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + NULL, +}; + +#endif // GL_SHADERS + +void SetupGLFunc4(void) { pglActiveTexture = GetGLFunc("glActiveTexture"); pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); @@ -516,17 +838,270 @@ boolean SetupGLFunc13(void) pglBufferData = GetGLFunc("glBufferData"); pglDeleteBuffers = GetGLFunc("glDeleteBuffers"); +#ifdef GL_SHADERS + pglCreateShader = GetGLFunc("glCreateShader"); + pglShaderSource = GetGLFunc("glShaderSource"); + pglCompileShader = GetGLFunc("glCompileShader"); + pglGetShaderiv = GetGLFunc("glGetShaderiv"); + pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog"); + pglDeleteShader = GetGLFunc("glDeleteShader"); + pglCreateProgram = GetGLFunc("glCreateProgram"); + pglAttachShader = GetGLFunc("glAttachShader"); + pglLinkProgram = GetGLFunc("glLinkProgram"); + pglGetProgramiv = GetGLFunc("glGetProgramiv"); + pglUseProgram = GetGLFunc("glUseProgram"); + pglUniform1i = GetGLFunc("glUniform1i"); + pglUniform1f = GetGLFunc("glUniform1f"); + pglUniform2f = GetGLFunc("glUniform2f"); + pglUniform3f = GetGLFunc("glUniform3f"); + pglUniform4f = GetGLFunc("glUniform4f"); + pglUniform1fv = GetGLFunc("glUniform1fv"); + pglUniform2fv = GetGLFunc("glUniform2fv"); + pglUniform3fv = GetGLFunc("glUniform3fv"); + pglGetUniformLocation = GetGLFunc("glGetUniformLocation"); +#endif + + // GLU + pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps"); +} + +// jimita +EXPORT boolean HWRAPI(LoadShaders) (void) +{ +#ifdef GL_SHADERS + GLuint gl_vertShader, gl_fragShader; + GLint i, result; + + if (!pglUseProgram) return false; + + gl_customvertexshaders[0] = NULL; + gl_customfragmentshaders[0] = NULL; + + for (i = 0; vertex_shaders[i] && fragment_shaders[i]; i++) + { + gl_shaderprogram_t *shader; + const GLchar* vert_shader = vertex_shaders[i]; + const GLchar* frag_shader = fragment_shaders[i]; + boolean custom = ((gl_customvertexshaders[i] || gl_customfragmentshaders[i]) && (i > 0)); + + // 18032019 + if (gl_customvertexshaders[i]) + vert_shader = gl_customvertexshaders[i]; + if (gl_customfragmentshaders[i]) + frag_shader = gl_customfragmentshaders[i]; + + if (i >= MAXSHADERS) + break; + if (i >= MAXSHADERPROGRAMS) + break; + + shader = &gl_shaderprograms[i]; + shader->program = 0; + shader->custom = custom; + + // + // Load and compile vertex shader + // + gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); + if (!gl_vertShader) + { + GL_MSG_Error("LoadShaders: Error creating vertex shader %d\n", i); + continue; + } + + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); + + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + GLchar* infoLog; + GLint logLength; + + pglGetShaderiv(gl_vertShader, GL_INFO_LOG_LENGTH, &logLength); + + infoLog = malloc(logLength); + pglGetShaderInfoLog(gl_vertShader, logLength, NULL, infoLog); + + GL_MSG_Error("LoadShaders: Error compiling vertex shader %d\n%s", i, infoLog); + continue; + } + + // + // Load and compile fragment shader + // + gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragShader) + { + GL_MSG_Error("LoadShaders: Error creating fragment shader %d\n", i); + continue; + } + + pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); + pglCompileShader(gl_fragShader); + + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + GLchar* infoLog; + GLint logLength; + + pglGetShaderiv(gl_fragShader, GL_INFO_LOG_LENGTH, &logLength); + + infoLog = malloc(logLength); + pglGetShaderInfoLog(gl_fragShader, logLength, NULL, infoLog); + + GL_MSG_Error("LoadShaders: Error compiling fragment shader %d\n%s", i, infoLog); + continue; + } + + shader->program = pglCreateProgram(); + pglAttachShader(shader->program, gl_vertShader); + pglAttachShader(shader->program, gl_fragShader); + pglLinkProgram(shader->program); + + // check link status + pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); + + // delete the shader objects + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + + // couldn't link? + if (result != GL_TRUE) + { + shader->program = 0; + shader->custom = false; + GL_MSG_Error("LoadShaders: Error linking shader program %d\n", i); + continue; + } + + // 13062019 +#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); + + // lighting + shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); + shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); + shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); + shader->uniforms[gluniform_lighting] = GETUNI("lighting"); + shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); + shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); + + // misc. (custom shaders) + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + +#undef GETUNI + } +#endif return true; } +// +// Shader info +// Those are given to the uniforms. +// + +EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) +{ +#ifdef GL_SHADERS + switch (info) + { + case HWD_SHADERINFO_LEVELTIME: + shader_leveltime = value; + break; + default: + break; + } +#else + (void)info; + (void)value; +#endif +} + +// +// Custom shader loading +// +EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment) +{ +#ifdef GL_SHADERS + if (!pglUseProgram) return; + if (number < 1 || number > MAXSHADERS) + I_Error("LoadCustomShader(): cannot load shader %d (max %d)", number, MAXSHADERS); + + if (fragment) + { + gl_customfragmentshaders[number] = malloc(size+1); + strncpy(gl_customfragmentshaders[number], shader, size); + gl_customfragmentshaders[number][size] = 0; + } + else + { + gl_customvertexshaders[number] = malloc(size+1); + strncpy(gl_customvertexshaders[number], shader, size); + gl_customvertexshaders[number][size] = 0; + } +#else + (void)number; + (void)shader; + (void)size; + (void)fragment; +#endif +} + +EXPORT boolean HWRAPI(InitCustomShaders) (void) +{ +#ifdef GL_SHADERS + KillShaders(); + return LoadShaders(); +#endif +} + +EXPORT void HWRAPI(SetShader) (int shader) +{ +#ifdef GL_SHADERS + if (gl_allowshaders) + { + if ((GLuint)shader != gl_currentshaderprogram) + { + gl_currentshaderprogram = shader; + gl_shaderprogramchanged = true; + } + gl_shadersenabled = true; + return; + } +#else + (void)shader; +#endif + gl_shadersenabled = false; +} + +EXPORT void HWRAPI(UnSetShader) (void) +{ +#ifdef GL_SHADERS + gl_shadersenabled = false; + gl_currentshaderprogram = 0; + if (!pglUseProgram) return; + pglUseProgram(0); +#endif +} + +EXPORT void HWRAPI(KillShaders) (void) +{ + // unused......................... +} + // -----------------+ // SetNoTexture : Disable texture // -----------------+ static void SetNoTexture(void) { - // Set small white texture. + // Disable texture. if (tex_downloaded != NOTEXTURE_NUM) { + if (NOTEXTURE_NUM == 0) + pglGenTextures(1, &NOTEXTURE_NUM); pglBindTexture(GL_TEXTURE_2D, NOTEXTURE_NUM); tex_downloaded = NOTEXTURE_NUM; } @@ -544,7 +1119,7 @@ static void GLPerspective(GLfloat fovy, GLfloat aspect) const GLfloat zNear = NEAR_CLIPPING_PLANE; const GLfloat zFar = FAR_CLIPPING_PLANE; const GLfloat radians = (GLfloat)(fovy / 2.0f * M_PIl / 180.0f); - const GLfloat sine = sinf(radians); + const GLfloat sine = sin(radians); const GLfloat deltaZ = zFar - zNear; GLfloat cotangent; @@ -607,7 +1182,7 @@ static void GLProject(GLfloat objX, GLfloat objY, GLfloat objZ, // -----------------+ void SetModelView(GLint w, GLint h) { -// DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h); +// GL_DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h); // The screen textures need to be flushed if the width or height change so that they be remade for the correct size if (screen_width != w || screen_height != h) @@ -617,9 +1192,6 @@ void SetModelView(GLint w, GLint h) screen_height = h; pglViewport(0, 0, w, h); -#ifdef GL_ACCUM_BUFFER_BIT - pglClear(GL_ACCUM_BUFFER_BIT); -#endif pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); @@ -641,16 +1213,11 @@ void SetModelView(GLint w, GLint h) // -----------------+ void SetStates(void) { - // Bind little white RGBA texture to ID NOTEXTURE_NUM. - /* - FUINT Data[8*8]; - INT32 i; - */ #ifdef GL_LIGHT_MODEL_AMBIENT GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; #endif -// DBG_Printf("SetStates()\n"); +// GL_DBG_Printf("SetStates()\n"); // Hurdler: not necessary, is it? pglShadeModel(GL_SMOOTH); // iterate vertice colors @@ -675,30 +1242,19 @@ void SetStates(void) pglDepthRange(0.0f, 1.0f); pglDepthFunc(GL_LEQUAL); - // this set CurrentPolyFlags to the acctual configuration + // this set CurrentPolyFlags to the actual configuration CurrentPolyFlags = 0xffffffff; SetBlend(0); - /* - for (i = 0; i < 64; i++) - Data[i] = 0xffFFffFF; // white pixel - */ - - tex_downloaded = (GLuint)-1; + tex_downloaded = 0; SetNoTexture(); - //pglBindTexture(GL_TEXTURE_2D, NOTEXTURE_NUM); - //tex_downloaded = NOTEXTURE_NUM; - //pglTexImage2D(GL_TEXTURE_2D, 0, 4, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data); pglPolygonOffset(-1.0f, -1.0f); //pglEnable(GL_CULL_FACE); //pglCullFace(GL_FRONT); - //glFogi(GL_FOG_MODE, GL_EXP); - //pglHint(GL_FOG_HINT, GL_FASTEST); - //pglFogfv(GL_FOG_COLOR, fogcolor); - //pglFogf(GL_FOG_DENSITY, 0.0005f); + pglDisable(GL_FOG); // Lighting for models #ifdef GL_LIGHT_MODEL_AMBIENT @@ -719,37 +1275,16 @@ void SetStates(void) // -----------------+ void Flush(void) { - //DBG_Printf ("HWR_Flush()\n"); + //GL_DBG_Printf ("HWR_Flush()\n"); while (gr_cachehead) { - // this is not necessary at all, because you have loaded them normally, - // and so they already are in your list! -#if 0 - //Hurdler: 25/04/2000: now support colormap in hardware mode - FTextureInfo *tmp = gr_cachehead->nextskin; - - // The memory should be freed in the main code - while (tmp) - { - pglDeleteTextures(1, &tmp->downloaded); - tmp->downloaded = 0; - tmp = tmp->nextcolormap; - } -#endif - pglDeleteTextures(1, (GLuint *)&gr_cachehead->downloaded); + if (gr_cachehead->downloaded) + pglDeleteTextures(1, (GLuint *)&gr_cachehead->downloaded); gr_cachehead->downloaded = 0; gr_cachehead = gr_cachehead->nextmipmap; } gr_cachetail = gr_cachehead = NULL; //Hurdler: well, gr_cachehead is already NULL - NextTexAvail = FIRST_TEX_AVAIL; -#if 0 - if (screentexture != FIRST_TEX_AVAIL) - { - pglDeleteTextures(1, &screentexture); - screentexture = FIRST_TEX_AVAIL; - } -#endif tex_downloaded = 0; } @@ -787,10 +1322,8 @@ INT32 isExtAvailable(const char *extension, const GLubyte *start) // Init : Initialise the OpenGL interface API // Returns : // -----------------+ -EXPORT boolean HWRAPI(Init) (I_Error_t FatalErrorFunction) +EXPORT boolean HWRAPI(Init) (void) { - I_Error_GL = FatalErrorFunction; - DBG_Printf ("%s %s\n", DRIVER_STRING, VERSIONSTRING); return LoadGL(); } @@ -800,7 +1333,7 @@ EXPORT boolean HWRAPI(Init) (I_Error_t FatalErrorFunction) // -----------------+ EXPORT void HWRAPI(ClearMipMapCache) (void) { - // DBG_Printf ("HWR_Flush(exe)\n"); + // GL_DBG_Printf ("HWR_Flush(exe)\n"); Flush(); } @@ -814,7 +1347,7 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 * dst_data) { INT32 i; - // DBG_Printf ("ReadRect()\n"); + // GL_DBG_Printf ("ReadRect()\n"); if (dst_stride == width*3) { GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1); @@ -862,7 +1395,7 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, // -----------------+ EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip) { - // DBG_Printf ("GClipRect(%d, %d, %d, %d)\n", minx, miny, maxx, maxy); + // GL_DBG_Printf ("GClipRect(%d, %d, %d, %d)\n", minx, miny, maxx, maxy); pglViewport(minx, screen_height-maxy, maxx-minx, maxy-miny); NEAR_CLIPPING_PLANE = nearclip; @@ -886,7 +1419,7 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat * ClearColor) { - // DBG_Printf ("ClearBuffer(%d)\n", alpha); + // GL_DBG_Printf ("ClearBuffer(%d)\n", alpha); GLbitfield ClearMask = 0; if (ColorMask) @@ -921,7 +1454,7 @@ EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1, F2DCoord * v2, RGBA_t Color) { - // DBG_Printf ("DrawLine() (%f %f %f) %d\n", v1->x, -v1->y, -v1->z, v1->argb); + // GL_DBG_Printf ("DrawLine() (%f %f %f) %d\n", v1->x, -v1->y, -v1->z, v1->argb); GLfloat p[12]; GLfloat dx, dy; GLfloat angle; @@ -1064,7 +1597,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) else #endif if (PolyFlags & PF_Modulated) - { // mix texture colour with Surface->FlatColor + { // mix texture colour with Surface->PolyColor pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } else @@ -1103,6 +1636,207 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) CurrentPolyFlags = PolyFlags; } +// -----------------+ +// UpdateTexture : Updates the texture data. +// -----------------+ +EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo) +{ + // Download a mipmap + boolean updatemipmap = true; + static RGBA_t tex[2048*2048]; + const GLvoid *ptex = tex; + INT32 w, h; + GLuint texnum = 0; + + if (!pTexInfo->downloaded) + { + pglGenTextures(1, &texnum); + pTexInfo->downloaded = texnum; + updatemipmap = false; + } + else + texnum = pTexInfo->downloaded; + + //GL_DBG_Printf ("DownloadMipmap %d %x\n",(INT32)texnum,pTexInfo->grInfo.data); + + w = pTexInfo->width; + h = pTexInfo->height; + + if ((pTexInfo->grInfo.format == GR_TEXFMT_P_8) || + (pTexInfo->grInfo.format == GR_TEXFMT_AP_88)) + { + const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data; + INT32 i, j; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + if ((*pImgData == HWR_PATCHES_CHROMAKEY_COLORINDEX) && + (pTexInfo->flags & TF_CHROMAKEYED)) + { + tex[w*j+i].s.red = 0; + tex[w*j+i].s.green = 0; + tex[w*j+i].s.blue = 0; + tex[w*j+i].s.alpha = 0; + pTexInfo->flags |= TF_TRANSPARENT; // there is a hole in it + } + else + { + tex[w*j+i].s.red = myPaletteData[*pImgData].s.red; + tex[w*j+i].s.green = myPaletteData[*pImgData].s.green; + tex[w*j+i].s.blue = myPaletteData[*pImgData].s.blue; + tex[w*j+i].s.alpha = myPaletteData[*pImgData].s.alpha; + } + + pImgData++; + + if (pTexInfo->grInfo.format == GR_TEXFMT_AP_88) + { + if (!(pTexInfo->flags & TF_CHROMAKEYED)) + tex[w*j+i].s.alpha = *pImgData; + pImgData++; + } + + } + } + } + else if (pTexInfo->grInfo.format == GR_RGBA) + { + // corona test : passed as ARGB 8888, which is not in glide formats + // Hurdler: not used for coronas anymore, just for dynamic lighting + ptex = pTexInfo->grInfo.data; + } + else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88) + { + const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data; + INT32 i, j; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + tex[w*j+i].s.red = *pImgData; + tex[w*j+i].s.green = *pImgData; + tex[w*j+i].s.blue = *pImgData; + pImgData++; + tex[w*j+i].s.alpha = *pImgData; + pImgData++; + } + } + } + else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8) // Used for fade masks + { + const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data; + INT32 i, j; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + tex[w*j+i].s.red = 255; // 255 because the fade mask is modulated with the screen texture, so alpha affects it while the colours don't + tex[w*j+i].s.green = 255; + tex[w*j+i].s.blue = 255; + tex[w*j+i].s.alpha = *pImgData; + pImgData++; + } + } + } + else + GL_MSG_Warning ("SetTexture(bad format) %ld\n", pTexInfo->grInfo.format); + + // the texture number was already generated by pglGenTextures + pglBindTexture(GL_TEXTURE_2D, texnum); + tex_downloaded = texnum; + + // disable texture filtering on any texture that has holes so there's no dumb borders or blending issues + if (pTexInfo->flags & TF_TRANSPARENT) + { + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + else + { + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + } + + if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88) + { + //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + if (MipMap) + { + pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + if (pTexInfo->flags & TF_TRANSPARENT) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff + else + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR); + } + else + { + if (updatemipmap) + pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + else + pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + } + } + else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8) + { + //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + if (MipMap) + { + pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + if (pTexInfo->flags & TF_TRANSPARENT) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff + else + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR); + } + else + { + if (updatemipmap) + pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + else + pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + } + } + else + { + if (MipMap) + { + pgluBuild2DMipmaps(GL_TEXTURE_2D, textureformatGL, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + // Control the mipmap level of detail + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail + if (pTexInfo->flags & TF_TRANSPARENT) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff + else + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5); + } + else + { + if (updatemipmap) + pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + else + pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); + } + } + + if (pTexInfo->flags & TF_WRAPX) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + else + Clamp2D(GL_TEXTURE_WRAP_S); + + if (pTexInfo->flags & TF_WRAPY) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + else + Clamp2D(GL_TEXTURE_WRAP_T); + + if (maximumAnisotropy) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic_filter); +} // -----------------+ // SetTexture : The mipmap becomes the current texture source @@ -1124,176 +1858,7 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } else { - // Download a mipmap - static RGBA_t tex[2048*2048]; - const GLvoid *ptex = tex; - INT32 w, h; - - //DBG_Printf ("DownloadMipmap %d %x\n",NextTexAvail,pTexInfo->grInfo.data); - - w = pTexInfo->width; - h = pTexInfo->height; - - if ((pTexInfo->grInfo.format == GR_TEXFMT_P_8) || - (pTexInfo->grInfo.format == GR_TEXFMT_AP_88)) - { - const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data; - INT32 i, j; - - for (j = 0; j < h; j++) - { - for (i = 0; i < w; i++) - { - if ((*pImgData == HWR_PATCHES_CHROMAKEY_COLORINDEX) && - (pTexInfo->flags & TF_CHROMAKEYED)) - { - tex[w*j+i].s.red = 0; - tex[w*j+i].s.green = 0; - tex[w*j+i].s.blue = 0; - tex[w*j+i].s.alpha = 0; - pTexInfo->flags |= TF_TRANSPARENT; // there is a hole in it - } - else - { - tex[w*j+i].s.red = myPaletteData[*pImgData].s.red; - tex[w*j+i].s.green = myPaletteData[*pImgData].s.green; - tex[w*j+i].s.blue = myPaletteData[*pImgData].s.blue; - tex[w*j+i].s.alpha = myPaletteData[*pImgData].s.alpha; - } - - pImgData++; - - if (pTexInfo->grInfo.format == GR_TEXFMT_AP_88) - { - if (!(pTexInfo->flags & TF_CHROMAKEYED)) - tex[w*j+i].s.alpha = *pImgData; - pImgData++; - } - - } - } - } - else if (pTexInfo->grInfo.format == GR_RGBA) - { - // corona test : passed as ARGB 8888, which is not in glide formats - // Hurdler: not used for coronas anymore, just for dynamic lighting - ptex = pTexInfo->grInfo.data; - } - else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88) - { - const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data; - INT32 i, j; - - for (j = 0; j < h; j++) - { - for (i = 0; i < w; i++) - { - tex[w*j+i].s.red = *pImgData; - tex[w*j+i].s.green = *pImgData; - tex[w*j+i].s.blue = *pImgData; - pImgData++; - tex[w*j+i].s.alpha = *pImgData; - pImgData++; - } - } - } - else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8) // Used for fade masks - { - const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data; - INT32 i, j; - - for (j = 0; j < h; j++) - { - for (i = 0; i < w; i++) - { - tex[w*j+i].s.red = 255; // 255 because the fade mask is modulated with the screen texture, so alpha affects it while the colours don't - tex[w*j+i].s.green = 255; - tex[w*j+i].s.blue = 255; - tex[w*j+i].s.alpha = *pImgData; - pImgData++; - } - } - } - else - DBG_Printf ("SetTexture(bad format) %ld\n", pTexInfo->grInfo.format); - - pTexInfo->downloaded = NextTexAvail++; - tex_downloaded = pTexInfo->downloaded; - pglBindTexture(GL_TEXTURE_2D, pTexInfo->downloaded); - - // disable texture filtering on any texture that has holes so there's no dumb borders or blending issues - if (pTexInfo->flags & TF_TRANSPARENT) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - else - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); - } - - if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88) - { - //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - if (MipMap) - { - pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); - if (pTexInfo->flags & TF_TRANSPARENT) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff - else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); - //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR); - } - else - pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - } - else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8) - { - //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - if (MipMap) - { - pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); - if (pTexInfo->flags & TF_TRANSPARENT) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff - else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); - //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR); - } - else - pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - } - else - { - if (MipMap) - { - pgluBuild2DMipmaps(GL_TEXTURE_2D, textureformatGL, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - // Control the mipmap level of detail - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail - if (pTexInfo->flags & TF_TRANSPARENT) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff - else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5); - } - else - pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); - } - - if (pTexInfo->flags & TF_WRAPX) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - else - Clamp2D(GL_TEXTURE_WRAP_S); - - if (pTexInfo->flags & TF_WRAPY) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - else - Clamp2D(GL_TEXTURE_WRAP_T); - - if (maximumAnisotropy) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic_filter); - + UpdateTexture(pTexInfo); pTexInfo->nextmipmap = NULL; if (gr_cachetail) { // insertion at the tail @@ -1305,32 +1870,132 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } } - -// -----------------+ -// DrawPolygon : Render a polygon, set the texture, set render mode -// -----------------+ -EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, - //FTextureInfo *pTexInfo, - FOutVector *pOutVerts, - FUINT iNumPts, - FBITFIELD PolyFlags) +static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { - FUINT i; - FUINT j; +#ifdef GL_SHADERS + if (gl_shadersenabled && pglUseProgram) + { + gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; + if (shader->program) + { + if (gl_shaderprogramchanged) + { + pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program); + gl_shaderprogramchanged = false; + } + Shader_SetUniforms(Surface, poly, tint, fade); + return shader; + } + else + pglUseProgram(0); + } +#else + (void)Surface; + (void)poly; + (void)tint; + (void)fade; +#endif + return NULL; +} + +static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) +{ +#ifdef GL_SHADERS + if (gl_shadersenabled) + { + gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; + if (!shader->program) + return; + + #define UNIFORM_1(uniform, a, function) \ + if (uniform != -1) \ + function (uniform, a); + + #define UNIFORM_2(uniform, a, b, function) \ + if (uniform != -1) \ + function (uniform, a, b); + + #define UNIFORM_3(uniform, a, b, c, function) \ + if (uniform != -1) \ + function (uniform, a, b, c); + + #define UNIFORM_4(uniform, a, b, c, d, function) \ + if (uniform != -1) \ + function (uniform, a, b, c, d); + + // polygon + UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f); + UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f); + UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f); + if (Surface != NULL) + { + UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f); + UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f); + UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f); + } + UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)shader_leveltime) / TICRATE, pglUniform1f); + + #undef UNIFORM_1 + #undef UNIFORM_2 + #undef UNIFORM_3 + #undef UNIFORM_4 + } +#else + (void)Surface; + (void)poly; + (void)tint; + (void)fade; +#endif +} + +// code that is common between DrawPolygon and DrawIndexedTriangles +// the corona thing is there too, i have no idea if that stuff works with DrawIndexedTriangles and batching +static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD PolyFlags) +{ + static GLRGBAFloat poly = {0,0,0,0}; + static GLRGBAFloat tint = {0,0,0,0}; + static GLRGBAFloat fade = {0,0,0,0}; if ((PolyFlags & PF_Corona) && (oglflags & GLF_NOZBUFREAD)) PolyFlags &= ~(PF_NoDepthTest|PF_Corona); SetBlend(PolyFlags); //TODO: inline (#pragma..) - // If Modulated, mix the surface colour to the texture - if ((CurrentPolyFlags & PF_Modulated) && pSurf) - pglColor4ubv((GLubyte*)&pSurf->FlatColor.s); + // PolyColor + if (pSurf) + { + // If Modulated, mix the surface colour to the texture + if (CurrentPolyFlags & PF_Modulated) + { + // Poly color + poly.red = byte2float[pSurf->PolyColor.s.red]; + poly.green = byte2float[pSurf->PolyColor.s.green]; + poly.blue = byte2float[pSurf->PolyColor.s.blue]; + poly.alpha = byte2float[pSurf->PolyColor.s.alpha]; + + pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); + } + + // Tint color + tint.red = byte2float[pSurf->TintColor.s.red]; + tint.green = byte2float[pSurf->TintColor.s.green]; + tint.blue = byte2float[pSurf->TintColor.s.blue]; + tint.alpha = byte2float[pSurf->TintColor.s.alpha]; + + // Fade color + fade.red = byte2float[pSurf->FadeColor.s.red]; + fade.green = byte2float[pSurf->FadeColor.s.green]; + fade.blue = byte2float[pSurf->FadeColor.s.blue]; + fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; + } // this test is added for new coronas' code (without depth buffer) // I think I should do a separate function for drawing coronas, so it will be a little faster if (PolyFlags & PF_Corona) // check to see if we need to draw the corona { + FUINT i; + FUINT j; + //rem: all 8 (or 8.0f) values are hard coded: it can be changed to a higher value GLfloat buf[8][8]; GLfloat cx, cy, cz; @@ -1347,18 +2012,18 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, // I dont know if this is slow or not GLProject(cx, cy, cz, &px, &py, &pz); - //DBG_Printf("Projection: (%f, %f, %f)\n", px, py, pz); + //GL_DBG_Printf("Projection: (%f, %f, %f)\n", px, py, pz); if ((pz < 0.0l) || - (px < -8.0l) || - (py < viewport[1]-8.0l) || - (px > viewport[2]+8.0l) || - (py > viewport[1]+viewport[3]+8.0l)) + (px < -8.0l) || + (py < viewport[1]-8.0l) || + (px > viewport[2]+8.0l) || + (py > viewport[1]+viewport[3]+8.0l)) return; // the damned slow glReadPixels functions :( pglReadPixels((INT32)px-4, (INT32)py, 8, 8, GL_DEPTH_COMPONENT, GL_FLOAT, buf); - //DBG_Printf("DepthBuffer: %f %f\n", buf[0][0], buf[3][3]); + //GL_DBG_Printf("DepthBuffer: %f %f\n", buf[0][0], buf[3][3]); for (i = 0; i < 8; i++) for (j = 0; j < 8; j++) @@ -1371,24 +2036,34 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, if (py > viewport[1]+viewport[3]-4) scalef -= (GLfloat)(8*(4-(viewport[1]+viewport[3]-py))); scalef /= 64; - //DBG_Printf("Scale factor: %f\n", scalef); + //GL_DBG_Printf("Scale factor: %f\n", scalef); if (scalef < 0.05f) return; // GLubyte c[4]; - c[0] = pSurf->FlatColor.s.red; - c[1] = pSurf->FlatColor.s.green; - c[2] = pSurf->FlatColor.s.blue; + c[0] = pSurf->PolyColor.s.red; + c[1] = pSurf->PolyColor.s.green; + c[2] = pSurf->PolyColor.s.blue; - alpha = byte2float[pSurf->FlatColor.s.alpha]; + alpha = byte2float[pSurf->PolyColor.s.alpha]; alpha *= scalef; // change the alpha value (it seems better than changing the size of the corona) c[3] = (unsigned char)(alpha * 255); pglColor4ubv(c); } + Shader_Load(pSurf, &poly, &tint, &fade); +} + +// -----------------+ +// DrawPolygon : Render a polygon, set the texture, set render mode +// -----------------+ +EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags) +{ + PreparePolygon(pSurf, pOutVerts, PolyFlags); + pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); - pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].sow); + pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts); if (PolyFlags & PF_RemoveYWrap) @@ -1401,6 +2076,17 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, Clamp2D(GL_TEXTURE_WRAP_T); } +EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, UINT32 *IndexArray) +{ + PreparePolygon(pSurf, pOutVerts, PolyFlags); + + pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); + pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); + pglDrawElements(GL_TRIANGLES, iNumPts, GL_UNSIGNED_INT, IndexArray); + + // the DrawPolygon variant of this has some code about polyflags and wrapping here but havent noticed any problems from omitting it? +} + typedef struct vbo_vertex_s { float x, y, z; @@ -1663,46 +2349,16 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) model_lighting = Value; break; - case HWD_SET_FOG_COLOR: - { - GLfloat fogcolor[4]; - - fogcolor[0] = byte2float[((Value>>16)&0xff)]; - fogcolor[1] = byte2float[((Value>>8)&0xff)]; - fogcolor[2] = byte2float[((Value)&0xff)]; - fogcolor[3] = 0x0; - pglFogfv(GL_FOG_COLOR, fogcolor); - break; - } - - case HWD_SET_FOG_DENSITY: - pglFogf(GL_FOG_DENSITY, Value*1200/(500*1000000.0f)); - break; - - case HWD_SET_FOG_MODE: - if (Value) + case HWD_SET_SHADERS: + switch (Value) { - pglEnable(GL_FOG); - // experimental code - /* - switch (Value) - { - case 1: - glFogi(GL_FOG_MODE, GL_LINEAR); - pglFogf(GL_FOG_START, -1000.0f); - pglFogf(GL_FOG_END, 2000.0f); - break; - case 2: - glFogi(GL_FOG_MODE, GL_EXP); - break; - case 3: - glFogi(GL_FOG_MODE, GL_EXP2); - break; - } - */ + case 1: + gl_allowshaders = true; + break; + default: + gl_allowshaders = false; + break; } - else - pglDisable(GL_FOG); break; case HWD_SET_TEXTUREFILTERMODE: @@ -1957,12 +2613,13 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) } } -#define BUFFER_OFFSET(i) ((char*)NULL + (i)) +#define BUFFER_OFFSET(i) ((void*)(i)) -static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 *color) +static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) { - GLfloat ambient[4]; - GLfloat diffuse[4]; + static GLRGBAFloat poly = {0,0,0,0}; + static GLRGBAFloat tint = {0,0,0,0}; + static GLRGBAFloat fade = {0,0,0,0}; float pol = 0.0f; float scalex, scaley, scalez; @@ -1971,8 +2628,12 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 int i; - // Because Otherwise, scaling the screen negatively vertically breaks the lighting + // Because otherwise, scaling the screen negatively vertically breaks the lighting GLfloat LightPos[] = {0.0f, 1.0f, 0.0f, 0.0f}; +#ifdef GL_LIGHT_MODEL_AMBIENT + GLfloat ambient[4]; + GLfloat diffuse[4]; +#endif // Affect input model scaling scale *= 0.5f; @@ -1993,16 +2654,23 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 pol = 0.0f; } - if (color) + poly.red = byte2float[Surface->PolyColor.s.red]; + poly.green = byte2float[Surface->PolyColor.s.green]; + poly.blue = byte2float[Surface->PolyColor.s.blue]; + poly.alpha = byte2float[Surface->PolyColor.s.alpha]; + +#ifdef GL_LIGHT_MODEL_AMBIENT + if (model_lighting && (!gl_shadersenabled)) // doesn't work with shaders anyway { - ambient[0] = (color[0]/255.0f); - ambient[1] = (color[1]/255.0f); - ambient[2] = (color[2]/255.0f); - ambient[3] = (color[3]/255.0f); - diffuse[0] = (color[0]/255.0f); - diffuse[1] = (color[1]/255.0f); - diffuse[2] = (color[2]/255.0f); - diffuse[3] = (color[3]/255.0f); + ambient[0] = poly.red; + ambient[1] = poly.green; + ambient[2] = poly.blue; + ambient[3] = poly.alpha; + + diffuse[0] = poly.red; + diffuse[1] = poly.green; + diffuse[2] = poly.blue; + diffuse[3] = poly.alpha; if (ambient[0] > 0.75f) ambient[0] = 0.75f; @@ -2010,7 +2678,31 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 ambient[1] = 0.75f; if (ambient[2] > 0.75f) ambient[2] = 0.75f; + + pglLightfv(GL_LIGHT0, GL_POSITION, LightPos); + pglShadeModel(GL_SMOOTH); + + pglEnable(GL_LIGHTING); + pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); + pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); } +#endif + else + pglColor4ubv((GLubyte*)&Surface->PolyColor.s); + + SetBlend((poly.alpha < 1 ? PF_Translucent : (PF_Masked|PF_Occlude))|PF_Modulated); + + tint.red = byte2float[Surface->TintColor.s.red]; + tint.green = byte2float[Surface->TintColor.s.green]; + tint.blue = byte2float[Surface->TintColor.s.blue]; + tint.alpha = byte2float[Surface->TintColor.s.alpha]; + + fade.red = byte2float[Surface->FadeColor.s.red]; + fade.green = byte2float[Surface->FadeColor.s.green]; + fade.blue = byte2float[Surface->FadeColor.s.blue]; + fade.alpha = byte2float[Surface->FadeColor.s.alpha]; + + Shader_Load(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); @@ -2039,31 +2731,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 } #endif - if (model_lighting) - { - pglLightfv(GL_LIGHT0, GL_POSITION, LightPos); - pglShadeModel(GL_SMOOTH); - } - - if (color) - { -#ifdef GL_LIGHT_MODEL_AMBIENT - if (model_lighting) - { - pglEnable(GL_LIGHTING); - pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); - pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); - } - else -#endif - pglColor4ubv((GLubyte*)color); - - if (color[3] < 255) - SetBlend(PF_Translucent|PF_Modulated|PF_Clip); - else - SetBlend(PF_Masked|PF_Modulated|PF_Occlude|PF_Clip); - } - pglPushMatrix(); // should be the same as glLoadIdentity //Hurdler: now it seems to work pglTranslatef(pos->x, pos->z, pos->y); @@ -2124,13 +2791,12 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 { short *vertPtr; char *normPtr; - int j; + int j = 0; // Dangit, I soooo want to do this in a GLSL shader... AllocLerpTinyBuffer(mesh->numVertices * sizeof(short) * 3); vertPtr = vertTinyBuffer; normPtr = normTinyBuffer; - j = 0; for (j = 0; j < mesh->numVertices * 3; j++) { @@ -2201,19 +2867,24 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 pglDisableClientState(GL_NORMAL_ARRAY); pglPopMatrix(); // should be the same as glLoadIdentity - if (color) - pglDisable(GL_LIGHTING); - pglShadeModel(GL_FLAT); pglDisable(GL_CULL_FACE); pglDisable(GL_NORMALIZE); + +#ifdef GL_LIGHT_MODEL_AMBIENT + if (model_lighting && (!gl_shadersenabled)) + { + pglDisable(GL_LIGHTING); + pglShadeModel(GL_FLAT); + } +#endif } // -----------------+ -// HWRAPI DrawMD2 : Draw an MD2 model with glcommands +// HWRAPI DrawModel : Draw a model // -----------------+ -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 *color) +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) { - DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, color); + DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, Surface); } // -----------------+ @@ -2222,8 +2893,11 @@ EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, EXPORT void HWRAPI(SetTransform) (FTransform *stransform) { static boolean special_splitscreen; + boolean shearing = false; float used_fov; + pglLoadIdentity(); + if (stransform) { used_fov = stransform->fovxangle; @@ -2245,6 +2919,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglTranslatef(-stransform->x, -stransform->z, -stransform->y); special_splitscreen = stransform->splitscreen; + shearing = stransform->shearing; } else { @@ -2255,6 +2930,15 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); + // jimita 14042019 + // Simulate Software's y-shearing + // https://zdoom.org/wiki/Y-shearing + if (shearing) + { + float fdy = stransform->viewaiming * 2; + pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f); + } + if (special_splitscreen) { used_fov = atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI; @@ -2267,6 +2951,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglMatrixMode(GL_MODELVIEW); pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer) + } EXPORT INT32 HWRAPI(GetTextureUsed) (void) @@ -2298,11 +2983,6 @@ EXPORT INT32 HWRAPI(GetTextureUsed) (void) return res; } -EXPORT INT32 HWRAPI(GetRenderVersion) (void) -{ - return VERSION; -} - EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) { INT32 x, y; @@ -2340,6 +3020,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) pglVertexPointer(3, GL_FLOAT, 0, blackBack); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + pglEnableClientState(GL_TEXTURE_COORD_ARRAY); for(x=0;xV_INVERTMAP) + cstart = "\x80"; + else if (chatcolor == V_MAGENTAMAP) + cstart = "\x81"; + else if (chatcolor == V_YELLOWMAP) + cstart = "\x82"; + else if (chatcolor == V_GREENMAP) + cstart = "\x83"; + else if (chatcolor == V_BLUEMAP) + cstart = "\x84"; + else if (chatcolor == V_REDMAP) + cstart = "\x85"; + else if (chatcolor == V_GRAYMAP) + cstart = "\x86"; + else if (chatcolor == V_ORANGEMAP) + cstart = "\x87"; + else if (chatcolor == V_SKYMAP) + cstart = "\x88"; + else if (chatcolor == V_PURPLEMAP) + cstart = "\x89"; + else if (chatcolor == V_AQUAMAP) + cstart = "\x8a"; + else if (chatcolor == V_PERIDOTMAP) + cstart = "\x8b"; + else if (chatcolor == V_AZUREMAP) + cstart = "\x8c"; + else if (chatcolor == V_BROWNMAP) + cstart = "\x8d"; + else if (chatcolor == V_ROSYMAP) + cstart = "\x8e"; + else if (chatcolor == V_INVERTMAP) + cstart = "\x8f"; } prefix = cstart; @@ -2171,18 +2100,14 @@ void HU_Drawer(void) { if (netgame || multiplayer) { -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_rankings)) -#endif - HU_DrawRankings(); - if (gametype == GT_COOP) + HU_DrawRankings(); + if (gametyperules & GTR_CAMPAIGN) HU_DrawNetplayCoopOverlay(); } else HU_DrawCoopOverlay(); -#ifdef HAVE_BLUA LUAh_ScoresHUD(); -#endif } if (gamestate != GS_LEVEL) @@ -3165,29 +3090,20 @@ static void HU_DrawRankings(void) static void HU_DrawCoopOverlay(void) { - if (token -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_tokens) -#endif - ) + if (token && LUA_HudEnabled(hud_tokens)) { V_DrawString(168, 176, 0, va("- %d", token)); V_DrawSmallScaledPatch(148, 172, 0, tokenicon); } -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_tabemblems)) -#endif - if (!modifiedgame || savemoddata) + if (LUA_HudEnabled(hud_tabemblems) && (!modifiedgame || savemoddata)) { V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(), numemblems+numextraemblems)); V_DrawScaledPatch(128, 144 - SHORT(emblemicon->height)/4, 0, emblemicon); } -#ifdef HAVE_BLUA if (!LUA_HudEnabled(hud_coopemeralds)) return; -#endif if (emeralds & EMERALD1) V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)-32, 0, emeraldpics[0][0]); @@ -3209,20 +3125,14 @@ static void HU_DrawNetplayCoopOverlay(void) { int i; - if (token -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_tokens) -#endif - ) + if (token && LUA_HudEnabled(hud_tokens)) { V_DrawString(168, 10, 0, va("- %d", token)); V_DrawSmallScaledPatch(148, 6, 0, tokenicon); } -#ifdef HAVE_BLUA if (!LUA_HudEnabled(hud_coopemeralds)) return; -#endif for (i = 0; i < 7; ++i) { diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 3502a1b2d..63d85f1b8 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -85,7 +85,7 @@ 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 *ttlnum[10]; extern patch_t *emeraldpics[3][8]; extern patch_t *rflagico; extern patch_t *bflagico; diff --git a/src/i_addrinfo.c b/src/i_addrinfo.c index dd3b5ab0f..e77774549 100644 --- a/src/i_addrinfo.c +++ b/src/i_addrinfo.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2011-2019 by Sonic Team Junior. +// Copyright (C) 2011-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_addrinfo.h b/src/i_addrinfo.h index 3108c422e..7ae006719 100644 --- a/src/i_addrinfo.h +++ b/src/i_addrinfo.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2011-2019 by Sonic Team Junior. +// Copyright (C) 2011-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_joy.h b/src/i_joy.h index 5f9b63712..2a2797fc4 100644 --- a/src/i_joy.h +++ b/src/i_joy.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_net.h b/src/i_net.h index e96891d9d..5d93f191e 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_sound.h b/src/i_sound.h index fbaa93053..4bd05d234 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_system.h b/src/i_system.h index a60b56310..dd0b65f6d 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -46,6 +46,8 @@ UINT32 I_GetFreeMem(UINT32 *total); */ tic_t I_GetTime(void); +int I_GetTimeMicros(void);// provides microsecond counter for render stats + /** \brief The I_Sleep function \return void diff --git a/src/i_tcp.c b/src/i_tcp.c index 502eb6732..5180869a5 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -487,7 +487,7 @@ static void cleanupnodes(void) // Why can't I start at zero? for (j = 1; j < MAXNETNODES; j++) - if (!(nodeingame[j] || SV_SendingFile(j))) + if (!(nodeingame[j] || SendingFile(j))) nodeconnected[j] = false; } @@ -1423,6 +1423,7 @@ static void SOCK_ClearBans(void) boolean I_InitTcpNetwork(void) { char serverhostname[255]; + const char *urlparam = NULL; boolean ret = false; // initilize the OS's TCP/IP stack if (!I_InitTcpDriver()) @@ -1476,10 +1477,12 @@ boolean I_InitTcpNetwork(void) ret = true; } - else if (M_CheckParm("-connect")) + else if ((urlparam = M_GetUrlProtocolArg()) != NULL || M_CheckParm("-connect")) { - if (M_IsNextParm()) - strcpy(serverhostname, M_GetNextParm()); + if (urlparam != NULL) + strlcpy(serverhostname, urlparam, sizeof(serverhostname)); + else if (M_IsNextParm()) + strlcpy(serverhostname, M_GetNextParm(), sizeof(serverhostname)); else serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it diff --git a/src/i_tcp.h b/src/i_tcp.h index ea8b0a94f..738b8b4d1 100644 --- a/src/i_tcp.h +++ b/src/i_tcp.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_video.h b/src/i_video.h index 76b984d25..98ed7f38a 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -32,10 +32,14 @@ typedef enum render_none = 3 // for dedicated server } rendermode_t; -/** \brief currect render mode +/** \brief current render mode */ extern rendermode_t rendermode; +/** \brief OpenGL state + 0 = never loaded, 1 = loaded successfully, -1 = failed loading +*/ +extern INT32 vid_opengl_state; /** \brief use highcolor modes if true */ @@ -44,9 +48,8 @@ extern boolean highcolor; /** \brief setup video mode */ void I_StartupGraphics(void); -void I_StartupHardwareGraphics(void); -/** \brief restore old video mode +/** \brief shutdown video mode */ void I_ShutdownGraphics(void); @@ -82,11 +85,22 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h); \param modenum video mode to set to - \return currect video mode + \return current video mode */ INT32 VID_SetMode(INT32 modenum); + +/** \brief Checks the render state +*/ void VID_CheckRenderer(void); +/** \brief Load OpenGL mode +*/ +void VID_StartupOpenGL(void); + +/** \brief Checks if OpenGL loaded +*/ +void VID_CheckGLLoaded(rendermode_t oldrender); + /** \brief The VID_GetModeName function \param modenum video mode number diff --git a/src/info.c b/src/info.c index 9eb4562aa..62048b64a 100644 --- a/src/info.c +++ b/src/info.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -20,6 +20,7 @@ #include "m_misc.h" #include "z_zone.h" #include "d_player.h" +#include "v_video.h" // V_*MAP constants #include "lzf.h" #ifdef HWRENDER #include "hardware/hw_light.h" @@ -187,6 +188,8 @@ char sprnames[NUMSPRITES + 1][5] = // Projectiles "MISL", + "LASR", // GFZ3 laser + "LASF", // GFZ3 laser flames "TORP", // Torpedo "ENRG", // Energy ball "MINE", // Skim mine @@ -1427,11 +1430,13 @@ state_t states[NUMSTATES] = {SPR_FANG, 8, 0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2}, // S_FANG_PINCHPATHINGSTART1 {SPR_FANG, 8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING}, // S_FANG_PINCHPATHINGSTART2 - {SPR_FANG, 8, 0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE1}, // S_FANG_PINCHPATHING + {SPR_FANG, 8, 0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE0}, // S_FANG_PINCHPATHING + {SPR_FANG, 8, 0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_FANG_PINCHBOUNCE1}, // S_FANG_PINCHBOUNCE0 {SPR_FANG, 8, 2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2}, // S_FANG_PINCHBOUNCE1 {SPR_FANG, 9, 2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3}, // S_FANG_PINCHBOUNCE2 {SPR_FANG, 10, 2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE3 - {SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL1, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE4 + {SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE4 + {SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 1, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL0 {SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2}, // S_FANG_PINCHFALL1 {SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL2 {SPR_FANG, 4, 0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID1 @@ -2058,7 +2063,15 @@ state_t states[NUMSTATES] = {SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET}, // S_ROCKET - {SPR_MISL, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LASER + {SPR_LASR, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_NULL}, // S_LASER + {SPR_LASR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_LASER2 + {SPR_LASR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL}, // S_LASERFLASH + + {SPR_LASF, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_LASERFLAME2}, // S_LASERFLAME1 + {SPR_LASF, FF_FULLBRIGHT|1, 1, {A_ChangeHeight}, 156*FRACUNIT, 3, S_LASERFLAME3}, // S_LASERFLAME2 + {SPR_LASF, FF_FULLBRIGHT|2, 0, {A_ChangeHeight}, 32*FRACUNIT, 3, S_LASERFLAME4}, // S_LASERFLAME3 + {SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|2, 4, {NULL}, 1, 2, S_LASERFLAME5}, // S_LASERFLAME4 + {SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|4, 28, {NULL}, 2, 2, S_NULL}, // S_LASERFLAME5 {SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO}, // S_TORPEDO @@ -3351,7 +3364,7 @@ state_t states[NUMSTATES] = // CTF Sign {SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG - + // Finish flag {SPR_FNSF, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_FINISHFLAG @@ -5665,28 +5678,28 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_EGGMOBILE_FIRE -1, // doomednum - S_SPINFIRE1, // spawnstate + S_LASERFLAME1, // spawnstate 1, // spawnhealth S_NULL, // seestate - sfx_None, // seesound + sfx_s3kc2s, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance - sfx_None, // painsound + sfx_s3k8d, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 14*FRACUNIT, // height + 24*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset DMG_FIRE, // mass 1, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_FIRE, // flags + MF_NOGRAVITY|MF_FIRE|MF_PAIN, // flags S_NULL // raisestate }, @@ -9637,8 +9650,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // painstate 0, // painchance sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate + S_LASERFLASH, // meleestate + S_LASER2, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound @@ -9649,7 +9662,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 20, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags + MF_MISSILE|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -17999,7 +18012,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags S_NULL // raisestate }, - + { // MT_FINISHFLAG -1, // doomednum S_FINISHFLAG, // spawnstate @@ -19844,7 +19857,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, - + { // MT_FLINGNIGHTSSTAR -1, // doomednum S_NIGHTSSTAR, // spawnstate @@ -21606,8 +21619,140 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = #endif }; +skincolor_t skincolors[MAXSKINCOLORS] = { + {"None", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_NONE -/** Patches the mobjinfo table and state table. + // Greyscale ranges + {"White", {0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x11}, SKINCOLOR_BLACK, 5, 0, true}, // SKINCOLOR_WHITE + {"Bone", {0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x05, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x11, 0x12}, SKINCOLOR_JET, 7, 0, true}, // SKINCOLOR_BONE + {"Cloudy", {0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14}, SKINCOLOR_CARBON, 7, 0, true}, // SKINCOLOR_CLOUDY + {"Grey", {0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, SKINCOLOR_AETHER, 12, 0, true}, // SKINCOLOR_GREY + {"Silver", {0x02, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f}, SKINCOLOR_SLATE, 12, 0, true}, // SKINCOLOR_SILVER + {"Carbon", {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x17, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1c, 0x1d}, SKINCOLOR_CLOUDY, 7, V_GRAYMAP, true}, // SKINCOLOR_CARBON + {"Jet", {0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1a, 0x1b, 0x1c, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f}, SKINCOLOR_BONE, 7, V_GRAYMAP, true}, // SKINCOLOR_JET + {"Black", {0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f}, SKINCOLOR_WHITE, 7, V_GRAYMAP, true}, // SKINCOLOR_BLACK + + // Desaturated + {"Aether", {0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x91, 0x91, 0x91, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf}, SKINCOLOR_GREY, 15, 0, true}, // SKINCOLOR_AETHER + {"Slate", {0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0xaa, 0xaa, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xad, 0xae, 0xaf}, SKINCOLOR_SILVER, 12, 0, true}, // SKINCOLOR_SLATE + {"Bluebell", {0x90, 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0xac, 0xac, 0xad, 0xad, 0xa8, 0xa8, 0xa9, 0xfd, 0xfe}, SKINCOLOR_COPPER, 4, V_BLUEMAP, true}, // SKINCOLOR_BLUEBELL + {"Pink", {0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0x2b, 0x2c, 0x2e}, SKINCOLOR_AZURE, 9, V_REDMAP, true}, // SKINCOLOR_PINK + {"Yogurt", {0xd0, 0x30, 0xd8, 0xd9, 0xda, 0xdb, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe3, 0xe6, 0xe8, 0xe9}, SKINCOLOR_RUST, 7, V_BROWNMAP, true}, // SKINCOLOR_YOGURT + {"Brown", {0xdf, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef}, SKINCOLOR_TAN, 2, V_BROWNMAP, true}, // SKINCOLOR_BROWN + {"Bronze", {0xde, 0xe0, 0xe1, 0xe4, 0xe7, 0xe9, 0xeb, 0xec, 0xed, 0xed, 0xed, 0x19, 0x19, 0x1b, 0x1d, 0x1e}, SKINCOLOR_KETCHUP, 0, V_BROWNMAP, true}, // SKINCOLOR_BRONZE + {"Tan", {0x51, 0x51, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0xf5, 0xf5, 0xf9, 0xf9, 0xed, 0xed}, SKINCOLOR_BROWN, 12, V_BROWNMAP, true}, // SKINCOLOR_TAN + {"Beige", {0x54, 0x55, 0x56, 0x56, 0xf2, 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xed, 0xed}, SKINCOLOR_MOSS, 5, V_BROWNMAP, true}, // SKINCOLOR_BEIGE + {"Moss", {0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f}, SKINCOLOR_BEIGE, 13, V_GREENMAP, true}, // SKINCOLOR_MOSS + {"Azure", {0x90, 0x90, 0x91, 0x91, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf}, SKINCOLOR_PINK, 5, V_AZUREMAP, true}, // SKINCOLOR_AZURE + {"Lavender", {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_GOLD, 4, V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER + + // Viv's vivid colours (toast 21/07/17) + {"Ruby", {0xb0, 0xb0, 0xc9, 0xca, 0xcc, 0x26, 0x27, 0x28, 0x29, 0x2a, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfd}, SKINCOLOR_EMERALD, 10, V_REDMAP, true}, // SKINCOLOR_RUBY + {"Salmon", {0xd0, 0xd0, 0xd1, 0xd2, 0x20, 0x21, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e}, SKINCOLOR_FOREST, 6, V_REDMAP, true}, // SKINCOLOR_SALMON + {"Red", {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, SKINCOLOR_GREEN, 10, V_REDMAP, true}, // SKINCOLOR_RED + {"Crimson", {0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x1f}, SKINCOLOR_ICY, 10, V_REDMAP, true}, // SKINCOLOR_CRIMSON + {"Flame", {0x31, 0x32, 0x33, 0x36, 0x22, 0x22, 0x25, 0x25, 0x25, 0xcd, 0xcf, 0xcf, 0xc5, 0xc5, 0xc7, 0xc7}, SKINCOLOR_PURPLE, 8, V_REDMAP, true}, // SKINCOLOR_FLAME + {"Ketchup", {0x48, 0x49, 0x40, 0x33, 0x34, 0x36, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2b, 0x2c, 0x47, 0x2e, 0x2f}, SKINCOLOR_BRONZE, 8, V_REDMAP, true}, // SKINCOLOR_KETCHUP + {"Peachy", {0xd0, 0x30, 0x31, 0x31, 0x32, 0x32, 0xdc, 0xdc, 0xdc, 0xd3, 0xd4, 0xd4, 0xcc, 0xcd, 0xce, 0xcf}, SKINCOLOR_TEAL, 7, V_ROSYMAP, true}, // SKINCOLOR_PEACHY + {"Quail", {0xd8, 0xd9, 0xdb, 0xdc, 0xde, 0xdf, 0xd5, 0xd5, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0x1d, 0x1f}, SKINCOLOR_WAVE, 5, V_BROWNMAP, true}, // SKINCOLOR_QUAIL + {"Sunset", {0x51, 0x52, 0x40, 0x40, 0x34, 0x36, 0xd5, 0xd5, 0xd6, 0xd7, 0xcf, 0xcf, 0xc6, 0xc6, 0xc7, 0xfe}, SKINCOLOR_SAPPHIRE, 5, V_ORANGEMAP, true}, // SKINCOLOR_SUNSET + {"Copper", {0x58, 0x54, 0x40, 0x34, 0x35, 0x38, 0x3a, 0x3c, 0x3d, 0x2a, 0x2b, 0x2c, 0x2c, 0xba, 0xba, 0xbb}, SKINCOLOR_BLUEBELL, 5, V_ORANGEMAP, true}, // SKINCOLOR_COPPER + {"Apricot", {0x00, 0xd8, 0xd9, 0xda, 0xdb, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e}, SKINCOLOR_CYAN, 4, V_ORANGEMAP, true}, // SKINCOLOR_APRICOT + {"Orange", {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x2c}, SKINCOLOR_BLUE, 4, V_ORANGEMAP, true}, // SKINCOLOR_ORANGE + {"Rust", {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3f, 0x2c, 0x2d, 0x47, 0x2e, 0x2f, 0x2f}, SKINCOLOR_YOGURT, 8, V_ORANGEMAP, true}, // SKINCOLOR_RUST + {"Gold", {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_LAVENDER, 10, V_YELLOWMAP, true}, // SKINCOLOR_GOLD + {"Sandy", {0x53, 0x40, 0x41, 0x42, 0x43, 0xe6, 0xe9, 0xe9, 0xea, 0xec, 0xec, 0xc6, 0xc6, 0xc7, 0xc7, 0xfe}, SKINCOLOR_SKY, 8, V_YELLOWMAP, true}, // SKINCOLOR_SANDY + {"Yellow", {0x52, 0x53, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0xed}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, true}, // SKINCOLOR_YELLOW + {"Olive", {0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4e, 0xe7, 0xe7, 0xe9, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7, 0xfd}, SKINCOLOR_DUSK, 3, V_YELLOWMAP, true}, // SKINCOLOR_OLIVE + {"Lime", {0x50, 0x51, 0x52, 0x53, 0x48, 0xbc, 0xbd, 0xbe, 0xbe, 0xbf, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_MAGENTA, 9, V_PERIDOTMAP, true}, // SKINCOLOR_LIME + {"Peridot", {0x58, 0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0x5e, 0x5e, 0x5f, 0x5f, 0x77, 0x77}, SKINCOLOR_COBALT, 2, V_PERIDOTMAP, true}, // SKINCOLOR_PERIDOT + {"Apple", {0x49, 0x49, 0xbc, 0xbd, 0xbe, 0xbe, 0xbe, 0x67, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6d}, SKINCOLOR_RASPBERRY, 13, V_PERIDOTMAP, true}, // SKINCOLOR_APPLE + {"Green", {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_RED, 6, V_GREENMAP, true}, // SKINCOLOR_GREEN + {"Forest", {0x65, 0x66, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f}, SKINCOLOR_SALMON, 9, V_GREENMAP, true}, // SKINCOLOR_FOREST + {"Emerald", {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, SKINCOLOR_RUBY, 4, V_GREENMAP, true}, // SKINCOLOR_EMERALD + {"Mint", {0x00, 0x00, 0x58, 0x58, 0x59, 0x62, 0x62, 0x62, 0x64, 0x67, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a}, SKINCOLOR_VIOLET, 5, V_GREENMAP, true}, // SKINCOLOR_MINT + {"Seafoam", {0x01, 0x58, 0x59, 0x5a, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0xfd, 0xfd}, SKINCOLOR_PLUM, 6, V_AQUAMAP, true}, // SKINCOLOR_SEAFOAM + {"Aqua", {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_ROSY, 7, V_AQUAMAP, true}, // SKINCOLOR_AQUA + {"Teal", {0x78, 0x78, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0x8a}, SKINCOLOR_PEACHY, 7, V_SKYMAP, true}, // SKINCOLOR_TEAL + {"Wave", {0x00, 0x78, 0x78, 0x79, 0x8d, 0x87, 0x88, 0x89, 0x89, 0xae, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfd}, SKINCOLOR_QUAIL, 5, V_SKYMAP, true}, // SKINCOLOR_WAVE + {"Cyan", {0x80, 0x81, 0xff, 0xff, 0x83, 0x83, 0x8d, 0x8d, 0x8d, 0x8e, 0x7e, 0x7f, 0x76, 0x76, 0x77, 0x6e}, SKINCOLOR_APRICOT, 6, V_SKYMAP, true}, // SKINCOLOR_CYAN + {"Sky", {0x80, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x85, 0x85, 0x86, 0x87, 0x88, 0x89, 0x89, 0x8a, 0x8b}, SKINCOLOR_SANDY, 1, V_SKYMAP, true}, // SKINCOLOR_SKY + {"Cerulean", {0x85, 0x86, 0x87, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0xfd, 0xfd, 0xfd, 0x1f, 0x1f, 0x1f}, SKINCOLOR_NEON, 4, V_SKYMAP, true}, // SKINCOLOR_CERULEAN + {"Icy", {0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0x83, 0x83, 0x86, 0x87, 0x95, 0x95, 0xad, 0xad, 0xae, 0xaf}, SKINCOLOR_CRIMSON, 0, V_SKYMAP, true}, // SKINCOLOR_ICY + {"Sapphire", {0x80, 0x83, 0x86, 0x87, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, SKINCOLOR_SUNSET, 5, V_SKYMAP, true}, // SKINCOLOR_SAPPHIRE + {"Cornflower", {0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x9a, 0x9c, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e}, SKINCOLOR_YELLOW, 4, V_BLUEMAP, true}, // SKINCOLOR_CORNFLOWER + {"Blue", {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, SKINCOLOR_ORANGE, 5, V_BLUEMAP, true}, // SKINCOLOR_BLUE + {"Cobalt", {0x93, 0x94, 0x95, 0x96, 0x98, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfd, 0xfe, 0xfe}, SKINCOLOR_PERIDOT, 5, V_BLUEMAP, true}, // SKINCOLOR_COBALT + {"Vapor", {0x80, 0x81, 0x83, 0x86, 0x94, 0x94, 0xa3, 0xa3, 0xa4, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa9, 0xa9}, SKINCOLOR_LILAC, 4, V_SKYMAP, true}, // SKINCOLOR_VAPOR + {"Dusk", {0x92, 0x93, 0x94, 0x94, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xa9, 0xa9, 0xfd, 0xfd}, SKINCOLOR_OLIVE, 0, V_BLUEMAP, true}, // SKINCOLOR_DUSK + {"Pastel", {0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, SKINCOLOR_BUBBLEGUM, 9, V_PURPLEMAP, true}, // SKINCOLOR_PASTEL + {"Purple", {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9}, SKINCOLOR_FLAME, 7, V_PURPLEMAP, true}, // SKINCOLOR_PURPLE + {"Bubblegum", {0x00, 0xd0, 0xd0, 0xc8, 0xc8, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, SKINCOLOR_PASTEL, 8, V_MAGENTAMAP, true}, // SKINCOLOR_BUBBLEGUM + {"Magenta", {0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb}, SKINCOLOR_LIME, 6, V_MAGENTAMAP, true}, // SKINCOLOR_MAGENTA + {"Neon", {0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb, 0xc7, 0xc7, 0x1d, 0x1d, 0x1e}, SKINCOLOR_CERULEAN, 2, V_MAGENTAMAP, true}, // SKINCOLOR_NEON + {"Violet", {0xd0, 0xd1, 0xd2, 0xca, 0xcc, 0xb8, 0xb9, 0xb9, 0xba, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfe, 0xfe}, SKINCOLOR_MINT, 6, V_MAGENTAMAP, true}, // SKINCOLOR_VIOLET + {"Lilac", {0x00, 0xd0, 0xd1, 0xd2, 0xd3, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xfe, 0x1f}, SKINCOLOR_VAPOR, 4, V_ROSYMAP, true}, // SKINCOLOR_LILAC + {"Plum", {0xc8, 0xd3, 0xd5, 0xd6, 0xd7, 0xce, 0xcf, 0xb9, 0xb9, 0xba, 0xba, 0xa9, 0xa9, 0xa9, 0xfd, 0xfe}, SKINCOLOR_MINT, 7, V_ROSYMAP, true}, // SKINCOLOR_PLUM + {"Raspberry", {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, SKINCOLOR_APPLE, 13, V_MAGENTAMAP, true}, // SKINCOLOR_RASPBERRY + {"Rosy", {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_AQUA, 1, V_ROSYMAP, true}, // SKINCOLOR_ROSY + + // super + {"Super Silver 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03}, SKINCOLOR_BLACK, 15, 0, false}, // SKINCOLOR_SUPERSILVER1 + {"Super Silver 2", {0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07}, SKINCOLOR_BLACK, 6, 0, false}, // SKINCOLOR_SUPERSILVER2 + {"Super Silver 3", {0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b}, SKINCOLOR_BLACK, 5, 0, false}, // SKINCOLOR_SUPERSILVER3 + {"Super Silver 4", {0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11}, SKINCOLOR_BLACK, 5, V_GRAYMAP, false}, // SKINCOLOR_SUPERSILVER4 + {"Super Silver 5", {0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13}, SKINCOLOR_BLACK, 5, V_GRAYMAP, false}, // SKINCOLOR_SUPERSILVER5 + + {"Super Red 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2}, SKINCOLOR_CYAN, 15, 0, false}, // SKINCOLOR_SUPERRED1 + {"Super Red 2", {0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21}, SKINCOLOR_CYAN, 14, V_ROSYMAP, false}, // SKINCOLOR_SUPERRED2 + {"Super Red 3", {0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23}, SKINCOLOR_CYAN, 13, V_REDMAP, false}, // SKINCOLOR_SUPERRED3 + {"Super Red 4", {0x00, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24}, SKINCOLOR_CYAN, 11, V_REDMAP, false}, // SKINCOLOR_SUPERRED4 + {"Super Red 5", {0xd0, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25}, SKINCOLOR_CYAN, 10, V_REDMAP, false}, // SKINCOLOR_SUPERRED5 + + {"Super Orange 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34}, SKINCOLOR_SAPPHIRE, 15, 0, false}, // SKINCOLOR_SUPERORANGE1 + {"Super Orange 2", {0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34}, SKINCOLOR_SAPPHIRE, 12, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE2 + {"Super Orange 3", {0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35}, SKINCOLOR_SAPPHIRE, 9, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE3 + {"Super Orange 4", {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, SKINCOLOR_SAPPHIRE, 4, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE4 + {"Super Orange 5", {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_SAPPHIRE, 3, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE5 + + {"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48}, SKINCOLOR_CORNFLOWER, 15, 0, false}, // SKINCOLOR_SUPERGOLD1 + {"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41}, SKINCOLOR_CORNFLOWER, 9, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD2 + {"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD3 + {"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD4 + {"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD5 + + {"Super Peridot 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, SKINCOLOR_COBALT, 15, 0, false}, // SKINCOLOR_SUPERPERIDOT1 + {"Super Peridot 2", {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, SKINCOLOR_COBALT, 4, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT2 + {"Super Peridot 3", {0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf}, SKINCOLOR_COBALT, 3, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT3 + {"Super Peridot 4", {0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f}, SKINCOLOR_COBALT, 3, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT4 + {"Super Peridot 5", {0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f, 0x77}, SKINCOLOR_COBALT, 3, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT5 + + {"Super Sky 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84}, SKINCOLOR_RUST, 15, 0, false}, // SKINCOLOR_SUPERSKY1 + {"Super Sky 2", {0x00, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86}, SKINCOLOR_RUST, 4, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY2 + {"Super Sky 3", {0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87}, SKINCOLOR_RUST, 3, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY3 + {"Super Sky 4", {0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a}, SKINCOLOR_RUST, 3, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY4 + {"Super Sky 5", {0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a, 0x8b}, SKINCOLOR_RUST, 3, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY5 + + {"Super Purple 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa2}, SKINCOLOR_EMERALD, 15, 0, false}, // SKINCOLOR_SUPERPURPLE1 + {"Super Purple 2", {0x00, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5}, SKINCOLOR_EMERALD, 4, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE2 + {"Super Purple 3", {0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE3 + {"Super Purple 4", {0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE4 + {"Super Purple 5", {0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9, 0xfd}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE5 + + {"Super Rust 1", {0x00, 0xd0, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x32, 0x33, 0x37, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x2e}, SKINCOLOR_CYAN, 14, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST1 + {"Super Rust 2", {0x30, 0x31, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x47, 0x2e}, SKINCOLOR_CYAN, 10, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST2 + {"Super Rust 3", {0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x3a, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x2e, 0x2e}, SKINCOLOR_CYAN, 9, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST3 + {"Super Rust 4", {0x48, 0x40, 0x41, 0x42, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x2e, 0x2e, 0x2e}, SKINCOLOR_CYAN, 8, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST4 + {"Super Rust 5", {0x41, 0x42, 0x43, 0x43, 0x44, 0x44, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, 0xee, 0xef, 0xef}, SKINCOLOR_CYAN, 8, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST5 + + {"Super Tan 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52}, SKINCOLOR_BROWN, 14, 0, false}, // SKINCOLOR_SUPERTAN1 + {"Super Tan 2", {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, SKINCOLOR_BROWN, 13, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN2 + {"Super Tan 3", {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, SKINCOLOR_BROWN, 12, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN3 + {"Super Tan 4", {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, SKINCOLOR_BROWN, 11, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN4 + {"Super Tan 5", {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef}, SKINCOLOR_BROWN, 10, V_BROWNMAP, false} // SKINCOLOR_SUPERTAN5 +}; + +/** Patches the mobjinfo, state, and skincolor tables. * Free slots are emptied out and set to initial values. */ void P_PatchInfoTables(void) @@ -21635,6 +21780,11 @@ void P_PatchInfoTables(void) sprnames[i][0] = '\0'; // i == NUMSPRITES memset(&states[S_FIRSTFREESLOT], 0, sizeof (state_t) * NUMSTATEFREESLOTS); memset(&mobjinfo[MT_FIRSTFREESLOT], 0, sizeof (mobjinfo_t) * NUMMOBJFREESLOTS); + memset(&skincolors[SKINCOLOR_FIRSTFREESLOT], 0, sizeof (skincolor_t) * NUMCOLORFREESLOTS); + for (i = SKINCOLOR_FIRSTFREESLOT; i <= SKINCOLOR_LASTFREESLOT; i++) { + skincolors[i].accessible = false; + skincolors[i].name[0] = '\0'; + } for (i = MT_FIRSTFREESLOT; i <= MT_LASTFREESLOT; i++) mobjinfo[i].doomednum = -1; } @@ -21643,7 +21793,8 @@ void P_PatchInfoTables(void) static char *sprnamesbackup; static state_t *statesbackup; static mobjinfo_t *mobjinfobackup; -static size_t sprnamesbackupsize, statesbackupsize, mobjinfobackupsize; +static skincolor_t *skincolorsbackup; +static size_t sprnamesbackupsize, statesbackupsize, mobjinfobackupsize, skincolorsbackupsize; #endif void P_BackupTables(void) @@ -21653,6 +21804,7 @@ void P_BackupTables(void) sprnamesbackup = Z_Malloc(sizeof(sprnames), PU_STATIC, NULL); statesbackup = Z_Malloc(sizeof(states), PU_STATIC, NULL); mobjinfobackup = Z_Malloc(sizeof(mobjinfo), PU_STATIC, NULL); + skincolorsbackup = Z_Malloc(sizeof(skincolors), PU_STATIC, NULL); // Sprite names sprnamesbackupsize = lzf_compress(sprnames, sizeof(sprnames), sprnamesbackup, sizeof(sprnames)); @@ -21674,6 +21826,13 @@ void P_BackupTables(void) mobjinfobackup = Z_Realloc(mobjinfobackup, mobjinfobackupsize, PU_STATIC, NULL); else M_Memcpy(mobjinfobackup, mobjinfo, sizeof(mobjinfo)); + + //Skincolor info + skincolorsbackupsize = lzf_compress(skincolors, sizeof(skincolors), skincolorsbackup, sizeof(skincolors)); + if (skincolorsbackupsize > 0) + skincolorsbackup = Z_Realloc(skincolorsbackup, skincolorsbackupsize, PU_STATIC, NULL); + else + M_Memcpy(skincolorsbackup, skincolors, sizeof(skincolors)); #endif } @@ -21706,5 +21865,13 @@ void P_ResetData(INT32 flags) else M_Memcpy(mobjinfo, mobjinfobackup, sizeof(mobjinfobackup)); } + + if (flags & 8) + { + if (skincolorsbackupsize > 0) + lzf_decompress(skincolorsbackup, skincolorsbackupsize, skincolors, sizeof(skincolors)); + else + M_Memcpy(skincolors, skincolorsbackup, sizeof(skincolorsbackup)); + } #endif } diff --git a/src/info.h b/src/info.h index 9aa94b46e..476ad2b73 100644 --- a/src/info.h +++ b/src/info.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -165,6 +165,7 @@ void A_SetTics(); void A_SetRandomTics(); void A_ChangeColorRelative(); void A_ChangeColorAbsolute(); +void A_Dye(); void A_MoveRelative(); void A_MoveAbsolute(); void A_Thrust(); @@ -283,6 +284,7 @@ void A_RolloutRock(); void A_DragonbomberSpawn(); void A_DragonWing(); void A_DragonSegment(); +void A_ChangeHeight(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 512 @@ -450,6 +452,8 @@ typedef enum sprite // Projectiles SPR_MISL, + SPR_LASR, // GFZ3 laser + SPR_LASF, // GFZ3 laser flames SPR_TORP, // Torpedo SPR_ENRG, // Energy ball SPR_MINE, // Skim mine @@ -1604,10 +1608,12 @@ typedef enum state S_FANG_PINCHPATHINGSTART1, S_FANG_PINCHPATHINGSTART2, S_FANG_PINCHPATHING, + S_FANG_PINCHBOUNCE0, S_FANG_PINCHBOUNCE1, S_FANG_PINCHBOUNCE2, S_FANG_PINCHBOUNCE3, S_FANG_PINCHBOUNCE4, + S_FANG_PINCHFALL0, S_FANG_PINCHFALL1, S_FANG_PINCHFALL2, S_FANG_PINCHSKID1, @@ -2219,6 +2225,14 @@ typedef enum state S_ROCKET, S_LASER, + S_LASER2, + S_LASERFLASH, + + S_LASERFLAME1, + S_LASERFLAME2, + S_LASERFLAME3, + S_LASERFLAME4, + S_LASERFLAME5, S_TORPEDO, @@ -3486,7 +3500,7 @@ typedef enum state // Got Flag Sign S_GOTFLAG, - + // Finish flag S_FINISHFLAG, diff --git a/src/keys.h b/src/keys.h index 8819aaa86..6cdd7956c 100644 --- a/src/keys.h +++ b/src/keys.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/locale/en.po b/src/locale/en.po index 83e118772..30ebe4368 100644 --- a/src/locale/en.po +++ b/src/locale/en.po @@ -2068,7 +2068,7 @@ msgstr "" #: m_cheat.c:292 #, c-format -msgid "Sissy Mode %s\n" +msgid "Cheese Mode %s\n" msgstr "" #: m_cheat.c:315 m_cheat.c:349 m_cheat.c:514 m_cheat.c:538 m_cheat.c:557 diff --git a/src/locale/srb2.pot b/src/locale/srb2.pot index 087c8720c..960c36dbe 100644 --- a/src/locale/srb2.pot +++ b/src/locale/srb2.pot @@ -2145,7 +2145,7 @@ msgstr "" #: m_cheat.c:294 #, c-format -msgid "Sissy Mode %s\n" +msgid "Cheese Mode %s\n" msgstr "" #: m_cheat.c:314 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b16ac6a60..db70a11a2 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,17 +11,14 @@ /// \brief basic functions for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" #include "p_local.h" #include "p_setup.h" // So we can have P_SetupLevelSky -#ifdef ESLOPE -#include "p_slopes.h" // P_GetZAt -#endif +#include "p_slopes.h" // P_GetSlopeZAt #include "z_zone.h" #include "r_main.h" #include "r_draw.h" -#include "r_things.h" +#include "r_things.h" // R_Frame2Char etc #include "m_random.h" #include "s_sound.h" #include "g_game.h" @@ -30,6 +27,7 @@ #include "hu_stuff.h" // HU_AddChatText #include "console.h" #include "d_netcmd.h" // IsPlayerAdmin +#include "m_menu.h" // Player Setup menu color stuff #include "lua_script.h" #include "lua_libs.h" @@ -147,6 +145,8 @@ static const struct { {META_STATE, "state_t"}, {META_MOBJINFO, "mobjinfo_t"}, {META_SFXINFO, "sfxinfo_t"}, + {META_SKINCOLOR, "skincolor_t"}, + {META_COLORRAMP, "skincolor_t.ramp"}, {META_SPRITEINFO, "spriteinfo_t"}, {META_PIVOTLIST, "spriteframepivot_t[]"}, {META_FRAMEPIVOT, "spriteframepivot_t"}, @@ -221,10 +221,16 @@ static const char *GetUserdataUType(lua_State *L) // or players[0].powers -> "player_t.powers" static int lib_userdataType(lua_State *L) { + int type; lua_settop(L, 1); // pop everything except arg 1 (in case somebody decided to add more) - luaL_checktype(L, 1, LUA_TUSERDATA); - lua_pushstring(L, GetUserdataUType(L)); - return 1; + type = lua_type(L, 1); + if (type == LUA_TLIGHTUSERDATA || type == LUA_TUSERDATA) + { + lua_pushstring(L, GetUserdataUType(L)); + return 1; + } + else + return luaL_typerror(L, 1, "userdata"); } static int lib_isPlayerAdmin(lua_State *L) @@ -249,6 +255,43 @@ static int lib_reserveLuabanks(lua_State *L) return 1; } +// M_MENU +////////////// + +static int lib_pMoveColorBefore(lua_State *L) +{ + UINT16 color = (UINT16)luaL_checkinteger(L, 1); + UINT16 targ = (UINT16)luaL_checkinteger(L, 2); + + NOHUD + M_MoveColorBefore(color, targ); + return 0; +} + +static int lib_pMoveColorAfter(lua_State *L) +{ + UINT16 color = (UINT16)luaL_checkinteger(L, 1); + UINT16 targ = (UINT16)luaL_checkinteger(L, 2); + + NOHUD + M_MoveColorAfter(color, targ); + return 0; +} + +static int lib_pGetColorBefore(lua_State *L) +{ + UINT16 color = (UINT16)luaL_checkinteger(L, 1); + lua_pushinteger(L, M_GetColorBefore(color)); + return 1; +} + +static int lib_pGetColorAfter(lua_State *L) +{ + UINT16 color = (UINT16)luaL_checkinteger(L, 1); + lua_pushinteger(L, M_GetColorAfter(color)); + return 1; +} + // M_RANDOM ////////////// @@ -1040,11 +1083,60 @@ static int lib_pSetObjectMomZ(lua_State *L) return 0; } +static int lib_pPlayJingle(lua_State *L) +{ + player_t *player = NULL; + jingletype_t jingletype = luaL_checkinteger(L, 2); + //NOHUD + //INLEVEL + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (jingletype >= NUMJINGLES) + return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1); + P_PlayJingle(player, jingletype); + return 0; +} + +static int lib_pPlayJingleMusic(lua_State *L) +{ + player_t *player = NULL; + const char *musnamearg = luaL_checkstring(L, 2); + char musname[7], *p = musname; + UINT16 musflags = luaL_optinteger(L, 3, 0); + boolean looping = lua_opttrueboolean(L, 4); + jingletype_t jingletype = luaL_optinteger(L, 5, JT_OTHER); + //NOHUD + //INLEVEL + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (jingletype >= NUMJINGLES) + return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1); + + musname[6] = '\0'; + strncpy(musname, musnamearg, 6); + + while (*p) { + *p = tolower(*p); + ++p; + } + + P_PlayJingleMusic(player, musname, musflags, looping, jingletype); + return 0; +} + static int lib_pRestoreMusic(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - NOHUD - INLEVEL + //NOHUD + //INLEVEL if (!player) return LUA_ErrInvalid(L, "player_t"); if (P_IsLocalPlayer(player)) @@ -1674,11 +1766,15 @@ static int lib_pPlayVictorySound(lua_State *L) static int lib_pPlayLivesJingle(lua_State *L) { - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - NOHUD - INLEVEL - if (!player) - return LUA_ErrInvalid(L, "player_t"); + player_t *player = NULL; + //NOHUD + //INLEVEL + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } P_PlayLivesJingle(player); return 0; } @@ -2123,23 +2219,27 @@ static int lib_evStartCrumble(lua_State *L) return 0; } -#ifdef ESLOPE // P_SLOPES //////////// static int lib_pGetZAt(lua_State *L) { - pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); //HUDSAFE - if (!slope) - return LUA_ErrInvalid(L, "pslope_t"); + if (lua_isnil(L, 1)) + { + fixed_t z = luaL_checkfixed(L, 4); + lua_pushfixed(L, P_GetZAt(NULL, x, y, z)); + } + else + { + pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); + lua_pushfixed(L, P_GetSlopeZAt(slope, x, y)); + } - lua_pushfixed(L, P_GetZAt(slope, x, y)); return 1; } -#endif // R_DEFS //////////// @@ -2328,10 +2428,10 @@ static int lib_rGetColorByName(lua_State *L) // SKINCOLOR_GREEN > "Green" for example static int lib_rGetNameByColor(lua_State *L) { - UINT8 colornum = (UINT8)luaL_checkinteger(L, 1); - if (!colornum || colornum >= MAXSKINCOLORS) - return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, MAXSKINCOLORS-1); - lua_pushstring(L, Color_Names[colornum]); + UINT16 colornum = (UINT16)luaL_checkinteger(L, 1); + if (!colornum || colornum >= numskincolors) + return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, numskincolors-1); + lua_pushstring(L, skincolors[colornum].name); return 1; } @@ -2342,7 +2442,7 @@ static int lib_sStartSound(lua_State *L) const void *origin = NULL; sfxenum_t sound_id = luaL_checkinteger(L, 2); player_t *player = NULL; - //NOHUD // kys @whoever did this. + //NOHUD if (sound_id >= NUMSFX) return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1); if (!lua_isnil(L, 1)) @@ -2373,7 +2473,7 @@ static int lib_sStartSoundAtVolume(lua_State *L) sfxenum_t sound_id = luaL_checkinteger(L, 2); INT32 volume = (INT32)luaL_checkinteger(L, 3); player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnil(L, 1)) { @@ -2397,13 +2497,27 @@ static int lib_sStartSoundAtVolume(lua_State *L) static int lib_sStopSound(lua_State *L) { void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - NOHUD + //NOHUD if (!origin) return LUA_ErrInvalid(L, "mobj_t"); S_StopSound(origin); return 0; } +static int lib_sStopSoundByID(lua_State *L) +{ + void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + sfxenum_t sound_id = luaL_checkinteger(L, 2); + //NOHUD + if (!origin) + return LUA_ErrInvalid(L, "mobj_t"); + if (sound_id >= NUMSFX) + return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1); + + S_StopSoundByID(origin, sound_id); + return 0; +} + static int lib_sChangeMusic(lua_State *L) { #ifdef MUSICSLOT_COMPATIBILITY @@ -2414,7 +2528,7 @@ static int lib_sChangeMusic(lua_State *L) boolean looping; player_t *player = NULL; UINT16 music_flags = 0; - NOHUD + //NOHUD if (lua_isnumber(L, 1)) { @@ -2443,7 +2557,7 @@ static int lib_sChangeMusic(lua_State *L) boolean looping = (boolean)lua_opttrueboolean(L, 2); player_t *player = NULL; UINT16 music_flags = 0; - NOHUD + //NOHUD #endif if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) @@ -2474,7 +2588,7 @@ static int lib_sSpeedMusic(lua_State *L) fixed_t fixedspeed = luaL_checkfixed(L, 1); float speed = FIXED_TO_FLOAT(fixedspeed); player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) { player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); @@ -2489,7 +2603,7 @@ static int lib_sSpeedMusic(lua_State *L) static int lib_sStopMusic(lua_State *L) { player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) { player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2505,7 +2619,7 @@ static int lib_sSetInternalMusicVolume(lua_State *L) { UINT32 volume = (UINT32)luaL_checkinteger(L, 1); player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) { player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); @@ -2525,7 +2639,7 @@ static int lib_sSetInternalMusicVolume(lua_State *L) static int lib_sStopFadingMusic(lua_State *L) { player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) { player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2548,7 +2662,7 @@ static int lib_sFadeMusic(lua_State *L) UINT32 ms; INT32 source_volume; player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) { player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); @@ -2576,8 +2690,6 @@ static int lib_sFadeMusic(lua_State *L) ms = (UINT32)luaL_checkinteger(L, 3); } - NOHUD - if (!player || P_IsLocalPlayer(player)) lua_pushboolean(L, S_FadeMusicFromVolume(target_volume, source_volume, ms)); else @@ -2589,7 +2701,7 @@ static int lib_sFadeOutStopMusic(lua_State *L) { UINT32 ms = (UINT32)luaL_checkinteger(L, 1); player_t *player = NULL; - NOHUD + //NOHUD if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) { player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); @@ -2605,10 +2717,29 @@ static int lib_sFadeOutStopMusic(lua_State *L) return 1; } +static int lib_sGetMusicLength(lua_State *L) +{ + lua_pushinteger(L, S_GetMusicLength()); + return 1; +} + +static int lib_sGetMusicPosition(lua_State *L) +{ + lua_pushinteger(L, S_GetMusicPosition()); + return 1; +} + +static int lib_sSetMusicPosition(lua_State *L) +{ + UINT32 pos = (UINT32)luaL_checkinteger(L, 1); + lua_pushboolean(L, S_SetMusicPosition(pos)); + return 1; +} + static int lib_sOriginPlaying(lua_State *L) { void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - NOHUD + //NOHUD INLEVEL if (!origin) return LUA_ErrInvalid(L, "mobj_t"); @@ -2619,7 +2750,7 @@ static int lib_sOriginPlaying(lua_State *L) static int lib_sIdPlaying(lua_State *L) { sfxenum_t id = luaL_checkinteger(L, 1); - NOHUD + //NOHUD if (id >= NUMSFX) return luaL_error(L, "sfx %d out of range (0 - %d)", id, NUMSFX-1); lua_pushboolean(L, S_IdPlaying(id)); @@ -2630,7 +2761,7 @@ static int lib_sSoundPlaying(lua_State *L) { void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); sfxenum_t id = luaL_checkinteger(L, 2); - NOHUD + //NOHUD INLEVEL if (!origin) return LUA_ErrInvalid(L, "mobj_t"); @@ -2648,7 +2779,7 @@ static int lib_sStartMusicCaption(lua_State *L) const char *caption = luaL_checkstring(L, 1); UINT16 lifespan = (UINT16)luaL_checkinteger(L, 2); //HUDSAFE - INLEVEL + //INLEVEL if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) { @@ -2807,15 +2938,50 @@ static int lib_gAddGametype(lua_State *L) return 0; } +static int Lcheckmapnumber (lua_State *L, int idx, const char *fun) +{ + if (ISINLEVEL) + return luaL_optinteger(L, idx, gamemap); + else + { + if (lua_isnoneornil(L, idx)) + { + return luaL_error(L, + "%s can only be used without a parameter while in a level.", + fun + ); + } + else + return luaL_checkinteger(L, idx); + } +} + static int lib_gBuildMapName(lua_State *L) { - INT32 map = luaL_optinteger(L, 1, gamemap); + INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapName"); //HUDSAFE - INLEVEL lua_pushstring(L, G_BuildMapName(map)); return 1; } +static int lib_gBuildMapTitle(lua_State *L) +{ + INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapTitle"); + char *name; + if (map < 1 || map > NUMMAPS) + { + return luaL_error(L, + "map number %d out of range (1 - %d)", + map, + NUMMAPS + ); + } + name = G_BuildMapTitle(map); + lua_pushstring(L, name); + Z_Free(name); + return 1; +} + static int lib_gDoReborn(lua_State *L) { INT32 playernum = luaL_checkinteger(L, 1); @@ -2937,6 +3103,14 @@ static int lib_gPlatformGametype(lua_State *L) return 1; } +static int lib_gCoopGametype(lua_State *L) +{ + //HUDSAFE + INLEVEL + lua_pushboolean(L, G_CoopGametype()); + return 1; +} + static int lib_gTagGametype(lua_State *L) { //HUDSAFE @@ -3002,6 +3176,12 @@ static luaL_Reg lib[] = { {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, + // m_menu + {"M_MoveColorAfter",lib_pMoveColorAfter}, + {"M_MoveColorBefore",lib_pMoveColorBefore}, + {"M_GetColorAfter",lib_pGetColorAfter}, + {"M_GetColorBefore",lib_pGetColorBefore}, + // m_random {"P_RandomFixed",lib_pRandomFixed}, {"P_RandomByte",lib_pRandomByte}, @@ -3069,6 +3249,8 @@ static luaL_Reg lib[] = { {"P_InSpaceSector",lib_pInSpaceSector}, {"P_InQuicksand",lib_pInQuicksand}, {"P_SetObjectMomZ",lib_pSetObjectMomZ}, + {"P_PlayJingle",lib_pPlayJingle}, + {"P_PlayJingleMusic",lib_pPlayJingleMusic}, {"P_RestoreMusic",lib_pRestoreMusic}, {"P_SpawnShieldOrb",lib_pSpawnShieldOrb}, {"P_SpawnGhostMobj",lib_pSpawnGhostMobj}, @@ -3151,10 +3333,8 @@ static luaL_Reg lib[] = { {"EV_CrumbleChain",lib_evCrumbleChain}, {"EV_StartCrumble",lib_evStartCrumble}, -#ifdef ESLOPE // p_slopes {"P_GetZAt",lib_pGetZAt}, -#endif // r_defs {"R_PointToAngle",lib_rPointToAngle}, @@ -3182,6 +3362,7 @@ static luaL_Reg lib[] = { {"S_StartSound",lib_sStartSound}, {"S_StartSoundAtVolume",lib_sStartSoundAtVolume}, {"S_StopSound",lib_sStopSound}, + {"S_StopSoundByID",lib_sStopSoundByID}, {"S_ChangeMusic",lib_sChangeMusic}, {"S_SpeedMusic",lib_sSpeedMusic}, {"S_StopMusic",lib_sStopMusic}, @@ -3189,6 +3370,9 @@ static luaL_Reg lib[] = { {"S_StopFadingMusic",lib_sStopFadingMusic}, {"S_FadeMusic",lib_sFadeMusic}, {"S_FadeOutStopMusic",lib_sFadeOutStopMusic}, + {"S_GetMusicLength",lib_sGetMusicLength}, + {"S_GetMusicPosition",lib_sGetMusicPosition}, + {"S_SetMusicPosition",lib_sSetMusicPosition}, {"S_OriginPlaying",lib_sOriginPlaying}, {"S_IdPlaying",lib_sIdPlaying}, {"S_SoundPlaying",lib_sSoundPlaying}, @@ -3197,6 +3381,7 @@ static luaL_Reg lib[] = { // g_game {"G_AddGametype", lib_gAddGametype}, {"G_BuildMapName",lib_gBuildMapName}, + {"G_BuildMapTitle",lib_gBuildMapTitle}, {"G_DoReborn",lib_gDoReborn}, {"G_SetCustomExitVars",lib_gSetCustomExitVars}, {"G_EnoughPlayersFinished",lib_gEnoughPlayersFinished}, @@ -3209,6 +3394,7 @@ static luaL_Reg lib[] = { {"G_GametypeHasSpectators",lib_gGametypeHasSpectators}, {"G_RingSlingerGametype",lib_gRingSlingerGametype}, {"G_PlatformGametype",lib_gPlatformGametype}, + {"G_CoopGametype",lib_gCoopGametype}, {"G_TagGametype",lib_gTagGametype}, {"G_CompetitionGametype",lib_gCompetitionGametype}, {"G_TicsToHours",lib_gTicsToHours}, @@ -3237,5 +3423,3 @@ int LUA_BaseLib(lua_State *L) luaL_register(L, NULL, lib); return 0; } - -#endif diff --git a/src/lua_blockmaplib.c b/src/lua_blockmaplib.c index 7f7dc9560..5aae73284 100644 --- a/src/lua_blockmaplib.c +++ b/src/lua_blockmaplib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2016 by Iestyn "Monster Iestyn" Jealous. -// Copyright (C) 2016-2019 by Sonic Team Junior. +// Copyright (C) 2016-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief blockmap library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "p_local.h" #include "r_main.h" // validcount #include "lua_script.h" @@ -81,9 +80,7 @@ static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *th { INT32 offset; const INT32 *list; // Big blockmap -#ifdef POLYOBJECTS polymaplink_t *plink; // haleyjd 02/22/06 -#endif line_t *ld; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) @@ -91,7 +88,6 @@ static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *th offset = y*bmapwidth + x; -#ifdef POLYOBJECTS // haleyjd 02/22/06: consider polyobject lines plink = polyblocklinks[offset]; @@ -134,7 +130,6 @@ static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *th } plink = (polymaplink_t *)(plink->link.next); } -#endif offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x]; @@ -264,5 +259,3 @@ int LUA_BlockmapLib(lua_State *L) lua_register(L, "searchBlockmap", lib_searchBlockmap); return 0; } - -#endif diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 48f2e20a8..4fe234dee 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief console modifying/etc library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" #include "p_local.h" #include "g_game.h" @@ -431,22 +430,8 @@ static int lib_cvRegisterVar(lua_State *L) static int lib_cvFindVar(lua_State *L) { - consvar_t *cv; - if (( cv = CV_FindVar(luaL_checkstring(L,1)) )) - { - lua_settop(L,1);/* We only want one argument in the stack. */ - lua_pushlightuserdata(L, cv);/* Now the second value on stack. */ - luaL_getmetatable(L, META_CVAR); - /* - The metatable is the last value on the stack, so this - applies it to the second value, which is the cvar. - */ - lua_setmetatable(L,2); - lua_pushvalue(L,2); - return 1; - } - else - return 0; + LUA_PushLightUserdata(L, CV_FindVar(luaL_checkstring(L,1)), META_CVAR); + return 1; } // CONS_Printf for a single player @@ -551,5 +536,3 @@ int LUA_ConsoleLib(lua_State *L) luaL_register(L, NULL, lib); return 0; } - -#endif diff --git a/src/lua_hook.h b/src/lua_hook.h index 94d2239f7..48f6cab32 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -10,8 +10,6 @@ /// \file lua_hook.h /// \brief hooks for Lua scripting -#ifdef HAVE_BLUA - #include "r_defs.h" #include "d_player.h" @@ -42,6 +40,7 @@ enum hook { hook_JumpSpinSpecial, hook_BotTiccmd, hook_BotAI, + hook_BotRespawn, hook_LinedefExecute, hook_PlayerMsg, hook_HurtMsg, @@ -58,6 +57,8 @@ enum hook { hook_ViewpointSwitch, hook_SeenPlayer, hook_PlayerThink, + hook_ShouldJingleContinue, + hook_GameQuit, hook_MAX // last hook }; @@ -92,6 +93,7 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 #define LUAh_JumpSpinSpecial(player) LUAh_PlayerHook(player, hook_JumpSpinSpecial) // Hook for P_DoJumpStuff (Spin button effect (mid-air)) boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name +boolean LUAh_BotRespawn(mobj_t *sonic, mobj_t *tails); // Hook for B_CheckRespawn boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for hurt messages @@ -110,5 +112,5 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_NAMECHECK #endif #define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink - -#endif +boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing +void LUAh_GameQuit(void); // Hook for game quitting \ No newline at end of file diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index f9dad6cb7..5cfd1bd3d 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,11 +11,10 @@ /// \brief hooks for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "doomstat.h" #include "p_mobj.h" #include "g_game.h" -#include "r_things.h" +#include "r_skins.h" #include "b_bot.h" #include "z_zone.h" @@ -53,6 +52,7 @@ const char *const hookNames[hook_MAX+1] = { "JumpSpinSpecial", "BotTiccmd", "BotAI", + "BotRespawn", "LinedefExecute", "PlayerMsg", "HurtMsg", @@ -69,6 +69,8 @@ const char *const hookNames[hook_MAX+1] = { "ViewpointSwitch", "SeenPlayer", "PlayerThink", + "ShouldJingleContinue", + "GameQuit", NULL }; @@ -80,8 +82,7 @@ struct hook_s UINT16 id; union { mobjtype_t mt; - char *skinname; - char *funcname; + char *str; } s; boolean error; }; @@ -108,6 +109,12 @@ static hook_p linedefexecutorhooks; // For other hooks, a unique linked list hook_p roothook; +static void PushHook(lua_State *L, hook_p hookp) +{ + lua_pushfstring(L, FMT_HOOKID, hookp->id); + lua_gettable(L, LUA_REGISTRYINDEX); +} + // Takes hook, function, and additional arguments (mobj type to act on, etc.) static int lib_addHook(lua_State *L) { @@ -142,34 +149,24 @@ static int lib_addHook(lua_State *L) case hook_HurtMsg: case hook_MobjMoveBlocked: case hook_MapThingSpawn: + case hook_FollowMobj: hook.s.mt = MT_NULL; if (lua_isnumber(L, 2)) hook.s.mt = lua_tonumber(L, 2); luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t"); break; case hook_BotAI: - hook.s.skinname = NULL; + case hook_ShouldJingleContinue: + hook.s.str = NULL; if (lua_isstring(L, 2)) { // lowercase copy - const char *s = lua_tostring(L, 2); - char *p = hook.s.skinname = ZZ_Alloc(strlen(s)+1); - do { - *p = tolower(*s); - ++p; - } while(*(++s)); - *p = 0; + hook.s.str = Z_StrDup(lua_tostring(L, 2)); + strlwr(hook.s.str); } break; case hook_LinedefExecute: // Linedef executor functions - { // uppercase copy - const char *s = luaL_checkstring(L, 2); - char *p = hook.s.funcname = ZZ_Alloc(strlen(s)+1); - do { - *p = toupper(*s); - ++p; - } while(*(++s)); - *p = 0; - } + hook.s.str = Z_StrDup(luaL_checkstring(L, 2)); + strupr(hook.s.str); break; default: break; @@ -203,6 +200,7 @@ static int lib_addHook(lua_State *L) case hook_MobjRemoved: case hook_MobjMoveBlocked: case hook_MapThingSpawn: + case hook_FollowMobj: lastp = &mobjhooks[hook.s.mt]; break; case hook_JumpSpecial: @@ -210,7 +208,6 @@ static int lib_addHook(lua_State *L) case hook_SpinSpecial: case hook_JumpSpinSpecial: case hook_PlayerSpawn: - case hook_FollowMobj: case hook_PlayerCanDamage: case hook_TeamSwitch: case hook_ViewpointSwitch: @@ -263,6 +260,7 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) I_Assert(mo->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) @@ -270,12 +268,11 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { + if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -292,12 +289,11 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { + if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -321,18 +317,18 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) return false; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = playerhooks; hookp; hookp = hookp->next) { if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) LUA_PushUserdata(gL, plr, META_PLAYER); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { + if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -356,6 +352,7 @@ void LUAh_MapChange(INT16 mapnumber) return; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_pushinteger(gL, mapnumber); for (hookp = roothook; hookp; hookp = hookp->next) @@ -363,10 +360,12 @@ void LUAh_MapChange(INT16 mapnumber) if (hookp->type != hook_MapChange) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - LUA_Call(gL, 1); + if (lua_pcall(gL, 1, 0, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + } } lua_settop(gL, 0); @@ -380,6 +379,7 @@ void LUAh_MapLoad(void) return; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_pushinteger(gL, gamemap); for (hookp = roothook; hookp; hookp = hookp->next) @@ -387,10 +387,12 @@ void LUAh_MapLoad(void) if (hookp->type != hook_MapLoad) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - LUA_Call(gL, 1); + if (lua_pcall(gL, 1, 0, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + } } lua_settop(gL, 0); @@ -404,6 +406,7 @@ void LUAh_PlayerJoin(int playernum) return; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_pushinteger(gL, playernum); for (hookp = roothook; hookp; hookp = hookp->next) @@ -411,10 +414,12 @@ void LUAh_PlayerJoin(int playernum) if (hookp->type != hook_PlayerJoin) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - LUA_Call(gL, 1); + if (lua_pcall(gL, 1, 0, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + } } lua_settop(gL, 0); @@ -427,20 +432,23 @@ void LUAh_PreThinkFrame(void) if (!gL || !(hooksAvailable[hook_PreThinkFrame/8] & (1<<(hook_PreThinkFrame%8)))) return; + lua_pushcfunction(gL, LUA_GetErrorMessage); + for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_PreThinkFrame) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 0)) { + PushHook(gL, hookp); + if (lua_pcall(gL, 0, 0, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; } } + + lua_pop(gL, 1); // Pop error handler } // Hook for frame (after mobj and player thinkers) @@ -450,22 +458,24 @@ void LUAh_ThinkFrame(void) if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8)))) return; + lua_pushcfunction(gL, LUA_GetErrorMessage); + for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_ThinkFrame) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 0)) { + PushHook(gL, hookp); + if (lua_pcall(gL, 0, 0, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; } } -} + lua_pop(gL, 1); // Pop error handler +} // Hook for frame (at end of tick, ie after overlays, precipitation, specials) void LUAh_PostThinkFrame(void) @@ -474,20 +484,23 @@ void LUAh_PostThinkFrame(void) if (!gL || !(hooksAvailable[hook_PostThinkFrame/8] & (1<<(hook_PostThinkFrame%8)))) return; + lua_pushcfunction(gL, LUA_GetErrorMessage); + for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_PostThinkFrame) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 0)) { + PushHook(gL, hookp); + if (lua_pcall(gL, 0, 0, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; } } + + lua_pop(gL, 1); // Pop error handler } // Hook for mobj collisions @@ -501,6 +514,7 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) I_Assert(thing1->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj collision hooks for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) @@ -508,16 +522,15 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, thing1, META_MOBJ); LUA_PushUserdata(gL, thing2, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -539,16 +552,15 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, thing1, META_MOBJ); LUA_PushUserdata(gL, thing2, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -579,6 +591,7 @@ UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which) I_Assert(thing->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj collision hooks for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) @@ -586,16 +599,15 @@ UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which) if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, thing, META_MOBJ); LUA_PushUserdata(gL, line, META_LINE); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -617,16 +629,15 @@ UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which) if (hookp->type != which) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, thing, META_MOBJ); LUA_PushUserdata(gL, line, META_LINE); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -658,16 +669,16 @@ boolean LUAh_MobjThinker(mobj_t *mo) I_Assert(mo->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj thinker hooks for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next) { - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { + if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -681,12 +692,11 @@ boolean LUAh_MobjThinker(mobj_t *mo) for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next) { - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { + if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -713,6 +723,7 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) I_Assert(special->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic touch special hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) @@ -720,16 +731,15 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) if (hookp->type != hook_TouchSpecial) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -746,16 +756,15 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) if (hookp->type != hook_TouchSpecial) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -782,6 +791,7 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 I_Assert(target->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic should damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) @@ -789,7 +799,7 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 if (hookp->type != hook_ShouldDamage) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); @@ -797,14 +807,13 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 lua_pushinteger(gL, damage); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { + if (lua_pcall(gL, 5, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -825,7 +834,7 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 { if (hookp->type != hook_ShouldDamage) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); @@ -833,14 +842,13 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 lua_pushinteger(gL, damage); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { + if (lua_pcall(gL, 5, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -872,6 +880,7 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 I_Assert(target->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) @@ -879,7 +888,7 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 if (hookp->type != hook_MobjDamage) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); @@ -887,14 +896,13 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 lua_pushinteger(gL, damage); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { + if (lua_pcall(gL, 5, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -911,7 +919,7 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 if (hookp->type != hook_MobjDamage) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); @@ -919,14 +927,13 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 lua_pushinteger(gL, damage); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { + if (lua_pcall(gL, 5, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -953,6 +960,7 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 I_Assert(target->type < NUMMOBJTYPES); lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj death hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) @@ -960,20 +968,19 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 if (hookp->type != hook_MobjDeath) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + if (lua_pcall(gL, 4, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -990,20 +997,19 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 if (hookp->type != hook_MobjDeath) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + if (lua_pcall(gL, 4, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1028,22 +1034,22 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) return false; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_BotTiccmd) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, bot, META_PLAYER); LUA_PushUserdata(gL, cmd, META_TICCMD); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1068,23 +1074,23 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) return false; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_BotAI - || (hookp->s.skinname && strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + || (hookp->s.str && strcmp(hookp->s.str, ((skin_t*)tails->skin)->name))) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, sonic, META_MOBJ); LUA_PushUserdata(gL, tails, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 8, 0)) { + if (lua_pcall(gL, 2, 8, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1122,6 +1128,51 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) return hooked; } +// Hook for B_CheckRespawn +boolean LUAh_BotRespawn(mobj_t *sonic, mobj_t *tails) +{ + hook_p hookp; + UINT8 shouldRespawn = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_BotRespawn/8] & (1<<(hook_BotRespawn%8)))) + return false; + + lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_BotRespawn) + continue; + + if (lua_gettop(gL) == 1) + { + LUA_PushUserdata(gL, sonic, META_MOBJ); + LUA_PushUserdata(gL, tails, META_MOBJ); + } + PushHook(gL, hookp); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldRespawn = 1; // Force yes + else + shouldRespawn = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldRespawn; +} + // Hook for linedef executors boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { @@ -1131,24 +1182,27 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) return 0; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next) { - if (strcmp(hookp->s.funcname, line->text)) + if (strcmp(hookp->s.str, line->text)) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); - LUA_Call(gL, 3); + if (lua_pcall(gL, 3, 0, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + } hooked = true; } @@ -1165,13 +1219,14 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) return false; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_PlayerMsg) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c @@ -1189,13 +1244,12 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) } lua_pushstring(gL, msg); // msg } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + if (lua_pcall(gL, 4, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1221,6 +1275,7 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 return false; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = roothook; hookp; hookp = hookp->next) { @@ -1228,20 +1283,19 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 || (hookp->s.mt && !(inflictor && hookp->s.mt == inflictor->type))) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damagetype); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + if (lua_pcall(gL, 4, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1260,7 +1314,7 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 void LUAh_NetArchiveHook(lua_CFunction archFunc) { hook_p hookp; - + int errorhandlerindex; if (!gL || !(hooksAvailable[hook_NetVars/8] & (1<<(hook_NetVars%8)))) return; @@ -1268,8 +1322,11 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc) I_Assert(lua_gettop(gL) > 0); I_Assert(lua_istable(gL, -1)); + lua_pushcfunction(gL, LUA_GetErrorMessage); + errorhandlerindex = lua_gettop(gL); + // tables becomes an upvalue of archFunc - lua_pushvalue(gL, -1); + lua_pushvalue(gL, -2); lua_pushcclosure(gL, archFunc, 1); // stack: tables, archFunc @@ -1278,13 +1335,15 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc) if (hookp->type != hook_NetVars) continue; - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -2); // archFunc - LUA_Call(gL, 1); + if (lua_pcall(gL, 1, 0, errorhandlerindex)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + } } - lua_pop(gL, 1); // pop archFunc + lua_pop(gL, 2); // Pop archFunc and error handler // stack: tables } @@ -1296,6 +1355,7 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing) return false; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); // Look for all generic mobj map thing spawn hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) @@ -1303,16 +1363,15 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing) if (hookp->type != hook_MapThingSpawn) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, mthing, META_MAPTHING); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1329,16 +1388,15 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing) if (hookp->type != hook_MapThingSpawn) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, mthing, META_MAPTHING); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1363,22 +1421,48 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj) return 0; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); - for (hookp = playerhooks; hookp; hookp = hookp->next) + // Look for all generic mobj follow item hooks + for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) { if (hookp->type != hook_FollowMobj) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, mobj, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } + + for (hookp = mobjhooks[mobj->type]; hookp; hookp = hookp->next) + { + if (hookp->type != hook_FollowMobj) + continue; + + if (lua_gettop(gL) == 1) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); + } + PushHook(gL, hookp); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1403,22 +1487,22 @@ UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj) return 0; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = playerhooks; hookp; hookp = hookp->next) { if (hookp->type != hook_PlayerCanDamage) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, mobj, META_MOBJ); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1446,22 +1530,25 @@ void LUAh_PlayerQuit(player_t *plr, kickreason_t reason) return; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = roothook; hookp; hookp = hookp->next) { if (hookp->type != hook_PlayerQuit) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit lua_pushinteger(gL, reason); // Reason for quitting } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - LUA_Call(gL, 2); + if (lua_pcall(gL, 2, 0, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + } } lua_settop(gL, 0); @@ -1474,20 +1561,23 @@ void LUAh_IntermissionThinker(void) if (!gL || !(hooksAvailable[hook_IntermissionThinker/8] & (1<<(hook_IntermissionThinker%8)))) return; + lua_pushcfunction(gL, LUA_GetErrorMessage); + 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)) { + PushHook(gL, hookp); + if (lua_pcall(gL, 0, 0, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; } } + + lua_pop(gL, 1); // Pop error handler } // Hook for team switching @@ -1500,13 +1590,14 @@ boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, b return true; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); for (hookp = playerhooks; hookp; hookp = hookp->next) { if (hookp->type != hook_TeamSwitch) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, player, META_PLAYER); lua_pushinteger(gL, newteam); @@ -1514,14 +1605,13 @@ boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, b lua_pushboolean(gL, tryingautobalance); lua_pushboolean(gL, tryingscramble); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { + if (lua_pcall(gL, 5, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1546,6 +1636,8 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean return 0; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + hud_running = true; // local hook for (hookp = playerhooks; hookp; hookp = hookp->next) @@ -1553,18 +1645,17 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean if (hookp->type != hook_ViewpointSwitch) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER); lua_pushboolean(gL, forced); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 0)) { + if (lua_pcall(gL, 3, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1582,6 +1673,7 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean } lua_settop(gL, 0); + hud_running = false; return canSwitchView; @@ -1597,6 +1689,8 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend) return true; lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + hud_running = true; // local hook for (hookp = playerhooks; hookp; hookp = hookp->next) @@ -1604,16 +1698,15 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend) if (hookp->type != hook_SeenPlayer) continue; - if (lua_gettop(gL) == 0) + if (lua_gettop(gL) == 1) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, seenfriend, META_PLAYER); } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + PushHook(gL, hookp); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + if (lua_pcall(gL, 2, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -1626,10 +1719,80 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend) } lua_settop(gL, 0); + hud_running = false; return hasSeenPlayer; } #endif // SEENAMES -#endif +boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname) +{ + hook_p hookp; + boolean keepplaying = false; + if (!gL || !(hooksAvailable[hook_ShouldJingleContinue/8] & (1<<(hook_ShouldJingleContinue%8)))) + return true; + + lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + + hud_running = true; // local hook + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_ShouldJingleContinue + || (hookp->s.str && strcmp(hookp->s.str, musname))) + continue; + + if (lua_gettop(gL) == 1) + { + LUA_PushUserdata(gL, player, META_PLAYER); + lua_pushstring(gL, musname); + } + PushHook(gL, hookp); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1) && lua_toboolean(gL, -1)) + keepplaying = true; // Keep playing this boolean + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + + hud_running = false; + + return keepplaying; +} + +// Hook for game quitting +void LUAh_GameQuit(void) +{ + hook_p hookp; + if (!gL || !(hooksAvailable[hook_GameQuit/8] & (1<<(hook_GameQuit%8)))) + return; + + lua_pushcfunction(gL, LUA_GetErrorMessage); + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_GameQuit) + continue; + + PushHook(gL, hookp); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + } + + lua_pop(gL, 1); // Pop error handler +} diff --git a/src/lua_hud.h b/src/lua_hud.h index a00a5cb02..4a7c596c8 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index bf8fe017b..4aa70574b 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief custom HUD rendering library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" #include "r_defs.h" #include "r_local.h" @@ -413,9 +412,9 @@ static int libd_cachePatch(lua_State *L) HUDONLY luapat = patchinfohead; - lumpnum = W_CheckNumForName(luaL_checkstring(L, 1)); + lumpnum = W_CheckNumForLongName(luaL_checkstring(L, 1)); if (lumpnum == LUMPERROR) - lumpnum = W_GetNumForName("MISSING"); + lumpnum = W_GetNumForLongName("MISSING"); for (i = 0; i < numluapatches; i++) { @@ -455,7 +454,7 @@ static int libd_cachePatch(lua_State *L) numluapatches++; #else HUDONLY - LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH); + LUA_PushUserdata(L, W_CachePatchLongName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH); #endif return 1; } @@ -879,8 +878,8 @@ static int libd_drawNameTag(lua_State *L) INT32 y; const char *str; INT32 flags; - UINT8 basecolor; - UINT8 outlinecolor; + UINT16 basecolor; + UINT16 outlinecolor; UINT8 *basecolormap = NULL; UINT8 *outlinecolormap = NULL; @@ -909,8 +908,8 @@ static int libd_drawScaledNameTag(lua_State *L) const char *str; INT32 flags; fixed_t scale; - UINT8 basecolor; - UINT8 outlinecolor; + UINT16 basecolor; + UINT16 outlinecolor; UINT8 *basecolormap = NULL; UINT8 *outlinecolormap = NULL; @@ -967,7 +966,7 @@ static int libd_nameTagWidth(lua_State *L) static int libd_getColormap(lua_State *L) { INT32 skinnum = TC_DEFAULT; - skincolors_t color = luaL_optinteger(L, 2, 0); + skincolornum_t color = luaL_optinteger(L, 2, 0); UINT8* colormap = NULL; HUDONLY if (lua_isnoneornil(L, 1)) @@ -1466,5 +1465,3 @@ void LUAh_IntermissionHUD(void) lua_pop(gL, -1); hud_running = false; } - -#endif diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 7a2465ef7..81a215c53 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief infotable editing library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" #include "info.h" #include "dehacked.h" @@ -26,6 +25,9 @@ #include "lua_libs.h" #include "lua_hud.h" // hud_running errors +extern CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; +extern void R_FlushTranslationColormapCache(void); + boolean LUA_CallAction(const char *action, mobj_t *actor); state_t *astate; @@ -389,10 +391,7 @@ static int lib_setSpriteInfo(lua_State *L) lua_Integer i = 0; const char *str = NULL; if (lua_isnumber(L, 2)) - { i = lua_tointeger(L, 2); - i++; // shift index in case of missing rotsprite support - } else str = luaL_checkstring(L, 2); @@ -1469,6 +1468,229 @@ static int lib_luabankslen(lua_State *L) return 1; } +//////////////////// +// SKINCOLOR INFO // +//////////////////// + +// Arbitrary skincolors[] table index -> skincolor_t * +static int lib_getSkinColor(lua_State *L) +{ + UINT32 i; + lua_remove(L, 1); + + i = luaL_checkinteger(L, 1); + if (!i || i >= numskincolors) + return luaL_error(L, "skincolors[] index %d out of range (1 - %d)", i, numskincolors-1); + LUA_PushUserdata(L, &skincolors[i], META_SKINCOLOR); + return 1; +} + +//Set the entire c->ramp array +static void setRamp(lua_State *L, skincolor_t* c) { + UINT32 i; + lua_pushnil(L); + for (i=0; iramp[i] = lua_isnumber(L,-1) ? (UINT8)luaL_checkinteger(L,-1) : 120; + lua_pop(L, 1); + } else + c->ramp[i] = 120; + } + lua_pop(L,1); +} + +// Lua table full of data -> skincolors[] +static int lib_setSkinColor(lua_State *L) +{ + UINT32 j; + skincolor_t *info; + UINT16 cnum; //skincolor num + lua_remove(L, 1); // don't care about skincolors[] userdata. + { + cnum = (UINT16)luaL_checkinteger(L, 1); + if (cnum < SKINCOLOR_FIRSTFREESLOT || cnum >= numskincolors) + return luaL_error(L, "skincolors[] index %d out of range (%d - %d)", cnum, SKINCOLOR_FIRSTFREESLOT, numskincolors-1); + info = &skincolors[cnum]; // get the skincolor to assign to. + } + luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table. + lua_remove(L, 1); // pop skincolor num, don't need it any more. + lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the skincolor. + + if (hud_running) + return luaL_error(L, "Do not alter skincolors in HUD rendering code!"); + + // clear the skincolor to start with, in case of missing table elements + memset(info,0,sizeof(skincolor_t)); + + Color_cons_t[cnum].value = cnum; + lua_pushnil(L); + while (lua_next(L, 1)) { + lua_Integer i = 0; + const char *str = NULL; + if (lua_isnumber(L, 2)) + i = lua_tointeger(L, 2); + else + str = luaL_checkstring(L, 2); + + if (i == 1 || (str && fastcmp(str,"name"))) { + const char* n = luaL_checkstring(L, 3); + strlcpy(info->name, n, MAXCOLORNAME+1); + if (strlen(n) > MAXCOLORNAME) + CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') longer than %d chars; shortened to %s.\n", n, MAXCOLORNAME, info->name); + } else if (i == 2 || (str && fastcmp(str,"ramp"))) { + if (!lua_istable(L, 3) && luaL_checkudata(L, 3, META_COLORRAMP) == NULL) + return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' must be a table or array."); + else if (lua_istable(L, 3)) + setRamp(L, info); + else + for (j=0; jramp[j] = (*((UINT8 **)luaL_checkudata(L, 3, META_COLORRAMP)))[j]; + R_FlushTranslationColormapCache(); + } else if (i == 3 || (str && fastcmp(str,"invcolor"))) + info->invcolor = (UINT16)luaL_checkinteger(L, 3); + else if (i == 4 || (str && fastcmp(str,"invshade"))) + info->invshade = (UINT8)luaL_checkinteger(L, 3)%COLORRAMPSIZE; + else if (i == 5 || (str && fastcmp(str,"chatcolor"))) + info->chatcolor = (UINT16)luaL_checkinteger(L, 3); + else if (i == 6 || (str && fastcmp(str,"accessible"))) { + boolean v = lua_isboolean(L,3) ? lua_toboolean(L, 3) : true; + if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) + return luaL_error(L, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", i); + else + info->accessible = v; + } + lua_pop(L, 1); + } + return 0; +} + +// #skincolors -> numskincolors +static int lib_skincolorslen(lua_State *L) +{ + lua_pushinteger(L, numskincolors); + return 1; +} + +// skincolor_t *, field -> number +static int skincolor_get(lua_State *L) +{ + skincolor_t *info = *((skincolor_t **)luaL_checkudata(L, 1, META_SKINCOLOR)); + const char *field = luaL_checkstring(L, 2); + + I_Assert(info != NULL); + I_Assert(info >= skincolors); + + if (fastcmp(field,"name")) + lua_pushstring(L, info->name); + else if (fastcmp(field,"ramp")) + LUA_PushUserdata(L, info->ramp, META_COLORRAMP); + else if (fastcmp(field,"invcolor")) + lua_pushinteger(L, info->invcolor); + else if (fastcmp(field,"invshade")) + lua_pushinteger(L, info->invshade); + else if (fastcmp(field,"chatcolor")) + lua_pushinteger(L, info->chatcolor); + else if (fastcmp(field,"accessible")) + lua_pushboolean(L, info->accessible); + else + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "skincolor_t", field); + return 1; +} + +// skincolor_t *, field, number -> skincolors[] +static int skincolor_set(lua_State *L) +{ + UINT32 i; + skincolor_t *info = *((skincolor_t **)luaL_checkudata(L, 1, META_SKINCOLOR)); + const char *field = luaL_checkstring(L, 2); + + I_Assert(info != NULL); + I_Assert(info >= skincolors); + + if (info-skincolors < SKINCOLOR_FIRSTFREESLOT || info-skincolors >= numskincolors) + return luaL_error(L, "skincolors[] index %d out of range (%d - %d)", info-skincolors, SKINCOLOR_FIRSTFREESLOT, numskincolors-1); + + if (fastcmp(field,"name")) { + const char* n = luaL_checkstring(L, 3); + if (strchr(n, ' ') != NULL) + CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') contains spaces.\n", n); + strlcpy(info->name, n, MAXCOLORNAME+1); + if (strlen(n) > MAXCOLORNAME) + CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') longer than %d chars; clipped to %s.\n", n, MAXCOLORNAME, info->name); + } else if (fastcmp(field,"ramp")) { + if (!lua_istable(L, 3) && luaL_checkudata(L, 3, META_COLORRAMP) == NULL) + return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' must be a table or array."); + else if (lua_istable(L, 3)) + setRamp(L, info); + else + for (i=0; iramp[i] = (*((UINT8 **)luaL_checkudata(L, 3, META_COLORRAMP)))[i]; + R_FlushTranslationColormapCache(); + } else if (fastcmp(field,"invcolor")) + info->invcolor = (UINT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"invshade")) + info->invshade = (UINT8)luaL_checkinteger(L, 3)%COLORRAMPSIZE; + else if (fastcmp(field,"chatcolor")) + info->chatcolor = (UINT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"accessible")) + info->accessible = lua_isboolean(L,3); + else + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "skincolor_t", field); + return 1; +} + +// skincolor_t * -> SKINCOLOR_* +static int skincolor_num(lua_State *L) +{ + skincolor_t *info = *((skincolor_t **)luaL_checkudata(L, 1, META_SKINCOLOR)); + + I_Assert(info != NULL); + I_Assert(info >= skincolors); + + lua_pushinteger(L, info-skincolors); + return 1; +} + +// ramp, n -> ramp[n] +static int colorramp_get(lua_State *L) +{ + UINT8 *colorramp = *((UINT8 **)luaL_checkudata(L, 1, META_COLORRAMP)); + UINT32 n = luaL_checkinteger(L, 2); + if (n >= COLORRAMPSIZE) + return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' index %d out of range (0 - %d)", n, COLORRAMPSIZE-1); + lua_pushinteger(L, colorramp[n]); + return 1; +} + +// ramp, n, value -> ramp[n] = value +static int colorramp_set(lua_State *L) +{ + UINT8 *colorramp = *((UINT8 **)luaL_checkudata(L, 1, META_COLORRAMP)); + UINT16 cnum = (UINT16)(((uint8_t*)colorramp - (uint8_t*)(skincolors[0].ramp))/sizeof(skincolor_t)); + UINT32 n = luaL_checkinteger(L, 2); + UINT8 i = (UINT8)luaL_checkinteger(L, 3); + if (cnum < SKINCOLOR_FIRSTFREESLOT || cnum >= numskincolors) + return luaL_error(L, "skincolors[] index %d out of range (%d - %d)", cnum, SKINCOLOR_FIRSTFREESLOT, numskincolors-1); + if (n >= COLORRAMPSIZE) + return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' index %d out of range (0 - %d)", n, COLORRAMPSIZE-1); + if (hud_running) + return luaL_error(L, "Do not alter skincolor_t in HUD rendering code!"); + colorramp[n] = i; + R_FlushTranslationColormapCache(); + return 0; +} + +// #ramp -> COLORRAMPSIZE +static int colorramp_len(lua_State *L) +{ + lua_pushinteger(L, COLORRAMPSIZE); + return 1; +} + ////////////////////////////// // // Now push all these functions into the Lua state! @@ -1506,6 +1728,28 @@ int LUA_InfoLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + luaL_newmetatable(L, META_SKINCOLOR); + lua_pushcfunction(L, skincolor_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, skincolor_set); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, skincolor_num); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + + luaL_newmetatable(L, META_COLORRAMP); + lua_pushcfunction(L, colorramp_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, colorramp_set); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, colorramp_len); + lua_setfield(L, -2, "__len"); + lua_pop(L,1); + luaL_newmetatable(L, META_SFXINFO); lua_pushcfunction(L, sfxinfo_get); lua_setfield(L, -2, "__index"); @@ -1609,6 +1853,19 @@ int LUA_InfoLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "mobjinfo"); + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getSkinColor); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_setSkinColor); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, lib_skincolorslen); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "skincolors"); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getSfxInfo); @@ -1635,7 +1892,6 @@ int LUA_InfoLib(lua_State *L) lua_pushcfunction(L, lib_spriteinfolen); lua_setfield(L, -2, "__len"); lua_setmetatable(L, -2); - lua_pushvalue(L, -1); lua_setglobal(L, "spriteinfo"); luaL_newmetatable(L, META_LUABANKS); @@ -1651,5 +1907,3 @@ int LUA_InfoLib(lua_State *L) return 0; } - -#endif diff --git a/src/lua_libs.h b/src/lua_libs.h index 6a908d03d..a78128e9f 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -10,8 +10,6 @@ /// \file lua_libs.h /// \brief libraries for Lua scripting -#ifdef HAVE_BLUA - extern lua_State *gL; #define LREG_VALID "VALID_USERDATA" @@ -22,6 +20,8 @@ extern lua_State *gL; #define META_STATE "STATE_T*" #define META_MOBJINFO "MOBJINFO_T*" #define META_SFXINFO "SFXINFO_T*" +#define META_SKINCOLOR "SKINCOLOR_T*" +#define META_COLORRAMP "SKINCOLOR_T*RAMP" #define META_SPRITEINFO "SPRITEINFO_T*" #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]" #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*" @@ -45,11 +45,9 @@ extern lua_State *gL; #define META_SEG "SEG_T*" #define META_NODE "NODE_T*" #endif -#ifdef ESLOPE #define META_SLOPE "PSLOPE_T*" #define META_VECTOR2 "VECTOR2_T" #define META_VECTOR3 "VECTOR3_T" -#endif #define META_MAPHEADER "MAPHEADER_T*" #define META_CVAR "CONSVAR_T*" @@ -88,5 +86,3 @@ int LUA_ThinkerLib(lua_State *L); int LUA_MapLib(lua_State *L); int LUA_BlockmapLib(lua_State *L); int LUA_HudLib(lua_State *L); - -#endif diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 99ee1d145..144a6b3f1 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,14 +11,11 @@ /// \brief game map library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "r_state.h" #include "p_local.h" #include "p_setup.h" #include "z_zone.h" -#ifdef ESLOPE #include "p_slopes.h" -#endif #include "r_main.h" #include "lua_script.h" @@ -42,13 +39,9 @@ enum sector_e { sector_heightsec, sector_camsec, sector_lines, -#ifdef ESLOPE sector_ffloors, sector_fslope, sector_cslope -#else - sector_ffloors -#endif }; static const char *const sector_opt[] = { @@ -65,10 +58,8 @@ static const char *const sector_opt[] = { "camsec", "lines", "ffloors", -#ifdef ESLOPE "f_slope", "c_slope", -#endif NULL}; enum subsector_e { @@ -148,6 +139,7 @@ static const char *const side_opt[] = { "toptexture", "bottomtexture", "midtexture", + "line", "sector", "special", "repeatcnt", @@ -181,10 +173,8 @@ enum ffloor_e { ffloor_toplightlevel, ffloor_bottomheight, ffloor_bottompic, -#ifdef ESLOPE ffloor_tslope, ffloor_bslope, -#endif ffloor_sector, ffloor_flags, ffloor_master, @@ -201,10 +191,8 @@ static const char *const ffloor_opt[] = { "toplightlevel", "bottomheight", "bottompic", -#ifdef ESLOPE "t_slope", "b_slope", -#endif "sector", // secnum pushed as control sector userdata "flags", "master", // control linedef @@ -290,7 +278,6 @@ static const char *const bbox_opt[] = { "right", NULL}; -#ifdef ESLOPE enum slope_e { slope_valid = 0, slope_o, @@ -325,7 +312,6 @@ static const char *const vector_opt[] = { "y", "z", NULL}; -#endif static const char *const array_opt[] ={"iterate",NULL}; static const char *const valid_opt[] ={"valid",NULL}; @@ -571,14 +557,12 @@ static int sector_get(lua_State *L) LUA_PushUserdata(L, sector->ffloors, META_FFLOOR); lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function return 1; -#ifdef ESLOPE case sector_fslope: // f_slope LUA_PushUserdata(L, sector->f_slope, META_SLOPE); return 1; case sector_cslope: // c_slope LUA_PushUserdata(L, sector->c_slope, META_SLOPE); return 1; -#endif } return 0; } @@ -602,10 +586,8 @@ static int sector_set(lua_State *L) case sector_camsec: // camsec case sector_lines: // lines case sector_ffloors: // ffloors -#ifdef ESLOPE case sector_fslope: // f_slope case sector_cslope: // c_slope -#endif default: return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); case sector_floorheight: { // floorheight @@ -1693,14 +1675,12 @@ static int ffloor_get(lua_State *L) lua_pushlstring(L, levelflat->name, i); return 1; } -#ifdef ESLOPE case ffloor_tslope: LUA_PushUserdata(L, *ffloor->t_slope, META_SLOPE); return 1; case ffloor_bslope: LUA_PushUserdata(L, *ffloor->b_slope, META_SLOPE); return 1; -#endif case ffloor_sector: LUA_PushUserdata(L, §ors[ffloor->secnum], META_SECTOR); return 1; @@ -1740,10 +1720,8 @@ static int ffloor_set(lua_State *L) switch(field) { case ffloor_valid: // valid -#ifdef ESLOPE case ffloor_tslope: // t_slope case ffloor_bslope: // b_slope -#endif case ffloor_sector: // sector case ffloor_master: // master case ffloor_target: // target @@ -1804,7 +1782,6 @@ static int ffloor_set(lua_State *L) return 0; } -#ifdef ESLOPE ////////////// // pslope_t // ////////////// @@ -1977,7 +1954,6 @@ static int vector3_get(lua_State *L) return 0; } -#endif ///////////////////// // mapheaderinfo[] // @@ -2034,6 +2010,8 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->typeoflevel); else if (fastcmp(field,"nextlevel")) lua_pushinteger(L, header->nextlevel); + else if (fastcmp(field,"marathonnext")) + lua_pushinteger(L, header->marathonnext); else if (fastcmp(field,"keywords")) lua_pushstring(L, header->keywords); else if (fastcmp(field,"musname")) @@ -2107,6 +2085,12 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->menuflags); else if (fastcmp(field,"startrings")) lua_pushinteger(L, header->startrings); + else if (fastcmp(field, "sstimer")) + lua_pushinteger(L, header->sstimer); + else if (fastcmp(field, "ssspheres")) + lua_pushinteger(L, header->ssspheres); + else if (fastcmp(field, "gravity")) + lua_pushfixed(L, header->gravity); // TODO add support for reading numGradedMares and grades else { // Read custom vars now @@ -2226,7 +2210,6 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__index"); lua_pop(L, 1); -#ifdef ESLOPE luaL_newmetatable(L, META_SLOPE); lua_pushcfunction(L, slope_get); lua_setfield(L, -2, "__index"); @@ -2244,7 +2227,6 @@ int LUA_MapLib(lua_State *L) lua_pushcfunction(L, vector3_get); lua_setfield(L, -2, "__index"); lua_pop(L, 1); -#endif luaL_newmetatable(L, META_MAPHEADER); lua_pushcfunction(L, mapheaderinfo_get); @@ -2337,5 +2319,3 @@ int LUA_MapLib(lua_State *L) lua_setglobal(L, "mapheaderinfo"); return 0; } - -#endif diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c index 9115c7321..7cbe7a6cc 100644 --- a/src/lua_mathlib.c +++ b/src/lua_mathlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief basic math library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA //#include "fastcmp.h" #include "tables.h" #include "p_local.h" @@ -114,7 +113,8 @@ static int lib_fixeddiv(lua_State *L) static int lib_fixedrem(lua_State *L) { - lua_pushfixed(L, FixedRem(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2))); + LUA_Deprecated(L, "FixedRem(a, b)", "a % b"); + lua_pushfixed(L, luaL_checkfixed(L, 1) % luaL_checkfixed(L, 2)); return 1; } @@ -173,15 +173,14 @@ static int lib_all7emeralds(lua_State *L) return 1; } -// Whee, special Lua-exclusive function for making use of Color_Opposite[] // Returns both color and signpost shade numbers! static int lib_coloropposite(lua_State *L) { - UINT8 colornum = (UINT8)luaL_checkinteger(L, 1); - if (!colornum || colornum >= MAXSKINCOLORS) - return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, MAXSKINCOLORS-1); - lua_pushinteger(L, Color_Opposite[colornum-1][0]); // push color - lua_pushinteger(L, Color_Opposite[colornum-1][1]); // push sign shade index, 0-15 + UINT16 colornum = (UINT16)luaL_checkinteger(L, 1); + if (!colornum || colornum >= numskincolors) + return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, numskincolors-1); + lua_pushinteger(L, skincolors[colornum].invcolor); // push color + lua_pushinteger(L, skincolors[colornum].invshade); // push sign shade index, 0-15 return 2; } @@ -217,5 +216,3 @@ int LUA_MathLib(lua_State *L) luaL_register(L, NULL, lib); return 0; } - -#endif diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 90733b2c6..4d0efa9e2 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,9 +11,8 @@ /// \brief mobj/thing library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" -#include "r_things.h" +#include "r_skins.h" #include "p_local.h" #include "g_game.h" #include "p_setup.h" @@ -85,9 +84,7 @@ enum mobj_e { mobj_extravalue2, mobj_cusval, mobj_cvmem, -#ifdef ESLOPE mobj_standingslope, -#endif mobj_colorized, mobj_shadowscale }; @@ -153,9 +150,7 @@ static const char *const mobj_opt[] = { "extravalue2", "cusval", "cvmem", -#ifdef ESLOPE "standingslope", -#endif "colorized", "shadowscale", NULL}; @@ -384,11 +379,9 @@ static int mobj_get(lua_State *L) case mobj_cvmem: lua_pushinteger(L, mo->cvmem); break; -#ifdef ESLOPE case mobj_standingslope: LUA_PushUserdata(L, mo->standingslope, META_SLOPE); break; -#endif case mobj_colorized: lua_pushboolean(L, mo->colorized); break; @@ -456,10 +449,8 @@ static int mobj_set(lua_State *L) return UNIMPLEMENTED; case mobj_angle: mo->angle = luaL_checkangle(L, 3); - if (mo->player == &players[consoleplayer]) - localangle = mo->angle; - else if (mo->player == &players[secondarydisplayplayer]) - localangle2 = mo->angle; + if (mo->player) + P_SetPlayerAngle(mo->player, mo->angle); break; case mobj_rollangle: mo->rollangle = luaL_checkangle(L, 3); @@ -581,9 +572,9 @@ static int mobj_set(lua_State *L) } case mobj_color: { - UINT8 newcolor = (UINT8)luaL_checkinteger(L,3); - if (newcolor >= MAXTRANSLATIONS) - return luaL_error(L, "mobj.color %d out of range (0 - %d).", newcolor, MAXTRANSLATIONS-1); + UINT16 newcolor = (UINT16)luaL_checkinteger(L,3); + if (newcolor >= numskincolors) + return luaL_error(L, "mobj.color %d out of range (0 - %d).", newcolor, numskincolors-1); mo->color = newcolor; break; } @@ -717,10 +708,8 @@ static int mobj_set(lua_State *L) case mobj_cvmem: mo->cvmem = luaL_checkinteger(L, 3); break; -#ifdef ESLOPE case mobj_standingslope: return NOSET; -#endif case mobj_colorized: mo->colorized = luaL_checkboolean(L, 3); break; @@ -838,6 +827,15 @@ static int mapthing_set(lua_State *L) return 0; } +static int mapthing_num(lua_State *L) +{ + mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); + if (!mt) + return luaL_error(L, "accessed mapthing_t doesn't exist anymore."); + lua_pushinteger(L, mt-mapthings); + return 1; +} + static int lib_iterateMapthings(lua_State *L) { size_t i = 0; @@ -902,6 +900,9 @@ int LUA_MobjLib(lua_State *L) lua_pushcfunction(L, mapthing_set); lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, mapthing_num); + lua_setfield(L, -2, "__len"); lua_pop(L,1); lua_newuserdata(L, 0); @@ -915,5 +916,3 @@ int LUA_MobjLib(lua_State *L) lua_setglobal(L, "mapthings"); return 0; } - -#endif diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index d1da97d70..1ce9be525 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief player object library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" #include "p_mobj.h" #include "d_player.h" @@ -97,6 +96,10 @@ static int player_get(lua_State *L) lua_pushboolean(L, true); else if (fastcmp(field,"name")) lua_pushstring(L, player_names[plr-players]); + else if (fastcmp(field,"realmo")) + LUA_PushUserdata(L, plr->mo, META_MOBJ); + // Kept for backward-compatibility + // Should be fixed to work like "realmo" later else if (fastcmp(field,"mo")) { if (plr->spectator) @@ -398,7 +401,7 @@ static int player_set(lua_State *L) if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); - if (fastcmp(field,"mo")) { + if (fastcmp(field,"mo") || fastcmp(field,"realmo")) { mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); plr->mo->player = NULL; // remove player pointer from old mobj (newmo->player = plr)->mo = newmo; // set player pointer for new mobj, and set new mobj as the player's mobj @@ -458,9 +461,9 @@ static int player_set(lua_State *L) plr->flashpal = (UINT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"skincolor")) { - UINT8 newcolor = (UINT8)luaL_checkinteger(L,3); - if (newcolor >= MAXSKINCOLORS) - return luaL_error(L, "player.skincolor %d out of range (0 - %d).", newcolor, MAXSKINCOLORS-1); + UINT16 newcolor = (UINT16)luaL_checkinteger(L,3); + if (newcolor >= numskincolors) + return luaL_error(L, "player.skincolor %d out of range (0 - %d).", newcolor, numskincolors-1); plr->skincolor = newcolor; } else if (fastcmp(field,"score")) @@ -874,5 +877,3 @@ int LUA_PlayerLib(lua_State *L) lua_setglobal(L, "players"); return 0; } - -#endif diff --git a/src/lua_script.c b/src/lua_script.c index eb6c54ae0..5fb153c0e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief Lua scripting basics #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" #include "dehacked.h" #include "z_zone.h" @@ -24,9 +23,7 @@ #include "byteptr.h" #include "p_saveg.h" #include "p_local.h" -#ifdef ESLOPE #include "p_slopes.h" // for P_SlopeById -#endif #ifdef LUA_ALLOW_BYTECODE #include "d_netfil.h" // for LUA_DumpFile #endif @@ -81,6 +78,58 @@ FUNCNORETURN static int LUA_Panic(lua_State *L) #endif } +#define LEVELS1 12 // size of the first part of the stack +#define LEVELS2 10 // size of the second part of the stack + +// Error handler used with pcall() when loading scripts or calling hooks +// Takes a string with the original error message, +// appends the traceback to it, and return the result +int LUA_GetErrorMessage(lua_State *L) +{ + int level = 1; + int firstpart = 1; // still before eventual `...' + lua_Debug ar; + + lua_pushliteral(L, "\nstack traceback:"); + while (lua_getstack(L, level++, &ar)) + { + if (level > LEVELS1 && firstpart) + { + // no more than `LEVELS2' more levels? + if (!lua_getstack(L, level + LEVELS2, &ar)) + level--; // keep going + else + { + lua_pushliteral(L, "\n ..."); // too many levels + while (lua_getstack(L, level + LEVELS2, &ar)) // find last levels + level++; + } + firstpart = 0; + continue; + } + lua_pushliteral(L, "\n "); + lua_getinfo(L, "Snl", &ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + if (*ar.namewhat != '\0') // is there a name? + lua_pushfstring(L, " in function " LUA_QS, ar.name); + else + { + if (*ar.what == 'm') // main? + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); // C function or tail call + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); + } + lua_concat(L, lua_gettop(L)); + } + lua_concat(L, lua_gettop(L)); + return 1; +} + // Moved here from lib_getenum. int LUA_PushGlobals(lua_State *L, const char *word) { @@ -118,7 +167,10 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushboolean(L, splitscreen); return 1; } else if (fastcmp(word,"gamecomplete")) { - lua_pushboolean(L, gamecomplete); + lua_pushboolean(L, (gamecomplete != 0)); + return 1; + } else if (fastcmp(word,"marathonmode")) { + lua_pushinteger(L, marathonmode); return 1; } else if (fastcmp(word,"devparm")) { lua_pushboolean(L, devparm); @@ -148,6 +200,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"spstage_start")) { lua_pushinteger(L, spstage_start); return 1; + } else if (fastcmp(word,"spmarathon_start")) { + lua_pushinteger(L, spmarathon_start); + return 1; } else if (fastcmp(word,"sstage_start")) { lua_pushinteger(L, sstage_start); return 1; @@ -271,6 +326,12 @@ int LUA_PushGlobals(lua_State *L, const char *word) return 0; LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER); return 1; + } else if (fastcmp(word,"isserver")) { + lua_pushboolean(L, server); + return 1; + } else if (fastcmp(word,"isdedicatedserver")) { + lua_pushboolean(L, dedicated); + return 1; // end local player variables } else if (fastcmp(word,"server")) { if ((!multiplayer || !netgame) && !playeringame[serverplayer]) @@ -398,11 +459,13 @@ void LUA_ClearExtVars(void) // Use this variable to prevent certain functions from running // if they were not called on lump load // (i.e. they were called in hooks or coroutines etc) -boolean lua_lumploading = false; +INT32 lua_lumploading = 0; // Load a script from a MYFILE -static inline void LUA_LoadFile(MYFILE *f, char *name) +static inline void LUA_LoadFile(MYFILE *f, char *name, boolean noresults) { + int errorhandlerindex; + if (!name) name = wadfiles[f->wad]->filename; CONS_Printf("Loading Lua script from %s\n", name); @@ -411,19 +474,22 @@ static inline void LUA_LoadFile(MYFILE *f, char *name) lua_pushinteger(gL, f->wad); lua_setfield(gL, LUA_REGISTRYINDEX, "WAD"); - lua_lumploading = true; // turn on loading flag + lua_lumploading++; // turn on loading flag - if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, 0, 0)) { + lua_pushcfunction(gL, LUA_GetErrorMessage); + errorhandlerindex = lua_gettop(gL); + if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, noresults ? 0 : LUA_MULTRET, lua_gettop(gL) - 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); lua_pop(gL,1); } lua_gc(gL, LUA_GCCOLLECT, 0); + lua_remove(gL, errorhandlerindex); - lua_lumploading = false; // turn off again + lua_lumploading--; // turn off again } // Load a script from a lump -void LUA_LoadLump(UINT16 wad, UINT16 lump) +void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults) { MYFILE f; char *name; @@ -444,13 +510,13 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) else // If it's not a .lua file, copy the lump name in too. { lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump]; - len += 1 + strlen(lump_p->name2); // length of file name, '|', and lump name + len += 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name name = malloc(len+1); - sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2); + sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->fullname); name[len] = '\0'; } - LUA_LoadFile(&f, name); // actually load file! + LUA_LoadFile(&f, name, noresults); // actually load file! free(name); Z_Free(f.data); @@ -571,6 +637,27 @@ fixed_t LUA_EvalMath(const char *word) return res; } +/* +LUA_PushUserdata but no userdata is created. +You can't invalidate it therefore. +*/ + +void LUA_PushLightUserdata (lua_State *L, void *data, const char *meta) +{ + if (data) + { + lua_pushlightuserdata(L, data); + luaL_getmetatable(L, meta); + /* + The metatable is the last value on the stack, so this + applies it to the second value, which is the userdata. + */ + lua_setmetatable(L, -2); + } + else + lua_pushnil(L); +} + // Takes a pointer, any pointer, and a metatable name // Creates a userdata for that pointer with the given metatable // Pushes it to the stack and stores it in the registry. @@ -712,9 +799,13 @@ void LUA_InvalidatePlayer(player_t *player) enum { ARCH_NULL=0, - ARCH_BOOLEAN, - ARCH_SIGNED, - ARCH_STRING, + ARCH_TRUE, + ARCH_FALSE, + ARCH_INT8, + ARCH_INT16, + ARCH_INT32, + ARCH_SMALLSTRING, + ARCH_LARGESTRING, ARCH_TABLE, ARCH_MOBJINFO, @@ -732,10 +823,9 @@ enum ARCH_NODE, #endif ARCH_FFLOOR, -#ifdef ESLOPE ARCH_SLOPE, -#endif ARCH_MAPHEADER, + ARCH_SKINCOLOR, ARCH_TEND=0xFF, }; @@ -759,10 +849,9 @@ static const struct { {META_NODE, ARCH_NODE}, #endif {META_FFLOOR, ARCH_FFLOOR}, -#ifdef ESLOPE {META_SLOPE, ARCH_SLOPE}, -#endif {META_MAPHEADER, ARCH_MAPHEADER}, + {META_SKINCOLOR, ARCH_SKINCOLOR}, {NULL, ARCH_NULL} }; @@ -803,22 +892,33 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) WRITEUINT8(save_p, ARCH_NULL); return 2; case LUA_TBOOLEAN: - WRITEUINT8(save_p, ARCH_BOOLEAN); - WRITEUINT8(save_p, lua_toboolean(gL, myindex)); + WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE); break; case LUA_TNUMBER: { lua_Integer number = lua_tointeger(gL, myindex); - WRITEUINT8(save_p, ARCH_SIGNED); - WRITEFIXED(save_p, number); + if (number >= INT8_MIN && number <= INT8_MAX) + { + WRITEUINT8(save_p, ARCH_INT8); + WRITESINT8(save_p, number); + } + else if (number >= INT16_MIN && number <= INT16_MAX) + { + WRITEUINT8(save_p, ARCH_INT16); + WRITEINT16(save_p, number); + } + else + { + WRITEUINT8(save_p, ARCH_INT32); + WRITEFIXED(save_p, number); + } break; } case LUA_TSTRING: { - UINT16 len = (UINT16)lua_objlen(gL, myindex); // get length of string, including embedded zeros + UINT32 len = (UINT32)lua_objlen(gL, myindex); // get length of string, including embedded zeros const char *s = lua_tostring(gL, myindex); - UINT16 i = 0; - WRITEUINT8(save_p, ARCH_STRING); + UINT32 i = 0; // if you're wondering why we're writing a string to save_p this way, // it turns out that Lua can have embedded zeros ('\0') in the strings, // so we can't use WRITESTRING as that cuts off when it finds a '\0'. @@ -826,7 +926,16 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) // fixing the awful crashes previously encountered for reading strings longer than 1024 // (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?) // -- Monster Iestyn 05/08/18 - WRITEUINT16(save_p, len); // save size of string + if (len < 255) + { + WRITEUINT8(save_p, ARCH_SMALLSTRING); + WRITEUINT8(save_p, len); // save size of string + } + else + { + WRITEUINT8(save_p, ARCH_LARGESTRING); + WRITEUINT32(save_p, len); // save size of string + } while (i < len) WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros break; @@ -996,16 +1105,8 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) if (!rover) WRITEUINT8(save_p, ARCH_NULL); else { - ffloor_t *r2; - UINT16 i = 0; - // search for id - for (r2 = rover->target->ffloors; r2; r2 = r2->next) - { - if (r2 == rover) - break; - i++; - } - if (!r2) + UINT16 i = P_GetFFloorID(rover); + if (i == UINT16_MAX) // invalid ID WRITEUINT8(save_p, ARCH_NULL); else { @@ -1016,7 +1117,6 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) } break; } -#ifdef ESLOPE case ARCH_SLOPE: { pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex)); @@ -1028,7 +1128,6 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) } break; } -#endif case ARCH_MAPHEADER: { mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); @@ -1040,6 +1139,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) } break; } + + case ARCH_SKINCOLOR: + { + skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex)); + WRITEUINT8(save_p, ARCH_SKINCOLOR); + WRITEUINT16(save_p, info - skincolors); + break; + } default: WRITEUINT8(save_p, ARCH_NULL); return 2; @@ -1166,21 +1273,36 @@ static UINT8 UnArchiveValue(int TABLESINDEX) case ARCH_NULL: lua_pushnil(gL); break; - case ARCH_BOOLEAN: - lua_pushboolean(gL, READUINT8(save_p)); + case ARCH_TRUE: + lua_pushboolean(gL, true); break; - case ARCH_SIGNED: + case ARCH_FALSE: + lua_pushboolean(gL, false); + break; + case ARCH_INT8: + lua_pushinteger(gL, READSINT8(save_p)); + break; + case ARCH_INT16: + lua_pushinteger(gL, READINT16(save_p)); + break; + case ARCH_INT32: lua_pushinteger(gL, READFIXED(save_p)); break; - case ARCH_STRING: + case ARCH_SMALLSTRING: + case ARCH_LARGESTRING: { - UINT16 len = READUINT16(save_p); // length of string, including embedded zeros + UINT32 len; char *value; - UINT16 i = 0; + UINT32 i = 0; + // See my comments in the ArchiveValue function; // it's much the same for reading strings as writing them! // (i.e. we can't use READSTRING either) // -- Monster Iestyn 05/08/18 + if (type == ARCH_SMALLSTRING) + len = READUINT8(save_p); // length of string, including embedded zeros + else + len = READUINT32(save_p); // length of string, including embedded zeros value = malloc(len); // make temp buffer of size len // now read the actual string while (i < len) @@ -1250,14 +1372,15 @@ static UINT8 UnArchiveValue(int TABLESINDEX) LUA_PushUserdata(gL, rover, META_FFLOOR); break; } -#ifdef ESLOPE case ARCH_SLOPE: LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE); break; -#endif case ARCH_MAPHEADER: LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER); break; + case ARCH_SKINCOLOR: + LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR); + break; case ARCH_TEND: return 1; } @@ -1423,5 +1546,3 @@ int Lua_optoption(lua_State *L, int narg, return i; return -1; } - -#endif // HAVE_BLUA diff --git a/src/lua_script.h b/src/lua_script.h index 8f27dcb4c..5a3520d11 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -10,8 +10,6 @@ /// \file lua_script.h /// \brief Lua scripting basics -#ifdef HAVE_BLUA - #include "m_fixed.h" #include "doomtype.h" #include "d_player.h" @@ -39,13 +37,15 @@ void LUA_ClearExtVars(void); #endif -extern boolean lua_lumploading; // is LUA_LoadLump being called? +extern INT32 lua_lumploading; // is LUA_LoadLump being called? -void LUA_LoadLump(UINT16 wad, UINT16 lump); +int LUA_GetErrorMessage(lua_State *L); +void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults); #ifdef LUA_ALLOW_BYTECODE void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); +void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta); void LUA_PushUserdata(lua_State *L, void *data, const char *meta); void LUA_InvalidateUserdata(void *data); void LUA_InvalidateLevel(void); @@ -100,7 +100,8 @@ void COM_Lua_f(void); // uncomment if you want seg_t/node_t in Lua // #define HAVE_LUA_SEGS -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This can only be used in a level!"); +#define ISINLEVEL \ + (gamestate == GS_LEVEL || titlemapinaction) -#endif +#define INLEVEL if (! ISINLEVEL)\ +return luaL_error(L, "This can only be used in a level!"); diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index a4ab075b4..3e4ddb9f0 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,9 +11,8 @@ /// \brief player skin structure library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "fastcmp.h" -#include "r_things.h" +#include "r_skins.h" #include "sounds.h" #include "lua_script.h" @@ -358,5 +357,3 @@ int LUA_SkinLib(lua_State *L) return 0; } - -#endif diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c index 1462b26ef..82baa6469 100644 --- a/src/lua_thinkerlib.c +++ b/src/lua_thinkerlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,7 +11,6 @@ /// \brief thinker library for Lua scripting #include "doomdef.h" -#ifdef HAVE_BLUA #include "p_local.h" #include "lua_script.h" #include "lua_libs.h" @@ -139,5 +138,3 @@ int LUA_ThinkerLib(lua_State *L) lua_setglobal(L, "mobjs"); return 0; } - -#endif diff --git a/src/m_aatree.c b/src/m_aatree.c index efa92cbe0..c0bb739f8 100644 --- a/src/m_aatree.c +++ b/src/m_aatree.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_aatree.h b/src/m_aatree.h index af95f91b8..b784eb17a 100644 --- a/src/m_aatree.h +++ b/src/m_aatree.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_anigif.c b/src/m_anigif.c index faa8f29e1..1b71a09bc 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2013 by "Ninji". -// Copyright (C) 2013-2019 by Sonic Team Junior. +// Copyright (C) 2013-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -490,29 +490,28 @@ const UINT8 gifframe_gchead[4] = {0x21,0xF9,0x04,0x04}; // GCE, bytes, packed by static UINT8 *gifframe_data = NULL; static size_t gifframe_size = 8192; +// +// GIF_rgbconvert +// converts an RGB frame to a frame with a palette. +// #ifdef HWRENDER -static void hwrconvert(void) +static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) { - UINT8 *linear = HWR_GetScreenshot(); - UINT8 *dest = screens[2]; UINT8 r, g, b; - INT32 x, y; - size_t i = 0; + size_t src = 0, dest = 0; + size_t size = (vid.width * vid.height * 3); InitColorLUT(gif_framepalette); - for (y = 0; y < vid.height; y++) + while (src < size) { - for (x = 0; x < vid.width; x++, i += 3) - { - r = (UINT8)linear[i]; - g = (UINT8)linear[i + 1]; - b = (UINT8)linear[i + 2]; - dest[(y * vid.width) + x] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS]; - } + r = (UINT8)linear[src]; + g = (UINT8)linear[src + 1]; + b = (UINT8)linear[src + 2]; + scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS]; + src += (3 * scrbuf_downscaleamt); + dest += scrbuf_downscaleamt; } - - free(linear); } #endif @@ -556,7 +555,11 @@ static void GIF_framewrite(void) I_ReadScreen(movie_screen); #ifdef HWRENDER else if (rendermode == render_opengl) - hwrconvert(); + { + UINT8 *linear = HWR_GetScreenshot(); + GIF_rgbconvert(linear, movie_screen); + free(linear); + } #endif } else @@ -565,18 +568,20 @@ static void GIF_framewrite(void) blitw = vid.width; blith = vid.height; - if (gif_frames == 0) - { - if (rendermode == render_soft) - I_ReadScreen(movie_screen); #ifdef HWRENDER - else if (rendermode == render_opengl) - { - hwrconvert(); - VID_BlitLinearScreen(screens[2], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); - } -#endif + // Copy the current OpenGL frame into the base screen + if (rendermode == render_opengl) + { + UINT8 *linear = HWR_GetScreenshot(); + GIF_rgbconvert(linear, screens[0]); + free(linear); } +#endif + + // Copy the first frame into the movie screen + // OpenGL already does the same above. + if (gif_frames == 0 && rendermode == render_soft) + I_ReadScreen(movie_screen); movie_screen = screens[0]; } diff --git a/src/m_anigif.h b/src/m_anigif.h index 9eb6faa75..4bb45b67d 100644 --- a/src/m_anigif.h +++ b/src/m_anigif.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 2013-2019 by Sonic Team Junior. +// Copyright (C) 2013-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_argv.c b/src/m_argv.c index 129706127..7d43d96bc 100644 --- a/src/m_argv.c +++ b/src/m_argv.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -34,6 +34,25 @@ boolean myargmalloc = false; */ static INT32 found; +/** \brief Parses a server URL (such as srb2://127.0.0.1) as may be passed to the game via a web browser, etc. + + \return the contents of the URL after the protocol (a server to join), or NULL if not found +*/ +const char *M_GetUrlProtocolArg(void) +{ + INT32 i; + const size_t len = strlen(SERVER_URL_PROTOCOL); + + for (i = 1; i < myargc; i++) + { + if (strlen(myargv[i]) > len && !strnicmp(myargv[i], SERVER_URL_PROTOCOL, len)) + { + return &myargv[i][len]; + } + } + + return NULL; +} /** \brief The M_CheckParm function diff --git a/src/m_argv.h b/src/m_argv.h index 57c3f9d50..92770f4e9 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -21,6 +21,9 @@ extern INT32 myargc; extern char **myargv; extern boolean myargmalloc; +// Looks for an srb2:// (or similar) URL passed in as an argument and returns the IP to connect to if found. +const char *M_GetUrlProtocolArg(void); + // Returns the position of the given parameter in the arg list (0 if not found). INT32 M_CheckParm(const char *check); diff --git a/src/m_bbox.c b/src/m_bbox.c index 5af1b4ef8..02d534164 100644 --- a/src/m_bbox.c +++ b/src/m_bbox.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_bbox.h b/src/m_bbox.h index dce3cf15a..9b63c61b6 100644 --- a/src/m_bbox.h +++ b/src/m_bbox.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_cheat.c b/src/m_cheat.c index 980d9fc21..c42763afd 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -288,7 +288,7 @@ void Command_CheatGod_f(void) plyr = &players[consoleplayer]; plyr->pflags ^= PF_GODMODE; - CONS_Printf(M_GetText("Sissy Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off")); + CONS_Printf(M_GetText("Cheese Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off")); G_SetGameModified(multiplayer); } @@ -555,7 +555,8 @@ void Command_Teleport_f(void) p->mo->flags2 &= ~MF2_OBJECTFLIP; } - localangle = p->mo->angle = p->drawangle = FixedAngle(mt->angle<mo->angle = p->drawangle = FixedAngle(mt->angle<mo->angle); } else // scan the thinkers to find starposts... { @@ -619,7 +620,8 @@ void Command_Teleport_f(void) p->mo->flags2 &= ~MF2_OBJECTFLIP; } - localangle = p->mo->angle = p->drawangle = mo2->angle; + p->mo->angle = p->drawangle = mo2->angle; + P_SetPlayerAngle(p, p->mo->angle); } CONS_Printf(M_GetText("Teleporting to checkpoint %d, %d...\n"), starpostnum, starpostpath); @@ -673,7 +675,10 @@ void Command_Teleport_f(void) i = COM_CheckParm("-ang"); if (i) - localangle = p->drawangle = p->mo->angle = FixedAngle(atoi(COM_Argv(i + 1))<drawangle = p->mo->angle = FixedAngle(atoi(COM_Argv(i + 1))<mo->angle); + } i = COM_CheckParm("-aim"); if (i) @@ -788,7 +793,7 @@ void Command_CauseCfail_f(void) } #endif -#if defined(HAVE_BLUA) && defined(LUA_ALLOW_BYTECODE) +#ifdef LUA_ALLOW_BYTECODE void Command_Dumplua_f(void) { if (modifiedgame) @@ -934,6 +939,12 @@ void Command_Setcontinues_f(void) REQUIRE_NOULTIMATE; REQUIRE_PANDORA; + if (!continuesInSession) + { + CONS_Printf(M_GetText("This session does not use continues.\n")); + return; + } + if (COM_Argc() > 1) { INT32 numcontinues = atoi(COM_Argv(1)); @@ -972,7 +983,7 @@ static mobjflag2_t op_oldflags2 = 0; static UINT32 op_oldeflags = 0; static fixed_t op_oldmomx = 0, op_oldmomy = 0, op_oldmomz = 0, op_oldheight = 0; static statenum_t op_oldstate = 0; -static UINT8 op_oldcolor = 0; +static UINT16 op_oldcolor = 0; // // Static calculation / common output help @@ -1025,13 +1036,9 @@ static boolean OP_HeightOkay(player_t *player, UINT8 ceiling) if (ceiling) { -#ifdef ESLOPE // Truncate position to match where mapthing would be when spawned - // (this applies to every further P_GetZAt call as well) - fixed_t cheight = sec->c_slope ? P_GetZAt(sec->c_slope, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000) : sec->ceilingheight; -#else - fixed_t cheight = sec->ceilingheight; -#endif + // (this applies to every further P_GetSlopeZAt call as well) + fixed_t cheight = P_GetSectorCeilingZAt(sec, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000); if (((cheight - player->mo->z - player->mo->height)>>FRACBITS) >= (1 << (16-ZSHIFT))) { @@ -1042,11 +1049,7 @@ static boolean OP_HeightOkay(player_t *player, UINT8 ceiling) } else { -#ifdef ESLOPE - fixed_t fheight = sec->f_slope ? P_GetZAt(sec->f_slope, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000) : sec->floorheight; -#else - fixed_t fheight = sec->floorheight; -#endif + fixed_t fheight = P_GetSectorFloorZAt(sec, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000); if (((player->mo->z - fheight)>>FRACBITS) >= (1 << (16-ZSHIFT))) { CONS_Printf(M_GetText("Sorry, you're too %s to place this object (max: %d %s).\n"), M_GetText("high"), @@ -1062,9 +1065,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c mapthing_t *mt = mapthings; sector_t *sec = player->mo->subsector->sector; -#ifdef HAVE_BLUA LUA_InvalidateMapthings(); -#endif mapthings = Z_Realloc(mapthings, ++nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); @@ -1095,20 +1096,12 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c mt->y = (INT16)(player->mo->y>>FRACBITS); if (ceiling) { -#ifdef ESLOPE - fixed_t cheight = sec->c_slope ? P_GetZAt(sec->c_slope, mt->x << FRACBITS, mt->y << FRACBITS) : sec->ceilingheight; -#else - fixed_t cheight = sec->ceilingheight; -#endif + fixed_t cheight = P_GetSectorCeilingZAt(sec, mt->x << FRACBITS, mt->y << FRACBITS); mt->z = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS); } else { -#ifdef ESLOPE - fixed_t fheight = sec->f_slope ? P_GetZAt(sec->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : sec->floorheight; -#else - fixed_t fheight = sec->floorheight; -#endif + fixed_t fheight = P_GetSectorFloorZAt(sec, mt->x << FRACBITS, mt->y << FRACBITS); mt->z = (UINT16)((player->mo->z - fheight)>>FRACBITS); } mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle))); @@ -1354,20 +1347,12 @@ void OP_ObjectplaceMovement(player_t *player) if (!!(mobjinfo[op_currentthing].flags & MF_SPAWNCEILING) ^ !!(cv_opflags.value & MTF_OBJECTFLIP)) { -#ifdef ESLOPE - fixed_t cheight = sec->c_slope ? P_GetZAt(sec->c_slope, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000) : sec->ceilingheight; -#else - fixed_t cheight = sec->ceilingheight; -#endif + fixed_t cheight = P_GetSectorCeilingZAt(sec, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000); op_displayflags = (UINT16)((cheight - player->mo->z - mobjinfo[op_currentthing].height)>>FRACBITS); } else { -#ifdef ESLOPE - fixed_t fheight = sec->f_slope ? P_GetZAt(sec->f_slope, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000) : sec->floorheight; -#else - fixed_t fheight = sec->floorheight; -#endif + fixed_t fheight = P_GetSectorFloorZAt(sec, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000); op_displayflags = (UINT16)((player->mo->z - fheight)>>FRACBITS); } op_displayflags <<= ZSHIFT; diff --git a/src/m_cheat.h b/src/m_cheat.h index 3c4403e7f..ac2540408 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -68,7 +68,7 @@ void Command_Toggletwod_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif -#if defined(HAVE_BLUA) && defined(LUA_ALLOW_BYTECODE) +#ifdef LUA_ALLOW_BYTECODE void Command_Dumplua_f(void); #endif diff --git a/src/m_cond.c b/src/m_cond.c index 08f3fe038..36fcd7cf2 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -18,7 +18,7 @@ #include "v_video.h" // video flags #include "g_game.h" // record info -#include "r_things.h" // numskins +#include "r_skins.h" // numskins #include "r_draw.h" // R_GetColorByName // Map triggers for linedef executors @@ -523,9 +523,9 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum) return NULL; } -skincolors_t M_GetEmblemColor(emblem_t *em) +skincolornum_t M_GetEmblemColor(emblem_t *em) { - if (!em || em->color >= MAXSKINCOLORS) + if (!em || em->color >= numskincolors) return SKINCOLOR_NONE; return em->color; } @@ -549,9 +549,9 @@ const char *M_GetEmblemPatch(emblem_t *em, boolean big) return pnamebuf; } -skincolors_t M_GetExtraEmblemColor(extraemblem_t *em) +skincolornum_t M_GetExtraEmblemColor(extraemblem_t *em) { - if (!em || em->color >= MAXSKINCOLORS) + if (!em || em->color >= numskincolors) return SKINCOLOR_NONE; return em->color; } diff --git a/src/m_cond.h b/src/m_cond.h index 7fe3105fb..9bb162ff3 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 2012-2019 by Sonic Team Junior. +// Copyright (C) 2012-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -90,7 +90,7 @@ typedef struct INT16 tag; ///< Tag of emblem mapthing INT16 level; ///< Level on which this emblem can be found. UINT8 sprite; ///< emblem sprite to use, 0 - 25 - UINT8 color; ///< skincolor to use + UINT16 color; ///< skincolor to use INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin) char hint[110]; ///< Hint for emblem hints menu UINT8 collected; ///< Do you have this emblem? @@ -102,7 +102,7 @@ typedef struct UINT8 conditionset; ///< Condition set that awards this emblem. UINT8 showconditionset; ///< Condition set that shows this emblem. UINT8 sprite; ///< emblem sprite to use, 0 - 25 - UINT8 color; ///< skincolor to use + UINT16 color; ///< skincolor to use UINT8 collected; ///< Do you have this emblem? } extraemblem_t; @@ -172,9 +172,9 @@ INT32 M_CountEmblems(void); // Emblem shit emblem_t *M_GetLevelEmblems(INT32 mapnum); -skincolors_t M_GetEmblemColor(emblem_t *em); +skincolornum_t M_GetEmblemColor(emblem_t *em); const char *M_GetEmblemPatch(emblem_t *em, boolean big); -skincolors_t M_GetExtraEmblemColor(extraemblem_t *em); +skincolornum_t M_GetExtraEmblemColor(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 diff --git a/src/m_dllist.h b/src/m_dllist.h index 8f8d4c1fb..680c2cd80 100644 --- a/src/m_dllist.h +++ b/src/m_dllist.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2005 by James Haley -// Copyright (C) 2005-2019 by Sonic Team Junior. +// Copyright (C) 2005-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_fixed.c b/src/m_fixed.c index 6be54c486..eb10fd5f8 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_fixed.h b/src/m_fixed.h index 02d4c73ff..289ca442a 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -38,8 +38,20 @@ typedef INT32 fixed_t; /*! \brief convert fixed_t into floating number */ -#define FIXED_TO_FLOAT(x) (((float)(x)) / ((float)FRACUNIT)) -#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT)) + +FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat(fixed_t x) +{ + return x / (float)FRACUNIT; +} + +FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f) +{ + return (fixed_t)(f * FRACUNIT); +} + +// for backwards compat +#define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT)) +#define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT)) #if defined (__WATCOMC__) && FRACBITS == 16 @@ -192,18 +204,6 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedDiv(fixed_t a, fixed_t b) return FixedDiv2(a, b); } -/** \brief The FixedRem function - - \param x fixed_t number - \param y fixed_t number - - \return remainder of dividing x by y -*/ -FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRem(fixed_t x, fixed_t y) -{ - return x % y; -} - /** \brief The FixedSqrt function \param x fixed_t number diff --git a/src/m_menu.c b/src/m_menu.c index 8b564e068..f684354a5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -44,6 +44,7 @@ #include "p_local.h" #include "p_setup.h" #include "f_finale.h" +#include "lua_hook.h" #ifdef HWRENDER #include "hardware/hw_main.h" @@ -182,6 +183,7 @@ static tic_t keydown = 0; static void M_GoBack(INT32 choice); static void M_StopMessage(INT32 choice); +static boolean stopstopmessage = false; #ifndef NONET static void M_HandleServerPage(INT32 choice); @@ -252,6 +254,7 @@ static void M_ConfirmTeamScramble(INT32 choice); static void M_ConfirmTeamChange(INT32 choice); static void M_SecretsMenu(INT32 choice); static void M_SetupChoosePlayer(INT32 choice); +static UINT8 M_SetupChoosePlayerDirect(INT32 choice); static void M_QuitSRB2(INT32 choice); menu_t SP_MainDef, OP_MainDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; @@ -272,9 +275,14 @@ static void M_ModeAttackEndGame(INT32 choice); static void M_SetGuestReplay(INT32 choice); static void M_HandleChoosePlayerMenu(INT32 choice); static void M_ChoosePlayer(INT32 choice); +static void M_MarathonLiveEventBackup(INT32 choice); +static void M_Marathon(INT32 choice); +static void M_HandleMarathonChoosePlayer(INT32 choice); +static void M_StartMarathon(INT32 choice); menu_t SP_LevelStatsDef; static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; static menu_t SP_NightsAttackDef, SP_NightsReplayDef, SP_NightsGuestReplayDef, SP_NightsGhostDef; +static menu_t SP_MarathonDef; // Multiplayer static void M_SetupMultiPlayer(INT32 choice); @@ -312,11 +320,15 @@ static void M_AssignJoystick(INT32 choice); static void M_ChangeControl(INT32 choice); // Video & Sound +static void M_VideoOptions(INT32 choice); menu_t OP_VideoOptionsDef, OP_VideoModeDef, OP_ColorOptionsDef; #ifdef HWRENDER static void M_OpenGLOptionsMenu(void); -menu_t OP_OpenGLOptionsDef, OP_OpenGLFogDef; -#endif +menu_t OP_OpenGLOptionsDef; +#ifdef ALAM_LIGHTING +menu_t OP_OpenGLLightingDef; +#endif // ALAM_LIGHTING +#endif // HWRENDER menu_t OP_SoundOptionsDef; menu_t OP_SoundAdvancedDef; @@ -353,6 +365,7 @@ static void M_DrawLoad(void); static void M_DrawLevelStats(void); static void M_DrawTimeAttackMenu(void); static void M_DrawNightsAttackMenu(void); +static void M_DrawMarathon(void); static void M_DrawSetupChoosePlayerMenu(void); static void M_DrawControlsDefMenu(void); static void M_DrawCameraOptionsMenu(void); @@ -363,9 +376,6 @@ static void M_DrawVideoMode(void); static void M_DrawColorMenu(void); static void M_DrawScreenshotMenu(void); static void M_DrawMonitorToggles(void); -#ifdef HWRENDER -static void M_OGL_DrawFogMenu(void); -#endif #ifndef NONET static void M_DrawConnectMenu(void); static void M_DrawMPMainMenu(void); @@ -389,9 +399,6 @@ static boolean M_CancelConnect(void); static void M_HandleConnectIP(INT32 choice); #endif static void M_HandleSetupMultiPlayer(INT32 choice); -#ifdef HWRENDER -static void M_HandleFogColor(INT32 choice); -#endif static void M_HandleVideoMode(INT32 choice); static void M_ResetCvars(void); @@ -475,6 +482,13 @@ static consvar_t cv_dummylives = {"dummylives", "0", CV_HIDEN, liveslimit_cons_t 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}; +CV_PossibleValue_t marathon_cons_t[] = {{0, "Standard"}, {1, "Live Event Backup"}, {2, "Ultimate"}, {0, NULL}}; +CV_PossibleValue_t loadless_cons_t[] = {{0, "Realtime"}, {1, "In-game"}, {0, NULL}}; + +consvar_t cv_dummymarathon = {"dummymarathon", "Standard", CV_HIDEN, marathon_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_dummycutscenes = {"dummycutscenes", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_dummyloadless = {"dummyloadless", "Realtime", CV_HIDEN, loadless_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + // ========================================================================== // ORGANIZATION START. // ========================================================================== @@ -521,6 +535,8 @@ static menuitem_t MISC_AddonsMenu[] = // --------------------------------- static menuitem_t MAPauseMenu[] = { + {IT_CALL | IT_STRING, NULL, "Emblem Hints...", M_EmblemHints, 32}, + {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48}, {IT_CALL | IT_STRING, NULL, "Retry", M_ModeAttackRetry, 56}, {IT_CALL | IT_STRING, NULL, "Abort", M_ModeAttackEndGame, 64}, @@ -528,6 +544,7 @@ static menuitem_t MAPauseMenu[] = typedef enum { + mapause_hints, mapause_continue, mapause_retry, mapause_abort @@ -729,9 +746,9 @@ static menuitem_t SR_SoundTestMenu[] = static menuitem_t SR_EmblemHintMenu[] = { - {IT_STRING | IT_ARROWS, NULL, "Page", M_HandleEmblemHints, 10}, - {IT_STRING|IT_CVAR, NULL, "Emblem Radar", &cv_itemfinder, 20}, - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SPauseDef, 30} + {IT_STRING | IT_ARROWS, NULL, "Page", M_HandleEmblemHints, 10}, + {IT_STRING|IT_CVAR, NULL, "Emblem Radar", &cv_itemfinder, 20}, + {IT_WHITESTRING|IT_CALL, NULL, "Back", M_GoBack, 30} }; // -------------------------------- @@ -742,9 +759,10 @@ static menuitem_t SR_EmblemHintMenu[] = // Single Player Main static menuitem_t SP_MainMenu[] = { - {IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 84}, - {IT_SECRET, NULL, "Record Attack", M_TimeAttack, 92}, - {IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 100}, + {IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 76}, + {IT_SECRET, NULL, "Record Attack", M_TimeAttack, 84}, + {IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 92}, + {IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Marathon Run", M_Marathon, 100}, {IT_CALL | IT_STRING, NULL, "Tutorial", M_StartTutorial, 108}, {IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 116} }; @@ -754,6 +772,7 @@ enum sploadgame, sprecordattack, spnightsmode, + spmarathon, sptutorial, spstatistics }; @@ -878,7 +897,8 @@ static menuitem_t SP_NightsAttackLevelSelectMenu[] = static menuitem_t SP_NightsAttackMenu[] = { {IT_STRING|IT_KEYHANDLER, NULL, "Level Select...", &M_HandleTimeAttackLevelSelect, 52}, - {IT_STRING|IT_CVAR, NULL, "Show Records For", &cv_dummymares, 62}, + {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 62}, + {IT_STRING|IT_CVAR, NULL, "Show Records For", &cv_dummymares, 72}, {IT_DISABLED, NULL, "Guest Option...", &SP_NightsGuestReplayDef, 100}, {IT_DISABLED, NULL, "Replay...", &SP_NightsReplayDef, 110}, @@ -889,6 +909,7 @@ static menuitem_t SP_NightsAttackMenu[] = enum { nalevel, + nachar, narecords, naguest, @@ -897,6 +918,25 @@ enum nastart }; +// Marathon +static menuitem_t SP_MarathonMenu[] = +{ + {IT_STRING|IT_KEYHANDLER, NULL, "Character", M_HandleMarathonChoosePlayer, 90}, + {IT_STRING|IT_CVAR, NULL, "Category", &cv_dummymarathon, 100}, + {IT_STRING|IT_CVAR, NULL, "Timer", &cv_dummyloadless, 110}, + {IT_STRING|IT_CVAR, NULL, "Cutscenes", &cv_dummycutscenes, 120}, + {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartMarathon, 130}, +}; + +enum +{ + marathonplayer, + marathonultimate, + marathonloadless, + marathoncutscenes, + marathonstart +}; + // Statistics static menuitem_t SP_LevelStatsMenu[] = { @@ -1034,7 +1074,7 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Player 2 Controls...", &OP_P2ControlsDef, 20}, {IT_CVAR | IT_STRING, NULL, "Controls per key", &cv_controlperkey, 30}, - {IT_SUBMENU | IT_STRING, NULL, "Video Options...", &OP_VideoOptionsDef, 50}, + {IT_CALL | IT_STRING, NULL, "Video Options...", M_VideoOptions, 50}, {IT_SUBMENU | IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 60}, {IT_CALL | IT_STRING, NULL, "Server Options...", M_ServerOptions, 80}, @@ -1285,6 +1325,16 @@ static menuitem_t OP_Camera2ExtendedOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 126}, }; +enum +{ + op_video_resolution = 1, +#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) + op_video_fullscreen, +#endif + op_video_vsync, + op_video_renderer, +}; + static menuitem_t OP_VideoOptionsMenu[] = { {IT_HEADER, NULL, "Screen", NULL, 0}, @@ -1396,22 +1446,23 @@ static menuitem_t OP_OpenGLOptionsMenu[] = { {IT_HEADER, NULL, "3D Models", NULL, 0}, {IT_STRING|IT_CVAR, NULL, "Models", &cv_grmodels, 12}, - {IT_STRING|IT_CVAR, NULL, "Model interpolation", &cv_grmodelinterpolation, 22}, - {IT_STRING|IT_CVAR, NULL, "Model lighting", &cv_grmodellighting, 32}, + {IT_STRING|IT_CVAR, NULL, "Frame interpolation", &cv_grmodelinterpolation, 22}, + {IT_STRING|IT_CVAR, NULL, "Ambient lighting", &cv_grmodellighting, 32}, {IT_HEADER, NULL, "General", NULL, 51}, - {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 63}, - {IT_STRING|IT_CVAR, NULL, "Quality", &cv_scr_depth, 73}, - {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 83}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode,93}, + {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_grshaders, 63}, + {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_grshearing, 73}, + {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 83}, - {IT_HEADER, NULL, "Miscellaneous", NULL, 112}, - {IT_SUBMENU|IT_STRING, NULL, "Fog...", &OP_OpenGLFogDef, 124}, + {IT_HEADER, NULL, "Miscellaneous", NULL, 102}, + {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 114}, + {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_grfiltermode, 124}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode, 134}, #ifdef ALAM_LIGHTING - {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 134}, + {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 144}, #endif #if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL))) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 144}, + {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 154}, #endif }; @@ -1423,15 +1474,8 @@ static menuitem_t OP_OpenGLLightingMenu[] = {IT_STRING|IT_CVAR, NULL, "Dynamic lighting", &cv_grdynamiclighting, 20}, {IT_STRING|IT_CVAR, NULL, "Static lighting", &cv_grstaticlighting, 30}, }; -#endif +#endif // ALAM_LIGHTING -static menuitem_t OP_OpenGLFogMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Fog", &cv_grfog, 10}, - {IT_STRING|IT_KEYHANDLER, NULL, "Fog color", M_HandleFogColor, 20}, - {IT_STRING|IT_CVAR, NULL, "Fog density", &cv_grfogdensity, 30}, - {IT_STRING|IT_CVAR, NULL, "Software Fog",&cv_grsoftwarefog,40}, -}; #endif static menuitem_t OP_SoundOptionsMenu[] = @@ -1569,7 +1613,7 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_HEADER, NULL, "General", NULL, 0}, #ifndef NONET {IT_STRING | IT_CVAR | IT_CV_STRING, - NULL, "Server name", &cv_servername, 7}, + NULL, "Server name", &cv_servername, 7}, {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21}, {IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31}, @@ -1614,8 +1658,9 @@ static menuitem_t OP_ServerOptionsMenu[] = #ifndef NONET {IT_HEADER, NULL, "Advanced", NULL, 225}, - {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 231}, - {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 245}, + {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 231}, + {IT_STRING | IT_CVAR, NULL, "Join delay", &cv_joindelay, 246}, + {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 251}, #endif }; @@ -1687,7 +1732,7 @@ static INT32 highlightflags, recommendedflags, warningflags; // Sky Room menu_t SR_PandoraDef = { - MN_SR_MAIN + (MN_SR_PANDORA << 6), + MTREE2(MN_SR_MAIN, MN_SR_PANDORA), "M_PANDRA", sizeof (SR_PandorasBox)/sizeof (menuitem_t), &SPauseDef, @@ -1701,12 +1746,12 @@ menu_t SR_PandoraDef = menu_t SR_MainDef = DEFAULTMENUSTYLE(MN_SR_MAIN, "M_SECRET", SR_MainMenu, &MainDef, 60, 40); menu_t SR_LevelSelectDef = MAPPLATTERMENUSTYLE( - MN_SR_MAIN + (MN_SR_LEVELSELECT << 6), + MTREE2(MN_SR_MAIN, MN_SR_LEVELSELECT), NULL, SR_LevelSelectMenu); menu_t SR_UnlockChecklistDef = { - MN_SR_MAIN + (MN_SR_UNLOCKCHECKLIST << 6), + MTREE2(MN_SR_MAIN, MN_SR_UNLOCKCHECKLIST), "M_SECRET", 1, &SR_MainDef, @@ -1719,7 +1764,7 @@ menu_t SR_UnlockChecklistDef = menu_t SR_SoundTestDef = { - MN_SR_MAIN + (MN_SR_SOUNDTEST << 6), + MTREE2(MN_SR_MAIN, MN_SR_SOUNDTEST), NULL, sizeof (SR_SoundTestMenu)/sizeof (menuitem_t), &SR_MainDef, @@ -1732,7 +1777,7 @@ menu_t SR_SoundTestDef = menu_t SR_EmblemHintDef = { - MN_SR_MAIN + (MN_SR_EMBLEMHINT << 6), + MTREE2(MN_SR_MAIN, MN_SR_EMBLEMHINT), NULL, sizeof (SR_EmblemHintMenu)/sizeof (menuitem_t), &SPauseDef, @@ -1759,7 +1804,7 @@ menu_t SP_MainDef = //CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72); menu_t SP_LoadDef = { - MN_SP_MAIN + (MN_SP_LOAD << 6), + MTREE2(MN_SP_MAIN, MN_SP_LOAD), "M_PICKG", 1, &SP_MainDef, @@ -1771,12 +1816,12 @@ menu_t SP_LoadDef = }; menu_t SP_LevelSelectDef = MAPPLATTERMENUSTYLE( - MN_SP_MAIN + (MN_SP_LOAD << 6) + (MN_SP_PLAYER << 12) + (MN_SP_LEVELSELECT << 18), + MTREE4(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER, MN_SP_LEVELSELECT), NULL, SP_LevelSelectMenu); menu_t SP_LevelStatsDef = { - MN_SP_MAIN + (MN_SP_LEVELSTATS << 6), + MTREE2(MN_SP_MAIN, MN_SP_LEVELSTATS), "M_STATS", 1, &SP_MainDef, @@ -1788,12 +1833,12 @@ menu_t SP_LevelStatsDef = }; menu_t SP_TimeAttackLevelSelectDef = MAPPLATTERMENUSTYLE( - MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_TIMEATTACK_LEVELSELECT << 12), + MTREE3(MN_SP_MAIN, MN_SP_TIMEATTACK, MN_SP_TIMEATTACK_LEVELSELECT), "M_ATTACK", SP_TimeAttackLevelSelectMenu); static menu_t SP_TimeAttackDef = { - MN_SP_MAIN + (MN_SP_TIMEATTACK << 6), + MTREE2(MN_SP_MAIN, MN_SP_TIMEATTACK), "M_ATTACK", sizeof (SP_TimeAttackMenu)/sizeof (menuitem_t), &MainDef, // Doesn't matter. @@ -1805,7 +1850,7 @@ static menu_t SP_TimeAttackDef = }; static menu_t SP_ReplayDef = { - MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_REPLAY << 12), + MTREE3(MN_SP_MAIN, MN_SP_TIMEATTACK, MN_SP_REPLAY), "M_ATTACK", sizeof(SP_ReplayMenu)/sizeof(menuitem_t), &SP_TimeAttackDef, @@ -1817,7 +1862,7 @@ static menu_t SP_ReplayDef = }; static menu_t SP_GuestReplayDef = { - MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_GUESTREPLAY << 12), + MTREE3(MN_SP_MAIN, MN_SP_TIMEATTACK, MN_SP_GUESTREPLAY), "M_ATTACK", sizeof(SP_GuestReplayMenu)/sizeof(menuitem_t), &SP_TimeAttackDef, @@ -1829,7 +1874,7 @@ static menu_t SP_GuestReplayDef = }; static menu_t SP_GhostDef = { - MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_GHOST << 12), + MTREE3(MN_SP_MAIN, MN_SP_TIMEATTACK, MN_SP_GHOST), "M_ATTACK", sizeof(SP_GhostMenu)/sizeof(menuitem_t), &SP_TimeAttackDef, @@ -1841,12 +1886,12 @@ static menu_t SP_GhostDef = }; menu_t SP_NightsAttackLevelSelectDef = MAPPLATTERMENUSTYLE( - MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_LEVELSELECT << 12), + MTREE3(MN_SP_MAIN, MN_SP_NIGHTSATTACK, MN_SP_NIGHTS_LEVELSELECT), "M_NIGHTS", SP_NightsAttackLevelSelectMenu); static menu_t SP_NightsAttackDef = { - MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6), + MTREE2(MN_SP_MAIN, MN_SP_NIGHTSATTACK), "M_NIGHTS", sizeof (SP_NightsAttackMenu)/sizeof (menuitem_t), &MainDef, // Doesn't matter. @@ -1858,7 +1903,7 @@ static menu_t SP_NightsAttackDef = }; static menu_t SP_NightsReplayDef = { - MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_REPLAY << 12), + MTREE3(MN_SP_MAIN, MN_SP_NIGHTSATTACK, MN_SP_NIGHTS_REPLAY), "M_NIGHTS", sizeof(SP_NightsReplayMenu)/sizeof(menuitem_t), &SP_NightsAttackDef, @@ -1870,7 +1915,7 @@ static menu_t SP_NightsReplayDef = }; static menu_t SP_NightsGuestReplayDef = { - MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_GUESTREPLAY << 12), + MTREE3(MN_SP_MAIN, MN_SP_NIGHTSATTACK, MN_SP_NIGHTS_GUESTREPLAY), "M_NIGHTS", sizeof(SP_NightsGuestReplayMenu)/sizeof(menuitem_t), &SP_NightsAttackDef, @@ -1882,7 +1927,7 @@ static menu_t SP_NightsGuestReplayDef = }; static menu_t SP_NightsGhostDef = { - MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_GHOST << 12), + MTREE3(MN_SP_MAIN, MN_SP_NIGHTSATTACK, MN_SP_NIGHTS_GHOST), "M_NIGHTS", sizeof(SP_NightsGhostMenu)/sizeof(menuitem_t), &SP_NightsAttackDef, @@ -1893,10 +1938,22 @@ static menu_t SP_NightsGhostDef = NULL }; +static menu_t SP_MarathonDef = +{ + MTREE2(MN_SP_MAIN, MN_SP_MARATHON), + "M_ATTACK", // temporary + sizeof(SP_MarathonMenu)/sizeof(menuitem_t), + &MainDef, // Doesn't matter. + SP_MarathonMenu, + M_DrawMarathon, + 32, 40, + 0, + NULL +}; menu_t SP_PlayerDef = { - MN_SP_MAIN + (MN_SP_LOAD << 6) + (MN_SP_PLAYER << 12), + MTREE3(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER), "M_PICKP", sizeof (SP_PlayerMenu)/sizeof (menuitem_t), &SP_MainDef, @@ -1911,7 +1968,7 @@ menu_t SP_PlayerDef = menu_t MP_SplitServerDef = { - MN_MP_MAIN + (MN_MP_SPLITSCREEN << 6), + MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN), "M_MULTI", sizeof (MP_SplitServerMenu)/sizeof (menuitem_t), #ifndef NONET @@ -1943,7 +2000,7 @@ menu_t MP_MainDef = menu_t MP_ServerDef = { - MN_MP_MAIN + (MN_MP_SERVER << 6), + MTREE2(MN_MP_MAIN, MN_MP_SERVER), "M_MULTI", sizeof (MP_ServerMenu)/sizeof (menuitem_t), &MP_MainDef, @@ -1956,7 +2013,7 @@ menu_t MP_ServerDef = menu_t MP_ConnectDef = { - MN_MP_MAIN + (MN_MP_CONNECT << 6), + MTREE2(MN_MP_MAIN, MN_MP_CONNECT), "M_MULTI", sizeof (MP_ConnectMenu)/sizeof (menuitem_t), &MP_MainDef, @@ -1969,7 +2026,7 @@ menu_t MP_ConnectDef = menu_t MP_RoomDef = { - MN_MP_MAIN + (MN_MP_ROOM << 6), + MTREE2(MN_MP_MAIN, MN_MP_ROOM), "M_MULTI", sizeof (MP_RoomMenu)/sizeof (menuitem_t), &MP_ConnectDef, @@ -1984,9 +2041,9 @@ menu_t MP_RoomDef = menu_t MP_PlayerSetupDef = { #ifdef NONET - MN_MP_MAIN + (MN_MP_PLAYERSETUP << 6), + MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP), #else - MN_MP_MAIN + (MN_MP_SPLITSCREEN << 6) + (MN_MP_PLAYERSETUP << 12), + MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP), #endif "M_SPLAYR", sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), @@ -2002,12 +2059,13 @@ menu_t MP_PlayerSetupDef = menu_t OP_MainDef = DEFAULTMENUSTYLE( MN_OP_MAIN, "M_OPTTTL", OP_MainMenu, &MainDef, 50, 30); + menu_t OP_ChangeControlsDef = CONTROLMENUSTYLE( - MN_OP_MAIN + (MN_OP_CHANGECONTROLS << 12), // second level (<<6) set on runtime + MTREE3(MN_OP_MAIN, 0, MN_OP_CHANGECONTROLS), // second level set on runtime OP_ChangeControlsMenu, &OP_MainDef); menu_t OP_P1ControlsDef = { - MN_OP_MAIN + (MN_OP_P1CONTROLS << 6), + MTREE2(MN_OP_MAIN, MN_OP_P1CONTROLS), "M_CONTRO", sizeof(OP_P1ControlsMenu)/sizeof(menuitem_t), &OP_MainDef, @@ -2015,7 +2073,7 @@ menu_t OP_P1ControlsDef = { M_DrawControlsDefMenu, 50, 30, 0, NULL}; menu_t OP_P2ControlsDef = { - MN_OP_MAIN + (MN_OP_P2CONTROLS << 6), + MTREE2(MN_OP_MAIN, MN_OP_P2CONTROLS), "M_CONTRO", sizeof(OP_P2ControlsMenu)/sizeof(menuitem_t), &OP_MainDef, @@ -2024,20 +2082,22 @@ menu_t OP_P2ControlsDef = { 50, 30, 0, NULL}; menu_t OP_MouseOptionsDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1MOUSE << 12), + MTREE3(MN_OP_MAIN, MN_OP_P1CONTROLS, MN_OP_P1MOUSE), "M_CONTRO", OP_MouseOptionsMenu, &OP_P1ControlsDef, 35, 30); menu_t OP_Mouse2OptionsDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2MOUSE << 12), + MTREE3(MN_OP_MAIN, MN_OP_P2CONTROLS, MN_OP_P2MOUSE), "M_CONTRO", OP_Mouse2OptionsMenu, &OP_P2ControlsDef, 35, 30); + menu_t OP_Joystick1Def = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1JOYSTICK << 12), + MTREE3(MN_OP_MAIN, MN_OP_P1CONTROLS, MN_OP_P1JOYSTICK), "M_CONTRO", OP_Joystick1Menu, &OP_P1ControlsDef, 50, 30); menu_t OP_Joystick2Def = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2JOYSTICK << 12), + MTREE3(MN_OP_MAIN, MN_OP_P2CONTROLS, MN_OP_P2JOYSTICK), "M_CONTRO", OP_Joystick2Menu, &OP_P2ControlsDef, 50, 30); + menu_t OP_JoystickSetDef = { - MN_OP_MAIN + (MN_OP_JOYSTICKSET << MENUBITS*3), // second (<<6) and third level (<<12) set on runtime + MTREE4(MN_OP_MAIN, 0, 0, MN_OP_JOYSTICKSET), // second and third level set on runtime "M_CONTRO", sizeof (OP_JoystickSetMenu)/sizeof (menuitem_t), &OP_Joystick1Def, @@ -2049,7 +2109,7 @@ menu_t OP_JoystickSetDef = }; menu_t OP_CameraOptionsDef = { - MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1CAMERA << 12), + MTREE3(MN_OP_MAIN, MN_OP_P1CONTROLS, MN_OP_P1CAMERA), "M_CONTRO", sizeof (OP_CameraOptionsMenu)/sizeof (menuitem_t), &OP_P1ControlsDef, @@ -2060,7 +2120,7 @@ menu_t OP_CameraOptionsDef = { NULL }; menu_t OP_Camera2OptionsDef = { - MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2CAMERA << 12), + MTREE3(MN_OP_MAIN, MN_OP_P2CONTROLS, MN_OP_P2CAMERA), "M_CONTRO", sizeof (OP_Camera2OptionsMenu)/sizeof (menuitem_t), &OP_P2ControlsDef, @@ -2074,7 +2134,7 @@ menu_t OP_Camera2OptionsDef = { static menuitem_t OP_PlaystyleMenu[] = {{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandlePlaystyleMenu, 0}}; menu_t OP_PlaystyleDef = { - MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_PLAYSTYLE << 12), + MTREE3(MN_OP_MAIN, MN_OP_P1CONTROLS, MN_OP_PLAYSTYLE), ///@TODO the second level should be set in runtime NULL, 1, &OP_P1ControlsDef, @@ -2083,10 +2143,24 @@ menu_t OP_PlaystyleDef = { 0, 0, 0, NULL }; +static void M_VideoOptions(INT32 choice) +{ + (void)choice; +#ifdef HWRENDER + if (vid_opengl_state == -1) + { + OP_VideoOptionsMenu[op_video_renderer].status = (IT_TRANSTEXT | IT_PAIR); + OP_VideoOptionsMenu[op_video_renderer].patch = "Renderer"; + OP_VideoOptionsMenu[op_video_renderer].text = "Software"; + } + +#endif + M_SetupNextMenu(&OP_VideoOptionsDef); +} menu_t OP_VideoOptionsDef = { - MN_OP_MAIN + (MN_OP_VIDEO << 6), + MTREE2(MN_OP_MAIN, MN_OP_VIDEO), "M_VIDEO", sizeof (OP_VideoOptionsMenu)/sizeof (menuitem_t), &OP_MainDef, @@ -2098,7 +2172,7 @@ menu_t OP_VideoOptionsDef = }; menu_t OP_VideoModeDef = { - MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_VIDEOMODE << 12), + MTREE3(MN_OP_MAIN, MN_OP_VIDEO, MN_OP_VIDEOMODE), "M_VIDEO", 1, &OP_VideoOptionsDef, @@ -2110,7 +2184,7 @@ menu_t OP_VideoModeDef = }; menu_t OP_ColorOptionsDef = { - MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_COLOR << 12), + MTREE3(MN_OP_MAIN, MN_OP_VIDEO, MN_OP_COLOR), "M_VIDEO", sizeof (OP_ColorOptionsMenu)/sizeof (menuitem_t), &OP_VideoOptionsDef, @@ -2121,17 +2195,19 @@ menu_t OP_ColorOptionsDef = NULL }; menu_t OP_SoundOptionsDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_SOUND << 6), + MTREE2(MN_OP_MAIN, MN_OP_SOUND), "M_SOUND", OP_SoundOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_SoundAdvancedDef = DEFAULTMENUSTYLE(MN_OP_MAIN + (MN_OP_SOUND << 6), "M_SOUND", OP_SoundAdvancedMenu, &OP_SoundOptionsDef, 30, 30); +menu_t OP_SoundAdvancedDef = DEFAULTMENUSTYLE( + MTREE2(MN_OP_MAIN, MN_OP_SOUND), + "M_SOUND", OP_SoundAdvancedMenu, &OP_SoundOptionsDef, 30, 30); menu_t OP_ServerOptionsDef = DEFAULTSCROLLMENUSTYLE( - MN_OP_MAIN + (MN_OP_SERVER << 6), + MTREE2(MN_OP_MAIN, MN_OP_SERVER), "M_SERVER", OP_ServerOptionsMenu, &OP_MainDef, 30, 30); menu_t OP_MonitorToggleDef = { - MN_OP_MAIN + (MN_OP_SERVER << 6) + (MN_OP_MONITORTOGGLE << 12), + MTREE3(MN_OP_MAIN, MN_OP_SOUND, MN_OP_MONITORTOGGLE), "M_SERVER", sizeof (OP_MonitorToggleMenu)/sizeof (menuitem_t), &OP_ServerOptionsDef, @@ -2152,34 +2228,23 @@ static void M_OpenGLOptionsMenu(void) } menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12), + MTREE3(MN_OP_MAIN, MN_OP_VIDEO, MN_OP_OPENGL), "M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30); #ifdef ALAM_LIGHTING menu_t OP_OpenGLLightingDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12) + (MN_OP_OPENGL_LIGHTING << 18), + MTREE4(MN_OP_MAIN, MN_OP_VIDEO, MN_OP_OPENGL, MN_OP_OPENGL_LIGHTING), "M_VIDEO", OP_OpenGLLightingMenu, &OP_OpenGLOptionsDef, 60, 40); -#endif -menu_t OP_OpenGLFogDef = -{ - MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12) + (MN_OP_OPENGL_FOG << 18), - "M_VIDEO", - sizeof (OP_OpenGLFogMenu)/sizeof (menuitem_t), - &OP_OpenGLOptionsDef, - OP_OpenGLFogMenu, - M_OGL_DrawFogMenu, - 60, 40, - 0, - NULL -}; -#endif +#endif // ALAM_LIGHTING +#endif // HWRENDER + menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_DATA << 6), + MTREE2(MN_OP_MAIN, MN_OP_DATA), "M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_ScreenshotOptionsDef = { - MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_SCREENSHOTS << 12), - "M_DATA", + MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_SCREENSHOTS), + "M_SCREEN", sizeof (OP_ScreenshotOptionsMenu)/sizeof (menuitem_t), &OP_DataOptionsDef, OP_ScreenshotOptionsMenu, @@ -2190,11 +2255,11 @@ menu_t OP_ScreenshotOptionsDef = }; menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_ADDONS << 12), + MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_ADDONS), "M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); menu_t OP_EraseDataDef = DEFAULTMENUSTYLE( - MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_ERASEDATA << 12), + MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_ERASEDATA), "M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 60, 30); // ========================================================================== @@ -2490,6 +2555,8 @@ void M_InitMenuPresTables(void) strncpy(menupres[i].musname, "_recat", 7); else if (i == MN_SP_NIGHTSATTACK) strncpy(menupres[i].musname, "_nitat", 7); + else if (i == MN_SP_MARATHON) + strncpy(menupres[i].musname, "spec8", 6); else if (i == MN_SP_PLAYER || i == MN_SR_PLAYER) strncpy(menupres[i].musname, "_chsel", 7); else if (i == MN_SR_SOUNDTEST) @@ -2984,7 +3051,7 @@ static void M_GoBack(INT32 choice) netgame = multiplayer = false; } - if ((currentMenu->prevMenu == &MainDef) && (currentMenu == &SP_TimeAttackDef || currentMenu == &SP_NightsAttackDef)) + if ((currentMenu->prevMenu == &MainDef) && (currentMenu == &SP_TimeAttackDef || currentMenu == &SP_NightsAttackDef || currentMenu == &SP_MarathonDef)) { // D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate. @@ -3153,6 +3220,9 @@ boolean M_Responder(event_t *ev) if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) return false; + if (CON_Ready()) + return false; + if (noFurtherInput) { // Ignore input after enter/escape/other buttons @@ -3366,11 +3436,14 @@ boolean M_Responder(event_t *ev) { if (currentMenu->menuitems[itemOn].alphaKey != MM_EVENTHANDLER) { - if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER) + if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL) { if (routine) routine(ch); - M_StopMessage(0); + if (stopstopmessage) + stopstopmessage = false; + else + M_StopMessage(0); noFurtherInput = true; return true; } @@ -3512,6 +3585,7 @@ boolean M_Responder(event_t *ev) return false; default: + CON_Responder(ev); break; } @@ -3605,6 +3679,7 @@ void M_StartControlPanel(void) else if (modeattacking) { currentMenu = &MAPauseDef; + MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); itemOn = mapause_continue; } else if (!(netgame || multiplayer)) // Single Player @@ -3618,7 +3693,7 @@ void M_StartControlPanel(void) { INT32 numlives = 2; - SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); if (&players[consoleplayer]) { @@ -3636,10 +3711,10 @@ void M_StartControlPanel(void) } // We can always use level select though. :33 - SPauseMenu[spause_levelselect].status = (gamecomplete) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + SPauseMenu[spause_levelselect].status = (gamecomplete == 1) ? (IT_STRING | IT_CALL) : (IT_DISABLED); // And emblem hints. - SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); // Shift up Pandora's Box if both pandora and levelselect are active /*if (SPauseMenu[spause_pandora].status != (IT_DISABLED) @@ -3820,6 +3895,9 @@ void M_Init(void) CV_RegisterVar(&cv_dummylives); CV_RegisterVar(&cv_dummycontinues); CV_RegisterVar(&cv_dummymares); + CV_RegisterVar(&cv_dummymarathon); + CV_RegisterVar(&cv_dummyloadless); + CV_RegisterVar(&cv_dummycutscenes); quitmsg[QUITMSG] = M_GetText("Eggman's tied explosives\nto your girlfriend, and\nwill activate them if\nyou press the 'Y' key!\nPress 'N' to save her!\n\n(Press 'Y' to quit)"); quitmsg[QUITMSG1] = M_GetText("What would Tails say if\nhe saw you quitting the game?\n\n(Press 'Y' to quit)"); @@ -5045,6 +5123,17 @@ static boolean M_SetNextMapOnPlatter(void) } #endif +static boolean M_GametypeHasLevels(INT32 gt) +{ + INT32 mapnum; + + for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + if (M_CanShowLevelOnPlatter(mapnum, gt)) + return true; + + return false; +} + static INT32 M_CountRowsToShowOnPlatter(INT32 gt) { INT32 mapnum = 0, prevmapnum = 0, col = 0, rows = 0; @@ -5136,7 +5225,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) { if (M_CanShowLevelOnPlatter(mapnum, gt)) { - const INT32 actnum = mapheaderinfo[mapnum]->actnum; + const UINT8 actnum = mapheaderinfo[mapnum]->actnum; const boolean headingisname = (fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[mapnum]->lvlttl)); const boolean wide = (mapheaderinfo[mapnum]->menuflags & LF2_WIDEICON); @@ -5362,7 +5451,10 @@ static void M_HandleLevelPlatter(INT32 choice) case KEY_RIGHTARROW: if (levellistmode == LLM_CREATESERVER && !lsrow) { - CV_AddValue(&cv_newgametype, 1); + INT32 startinggametype = cv_newgametype.value; + do + CV_AddValue(&cv_newgametype, 1); + while (cv_newgametype.value != startinggametype && !M_GametypeHasLevels(cv_newgametype.value)); S_StartSound(NULL,sfx_menu1); lscol = 0; @@ -5391,7 +5483,10 @@ static void M_HandleLevelPlatter(INT32 choice) case KEY_LEFTARROW: if (levellistmode == LLM_CREATESERVER && !lsrow) { - CV_AddValue(&cv_newgametype, -1); + INT32 startinggametype = cv_newgametype.value; + do + CV_AddValue(&cv_newgametype, -1); + while (cv_newgametype.value != startinggametype && !M_GametypeHasLevels(cv_newgametype.value)); S_StartSound(NULL,sfx_menu1); lscol = 0; @@ -5711,6 +5806,8 @@ 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; + ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH); + ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH); V_DrawFixedPatch(235<>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING); - break; -#endif - /* FALLTHRU */ case EXT_SOC: case EXT_WAD: #ifdef USE_KART @@ -6682,6 +6773,7 @@ static void M_PandorasBox(INT32 choice) else CV_StealthSetValue(&cv_dummylives, max(players[consoleplayer].lives, 1)); CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues); + SR_PandorasBox[3].status = (continuesInSession) ? (IT_STRING | IT_CVAR) : (IT_GRAYEDOUT); SR_PandorasBox[6].status = (players[consoleplayer].charflags & SF_SUPER) ? (IT_GRAYEDOUT) : (IT_STRING | IT_CALL); SR_PandorasBox[7].status = (emeralds == ((EMERALD7)*2)-1) ? (IT_GRAYEDOUT) : (IT_STRING | IT_CALL); M_SetupNextMenu(&SR_PandoraDef); @@ -6698,7 +6790,7 @@ static boolean M_ExitPandorasBox(void) } if (cv_dummylives.value != players[consoleplayer].lives) COM_ImmedExecute(va("setlives %d", cv_dummylives.value)); - if (cv_dummycontinues.value != players[consoleplayer].continues) + if (continuesInSession && cv_dummycontinues.value != players[consoleplayer].continues) COM_ImmedExecute(va("setcontinues %d", cv_dummycontinues.value)); return true; } @@ -6806,6 +6898,11 @@ static void M_RetryResponse(INT32 ch) static void M_Retry(INT32 choice) { (void)choice; + if (marathonmode) + { + M_RetryResponse(KEY_ENTER); + return; + } M_StartMessage(M_GetText("Retry this act from the last starpost?\n\n(Press 'Y' to confirm)\n"),M_RetryResponse,MM_YESNO); } @@ -6822,6 +6919,8 @@ static void M_SelectableClearMenus(INT32 choice) static void M_UltimateCheat(INT32 choice) { (void)choice; + if (Playing()) + LUAh_GameQuit(); I_Quit(); } @@ -7262,6 +7361,7 @@ static void M_EmblemHints(INT32 choice) SR_EmblemHintMenu[0].status = (local > NUMHINTS*2) ? (IT_STRING | IT_ARROWS) : (IT_DISABLED); SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER)) ? (IT_CVAR|IT_STRING) : (IT_SECRET); hintpage = 1; + SR_EmblemHintDef.prevMenu = currentMenu; M_SetupNextMenu(&SR_EmblemHintDef); itemOn = 2; // always start on back. } @@ -7489,7 +7589,7 @@ static void M_DrawSoundTest(void) { frame[1] = (2-st_time); frame[2] = ((cv_soundtest.value - 1) % 9); - frame[3] += (((cv_soundtest.value - 1) / 9) % (MAXSKINCOLORS - frame[3])); + frame[3] += (((cv_soundtest.value - 1) / 9) % (FIRSTSUPERCOLOR - frame[3])); if (st_time < 2) st_time++; } @@ -7942,12 +8042,30 @@ static void M_CustomLevelSelect(INT32 choice) static void M_SinglePlayerMenu(INT32 choice) { (void)choice; - SP_MainMenu[sptutorial].status = - tutorialmap ? IT_CALL|IT_STRING : IT_NOTHING|IT_DISABLED; - SP_MainMenu[sprecordattack].status = - (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; - SP_MainMenu[spnightsmode].status = - (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET; + + levellistmode = LLM_RECORDATTACK; + if (M_GametypeHasLevels(-1)) + SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; + else + SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED; + + levellistmode = LLM_NIGHTSATTACK; + if (M_GametypeHasLevels(-1)) + SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET; + else + SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED; + + SP_MainMenu[sptutorial].status = tutorialmap ? IT_CALL|IT_STRING : IT_NOTHING|IT_DISABLED; + + // If the FIRST stage immediately leads to the ending, or itself (which gets converted to the title screen in G_DoCompleted for marathonmode only), there's no point in having this option on the menu. You should use Record Attack in that circumstance, although if marathonnext is set this behaviour can be overridden if you make some weird mod that requires multiple playthroughs of the same map in sequence and has some in-level mechanism to break the cycle. + if (!M_SecretUnlocked(SECRET_RECORDATTACK) // also if record attack is locked + || (mapheaderinfo[spmarathon_start-1] + && !mapheaderinfo[spmarathon_start-1]->marathonnext + && (mapheaderinfo[spmarathon_start-1]->nextlevel == spmarathon_start + || mapheaderinfo[spmarathon_start-1]->nextlevel >= 1100))) + SP_MainMenu[spmarathon].status = IT_NOTHING|IT_DISABLED; + else + SP_MainMenu[spmarathon].status = IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED; M_SetupNextMenu(&SP_MainDef); } @@ -8039,7 +8157,7 @@ static void M_StartTutorial(INT32 choice) emeralds = 0; memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); - gamecomplete = false; + gamecomplete = 0; cursaveslot = 0; G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false); } @@ -8149,13 +8267,13 @@ static void M_DrawLoadGameData(void) { if (charskin->prefoppositecolor) { - col = charskin->prefoppositecolor - 1; - col = Color_Index[col][Color_Opposite[Color_Opposite[col][0] - 1][1]]; + col = charskin->prefoppositecolor; + col = skincolors[col].ramp[skincolors[skincolors[col].invcolor].invshade]; } else { - col = charskin->prefcolor - 1; - col = Color_Index[Color_Opposite[col][0]-1][Color_Opposite[col][1]]; + col = charskin->prefcolor; + col = skincolors[skincolors[col].invcolor].ramp[skincolors[col].invshade]; } } @@ -8209,9 +8327,19 @@ static void M_DrawLoadGameData(void) V_DrawRightAlignedThinString(x + 79, y, V_YELLOWMAP, savegameinfo[savetodraw].levelname); } - if ((savegameinfo[savetodraw].lives == -42) - || (savegameinfo[savetodraw].lives == -666)) + if (savegameinfo[savetodraw].lives == -42) + { + if (!useContinues) + V_DrawRightAlignedThinString(x + 80, y+1+60+16, V_GRAYMAP, "00000000"); continue; + } + + if (savegameinfo[savetodraw].lives == -666) + { + if (!useContinues) + V_DrawRightAlignedThinString(x + 80, y+1+60+16, V_REDMAP, "????????"); + continue; + } y += 64; @@ -8228,7 +8356,7 @@ static void M_DrawLoadGameData(void) y -= 4; - // character heads, lives, and continues + // character heads, lives, and continues/score { spritedef_t *sprdef; spriteframe_t *sprframe; @@ -8279,10 +8407,14 @@ skipbot: skipsign: y += 16; - tempx = x + 10; - if (savegameinfo[savetodraw].lives != INFLIVES - && savegameinfo[savetodraw].lives > 9) - tempx -= 4; + tempx = x; + if (useContinues) + { + tempx += 10; + if (savegameinfo[savetodraw].lives != INFLIVES + && savegameinfo[savetodraw].lives > 9) + tempx -= 4; + } if (!charskin) // shut up compiler goto skiplife; @@ -8312,22 +8444,45 @@ skiplife: else V_DrawString(tempx, y, 0, va("%d", savegameinfo[savetodraw].lives)); - tempx = x + 47; - if (savegameinfo[savetodraw].continues > 9) - tempx -= 4; - - // continues - if (savegameinfo[savetodraw].continues > 0) + if (!useContinues) { - V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTSAVE", PU_PATCH)); - V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); - V_DrawString(tempx + 16, y, 0, va("%d", savegameinfo[savetodraw].continues)); + INT32 workingscorenum = savegameinfo[savetodraw].continuescore; + char workingscorestr[11] = " 000000000\0"; + SINT8 j = 9; + // Change the above two lines if MAXSCORE ever changes from 8 digits long. + workingscorestr[0] = '\x86'; // done here instead of in initialiser 'cuz compiler complains + if (!workingscorenum) + j--; // just so ONE digit is not greyed out + else + { + while (workingscorenum) + { + workingscorestr[j--] = '0' + (workingscorenum % 10); + workingscorenum /= 10; + } + } + workingscorestr[j] = (savegameinfo[savetodraw].continuescore == MAXSCORE) ? '\x83' : '\x80'; + V_DrawRightAlignedThinString(x + 80, y+1, 0, workingscorestr); } else { - V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTNONE", PU_PATCH)); - V_DrawScaledPatch(tempx + 9, y + 2, 0, W_CachePatchName("STNONEX", PU_PATCH)); - V_DrawString(tempx + 16, y, V_GRAYMAP, "0"); + tempx = x + 47; + if (savegameinfo[savetodraw].continuescore > 9) + tempx -= 4; + + // continues + if (savegameinfo[savetodraw].continuescore > 0) + { + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTSAVE", PU_PATCH)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); + V_DrawString(tempx + 16, y, 0, va("%d", savegameinfo[savetodraw].continuescore)); + } + else + { + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTNONE", PU_PATCH)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, W_CachePatchName("STNONEX", PU_PATCH)); + V_DrawString(tempx + 16, y, V_GRAYMAP, "0"); + } } } } @@ -8460,9 +8615,11 @@ static void M_ReadSavegameInfo(UINT32 slot) CHECKPOS savegameinfo[slot].lives = READSINT8(save_p); // lives CHECKPOS - (void)READINT32(save_p); // Score + savegameinfo[slot].continuescore = READINT32(save_p); // score CHECKPOS - savegameinfo[slot].continues = READINT32(save_p); // continues + fake = READINT32(save_p); // continues + if (useContinues) + savegameinfo[slot].continuescore = fake; // File end marker check CHECKPOS @@ -8763,7 +8920,7 @@ static void M_CacheCharacterSelect(void) { INT32 i, skinnum; - for (i = 0; i < 32; i++) + for (i = 0; i < MAXSKINS; i++) { if (!description[i].used) continue; @@ -8775,7 +8932,7 @@ static void M_CacheCharacterSelect(void) } } -static void M_SetupChoosePlayer(INT32 choice) +static UINT8 M_SetupChoosePlayerDirect(INT32 choice) { INT32 skinnum; UINT8 i; @@ -8786,7 +8943,7 @@ static void M_SetupChoosePlayer(INT32 choice) if (!mapheaderinfo[startmap-1] || mapheaderinfo[startmap-1]->forcecharacter[0] == '\0') { - for (i = 0; i < 32; i++) // Handle charsels, availability, and unlocks. + for (i = 0; i < MAXSKINS; i++) // Handle charsels, availability, and unlocks. { if (description[i].used) // If the character's disabled through SOC, there's nothing we can do for it. { @@ -8794,7 +8951,7 @@ static void M_SetupChoosePlayer(INT32 choice) if (and) { char firstskin[SKINNAMESIZE+1]; - if (mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS) // skip tagteam characters for NiGHTS levels + if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS) // skip tagteam characters for NiGHTS levels continue; strncpy(firstskin, description[i].skinname, (and - description[i].skinname)); firstskin[(and - description[i].skinname)] = '\0'; @@ -8831,37 +8988,17 @@ static void M_SetupChoosePlayer(INT32 choice) if (firstvalid == lastvalid) // We're being forced into a specific character, so might as well just skip it. { - M_ChoosePlayer(firstvalid); - return; + return firstvalid; } // One last bit of order we can't do in the iteration above. description[firstvalid].prev = lastvalid; description[lastvalid].next = firstvalid; - 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); if (!allowed) { char_on = firstvalid; - if (startchar > 0 && startchar < 32) + if (startchar > 0 && startchar < MAXSKINS) { INT16 workchar = startchar; while (workchar--) @@ -8869,6 +9006,33 @@ static void M_SetupChoosePlayer(INT32 choice) } } + return MAXSKINS; +} + +static void M_SetupChoosePlayer(INT32 choice) +{ + UINT8 skinset = M_SetupChoosePlayerDirect(choice); + if (skinset != MAXSKINS) + { + M_ChoosePlayer(skinset); + return; + } + + M_ChangeMenuMusic("_chsel", true); + + /* the menus suck -James */ + if (currentMenu == &SP_LoadDef)/* from save states */ + { + SP_PlayerDef.menuid = MTREE3(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER); + } + else/* from Secret level select */ + { + SP_PlayerDef.menuid = MTREE2(MN_SR_MAIN, MN_SR_PLAYER); + } + + SP_PlayerDef.prevMenu = currentMenu; + M_SetupNextMenu(&SP_PlayerDef); + // finish scrolling the menu char_scroll = 0; charseltimer = 0; @@ -8926,6 +9090,10 @@ static void M_HandleChoosePlayerMenu(INT32 choice) case KEY_ENTER: S_StartSound(NULL, sfx_menu1); + char_scroll = 0; // finish scrolling the menu + M_DrawSetupChoosePlayerMenu(); // draw the finally selected character one last time for the fadeout + // Is this a hack? + charseltimer = 0; M_ChoosePlayer(char_on); break; @@ -8957,7 +9125,7 @@ static void M_DrawSetupChoosePlayerMenu(void) skin_t *charskin = &skins[0]; INT32 skinnum = 0; - UINT8 col; + UINT16 col; UINT8 *colormap = NULL; INT32 prev = -1, next = -1; @@ -8996,10 +9164,10 @@ static void M_DrawSetupChoosePlayerMenu(void) // Use the opposite of the character's skincolor col = description[char_on].oppositecolor; if (!col) - col = Color_Opposite[charskin->prefcolor - 1][0]; + col = skincolors[charskin->prefcolor].invcolor; // Make the translation colormap - colormap = R_GetTranslationColormap(TC_DEFAULT, col, 0); + colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_CACHE); // Don't render the title map hidetitlemap = true; @@ -9047,8 +9215,8 @@ static void M_DrawSetupChoosePlayerMenu(void) 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; + UINT16 curtextcolor = 0, prevtextcolor = 0, nexttextcolor = 0; + UINT16 curoutlinecolor = 0, prevoutlinecolor = 0, nextoutlinecolor = 0; // Name tag curtext = description[char_on].displayname; @@ -9059,7 +9227,7 @@ static void M_DrawSetupChoosePlayerMenu(void) if (!curtextcolor) curtextcolor = charskin->prefcolor; if (!curoutlinecolor) - curoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + curoutlinecolor = col = skincolors[charskin->prefcolor].invcolor; txsh = oxsh; ox = 8 + SHORT((description[char_on].charpic)->width)/2; @@ -9075,8 +9243,8 @@ static void M_DrawSetupChoosePlayerMenu(void) { V_DrawNameTag( x, y, V_CENTERNAMETAG, FRACUNIT, - R_GetTranslationColormap(TC_DEFAULT, curtextcolor, 0), - R_GetTranslationColormap(TC_DEFAULT, curoutlinecolor, 0), + R_GetTranslationColormap(TC_DEFAULT, curtextcolor, GTC_CACHE), + R_GetTranslationColormap(TC_DEFAULT, curoutlinecolor, GTC_CACHE), curtext ); } @@ -9098,7 +9266,7 @@ static void M_DrawSetupChoosePlayerMenu(void) if (!prevtextcolor) prevtextcolor = charskin->prefcolor; if (!prevoutlinecolor) - prevoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + prevoutlinecolor = col = skincolors[charskin->prefcolor].invcolor; x = (ox - txsh) - w; if (prevpatch) @@ -9108,8 +9276,8 @@ static void M_DrawSetupChoosePlayerMenu(void) { V_DrawNameTag( x, y, V_CENTERNAMETAG, FRACUNIT, - R_GetTranslationColormap(TC_DEFAULT, prevtextcolor, 0), - R_GetTranslationColormap(TC_DEFAULT, prevoutlinecolor, 0), + R_GetTranslationColormap(TC_DEFAULT, prevtextcolor, GTC_CACHE), + R_GetTranslationColormap(TC_DEFAULT, prevoutlinecolor, GTC_CACHE), prevtext ); } @@ -9128,7 +9296,7 @@ static void M_DrawSetupChoosePlayerMenu(void) if (!nexttextcolor) nexttextcolor = charskin->prefcolor; if (!nextoutlinecolor) - nextoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + nextoutlinecolor = col = skincolors[charskin->prefcolor].invcolor; x = (ox - txsh) + w; if (nextpatch) @@ -9138,8 +9306,8 @@ static void M_DrawSetupChoosePlayerMenu(void) { V_DrawNameTag( x, y, V_CENTERNAMETAG, FRACUNIT, - R_GetTranslationColormap(TC_DEFAULT, nexttextcolor, 0), - R_GetTranslationColormap(TC_DEFAULT, nextoutlinecolor, 0), + R_GetTranslationColormap(TC_DEFAULT, nexttextcolor, GTC_CACHE), + R_GetTranslationColormap(TC_DEFAULT, nextoutlinecolor, GTC_CACHE), nexttext ); } @@ -9165,7 +9333,7 @@ static void M_DrawSetupChoosePlayerMenu(void) // Chose the player you want to use Tails 03-02-2002 static void M_ChoosePlayer(INT32 choice) { - boolean ultmode = (ultimate_selectable && SP_PlayerDef.prevMenu == &SP_LoadDef && saveSlotSelected == NOSAVESLOT); + boolean ultmode = (currentMenu == &SP_MarathonDef) ? (cv_dummymarathon.value == 2) : (ultimate_selectable && SP_PlayerDef.prevMenu == &SP_LoadDef && saveSlotSelected == NOSAVESLOT); UINT8 skinnum; // skip this if forcecharacter or no characters available @@ -9177,11 +9345,6 @@ static void M_ChoosePlayer(INT32 choice) // M_SetupChoosePlayer didn't call us directly, that means we've been properly set up. else { - char_scroll = 0; // finish scrolling the menu - M_DrawSetupChoosePlayerMenu(); // draw the finally selected character one last time for the fadeout - // Is this a hack? - charseltimer = 0; - skinnum = description[choice].skinnum[0]; if ((botingame = (description[choice].skinnum[1] != -1))) { @@ -9195,11 +9358,11 @@ static void M_ChoosePlayer(INT32 choice) M_ClearMenus(true); - if (startmap != spstage_start) + if (!marathonmode && startmap != spstage_start) cursaveslot = 0; //lastmapsaved = 0; - gamecomplete = false; + gamecomplete = 0; G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this @@ -9949,9 +10112,6 @@ 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_PATCH); - ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH); - 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); @@ -10071,13 +10231,13 @@ static void M_ReplayTimeAttack(INT32 choice) static void M_EraseGuest(INT32 choice) { const char *rguest = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); - (void)choice; - if (FIL_FileExists(rguest)) - remove(rguest); - if (currentMenu == &SP_NightsGuestReplayDef) - M_SetupNextMenu(&SP_NightsAttackDef); - else - M_SetupNextMenu(&SP_TimeAttackDef); + + if (choice == 'y' || choice == KEY_ENTER) + { + if (FIL_FileExists(rguest)) + remove(rguest); + } + M_SetupNextMenu(currentMenu->prevMenu->prevMenu); Nextmap_OnChange(); M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING); } @@ -10201,6 +10361,368 @@ static void M_ModeAttackEndGame(INT32 choice) Nextmap_OnChange(); } +static void M_MarathonLiveEventBackup(INT32 choice) +{ + if (choice == 'y' || choice == KEY_ENTER) + { + marathonmode = MA_INIT; + G_LoadGame(MARATHONSLOT, 0); + cursaveslot = MARATHONSLOT; + if (!(marathonmode & MA_RUNNING)) + marathonmode = 0; + return; + } + + M_StopMessage(0); + stopstopmessage = true; + + if (choice == KEY_DEL) + { + if (FIL_FileExists(liveeventbackup)) // just in case someone deleted it while we weren't looking. + remove(liveeventbackup); + BwehHehHe(); + M_StartMessage("Live event backup erased.\n",M_Marathon,MM_NOTHING); + return; + } + + M_Marathon(-1); +} + +// Going to Marathon menu... +static void M_Marathon(INT32 choice) +{ + UINT8 skinset; + INT32 mapnum = 0; + + if (choice != -1 && FIL_FileExists(liveeventbackup)) + { + M_StartMessage(\ + "\x82Live event backup detected.\n\x80\ + Do you want to resurrect the last run?\n\ + (Fs in chat if we crashed on stream.)\n\ + \n\ + Press 'Y' or 'Enter' to resume,\n\ + 'Del' to delete, or any other\n\ + key to continue to Marathon Run.",M_MarathonLiveEventBackup,MM_YESNO); + return; + } + + fromlevelselect = false; + + startmap = spmarathon_start; + CV_SetValue(&cv_newgametype, GT_COOP); // Graue 09-08-2004 + + skinset = M_SetupChoosePlayerDirect(-1); + + SP_MarathonMenu[marathonplayer].status = (skinset == MAXSKINS) ? IT_KEYHANDLER|IT_STRING : IT_NOTHING|IT_DISABLED; + + while (mapnum < NUMMAPS) + { + if (mapheaderinfo[mapnum]) + { + if (mapheaderinfo[mapnum]->cutscenenum || mapheaderinfo[mapnum]->precutscenenum) + break; + } + mapnum++; + } + + SP_MarathonMenu[marathoncutscenes].status = (mapnum < NUMMAPS) ? IT_CVAR|IT_STRING : IT_NOTHING|IT_DISABLED; + + M_ChangeMenuMusic("spec8", true); + + SP_MarathonDef.prevMenu = &MainDef; + 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_MarathonDef); + itemOn = marathonstart; // "Start" is selected. + recatkdrawtimer = 50-8; + char_scroll = 0; +} + +static void M_HandleMarathonChoosePlayer(INT32 choice) +{ + INT32 selectval; + + if (keydown > 1) + return; + + switch (choice) + { + case KEY_DOWNARROW: + M_NextOpt(); + break; + case KEY_UPARROW: + M_PrevOpt(); + break; + + case KEY_LEFTARROW: + if ((selectval = description[char_on].prev) == char_on) + return; + char_on = selectval; + break; + case KEY_RIGHTARROW: + if ((selectval = description[char_on].next) == char_on) + return; + char_on = selectval; + break; + + case KEY_ESCAPE: + noFurtherInput = true; + M_GoBack(0); + return; + + default: + return; + } + S_StartSound(NULL, sfx_menu1); +} + +static void M_StartMarathon(INT32 choice) +{ + (void)choice; + marathontime = 0; + marathonmode = MA_RUNNING|MA_INIT; + if (cv_dummymarathon.value == 1) + cursaveslot = MARATHONSLOT; + if (!cv_dummycutscenes.value) + marathonmode |= MA_NOCUTSCENES; + if (cv_dummyloadless.value) + marathonmode |= MA_INGAME; + M_ChoosePlayer(char_on); +} + +// Drawing function for Marathon menu +void M_DrawMarathon(void) +{ + INT32 i, x, y, cursory = 0, cnt, soffset = 0, w; + UINT16 dispstatus; + consvar_t *cv; + const char *cvstring; + char *work; + angle_t fa; + INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy), xspan = (vid.width/dupz), yspan = (vid.height/dupz), diffx = (xspan - BASEVIDWIDTH)/2, diffy = (yspan - BASEVIDHEIGHT)/2, maxy = BASEVIDHEIGHT + diffy; + + // lactozilla: the renderer changed so recache patches + if (needpatchrecache) + M_CacheCharacterSelect(); + + curbgxspeed = 0; + curbgyspeed = 18; + + M_ChangeMenuMusic("spec8", true); // Eww, but needed for when user hits escape during demo playback + + V_DrawFill(-diffx, -diffy, diffx+(BASEVIDWIDTH-190)/2, yspan, 158); + V_DrawFill((BASEVIDWIDTH-190)/2, -diffy, 190, yspan, 31); + V_DrawFill((BASEVIDWIDTH+190)/2, -diffy, diffx+(BASEVIDWIDTH-190)/2, yspan, 158); + //M_DrawRecordAttackForeground(); + if (curfadevalue) + V_DrawFadeScreen(0xFF00, curfadevalue); + + x = (((BASEVIDWIDTH-82)/2)+11)<>ANGLETOFINESHIFT) & FINEMASK; + y -= (10*FINECOSINE(fa)); + + recatkdrawtimer++; + + soffset = cnt = (recatkdrawtimer%50); + if (!useBlackRock) + { + if (cnt > 8) + cnt = 8; + V_DrawFixedPatch(x+(6< 8) + { + cnt = 8; + V_DrawFixedPatch(x, y, FRACUNIT, V_TRANSLUCENT, W_CachePatchName("ENDEGRK5", PU_PATCH), NULL); + } + else + { + V_DrawFixedPatch(x, y, FRACUNIT, cnt<= 160) + col = 253; + V_DrawFill(((BASEVIDWIDTH-190)/2)-cursory-w, -diffy, w, yspan, col); + V_DrawFill(((BASEVIDWIDTH+190)/2)+cursory, -diffy, w, yspan, col); + cursory += w; + w *= 2; + } + } + + w = char_scroll + (((8-cnt)*(8-cnt))<<(FRACBITS-5)); + if (soffset == 50-1) + w += FRACUNIT/2; + + { + patch_t *fg = W_CachePatchName("RECATKFG", PU_PATCH); + INT32 trans = V_60TRANS+((cnt&~3)<<(V_ALPHASHIFT-2)); + INT32 height = (SHORT(fg->height)/2); + char patchname[7] = "CEMGx0"; + + dupz = (w*7)/6; //(w*42*120)/(360*6); -- I don't know why this works but I'm not going to complain. + dupz = ((dupz>>FRACBITS) % height); + y = height/2; + while (y+dupz >= -diffy) + y -= height; + while (y-2-dupz < maxy) + { + V_DrawFixedPatch(((BASEVIDWIDTH-190)<<(FRACBITS-1)), (y-2-dupz)<>ANGLETOFINESHIFT) & FINEMASK; + x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINESINE(fa)); + y = ((BASEVIDHEIGHT+16-20)<<(FRACBITS-1)) - (60*FINECOSINE(fa)); + w += (360<>FRACBITS) % height); + y = dupz+(height/4); + x = 105+dupz; + while (y >= -diffy) + { + x -= height; + y -= height; + } + while (y-dupz < maxy && x < (xspan/2)) + { + V_DrawFill((BASEVIDWIDTH/2)-x-height, -diffy, height, diffy+y+height, 153); + V_DrawFill((BASEVIDWIDTH/2)+x, (maxy-y)-height, height, height+y, 153); + y += height; + x += height; + } + } + + if (!soffset) + { + char_scroll += (360<= 360< (10*TICRATE)) + recatkdrawtimer -= (10*TICRATE); + } + + //M_DrawMenuTitle(); + + // draw menu (everything else goes on top of it) + // Sadly we can't just use generic mode menus because we need some extra hacks + x = currentMenu->x; + y = currentMenu->y; + + dispstatus = (currentMenu->menuitems[marathonplayer].status & IT_DISPLAY); + if (dispstatus == IT_STRING || dispstatus == IT_WHITESTRING) + { + soffset = 68; + if (description[char_on].charpic->width >= 256) + V_DrawTinyScaledPatch(224, 120, 0, description[char_on].charpic); + else + V_DrawSmallScaledPatch(224, 120, 0, description[char_on].charpic); + } + else + soffset = 0; + + for (i = 0; i < currentMenu->numitems; ++i) + { + dispstatus = (currentMenu->menuitems[i].status & IT_DISPLAY); + if (dispstatus != IT_STRING && dispstatus != IT_WHITESTRING) + continue; + + y = currentMenu->y+currentMenu->menuitems[i].alphaKey; + if (i == itemOn) + cursory = y; + + V_DrawString(x, y, (dispstatus == IT_WHITESTRING) ? V_YELLOWMAP : 0 , currentMenu->menuitems[i].text); + + cv = NULL; + cvstring = NULL; + work = NULL; + if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_CVAR) + { + cv = (consvar_t *)currentMenu->menuitems[i].itemaction; + cvstring = cv->string; + } + else if (i == marathonplayer) + { + if (description[char_on].displayname[0]) + { + work = Z_StrDup(description[char_on].displayname); + cnt = 0; + while (work[cnt]) + { + if (work[cnt] == '\n') + work[cnt] = ' '; + cnt++; + } + cvstring = work; + } + else + cvstring = description[char_on].skinname; + } + + // Cvar specific handling + if (cvstring) + { + INT32 flags = V_YELLOWMAP; + if (cv == &cv_dummymarathon && cv->value == 2) // ultimate_selectable + flags = V_REDMAP; + + // Should see nothing but strings + if (cv == &cv_dummymarathon && cv->value == 1) + { + w = V_ThinStringWidth(cvstring, 0); + V_DrawThinString(BASEVIDWIDTH - x - soffset - w, y+1, flags, cvstring); + } + else + { + w = V_StringWidth(cvstring, 0); + V_DrawString(BASEVIDWIDTH - x - soffset - w, y, flags, cvstring); + } + if (i == itemOn) + { + V_DrawCharacter(BASEVIDWIDTH - x - soffset - 10 - w - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + } + if (work) + Z_Free(work); + } + } + + // DRAW THE SKULL CURSOR + V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_PATCH)); + V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); + + // Draw press ESC to exit string on main record attack menu + V_DrawString(104-72, 180, V_TRANSLUCENT, M_GetText("Press ESC to exit")); +} + // ======== // END GAME // ======== @@ -10366,7 +10888,7 @@ static void M_DrawConnectMenu(void) for (i = 0; i < min(serverlistcount - serverlistpage * SERVERS_PER_PAGE, SERVERS_PER_PAGE); i++) { INT32 slindex = i + serverlistpage * SERVERS_PER_PAGE; - UINT32 globalflags = ((serverlist[slindex].info.numberofplayer >= serverlist[slindex].info.maxplayer) ? V_TRANSLUCENT : 0) + UINT32 globalflags = (serverlist[slindex].info.refusereason ? V_TRANSLUCENT : 0) |((itemOn == FIRSTSERVERLINE+i) ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE; V_DrawString(currentMenu->x, S_LINEY(i), globalflags, serverlist[slindex].info.servername); @@ -10730,7 +11252,8 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[ 3].status = IT_GRAYEDOUT; // Allow add-on downloading OP_ServerOptionsMenu[ 4].status = IT_GRAYEDOUT; // Allow players to join OP_ServerOptionsMenu[35].status = IT_GRAYEDOUT; // Master server - OP_ServerOptionsMenu[36].status = IT_GRAYEDOUT; // Attempts to resynchronise + OP_ServerOptionsMenu[36].status = IT_GRAYEDOUT; // Minimum delay between joins + OP_ServerOptionsMenu[37].status = IT_GRAYEDOUT; // Attempts to resynchronise } else { @@ -10742,14 +11265,15 @@ static void M_ServerOptions(INT32 choice) ? IT_GRAYEDOUT : (IT_STRING | IT_CVAR | IT_CV_STRING)); OP_ServerOptionsMenu[36].status = IT_STRING | IT_CVAR; + OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR; } #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 ); + OP_ServerOptionsDef.menuid = MTREE2(MN_OP_MAIN, MN_OP_SERVER); else/* from Multiplayer menu */ - OP_ServerOptionsDef.menuid = MN_MP_MAIN + ( MN_MP_SERVER_OPTIONS << 6 ); + OP_ServerOptionsDef.menuid = MTREE2(MN_MP_MAIN, MN_MP_SERVER_OPTIONS); OP_ServerOptionsDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_ServerOptionsDef); @@ -10979,15 +11503,15 @@ static UINT8 multi_spr2; // this is set before entering the MultiPlayer setup menu, // for either player 1 or 2 -static char setupm_name[MAXPLAYERNAME+1]; -static player_t *setupm_player; -static consvar_t *setupm_cvskin; -static consvar_t *setupm_cvcolor; -static consvar_t *setupm_cvname; -static consvar_t *setupm_cvdefaultskin; -static consvar_t *setupm_cvdefaultcolor; -static INT32 setupm_fakeskin; -static INT32 setupm_fakecolor; +static char setupm_name[MAXPLAYERNAME+1]; +static player_t *setupm_player; +static consvar_t *setupm_cvskin; +static consvar_t *setupm_cvcolor; +static consvar_t *setupm_cvname; +static consvar_t *setupm_cvdefaultskin; +static consvar_t *setupm_cvdefaultcolor; +static INT32 setupm_fakeskin; +static menucolor_t *setupm_fakecolor; static void M_DrawSetupMultiPlayerMenu(void) { @@ -11054,11 +11578,11 @@ static void M_DrawSetupMultiPlayerMenu(void) sprdef = &skins[setupm_fakeskin].sprites[multi_spr2]; - if (!setupm_fakecolor || !sprdef->numframes) // should never happen but hey, who knows + if (!setupm_fakecolor->color || !sprdef->numframes) // should never happen but hey, who knows goto faildraw; // ok, draw player sprite for sure now - colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor, 0); + colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, 0); if (multi_frame >= sprdef->numframes) multi_frame = 0; @@ -11104,11 +11628,11 @@ colordraw: // draw color string V_DrawRightAlignedString(BASEVIDWIDTH - x, y, ((MP_PlayerSetupMenu[2].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|(itemOn == 2 ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, - Color_Names[setupm_fakecolor]); + skincolors[setupm_fakecolor->color].name); if (itemOn == 2 && (MP_PlayerSetupMenu[2].status & IT_TYPE) != IT_SPACE) { - V_DrawCharacter(BASEVIDWIDTH - x - 10 - V_StringWidth(Color_Names[setupm_fakecolor], V_ALLOWLOWERCASE) - (skullAnimCounter/5), y, + V_DrawCharacter(BASEVIDWIDTH - x - 10 - V_StringWidth(skincolors[setupm_fakecolor->color].name, V_ALLOWLOWERCASE) - (skullAnimCounter/5), y, '\x1C' | V_YELLOWMAP, false); V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, '\x1D' | V_YELLOWMAP, false); @@ -11118,25 +11642,39 @@ colordraw: #define indexwidth 8 { - const INT32 colwidth = (282-charw)/(2*indexwidth); - INT32 i = -colwidth; - INT16 col = setupm_fakecolor - colwidth; - INT32 w = indexwidth; + const INT32 numcolors = (282-charw)/(2*indexwidth); // Number of colors per side + INT32 w = indexwidth; // Width of a singular color block + menucolor_t *mc = setupm_fakecolor->prev; // Last accessed color UINT8 h; + INT16 i; - while (col < 1) - col += MAXSKINCOLORS-1; - while (i <= colwidth) - { - if (!(i++)) - w = charw; - else - w = indexwidth; + // Draw color in the middle + x += numcolors*w; + for (h = 0; h < 16; h++) + V_DrawFill(x, y+h, charw, 1, skincolors[setupm_fakecolor->color].ramp[h]); + + //Draw colors from middle to left + for (i=0; icolor].accessible) + mc = mc->prev; for (h = 0; h < 16; h++) - V_DrawFill(x, y+h, w, 1, Color_Index[col-1][h]); - if (++col >= MAXSKINCOLORS) - col -= MAXSKINCOLORS-1; + V_DrawFill(x, y+h, w, 1, skincolors[mc->color].ramp[h]); + mc = mc->prev; + } + + // Draw colors from middle to right + mc = setupm_fakecolor->next; + x += numcolors*w + charw; + for (i=0; icolor].accessible) + mc = mc->next; + for (h = 0; h < 16; h++) + V_DrawFill(x, y+h, w, 1, skincolors[mc->color].ramp[h]); x += w; + mc = mc->next; } } #undef charw @@ -11147,7 +11685,7 @@ colordraw: V_DrawString(x, y, ((R_SkinAvailable(setupm_cvdefaultskin->string) != setupm_fakeskin - || setupm_cvdefaultcolor->value != setupm_fakecolor) + || setupm_cvdefaultcolor->value != setupm_fakecolor->color) ? 0 : V_TRANSLUCENT) | ((itemOn == 3) ? V_YELLOWMAP : 0), @@ -11195,19 +11733,19 @@ static void M_HandleSetupMultiPlayer(INT32 choice) else if (itemOn == 2) // player color { S_StartSound(NULL,sfx_menu1); // Tails - setupm_fakecolor--; + setupm_fakecolor = setupm_fakecolor->prev; } break; case KEY_ENTER: if (itemOn == 3 && (R_SkinAvailable(setupm_cvdefaultskin->string) != setupm_fakeskin - || setupm_cvdefaultcolor->value != setupm_fakecolor)) + || setupm_cvdefaultcolor->value != setupm_fakecolor->color)) { S_StartSound(NULL,sfx_strpst); // you know what? always putting these in the buffer won't hurt anything. COM_BufAddText (va("%s \"%s\"\n",setupm_cvdefaultskin->name,skins[setupm_fakeskin].name)); - COM_BufAddText (va("%s %d\n",setupm_cvdefaultcolor->name,setupm_fakecolor)); + COM_BufAddText (va("%s %d\n",setupm_cvdefaultcolor->name,setupm_fakecolor->color)); break; } /* FALLTHRU */ @@ -11228,7 +11766,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice) else if (itemOn == 2) // player color { S_StartSound(NULL,sfx_menu1); // Tails - setupm_fakecolor++; + setupm_fakecolor = setupm_fakecolor->next; } break; @@ -11244,11 +11782,13 @@ static void M_HandleSetupMultiPlayer(INT32 choice) } else if (itemOn == 2) { - UINT8 col = skins[setupm_fakeskin].prefcolor; - if (setupm_fakecolor != col) + UINT16 col = skins[setupm_fakeskin].prefcolor; + if ((setupm_fakecolor->color != col) && skincolors[col].accessible) { S_StartSound(NULL,sfx_menu1); // Tails - setupm_fakecolor = col; + for (setupm_fakecolor=menucolorhead;;setupm_fakecolor=setupm_fakecolor->next) + if (setupm_fakecolor->color == col || setupm_fakecolor == menucolortail) + break; } } break; @@ -11276,10 +11816,14 @@ static void M_HandleSetupMultiPlayer(INT32 choice) } // check color - if (setupm_fakecolor < 1) - setupm_fakecolor = MAXSKINCOLORS-1; - if (setupm_fakecolor > MAXSKINCOLORS-1) - setupm_fakecolor = 1; + if (itemOn == 2 && !skincolors[setupm_fakecolor->color].accessible) { + if (choice == KEY_LEFTARROW) + while (!skincolors[setupm_fakecolor->color].accessible) + setupm_fakecolor = setupm_fakecolor->prev; + else if (choice == KEY_RIGHTARROW || choice == KEY_ENTER) + while (!skincolors[setupm_fakecolor->color].accessible) + setupm_fakecolor = setupm_fakecolor->next; + } if (exitmenu) { @@ -11311,7 +11855,10 @@ static void M_SetupMultiPlayer(INT32 choice) setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); if (setupm_fakeskin == -1) setupm_fakeskin = 0; - setupm_fakecolor = setupm_cvcolor->value; + + for (setupm_fakecolor=menucolorhead;;setupm_fakecolor=setupm_fakecolor->next) + if (setupm_fakecolor->color == setupm_cvcolor->value || setupm_fakecolor == menucolortail) + break; // disable skin changes if we can't actually change skins if (!CanChangeSkin(consoleplayer)) @@ -11352,7 +11899,10 @@ static void M_SetupMultiPlayer2(INT32 choice) setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); if (setupm_fakeskin == -1) setupm_fakeskin = 0; - setupm_fakecolor = setupm_cvcolor->value; + + for (setupm_fakecolor=menucolorhead;;setupm_fakecolor=setupm_fakecolor->next) + if (setupm_fakecolor->color == setupm_cvcolor->value || setupm_fakecolor == menucolortail) + break; // disable skin changes if we can't actually change skins if (splitscreen && !CanChangeSkin(secondarydisplayplayer)) @@ -11384,12 +11934,181 @@ static boolean M_QuitMultiPlayerMenu(void) setupm_name[l] =0; COM_BufAddText (va("%s \"%s\"\n",setupm_cvname->name,setupm_name)); } - // you know what? always putting these in the buffer won't hurt anything. COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin].name)); - COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor)); + // send color if changed + if (setupm_fakecolor->color != setupm_cvcolor->value) + COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor->color)); return true; } +void M_AddMenuColor(UINT16 color) { + menucolor_t *c; + + if (color >= numskincolors) { + CONS_Printf("M_AddMenuColor: color %d does not exist.",color); + return; + } + + c = (menucolor_t *)malloc(sizeof(menucolor_t)); + c->color = color; + if (menucolorhead == NULL) { + c->next = c; + c->prev = c; + menucolorhead = c; + menucolortail = c; + } else { + c->next = menucolorhead; + c->prev = menucolortail; + menucolortail->next = c; + menucolorhead->prev = c; + menucolortail = c; + } +} + +void M_MoveColorBefore(UINT16 color, UINT16 targ) { + menucolor_t *look, *c = NULL, *t = NULL; + + if (color == targ) + return; + if (color >= numskincolors) { + CONS_Printf("M_MoveColorBefore: color %d does not exist.",color); + return; + } + if (targ >= numskincolors) { + CONS_Printf("M_MoveColorBefore: target color %d does not exist.",targ); + return; + } + + for (look=menucolorhead;;look=look->next) { + if (look->color == color) + c = look; + else if (look->color == targ) + t = look; + if (c != NULL && t != NULL) + break; + if (look==menucolortail) + return; + } + + if (c == t->prev) + return; + + if (t==menucolorhead) + menucolorhead = c; + if (c==menucolortail) + menucolortail = c->prev; + + c->prev->next = c->next; + c->next->prev = c->prev; + + c->prev = t->prev; + c->next = t; + t->prev->next = c; + t->prev = c; +} + +void M_MoveColorAfter(UINT16 color, UINT16 targ) { + menucolor_t *look, *c = NULL, *t = NULL; + + if (color == targ) + return; + if (color >= numskincolors) { + CONS_Printf("M_MoveColorAfter: color %d does not exist.\n",color); + return; + } + if (targ >= numskincolors) { + CONS_Printf("M_MoveColorAfter: target color %d does not exist.\n",targ); + return; + } + + for (look=menucolorhead;;look=look->next) { + if (look->color == color) + c = look; + else if (look->color == targ) + t = look; + if (c != NULL && t != NULL) + break; + if (look==menucolortail) + return; + } + + if (t == c->prev) + return; + + if (t==menucolortail) + menucolortail = c; + else if (c==menucolortail) + menucolortail = c->prev; + + c->prev->next = c->next; + c->next->prev = c->prev; + + c->next = t->next; + c->prev = t; + t->next->prev = c; + t->next = c; +} + +UINT16 M_GetColorBefore(UINT16 color) { + menucolor_t *look; + + if (color >= numskincolors) { + CONS_Printf("M_GetColorBefore: color %d does not exist.\n",color); + return 0; + } + + for (look=menucolorhead;;look=look->next) { + if (look->color == color) + return look->prev->color; + if (look==menucolortail) + return 0; + } +} + +UINT16 M_GetColorAfter(UINT16 color) { + menucolor_t *look; + + if (color >= numskincolors) { + CONS_Printf("M_GetColorAfter: color %d does not exist.\n",color); + return 0; + } + + for (look=menucolorhead;;look=look->next) { + if (look->color == color) + return look->next->color; + if (look==menucolortail) + return 0; + } +} + +void M_InitPlayerSetupColors(void) { + UINT8 i; + numskincolors = SKINCOLOR_FIRSTFREESLOT; + menucolorhead = menucolortail = NULL; + for (i=0; inext; + free(tmp); + } else { + free(look); + return; + } + } + + menucolorhead = menucolortail = NULL; +} + // ================= // DATA OPTIONS MENU // ================= @@ -11666,8 +12385,8 @@ static void M_Setup1PControlsMenu(INT32 choice) OP_ChangeControlsMenu[27+3].status = IT_CALL|IT_STRING2; OP_ChangeControlsDef.prevMenu = &OP_P1ControlsDef; - OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove first level (<< 6) - OP_ChangeControlsDef.menuid |= MN_OP_P1CONTROLS << MENUBITS; // combine first level (<< 6) + OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level + OP_ChangeControlsDef.menuid |= MN_OP_P1CONTROLS << MENUBITS; // combine second level M_SetupNextMenu(&OP_ChangeControlsDef); } @@ -11697,8 +12416,8 @@ static void M_Setup2PControlsMenu(INT32 choice) OP_ChangeControlsMenu[27+3].status = IT_GRAYEDOUT2; OP_ChangeControlsDef.prevMenu = &OP_P2ControlsDef; - OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove first level (<< 6) - OP_ChangeControlsDef.menuid |= MN_OP_P2CONTROLS << MENUBITS; // combine first level (<< 6) + OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level + OP_ChangeControlsDef.menuid |= MN_OP_P2CONTROLS << MENUBITS; // combine second level M_SetupNextMenu(&OP_ChangeControlsDef); } @@ -12110,7 +12829,6 @@ static void M_VideoModeMenu(INT32 choice) static void M_DrawMainVideoMenu(void) { - M_DrawGenericScrollMenu(); if (itemOn < 8) // where it starts to go offscreen; change this number if you change the layout of the video menu { @@ -12481,9 +13199,12 @@ void M_QuitResponse(INT32 ch) if (ch != 'y' && ch != KEY_ENTER) return; + if (Playing()) + LUAh_GameQuit(); if (!(netgame || cv_debug)) { S_ResetCaptions(); + marathonmode = 0; mrand = M_RandomKey(sizeof(quitsounds)/sizeof(INT32)); if (quitsounds[mrand]) S_StartSound(NULL, quitsounds[mrand]); @@ -12507,85 +13228,3 @@ static void M_QuitSRB2(INT32 choice) (void)choice; M_StartMessage(quitmsg[M_RandomKey(NUM_QUITMESSAGES)], M_QuitResponse, MM_YESNO); } - -#ifdef HWRENDER -// ===================================================================== -// OpenGL specific options -// ===================================================================== - -#define FOG_COLOR_ITEM 1 -// =================== -// M_OGL_DrawFogMenu() -// =================== -static void M_OGL_DrawFogMenu(void) -{ - INT32 mx, my; - - mx = currentMenu->x; - my = currentMenu->y; - M_DrawGenericMenu(); // use generic drawer for cursor, items and title - V_DrawString(BASEVIDWIDTH - mx - V_StringWidth(cv_grfogcolor.string, 0), - my + currentMenu->menuitems[FOG_COLOR_ITEM].alphaKey, V_YELLOWMAP, cv_grfogcolor.string); - // blink cursor on FOG_COLOR_ITEM if selected - if (itemOn == FOG_COLOR_ITEM && skullAnimCounter < 4) - V_DrawCharacter(BASEVIDWIDTH - mx, - my + currentMenu->menuitems[FOG_COLOR_ITEM].alphaKey, '_' | 0x80,false); -} - -//=================== -// M_HandleFogColor() -//=================== -static void M_HandleFogColor(INT32 choice) -{ - size_t i, l; - char temp[8]; - boolean exitmenu = false; // exit to previous menu and send name change - - switch (choice) - { - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); - itemOn++; - break; - - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); - itemOn--; - break; - - case KEY_ESCAPE: - exitmenu = true; - break; - - case KEY_BACKSPACE: - S_StartSound(NULL, sfx_menu1); - strcpy(temp, cv_grfogcolor.string); - strcpy(cv_grfogcolor.zstring, "000000"); - l = strlen(temp)-1; - for (i = 0; i < l; i++) - cv_grfogcolor.zstring[i + 6 - l] = temp[i]; - break; - - default: - if ((choice >= '0' && choice <= '9') || (choice >= 'a' && choice <= 'f') - || (choice >= 'A' && choice <= 'F')) - { - S_StartSound(NULL, sfx_menu1); - strcpy(temp, cv_grfogcolor.string); - strcpy(cv_grfogcolor.zstring, "000000"); - l = strlen(temp); - for (i = 0; i < l; i++) - cv_grfogcolor.zstring[5 - i] = temp[l - i]; - cv_grfogcolor.zstring[5] = (char)choice; - } - break; - } - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} -#endif diff --git a/src/m_menu.h b/src/m_menu.h index 862303426..221f1fd3f 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,9 +15,10 @@ #ifndef __X_MENU__ #define __X_MENU__ +#include "doomstat.h" // for NUMGAMETYPES #include "d_event.h" #include "command.h" -#include "r_things.h" // for SKINNAMESIZE +#include "r_skins.h" // for SKINNAMESIZE #include "f_finale.h" // for ttmode_enum // @@ -30,6 +31,9 @@ #define MENUBITS 6 // Menu IDs sectioned by numeric places to signify hierarchy +/** + * IF YOU MODIFY THIS, MODIFY MENUTYPES_LIST[] IN dehacked.c TO MATCH. + */ typedef enum { MN_NONE, @@ -57,6 +61,8 @@ typedef enum MN_SP_NIGHTS_REPLAY, MN_SP_NIGHTS_GHOST, + MN_SP_MARATHON, + // Multiplayer MN_MP_MAIN, MN_MP_SPLITSCREEN, // SplitServer @@ -88,8 +94,6 @@ typedef enum MN_OP_COLOR, MN_OP_OPENGL, MN_OP_OPENGL_LIGHTING, - MN_OP_OPENGL_FOG, - MN_OP_OPENGL_COLOR, MN_OP_SOUND, @@ -128,6 +132,9 @@ typedef enum MN_SPECIAL, NUMMENUTYPES, } menutype_t; // up to 63; MN_SPECIAL = 53 +#define MTREE2(a,b) (a | (b< -#if (defined (NOMD5) || defined (NOMSERV)) && !defined (NONET) +#if (defined (NOMSERV)) && !defined (NONET) #define NONET #endif diff --git a/src/mserv.h b/src/mserv.h index b851aed30..5f9b8da5f 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -68,7 +68,7 @@ extern consvar_t cv_masterserver, cv_servername; // < 0 to not connect (usually -1) (offline mode) // == 0 to show all rooms, not a valid hosting room // anything else is whatever room the MS assigns to that number (online mode) -INT16 ms_RoomId; +extern INT16 ms_RoomId; const char *GetMasterServerPort(void); const char *GetMasterServerIP(void); diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 7031c287d..3c3c507cd 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -47,8 +47,7 @@ void T_MoveCeiling(ceiling_t *ceiling) case 0: // IN STASIS break; case 1: // UP - res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false, - 1, ceiling->direction); + res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false, true, ceiling->direction); if (ceiling->type == bounceCeiling) { @@ -159,8 +158,7 @@ void T_MoveCeiling(ceiling_t *ceiling) break; case -1: // DOWN - res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, - ceiling->crush, 1, ceiling->direction); + res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, true, ceiling->direction); if (ceiling->type == bounceCeiling) { @@ -314,11 +312,10 @@ void T_CrushCeiling(ceiling_t *ceiling) if (ceiling->type == crushBothOnce) { // Move the floor - T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight-(ceiling->topheight-ceiling->bottomheight), false, 0, -ceiling->direction); + T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight-(ceiling->topheight-ceiling->bottomheight), false, false, -ceiling->direction); } - res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, - false, 1, ceiling->direction); + res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false, true, ceiling->direction); if (res == pastdest) { @@ -357,11 +354,10 @@ void T_CrushCeiling(ceiling_t *ceiling) if (ceiling->type == crushBothOnce) { // Move the floor - T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, 0, -ceiling->direction); + T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, false, -ceiling->direction); } - res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, - ceiling->crush, 1, ceiling->direction); + res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, true, ceiling->direction); if (res == pastdest) { @@ -399,7 +395,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) sector_t *sec; ceiling_t *ceiling; - while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) { sec = §ors[secnum]; @@ -619,7 +615,7 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) sector_t *sec; ceiling_t *ceiling; - while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) { sec = §ors[secnum]; diff --git a/src/p_enemy.c b/src/p_enemy.c index 2ddbd8d29..a38496d99 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -21,7 +21,7 @@ #include "s_sound.h" #include "m_random.h" #include "m_misc.h" -#include "r_things.h" +#include "r_skins.h" #include "i_video.h" #include "z_zone.h" #include "lua_hook.h" @@ -30,9 +30,7 @@ #include "hardware/hw3sound.h" #endif -#ifdef HAVE_BLUA boolean LUA_CallAction(const char *action, mobj_t *actor); -#endif player_t *stplyr; INT32 var1; @@ -191,6 +189,7 @@ void A_SetTics(mobj_t *actor); void A_SetRandomTics(mobj_t *actor); void A_ChangeColorRelative(mobj_t *actor); void A_ChangeColorAbsolute(mobj_t *actor); +void A_Dye(mobj_t *actor); void A_MoveRelative(mobj_t *actor); void A_MoveAbsolute(mobj_t *actor); void A_Thrust(mobj_t *actor); @@ -313,6 +312,7 @@ void A_RolloutRock(mobj_t *actor); void A_DragonbomberSpawn(mobj_t *actor); void A_DragonWing(mobj_t *actor); void A_DragonSegment(mobj_t *actor); +void A_ChangeHeight(mobj_t *actor); //for p_enemy.c @@ -981,10 +981,8 @@ void A_Look(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Look", actor)) return; -#endif if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale))) return; @@ -1016,10 +1014,8 @@ void A_Chase(mobj_t *actor) INT32 delta; INT32 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Chase", actor)) return; -#endif I_Assert(actor != NULL); I_Assert(!P_MobjWasRemoved(actor)); @@ -1109,10 +1105,8 @@ void A_FaceStabChase(mobj_t *actor) { INT32 delta; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FaceStabChase", actor)) return; -#endif if (actor->reactiontime) actor->reactiontime--; @@ -1233,10 +1227,8 @@ void A_FaceStabRev(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FaceStabRev", actor)) return; -#endif if (!actor->target) { @@ -1278,10 +1270,8 @@ void A_FaceStabHurl(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FaceStabHurl", actor)) return; -#endif if (actor->target) { @@ -1368,13 +1358,10 @@ void A_FaceStabHurl(mobj_t *actor) // void A_FaceStabMiss(mobj_t *actor) { - //INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FaceStabMiss", actor)) return; -#endif if (++actor->extravalue1 >= 3) { @@ -1408,10 +1395,8 @@ void A_StatueBurst(mobj_t *actor) mobjtype_t chunktype = (mobjtype_t)actor->info->raisestate; mobj_t *new; -#ifdef HAVE_BLUA if (LUA_CallAction("A_StatueBurst", actor)) return; -#endif if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1))) return; @@ -1460,10 +1445,9 @@ void A_StatueBurst(mobj_t *actor) // void A_JetJawRoam(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_JetJawRoam", actor)) return; -#endif + if (actor->reactiontime) { actor->reactiontime--; @@ -1489,10 +1473,9 @@ void A_JetJawRoam(mobj_t *actor) void A_JetJawChomp(mobj_t *actor) { INT32 delta; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetJawChomp", actor)) return; -#endif // turn towards movement direction if not there yet if (actor->movedir < NUMDIRS) @@ -1538,10 +1521,9 @@ void A_PointyThink(mobj_t *actor) boolean firsttime = true; INT32 sign; -#ifdef HAVE_BLUA if (LUA_CallAction("A_PointyThink", actor)) return; -#endif + actor->momx = actor->momy = actor->momz = 0; // Find nearest player @@ -1637,10 +1619,9 @@ void A_CheckBuddy(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_CheckBuddy", actor)) return; -#endif + if (locvar1 && (!actor->tracer || actor->tracer->health <= 0)) P_RemoveMobj(actor); else if (!locvar1 && (!actor->target || actor->target->health <= 0)) @@ -1680,11 +1661,9 @@ void A_HoodFire(mobj_t *actor) { mobj_t *arrow; INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodFire", actor)) return; -#endif // Check target first. if (!actor->target) @@ -1714,10 +1693,9 @@ void A_HoodThink(mobj_t *actor) { fixed_t dx, dy, dz, dm; boolean checksight; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodThink", actor)) return; -#endif // Check target first. if (!actor->target) @@ -1783,10 +1761,8 @@ void A_HoodThink(mobj_t *actor) // void A_HoodFall(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_HoodFall", actor)) return; -#endif if (!P_IsObjectOnGround(actor)) return; @@ -1805,10 +1781,8 @@ void A_HoodFall(mobj_t *actor) // void A_ArrowBonks(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_ArrowBonks", actor)) return; -#endif if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) @@ -1830,10 +1804,8 @@ void A_ArrowBonks(mobj_t *actor) // void A_SnailerThink(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_SnailerThink", actor)) return; -#endif if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { @@ -1905,10 +1877,8 @@ void A_SnailerThink(mobj_t *actor) // void A_SharpChase(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_SharpChase", actor)) return; -#endif if (actor->reactiontime) { @@ -1963,10 +1933,8 @@ void A_SharpSpin(mobj_t *actor) INT32 locvar2 = var2; angle_t oldang = actor->angle; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SharpSpin", actor)) return; -#endif if (actor->threshold && actor->target) { @@ -1998,10 +1966,8 @@ void A_SharpSpin(mobj_t *actor) // void A_SharpDecel(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_SharpDecel", actor)) return; -#endif if (actor->momx > 2 || actor->momy > 2) { @@ -2024,10 +1990,9 @@ void A_CrushstaceanWalk(mobj_t *actor) INT32 locvar1 = (var1 ? var1 : (INT32)actor->info->speed); INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushstaceanWalk", actor)) return; -#endif actor->reactiontime--; @@ -2053,12 +2018,10 @@ void A_CrushstaceanWalk(mobj_t *actor) // void A_CrushstaceanPunch(mobj_t *actor) { - //INT32 locvar1 = var1; INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushstaceanPunch", actor)) return; -#endif if (!actor->tracer) return; @@ -2088,10 +2051,9 @@ void A_CrushclawAim(mobj_t *actor) INT32 locvar2 = var2; mobj_t *crab = actor->tracer; angle_t ang; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushclawAim", actor)) return; -#endif if (!crab) { @@ -2150,10 +2112,9 @@ void A_CrushclawLaunch(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; mobj_t *crab = actor->tracer; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushclawLaunch", actor)) return; -#endif if (!crab) { @@ -2283,10 +2244,8 @@ void A_CrushclawLaunch(mobj_t *actor) // void A_VultureVtol(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_VultureVtol", actor)) return; -#endif if (!actor->target) return; @@ -2320,10 +2279,8 @@ void A_VultureVtol(mobj_t *actor) // void A_VultureCheck(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_VultureCheck", actor)) return; -#endif if (actor->momx || actor->momy) return; @@ -2378,10 +2335,8 @@ void A_VultureHover(mobj_t *actor) fixed_t memz = actor->z; SINT8 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_VultureHover", actor)) return; -#endif if (!actor->target || P_MobjWasRemoved(actor->target)) { @@ -2442,10 +2397,8 @@ void A_VultureBlast(mobj_t *actor) angle_t faa; fixed_t faacos, faasin; -#ifdef HAVE_BLUA if (LUA_CallAction("A_VultureBlast", actor)) return; -#endif S_StartSound(actor, actor->info->attacksound); @@ -2483,10 +2436,8 @@ void A_VultureFly(mobj_t *actor) mobj_t *dust; fixed_t momm; -#ifdef HAVE_BLUA if (LUA_CallAction("A_VultureFly", actor)) return; -#endif if (!actor->target || P_MobjWasRemoved(actor->target)) { @@ -2577,10 +2528,9 @@ void A_SkimChase(mobj_t *actor) { INT32 delta; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SkimChase", actor)) return; -#endif + if (actor->reactiontime) actor->reactiontime--; @@ -2664,10 +2614,9 @@ nomissile: // void A_FaceTarget(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_FaceTarget", actor)) return; -#endif + if (!actor->target) return; @@ -2683,10 +2632,9 @@ void A_FaceTarget(mobj_t *actor) // void A_FaceTracer(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_FaceTracer", actor)) return; -#endif + if (!actor->tracer) return; @@ -2713,10 +2661,9 @@ void A_LobShot(mobj_t *actor) fixed_t vertical, horizontal; fixed_t airtime = var2 & 65535; -#ifdef HAVE_BLUA if (LUA_CallAction("A_LobShot", actor)) return; -#endif + if (!actor->target) return; @@ -2814,10 +2761,9 @@ void A_FireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FireShot", actor)) return; -#endif + if (!actor->target) return; @@ -2853,10 +2799,9 @@ void A_SuperFireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SuperFireShot", actor)) return; -#endif + if (!actor->target) return; @@ -2901,10 +2846,9 @@ void A_BossFireShot(mobj_t *actor) INT32 locvar2 = var2; mobj_t *missile; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BossFireShot", actor)) return; -#endif + if (!actor->target) return; @@ -2986,10 +2930,8 @@ void A_Boss7FireMissiles(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss7FireMissiles", actor)) return; -#endif if (!actor->target) { @@ -3049,11 +2991,23 @@ void A_Boss1Laser(mobj_t *actor) angle_t angle; mobj_t *point; tic_t dur; + static const UINT8 LASERCOLORS[] = + { + SKINCOLOR_SUPERRED3, + SKINCOLOR_SUPERRED4, + SKINCOLOR_SUPERRED5, + SKINCOLOR_FLAME, + SKINCOLOR_RED, + SKINCOLOR_RED, + SKINCOLOR_FLAME, + SKINCOLOR_SUPERRED5, + SKINCOLOR_SUPERRED4, + SKINCOLOR_SUPERRED3, + }; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss1Laser", actor)) return; -#endif + if (!actor->target) return; @@ -3124,7 +3078,7 @@ void A_Boss1Laser(mobj_t *actor) point = P_SpawnMobj(x, y, z, locvar1); P_SetTarget(&point->target, actor); point->angle = actor->angle; - speed = point->radius*2; + speed = point->radius; point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed); point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed)); point->momy = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINESINE(point->angle>>ANGLETOFINESHIFT), speed)); @@ -3133,23 +3087,69 @@ void A_Boss1Laser(mobj_t *actor) { mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type); mo->angle = point->angle; + mo->color = LASERCOLORS[((UINT8)(i + 3*dur) >> 2) % sizeof(LASERCOLORS)]; // codeing P_UnsetThingPosition(mo); - mo->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY; + mo->flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY; P_SetThingPosition(mo); + if (dur & 1 && mo->info->missilestate) + { + P_SetMobjState(mo, mo->info->missilestate); + if (mo->info->meleestate) + { + mobj_t *mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_PARTICLE); + mo2->flags2 |= MF2_LINKDRAW; + P_SetTarget(&mo2->tracer, actor); + P_SetMobjState(mo2, mo->info->meleestate); + } + } + + if (dur == 1) + P_SpawnGhostMobj(mo); + x = point->x, y = point->y, z = point->z; if (P_RailThinker(point)) break; } + x += point->momx; + y += point->momy; floorz = P_FloorzAtPos(x, y, z, mobjinfo[MT_EGGMOBILE_FIRE].height); - if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1) + if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1 && dur & 1) { - point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE); + point = P_SpawnMobj(x, y, floorz, MT_EGGMOBILE_FIRE); + point->angle = actor->angle; + point->destscale = actor->scale; + P_SetScale(point, point->destscale); P_SetTarget(&point->target, actor); - point->destscale = 3*FRACUNIT; - point->scalespeed = FRACUNIT>>2; - point->fuse = TICRATE; + P_MobjCheckWater(point); + if (point->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) + { + for (i = 0; i < 2; i++) + { + UINT8 size = 3; + mobj_t *steam = P_SpawnMobj(x, y, point->watertop - size*mobjinfo[MT_DUST].height, MT_DUST); + P_SetScale(steam, size*actor->scale); + P_SetObjectMomZ(steam, FRACUNIT + 2*P_RandomFixed(), true); + P_InstaThrust(steam, FixedAngle(P_RandomKey(360)*FRACUNIT), 2*P_RandomFixed()); + if (point->info->painsound) + S_StartSound(steam, point->info->painsound); + } + } + else + { + fixed_t distx = P_ReturnThrustX(point, point->angle, point->radius); + fixed_t disty = P_ReturnThrustY(point, point->angle, point->radius); + if (P_TryMove(point, point->x + distx, point->y + disty, false) // prevents the sprite from clipping into the wall or dangling off ledges + && P_TryMove(point, point->x - 2*distx, point->y - 2*disty, false) + && P_TryMove(point, point->x + distx, point->y + disty, false)) + { + if (point->info->seesound) + S_StartSound(point, point->info->seesound); + } + else + P_RemoveMobj(point); + } } if (dur > 1) @@ -3175,10 +3175,9 @@ void A_FocusTarget(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FocusTarget", actor)) return; -#endif if (actor->target) { @@ -3227,10 +3226,10 @@ void A_Boss4Reverse(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; sfxenum_t locvar2 = (sfxenum_t)var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss4Reverse", actor)) return; -#endif + actor->reactiontime = 0; if (actor->movedir < 3) { @@ -3262,10 +3261,10 @@ void A_Boss4Reverse(mobj_t *actor) void A_Boss4SpeedUp(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss4SpeedUp", actor)) return; -#endif + S_StartSound(NULL, locvar1); actor->reactiontime = 2; } @@ -3280,10 +3279,10 @@ void A_Boss4SpeedUp(mobj_t *actor) void A_Boss4Raise(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss4Raise", actor)) return; -#endif + S_StartSound(NULL, locvar1); actor->reactiontime = 1; } @@ -3312,10 +3311,9 @@ void A_SkullAttack(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SkullAttack", actor)) return; -#endif + if (!actor->target) return; @@ -3431,10 +3429,9 @@ void A_BossZoom(mobj_t *actor) angle_t an; INT32 dist; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BossZoom", actor)) return; -#endif + if (!actor->target) return; @@ -3472,10 +3469,9 @@ void A_BossScream(mobj_t *actor) INT32 locvar2 = var2; mobjtype_t explodetype; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BossScream", actor)) return; -#endif + if (locvar1 & 1) fa = (FixedAngle(P_RandomKey(360)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; else @@ -3518,10 +3514,9 @@ void A_BossScream(mobj_t *actor) // void A_Scream(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Scream", actor)) return; -#endif + if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) S_StartScreamSound(actor, sfx_mario2); else if (actor->info->deathsound) @@ -3537,10 +3532,9 @@ void A_Scream(mobj_t *actor) // void A_Pain(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Pain", actor)) return; -#endif + if (actor->info->painsound) S_StartSound(actor, actor->info->painsound); @@ -3559,10 +3553,9 @@ void A_Fall(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Fall", actor)) return; -#endif + // actor is on ground, it can be walked over actor->flags &= ~MF_SOLID; @@ -3592,10 +3585,9 @@ void A_1upThinker(mobj_t *actor) fixed_t temp; INT32 closestplayer = -1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_1upThinker", actor)) return; -#endif + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].bot || players[i].spectator) @@ -3659,10 +3651,8 @@ void A_MonitorPop(mobj_t *actor) mobjtype_t item = 0; mobj_t *newmobj; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MonitorPop", actor)) return; -#endif // Spawn the "pop" explosion. if (actor->info->deathsound) @@ -3742,10 +3732,8 @@ void A_GoldMonitorPop(mobj_t *actor) mobjtype_t item = 0; mobj_t *newmobj; -#ifdef HAVE_BLUA if (LUA_CallAction("A_GoldMonitorPop", actor)) return; -#endif // Don't spawn the "pop" explosion, because the monitor isn't broken. if (actor->info->deathsound) @@ -3827,10 +3815,8 @@ void A_GoldMonitorPop(mobj_t *actor) // void A_GoldMonitorRestore(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_GoldMonitorRestore", actor)) return; -#endif actor->flags |= MF_MONITOR|MF_SHOOTABLE; actor->health = 1; // Just in case. @@ -3847,10 +3833,8 @@ void A_GoldMonitorSparkle(mobj_t *actor) { fixed_t i, ngangle, xofs, yofs; -#ifdef HAVE_BLUA if (LUA_CallAction("A_GoldMonitorSparkle", actor)) return; -#endif ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS); xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); @@ -3870,10 +3854,10 @@ void A_GoldMonitorSparkle(mobj_t *actor) void A_Explode(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Explode", actor)) return; -#endif + P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1); } @@ -3890,10 +3874,9 @@ void A_BossDeath(mobj_t *mo) mobj_t *mo2; line_t junk; INT32 i; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossDeath", mo)) return; -#endif if (mo->spawnpoint && mo->spawnpoint->extrainfo) P_LinedefExecute(LE_BOSSDEAD+(mo->spawnpoint->extrainfo*LE_PARAMWIDTH), mo, NULL); @@ -3973,12 +3956,10 @@ void A_BossDeath(mobj_t *mo) } bossjustdie: -#ifdef HAVE_BLUA if (LUAh_BossDeath(mo)) return; else if (P_MobjWasRemoved(mo)) return; -#endif // Spawn your junk switch (mo->type) @@ -4202,10 +4183,9 @@ void A_CustomPower(mobj_t *actor) INT32 locvar2 = var2; boolean spawnshield = false; -#ifdef HAVE_BLUA if (LUA_CallAction("A_CustomPower", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4243,10 +4223,9 @@ void A_GiveWeapon(mobj_t *actor) player_t *player; INT32 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_GiveWeapon", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4277,10 +4256,9 @@ void A_RingBox(mobj_t *actor) { player_t *player; -#ifdef HAVE_BLUA if (LUA_CallAction("A_RingBox", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4305,10 +4283,9 @@ void A_Invincibility(mobj_t *actor) { player_t *player; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Invincibility", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4339,10 +4316,9 @@ void A_SuperSneakers(mobj_t *actor) { player_t *player; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SuperSneakers", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4375,10 +4351,9 @@ void A_AwardScore(mobj_t *actor) { player_t *player; -#ifdef HAVE_BLUA if (LUA_CallAction("A_AwardScore", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4403,10 +4378,9 @@ void A_ExtraLife(mobj_t *actor) { player_t *player; -#ifdef HAVE_BLUA if (LUA_CallAction("A_ExtraLife", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4442,10 +4416,9 @@ void A_GiveShield(mobj_t *actor) player_t *player; UINT16 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_GiveShield", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4469,10 +4442,9 @@ void A_GravityBox(mobj_t *actor) { player_t *player; -#ifdef HAVE_BLUA if (LUA_CallAction("A_GravityBox", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -4495,10 +4467,9 @@ void A_GravityBox(mobj_t *actor) // void A_ScoreRise(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_ScoreRise", actor)) return; -#endif + // make logo rise! P_SetObjectMomZ(actor, actor->info->speed, false); } @@ -4515,10 +4486,9 @@ void A_BunnyHop(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BunnyHop", actor)) return; -#endif + if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) { @@ -4539,10 +4509,10 @@ void A_BubbleSpawn(mobj_t *actor) INT32 i, locvar1 = var1; UINT8 prandom; mobj_t *bubble = NULL; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_BubbleSpawn", actor)) return; -#endif + if (!(actor->eflags & MFE_UNDERWATER)) { // Don't draw or spawn bubbles above water @@ -4592,10 +4562,10 @@ void A_FanBubbleSpawn(mobj_t *actor) UINT8 prandom; mobj_t *bubble = NULL; fixed_t hz = actor->z + (4*actor->height)/5; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FanBubbleSpawn", actor)) return; -#endif + if (!(actor->eflags & MFE_UNDERWATER)) return; @@ -4639,10 +4609,9 @@ void A_BubbleRise(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BubbleRise", actor)) return; -#endif + if (actor->type == MT_EXTRALARGEBUBBLE) P_SetObjectMomZ(actor, FixedDiv(6*FRACUNIT,5*FRACUNIT), false); // make bubbles rise! else @@ -4676,10 +4645,9 @@ void A_BubbleRise(mobj_t *actor) // void A_BubbleCheck(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_BubbleCheck", actor)) return; -#endif + if (actor->eflags & MFE_UNDERWATER) actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw else @@ -4695,10 +4663,9 @@ void A_BubbleCheck(mobj_t *actor) // void A_AttractChase(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_AttractChase", actor)) return; -#endif + if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) return; @@ -4766,10 +4733,9 @@ void A_DropMine(mobj_t *actor) INT32 locvar2 = var2; fixed_t z; mobj_t *mine; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_DropMine", actor)) return; -#endif if (locvar2 & 65535) { @@ -4815,10 +4781,9 @@ void A_FishJump(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FishJump", actor)) return; -#endif if (locvar2) { @@ -4867,10 +4832,9 @@ void A_ThrownRing(mobj_t *actor) INT32 stop; player_t *player; fixed_t dist; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ThrownRing", actor)) return; -#endif if (leveltime % (TICRATE/7) == 0) { @@ -4986,7 +4950,7 @@ void A_ThrownRing(mobj_t *actor) continue; // Don't home in on teammates. - if ((gametyperules & GTR_TEAMFLAGS) + if ((gametyperules & GTR_TEAMS) && actor->target->player->ctfteam == player->ctfteam) continue; } @@ -5025,10 +4989,9 @@ void A_ThrownRing(mobj_t *actor) // void A_SetSolidSteam(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_SetSolidSteam", actor)) return; -#endif + actor->flags &= ~MF_NOCLIP; actor->flags |= MF_SOLID; if (!(actor->flags2 & MF2_AMBUSH)) @@ -5057,10 +5020,9 @@ void A_SetSolidSteam(mobj_t *actor) // void A_UnsetSolidSteam(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_UnsetSolidSteam", actor)) return; -#endif + actor->flags &= ~MF_SOLID; actor->flags |= MF_NOCLIP; } @@ -5078,10 +5040,8 @@ void A_SignSpin(mobj_t *actor) INT16 i; angle_t rotateangle = FixedAngle(locvar1 << FRACBITS); -#ifdef HAVE_BLUA if (LUA_CallAction("A_SignSpin", actor)) return; -#endif if (P_IsObjectOnGround(actor) && P_MobjFlip(actor) * actor->momz <= 0) { @@ -5146,15 +5106,15 @@ void A_SignPlayer(mobj_t *actor) INT32 locvar2 = var2; skin_t *skin = NULL; mobj_t *ov; - UINT8 facecolor, signcolor = (UINT8)locvar2; + UINT16 facecolor, signcolor = 0; UINT32 signframe = states[actor->info->raisestate].frame; -#ifdef HAVE_BLUA + facecolor = signcolor = (UINT16)locvar2; + if (LUA_CallAction("A_SignPlayer", actor)) return; -#endif - if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins || signcolor >= MAXTRANSLATIONS) + if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins || signcolor >= numskincolors) return; // if no face overlay, spawn one @@ -5182,12 +5142,10 @@ void A_SignPlayer(mobj_t *actor) ; else if (!skin->sprites[SPR2_SIGN].numframes) signcolor = facecolor; - else if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor? + else if ((facecolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor? signcolor = skin->prefoppositecolor; - else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor. - signcolor = Color_Opposite[actor->target->player->skincolor - 1][0]; - else - signcolor = SKINCOLOR_NONE; + else if (facecolor) // Set the sign to be an appropriate background color for this player's skincolor. + signcolor = skincolors[facecolor].invcolor; } else if (locvar1 != -3) // set to a defined skin { @@ -5223,7 +5181,7 @@ void A_SignPlayer(mobj_t *actor) else if (skin->prefoppositecolor) signcolor = skin->prefoppositecolor; else if (facecolor) - signcolor = Color_Opposite[facecolor - 1][0]; + signcolor = skincolors[facecolor].invcolor; } if (skin) @@ -5251,22 +5209,12 @@ void A_SignPlayer(mobj_t *actor) P_SetMobjState(ov, actor->info->meleestate); // S_EGGMANSIGN if (!signcolor) signcolor = SKINCOLOR_CARBON; + facecolor = signcolor; } actor->tracer->color = signcolor; - /* - If you're here from the comment above Color_Opposite, - the following line is the one which is dependent on the - array being symmetrical. It gets the opposite of the - opposite of your desired colour just so it can get the - brightness frame for the End Sign. It's not a great - design choice, but it's constant time array access and - the idea that the colours should be OPPOSITES is kind - of in the name. If you have a better idea, feel free - to let me know. ~toast 2016/07/20 - */ - if (signcolor && signcolor < MAXSKINCOLORS) - signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]); + if (signcolor && signcolor < numskincolors) + signframe += (15 - skincolors[facecolor].invshade); actor->tracer->frame = signframe; } @@ -5280,10 +5228,10 @@ void A_SignPlayer(mobj_t *actor) void A_OverlayThink(mobj_t *actor) { fixed_t destx, desty; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_OverlayThink", actor)) return; -#endif + if (!actor->target) return; @@ -5332,10 +5280,9 @@ void A_OverlayThink(mobj_t *actor) void A_JetChase(mobj_t *actor) { fixed_t thefloor; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetChase", actor)) return; -#endif if (actor->flags2 & MF2_AMBUSH) return; @@ -5429,10 +5376,9 @@ void A_JetbThink(mobj_t *actor) { sector_t *nextsector; fixed_t thefloor; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetbThink", actor)) return; -#endif if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) @@ -5495,10 +5441,9 @@ void A_JetbThink(mobj_t *actor) void A_JetgShoot(mobj_t *actor) { fixed_t dist; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetgShoot", actor)) return; -#endif if (!actor->target) return; @@ -5536,10 +5481,9 @@ void A_JetgShoot(mobj_t *actor) void A_ShootBullet(mobj_t *actor) { fixed_t dist; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ShootBullet", actor)) return; -#endif if (!actor->target) return; @@ -5598,10 +5542,8 @@ void A_MinusDigging(mobj_t *actor) fixed_t mz = (actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz : actor->floorz; mobj_t *par; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MinusDigging", actor)) return; -#endif if (!actor->target) { @@ -5681,10 +5623,8 @@ void A_MinusPopup(mobj_t *actor) angle_t ani = FixedAngle(FRACUNIT*360/num); INT32 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MinusPopup", actor)) return; -#endif if (actor->eflags & MFE_VERTICALFLIP) actor->momz = -10*FRACUNIT; @@ -5718,10 +5658,8 @@ void A_MinusCheck(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MinusCheck", actor)) return; -#endif if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) { @@ -5751,10 +5689,9 @@ void A_MinusCheck(mobj_t *actor) // void A_ChickenCheck(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_ChickenCheck", actor)) return; -#endif + if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) || (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz)) { @@ -5782,10 +5719,9 @@ void A_JetgThink(mobj_t *actor) sector_t *nextsector; fixed_t thefloor; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetgThink", actor)) return; -#endif if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) @@ -5834,10 +5770,8 @@ void A_JetgThink(mobj_t *actor) // void A_MouseThink(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_MouseThink", actor)) return; -#endif if (actor->reactiontime) actor->reactiontime--; @@ -5872,10 +5806,9 @@ void A_DetonChase(mobj_t *actor) { angle_t exact; fixed_t xydist, dist; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_DetonChase", actor)) return; -#endif // modify tracer threshold if (!actor->tracer || actor->tracer->health <= 0) @@ -6020,10 +5953,9 @@ void A_CapeChase(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; angle_t angle; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CapeChase", actor)) return; -#endif CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -6081,10 +6013,9 @@ void A_RotateSpikeBall(mobj_t *actor) { INT32 locvar1 = var1; const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RotateSpikeBall", actor)) return; -#endif if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen. { @@ -6134,10 +6065,8 @@ void A_UnidusBall(mobj_t *actor) INT32 locvar1 = var1; boolean canthrow = false; -#ifdef HAVE_BLUA if (LUA_CallAction("A_UnidusBall", actor)) return; -#endif actor->angle += ANGLE_11hh; @@ -6232,10 +6161,9 @@ void A_RockSpawn(mobj_t *actor) line_t *line; fixed_t dist; fixed_t randomoomph; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RockSpawn", actor)) return; -#endif if (i == -1) { @@ -6286,10 +6214,9 @@ void A_SlingAppear(mobj_t *actor) { UINT8 mlength = 4; mobj_t *spawnee, *hprev; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SlingAppear", actor)) return; -#endif P_UnsetThingPosition(actor); actor->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT); @@ -6337,10 +6264,9 @@ void A_SetFuse(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetFuse", actor)) return; -#endif if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value actor->fuse = locvar1; @@ -6367,10 +6293,9 @@ void A_CrawlaCommanderThink(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; boolean hovermode = (actor->health > 1 || actor->fuse); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrawlaCommanderThink", actor)) return; -#endif if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) @@ -6526,10 +6451,9 @@ void A_RingExplode(mobj_t *actor) mobj_t *mo2; thinker_t *th; angle_t d; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RingExplode", actor)) return; -#endif for (d = 0; d < 16; d++) P_SpawnParaloop(actor->x, actor->y, actor->z + actor->height, FixedMul(actor->info->painchance, actor->scale), 16, MT_NIGHTSPARKLE, S_NULL, d*(ANGLE_22h), true); @@ -6571,12 +6495,10 @@ void A_OldRingExplode(mobj_t *actor) { mobj_t *mo; const fixed_t ns = FixedMul(20 * FRACUNIT, actor->scale); INT32 locvar1 = var1; - //INT32 locvar2 = var2; boolean changecolor = (actor->target && actor->target->player); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_OldRingExplode", actor)) return; -#endif for (i = 0; i < 32; i++) { @@ -6601,7 +6523,7 @@ void A_OldRingExplode(mobj_t *actor) { if (changecolor) { - if (!(gametyperules & GTR_TEAMFLAGS)) + if (!(gametyperules & GTR_TEAMS)) mo->color = actor->target->color; //copy color else if (actor->target->player->ctfteam == 2) mo->color = skincolor_bluering; @@ -6617,7 +6539,7 @@ void A_OldRingExplode(mobj_t *actor) { if (changecolor) { - if (!(gametyperules & GTR_TEAMFLAGS)) + if (!(gametyperules & GTR_TEAMS)) mo->color = actor->target->color; //copy color else if (actor->target->player->ctfteam == 2) mo->color = skincolor_bluering; @@ -6632,7 +6554,7 @@ void A_OldRingExplode(mobj_t *actor) { if (changecolor) { - if (!(gametyperules & GTR_TEAMFLAGS)) + if (!(gametyperules & GTR_TEAMS)) mo->color = actor->target->color; //copy color else if (actor->target->player->ctfteam == 2) mo->color = skincolor_bluering; @@ -6650,12 +6572,9 @@ void A_MixUp(mobj_t *actor) { boolean teleported[MAXPLAYERS]; INT32 i, numplayers = 0, prandom = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_MixUp", actor)) return; -#else - (void)actor; -#endif if (!multiplayer) return; @@ -6896,13 +6815,8 @@ void A_MixUp(mobj_t *actor) P_SetThingPosition(players[i].mo); -#ifdef ESLOPE players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); -#else - players[i].mo->floorz = players[i].mo->subsector->sector->floorheight; - players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight; -#endif P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y); } @@ -6934,15 +6848,8 @@ void A_RecyclePowers(mobj_t *actor) INT32 weapons[MAXPLAYERS]; INT32 weaponheld[MAXPLAYERS]; -#ifdef HAVE_BLUA if (LUA_CallAction("A_RecyclePowers", actor)) return; -#endif - -#if !defined(WEIGHTEDRECYCLER) && !defined(HAVE_BLUA) - // actor is used in all scenarios but this one, funny enough - (void)actor; -#endif if (!multiplayer) { @@ -7069,10 +6976,9 @@ void A_RecyclePowers(mobj_t *actor) void A_Boss1Chase(mobj_t *actor) { INT32 delta; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss1Chase", actor)) return; -#endif if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { @@ -7193,10 +7099,9 @@ void A_Boss2Chase(mobj_t *actor) fixed_t radius; boolean reverse = false; INT32 speedvar; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2Chase", actor)) return; -#endif if (actor->health <= 0) return; @@ -7321,10 +7226,9 @@ void A_Boss2Chase(mobj_t *actor) // void A_Boss2Pogo(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss2Pogo", actor)) return; -#endif + if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0) { if (actor->state != &states[actor->info->raisestate]) @@ -7369,10 +7273,10 @@ void A_Boss2Pogo(mobj_t *actor) void A_Boss2TakeDamage(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2TakeDamage", actor)) return; -#endif + A_Pain(actor); actor->reactiontime = 1; // turn around if (locvar1 == 0) // old A_Invincibilerize behavior @@ -7392,10 +7296,9 @@ void A_Boss7Chase(mobj_t *actor) { INT32 delta; INT32 i; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss7Chase", actor)) return; -#endif if (actor->z != actor->floorz) return; @@ -7524,10 +7427,9 @@ void A_Boss7Chase(mobj_t *actor) // void A_GoopSplat(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_GoopSplat", actor)) return; -#endif + P_UnsetThingPosition(actor); if (sector_list) { @@ -7549,10 +7451,9 @@ void A_Boss2PogoSFX(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2PogoSFX", actor)) return; -#endif if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { @@ -7593,10 +7494,8 @@ void A_Boss2PogoTarget(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss2PogoTarget", actor)) return; -#endif if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing]) || P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) >= FixedMul(512*FRACUNIT, actor->scale)) @@ -7680,10 +7579,9 @@ void A_Boss2PogoTarget(mobj_t *actor) // void A_EggmanBox(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_EggmanBox", actor)) return; -#endif + if (!actor->target || !actor->target->player) { CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); @@ -7706,10 +7604,9 @@ void A_TurretFire(mobj_t *actor) fixed_t dist; INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_TurretFire", actor)) return; -#endif if (locvar2) dist = FixedMul(locvar2*FRACUNIT, actor->scale); @@ -7745,10 +7642,9 @@ void A_SuperTurretFire(mobj_t *actor) fixed_t dist; INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SuperTurretFire", actor)) return; -#endif if (locvar2) dist = FixedMul(locvar2*FRACUNIT, actor->scale); @@ -7782,10 +7678,9 @@ void A_SuperTurretFire(mobj_t *actor) void A_TurretStop(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_TurretStop", actor)) return; -#endif actor->flags2 &= ~MF2_FIRING; actor->flags2 &= ~MF2_SUPERFIRE; @@ -7803,10 +7698,8 @@ void A_TurretStop(mobj_t *actor) // void A_SparkFollow(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_SparkFollow", actor)) return; -#endif if ((!actor->target || (actor->target->health <= 0)) || (actor->target->player && !actor->target->player->powers[pw_super])) @@ -7840,10 +7733,10 @@ void A_BuzzFly(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_BuzzFly", actor)) return; -#endif + if (actor->flags2 & MF2_AMBUSH) return; @@ -7939,10 +7832,9 @@ void A_BuzzFly(mobj_t *actor) void A_GuardChase(mobj_t *actor) { INT32 delta; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_GuardChase", actor)) return; -#endif if (actor->reactiontime) actor->reactiontime--; @@ -8045,10 +7937,9 @@ void A_EggShield(mobj_t *actor) fixed_t newx, newy; fixed_t movex, movey; angle_t angle; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_EggShield", actor)) return; -#endif if (!actor->target || !actor->target->health) { @@ -8129,10 +8020,9 @@ void A_EggShield(mobj_t *actor) // void A_SetReactionTime(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_SetReactionTime", actor)) return; -#endif + if (var1) actor->reactiontime = var2; else @@ -8152,10 +8042,8 @@ void A_Boss1Spikeballs(mobj_t *actor) INT32 locvar2 = var2; mobj_t *ball; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss1Spikeballs", actor)) return; -#endif ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL); P_SetTarget(&ball->target, actor); @@ -8176,10 +8064,9 @@ void A_Boss1Spikeballs(mobj_t *actor) // void A_Boss3TakeDamage(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss3TakeDamage", actor)) return; -#endif + actor->movecount = var1; actor->movefactor = -512*FRACUNIT; @@ -8197,10 +8084,8 @@ void A_Boss3TakeDamage(mobj_t *actor) // void A_Boss3Path(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss3Path", actor)) return; -#endif if (actor->tracer && actor->tracer->health && actor->tracer->movecount) actor->movecount |= 1; @@ -8326,10 +8211,8 @@ void A_Boss3Path(mobj_t *actor) // void A_Boss3ShockThink(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss3ShockThink", actor)) return; -#endif if (actor->momx || actor->momy) actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy) + ANGLE_90; @@ -8380,10 +8263,9 @@ void A_LinedefExecute(mobj_t *actor) INT32 tagnum; INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_LinedefExecute", actor)) return; -#endif tagnum = locvar1; // state numbers option is no more, custom states cannot be guaranteed to stay the same number anymore, now that they can be defined by names instead @@ -8408,10 +8290,9 @@ void A_LinedefExecute(mobj_t *actor) // void A_PlaySeeSound(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_PlaySeeSound", actor)) return; -#endif + if (actor->info->seesound) S_StartScreamSound(actor, actor->info->seesound); } @@ -8425,10 +8306,9 @@ void A_PlaySeeSound(mobj_t *actor) // void A_PlayAttackSound(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_PlayAttackSound", actor)) return; -#endif + if (actor->info->attacksound) S_StartAttackSound(actor, actor->info->attacksound); } @@ -8442,10 +8322,9 @@ void A_PlayAttackSound(mobj_t *actor) // void A_PlayActiveSound(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_PlayActiveSound", actor)) return; -#endif + if (actor->info->activesound) S_StartSound(actor, actor->info->activesound); } @@ -8461,10 +8340,9 @@ void A_SmokeTrailer(mobj_t *actor) { mobj_t *th; INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SmokeTrailer", actor)) return; -#endif if (leveltime % 4) return; @@ -8503,10 +8381,9 @@ void A_SpawnObjectAbsolute(mobj_t *actor) mobj_t *mo; INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnObjectAbsolute", actor)) return; -#endif x = (INT16)(locvar1>>16); y = (INT16)(locvar1&65535); @@ -8540,10 +8417,9 @@ void A_SpawnObjectRelative(mobj_t *actor) mobj_t *mo; INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnObjectRelative", actor)) return; -#endif CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -8585,10 +8461,9 @@ void A_ChangeAngleRelative(mobj_t *actor) const fixed_t amax = locvar2*FRACUNIT; //const angle_t amin = FixedAngle(locvar1*FRACUNIT); //const angle_t amax = FixedAngle(locvar2*FRACUNIT); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeAngleRelative", actor)) return; -#endif #ifdef PARANOIA if (amin > amax) @@ -8619,10 +8494,9 @@ void A_ChangeAngleAbsolute(mobj_t *actor) const fixed_t amax = locvar2*FRACUNIT; //const angle_t amin = FixedAngle(locvar1*FRACUNIT); //const angle_t amax = FixedAngle(locvar2*FRACUNIT); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeAngleAbsolute", actor)) return; -#endif #ifdef PARANOIA if (amin > amax) @@ -8650,10 +8524,8 @@ void A_RollAngle(mobj_t *actor) INT32 locvar2 = var2; const angle_t angle = FixedAngle(locvar1*FRACUNIT); -#ifdef HAVE_BLUA if (LUA_CallAction("A_RollAngle", actor)) return; -#endif // relative (default) if (!locvar2) @@ -8676,10 +8548,9 @@ void A_ChangeRollAngleRelative(mobj_t *actor) INT32 locvar2 = var2; const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeRollAngleRelative", actor)) return; -#endif #ifdef PARANOIA if (amin > amax) @@ -8702,10 +8573,9 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor) INT32 locvar2 = var2; const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeRollAngleAbsolute", actor)) return; -#endif #ifdef PARANOIA if (amin > amax) @@ -8728,10 +8598,9 @@ void A_PlaySound(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_PlaySound", actor)) return; -#endif if (leveltime < 2 && (locvar2 >> 16)) return; @@ -8754,10 +8623,9 @@ void A_FindTarget(mobj_t *actor) thinker_t *th; mobj_t *mo2; fixed_t dist1 = 0, dist2 = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FindTarget", actor)) return; -#endif CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -8819,10 +8687,9 @@ void A_FindTracer(mobj_t *actor) thinker_t *th; mobj_t *mo2; fixed_t dist1 = 0, dist2 = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FindTracer", actor)) return; -#endif CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -8880,10 +8747,9 @@ void A_SetTics(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetTics", actor)) return; -#endif if (locvar1) actor->tics = locvar1; @@ -8902,10 +8768,9 @@ void A_SetRandomTics(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetRandomTics", actor)) return; -#endif actor->tics = P_RandomRange(locvar1, locvar2); } @@ -8921,19 +8786,18 @@ void A_ChangeColorRelative(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeColorRelative", actor)) return; -#endif if (locvar1) { // Have you ever seen anything so hideous? if (actor->target) - actor->color = (UINT8)(actor->color + actor->target->color); + actor->color = (UINT16)(actor->color + actor->target->color); } else - actor->color = (UINT8)(actor->color + locvar2); + actor->color = (UINT16)(actor->color + locvar2); } // Function: A_ChangeColorAbsolute @@ -8947,10 +8811,9 @@ void A_ChangeColorAbsolute(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeColorAbsolute", actor)) return; -#endif if (locvar1) { @@ -8958,7 +8821,41 @@ void A_ChangeColorAbsolute(mobj_t *actor) actor->color = actor->target->color; } else - actor->color = (UINT8)locvar2; + actor->color = (UINT16)locvar2; +} + +// Function: A_Dye +// +// Description: Colorizes an object. +// +// var1 = if (var1 != 0), dye your target instead of yourself +// var2 = color value to dye +// +void A_Dye(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + mobj_t *target = ((locvar1 && actor->target) ? actor->target : actor); + UINT8 color = (UINT8)locvar2; + if (LUA_CallAction("A_Dye", actor)) + return; + if (color >= numskincolors) + return; + + if (!color) + target->colorized = false; + else + target->colorized = true; + + // What if it's a player? + if (target->player) + { + target->player->powers[pw_dye] = color; + return; + } + + target->color = color; } // Function: A_MoveRelative @@ -8972,10 +8869,9 @@ void A_MoveRelative(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_MoveRelative", actor)) return; -#endif P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); } @@ -8991,10 +8887,9 @@ void A_MoveAbsolute(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_MoveAbsolute", actor)) return; -#endif P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); } @@ -9010,10 +8905,9 @@ void A_Thrust(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Thrust", actor)) return; -#endif if (!locvar1) CONS_Debug(DBG_GAMELOGIC, "A_Thrust: Var1 not specified!\n"); @@ -9037,10 +8931,9 @@ void A_ZThrust(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ZThrust", actor)) return; -#endif if (!locvar1) CONS_Debug(DBG_GAMELOGIC, "A_ZThrust: Var1 not specified!\n"); @@ -9072,10 +8965,9 @@ void A_SetTargetsTarget(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; mobj_t *oldtarg = NULL, *newtarg = NULL; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetTargetsTarget", actor)) return; -#endif // actor's target if (locvar1) // or tracer @@ -9117,10 +9009,9 @@ void A_SetObjectFlags(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; boolean unlinkthings = false; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectFlags", actor)) return; -#endif if (locvar2 == 2) locvar1 = actor->flags | locvar1; @@ -9159,10 +9050,9 @@ void A_SetObjectFlags2(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectFlags2", actor)) return; -#endif if (locvar2 == 2) actor->flags2 |= locvar1; @@ -9187,10 +9077,9 @@ void A_BossJetFume(mobj_t *actor) { mobj_t *filler; INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossJetFume", actor)) return; -#endif if (locvar1 == 0) // Boss1 jet fumes { @@ -9323,10 +9212,9 @@ void A_RandomState(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RandomState", actor)) return; -#endif P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2); } @@ -9343,10 +9231,8 @@ void A_RandomStateRange(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_RandomStateRange", actor)) return; -#endif P_SetMobjState(actor, P_RandomRange(locvar1, locvar2)); } @@ -9362,27 +9248,22 @@ void A_DualAction(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_DualAction", actor)) return; -#endif CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); var1 = states[locvar1].var1; var2 = states[locvar1].var2; -#ifdef HAVE_BLUA astate = &states[locvar1]; -#endif CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling First Action (state %d)...\n", locvar1); states[locvar1].action.acp1(actor); var1 = states[locvar2].var1; var2 = states[locvar2].var2; -#ifdef HAVE_BLUA astate = &states[locvar2]; -#endif CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling Second Action (state %d)...\n", locvar2); states[locvar2].action.acp1(actor); @@ -9400,10 +9281,9 @@ void A_RemoteAction(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; mobj_t *originaltarget = actor->target; // Hold on to the target for later. -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RemoteAction", actor)) return; -#endif // If >=0, find the closest target. if (locvar1 >= 0) @@ -9465,9 +9345,7 @@ void A_RemoteAction(mobj_t *actor) // Steal the var1 and var2 from "locvar2" var1 = states[locvar2].var1; var2 = states[locvar2].var2; -#ifdef HAVE_BLUA astate = &states[locvar2]; -#endif CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Calling action on %p\n" "var1 is %d\nvar2 is %d\n", actor->target, var1, var2); @@ -9486,10 +9364,9 @@ void A_RemoteAction(mobj_t *actor) // void A_ToggleFlameJet(mobj_t* actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_ToggleFlameJet", actor)) return; -#endif + // threshold - off delay // movecount - on timer @@ -9533,10 +9410,9 @@ void A_OrbitNights(mobj_t* actor) boolean ishelper = (var2 & 0x10000); boolean donotrescale = (var2 & 0x40000); INT32 xfactor = 32, yfactor = 32, zfactor = 20; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_OrbitNights", actor)) return; -#endif if (actor->flags & MF_GRENADEBOUNCE) { @@ -9607,10 +9483,10 @@ void A_GhostMe(mobj_t *actor) { INT32 locvar1 = var1; mobj_t *ghost; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_GhostMe", actor)) return; -#endif + ghost = P_SpawnGhostMobj(actor); if (ghost && locvar1 > 0) ghost->fuse = locvar1; @@ -9630,10 +9506,9 @@ void A_SetObjectState(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; mobj_t *target; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectState", actor)) return; -#endif if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer)) { @@ -9676,10 +9551,8 @@ void A_SetObjectTypeState(mobj_t *actor) mobj_t *mo2; fixed_t dist = 0; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SetObjectTypeState", actor)) return; -#endif for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { @@ -9719,10 +9592,9 @@ void A_KnockBack(mobj_t *actor) { INT32 locvar1 = var1; mobj_t *target; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_KnockBack", actor)) return; -#endif if (!locvar1) target = actor->target; @@ -9755,10 +9627,9 @@ void A_PushAway(mobj_t *actor) INT32 locvar2 = var2; mobj_t *target; // target angle_t an; // actor to target angle -#ifdef HAVE_BLUA + if (LUA_CallAction("A_PushAway", actor)) return; -#endif if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer)) return; @@ -9790,10 +9661,9 @@ void A_RingDrain(mobj_t *actor) { INT32 locvar1 = var1; player_t *player; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RingDrain", actor)) return; -#endif if (!actor->target || !actor->target->player) { @@ -9823,10 +9693,12 @@ void A_SplitShot(mobj_t *actor) const UINT16 loc2up = (UINT16)(locvar2 >> 16); const fixed_t offs = (fixed_t)(locvar1*FRACUNIT); const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SplitShot", actor)) return; -#endif + + if (!actor->target) + return; A_FaceTarget(actor); { @@ -9858,10 +9730,10 @@ void A_MissileSplit(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_MissileSplit", actor)) return; -#endif + if (actor->eflags & MFE_VERTICALFLIP) P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z+actor->height, locvar2); else @@ -9886,10 +9758,9 @@ void A_MultiShot(mobj_t *actor) const UINT16 loc1up = (UINT16)(locvar1 >> 16); INT32 count = 0; fixed_t ad; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_MultiShot", actor)) return; -#endif if (actor->target) A_FaceTarget(actor); @@ -9948,10 +9819,9 @@ void A_InstaLoop(mobj_t *actor) const angle_t fa = FixedAngleC(loc1lw*FRACUNIT*360, loc1up*FRACUNIT)>>ANGLETOFINESHIFT; const fixed_t ac = FINECOSINE(fa); const fixed_t as = FINESINE(fa); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_InstaLoop", actor)) return; -#endif P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale))); P_SetObjectMomZ(actor, FixedMul(as, force), false); @@ -9982,10 +9852,9 @@ void A_Custom3DRotate(mobj_t *actor) const fixed_t hOff = FixedMul(loc1up*FRACUNIT, actor->scale); const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale); const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Custom3DRotate", actor)) return; -#endif if (actor->target->health == 0) { @@ -10042,10 +9911,9 @@ void A_SearchForPlayers(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SearchForPlayers", actor)) return; -#endif if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { @@ -10076,10 +9944,9 @@ void A_CheckRandom(mobj_t *actor) INT32 locvar2 = var2; fixed_t chance = FRACUNIT; -#ifdef HAVE_BLUA if (LUA_CallAction("A_CheckRandom", actor)) return; -#endif + if ((locvar1 & 0xFFFF) == 0) return; @@ -10103,10 +9970,9 @@ void A_CheckTargetRings(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckTargetRings", actor)) return; -#endif if (!(actor->target) || !(actor->target->player)) return; @@ -10127,10 +9993,9 @@ void A_CheckRings(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; INT32 i, cntr = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckRings", actor)) return; -#endif for (i = 0; i < MAXPLAYERS; i++) cntr += players[i].rings; @@ -10152,10 +10017,9 @@ void A_CheckTotalRings(mobj_t *actor) INT32 locvar2 = var2; INT32 i, cntr = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckTotalRings", actor)) return; -#endif for (i = 0; i < MAXPLAYERS; i++) cntr += players[i].totalring; @@ -10175,10 +10039,9 @@ void A_CheckHealth(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckHealth", actor)) return; -#endif if (actor->health <= locvar1) P_SetMobjState(actor, locvar2); @@ -10198,10 +10061,9 @@ void A_CheckRange(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; fixed_t dist; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckRange", actor)) return; -#endif if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) return; @@ -10229,10 +10091,9 @@ void A_CheckHeight(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; fixed_t height; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckHeight", actor)) return; -#endif if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) return; @@ -10262,10 +10123,9 @@ void A_CheckTrueRange(mobj_t *actor) fixed_t height; // vertical range fixed_t dist; // horizontal range fixed_t l; // true range -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckTrueRange", actor)) return; -#endif if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) return; @@ -10314,10 +10174,9 @@ void A_CheckThingCount(mobj_t *actor) thinker_t *th; mobj_t *mo2; fixed_t dist = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckThingCount", actor)) return; -#endif for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { @@ -10361,10 +10220,8 @@ void A_CheckAmbush(mobj_t *actor) angle_t atp; // actor to target angle angle_t an; // angle between at and atp -#ifdef HAVE_BLUA if (LUA_CallAction("A_CheckAmbush", actor)) return; -#endif if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer)) return; @@ -10400,10 +10257,9 @@ void A_CheckCustomValue(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckCustomValue", actor)) return; -#endif if (actor->cusval >= locvar1) P_SetMobjState(actor, locvar2); @@ -10420,10 +10276,9 @@ void A_CheckCusValMemo(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckCusValMemo", actor)) return; -#endif if (actor->cvmem >= locvar1) P_SetMobjState(actor, locvar2); @@ -10446,10 +10301,9 @@ void A_SetCustomValue(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetCustomValue", actor)) return; -#endif if (cv_debug) CONS_Printf("Init custom value is %d\n", actor->cusval); @@ -10497,10 +10351,9 @@ void A_UseCusValMemo(mobj_t *actor) INT32 temp = actor->cusval; // value being manipulated INT32 tempM = actor->cvmem; // value used to manipulate temp with -#ifdef HAVE_BLUA + if (LUA_CallAction("A_UseCusValMemo", actor)) return; -#endif if (locvar1 == 1) // cvmem being changed using cusval { @@ -10561,10 +10414,9 @@ void A_RelayCustomValue(mobj_t *actor) INT32 temp; // reference value - var1 lower 16 bits changes this INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RelayCustomValue", actor)) return; -#endif if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) return; @@ -10621,10 +10473,9 @@ void A_CusValAction(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CusValAction", actor)) return; -#endif if (locvar2 == 5) { @@ -10657,9 +10508,7 @@ void A_CusValAction(mobj_t *actor) var2 = states[locvar1].var2; } -#ifdef HAVE_BLUA astate = &states[locvar1]; -#endif states[locvar1].action.acp1(actor); } @@ -10675,10 +10524,9 @@ void A_CusValAction(mobj_t *actor) void A_ForceStop(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ForceStop", actor)) return; -#endif actor->momx = actor->momy = 0; if (locvar1 == 0) @@ -10696,12 +10544,8 @@ void A_ForceWin(mobj_t *actor) { INT32 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_ForceWin", actor)) return; -#else - (void)actor; -#endif for (i = 0; i < MAXPLAYERS; i++) { @@ -10733,10 +10577,9 @@ void A_ForceWin(mobj_t *actor) void A_SpikeRetract(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpikeRetract", actor)) return; -#endif if (actor->flags & MF_NOBLOCKMAP) return; @@ -10818,10 +10661,9 @@ void A_Repeat(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Repeat", actor)) return; -#endif if (locvar1 && (!actor->extravalue2 || actor->extravalue2 > locvar1)) actor->extravalue2 = locvar1; @@ -10844,10 +10686,9 @@ void A_SetScale(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; mobj_t *target; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetScale", actor)) return; -#endif if (locvar1 <= 0) { @@ -10888,10 +10729,10 @@ void A_RemoteDamage(mobj_t *actor) INT32 locvar2 = var2; mobj_t *target; // we MUST have a target mobj_t *source = NULL; // on the other hand we don't necessarily need a source -#ifdef HAVE_BLUA + if (LUA_CallAction("A_RemoteDamage", actor)) return; -#endif + if (locvar1 == 1) target = actor->target; else if (locvar1 == 2) @@ -10941,10 +10782,9 @@ void A_HomingChase(mobj_t *actor) mobj_t *dest; fixed_t dist; fixed_t speedmul; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_HomingChase", actor)) return; -#endif if (locvar2 == 1) dest = actor->tracer; @@ -10995,10 +10835,9 @@ void A_TrapShot(mobj_t *actor) INT16 vertoff = (INT16)(locvar2 >> 16); fixed_t x, y, z; fixed_t speed; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_TrapShot", actor)) return; -#endif x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); @@ -11062,10 +10901,8 @@ void A_VileTarget(mobj_t *actor) mobjtype_t fogtype; INT32 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_VileTarget", actor)) return; -#endif if (!actor->target) return; @@ -11151,10 +10988,8 @@ void A_VileAttack(mobj_t *actor) mobj_t *fire; INT32 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_VileAttack", actor)) return; -#endif if (!actor->target) return; @@ -11265,10 +11100,8 @@ void A_VileFire(mobj_t *actor) INT32 locvar2 = var2; mobj_t *dest; -#ifdef HAVE_BLUA if (LUA_CallAction("A_VileFire", actor)) return; -#endif dest = actor->tracer; if (!dest) @@ -11353,10 +11186,8 @@ void A_BrakChase(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BrakChase", actor)) return; -#endif // Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly if (actor->tics > 1 && locvar1 < actor->tics) // Not much point, otherwise @@ -11475,10 +11306,9 @@ void A_BrakFireShot(mobj_t *actor) fixed_t x, y, z; INT32 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BrakFireShot", actor)) return; -#endif + if (!actor->target) return; @@ -11539,10 +11369,8 @@ void A_BrakLobShot(mobj_t *actor) INT32 locvar2 = var2 & 0x0000FFFF; INT32 aimDirect = var2 & 0xFFFF0000; -#ifdef HAVE_BLUA if (LUA_CallAction("A_BrakLobShot", actor)) return; -#endif if (!actor->target) return; // Don't even bother if we've got nothing to aim at. @@ -11647,10 +11475,8 @@ void A_NapalmScatter(mobj_t *actor) INT32 i; // for-loop cursor mobj_t *mo; // each and every spawned napalm burst -#ifdef HAVE_BLUA if (LUA_CallAction("A_NapalmScatter", actor)) return; -#endif // Some quick sanity-checking if (typeOfShot >= NUMMOBJTYPES) // I'd add a <0 check, too, but 0x0000FFFF isn't negative in this case @@ -11701,10 +11527,8 @@ void A_SpawnFreshCopy(mobj_t *actor) { mobj_t *newObject; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SpawnFreshCopy", actor)) return; -#endif newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); newObject->flags2 = actor->flags2 & MF2_AMBUSH; @@ -11778,10 +11602,9 @@ void A_FlickySpawn(mobj_t *actor) INT32 locvar2 = var2; INT32 test = (var1 >> 16); SINT8 moveforward = 0; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickySpawn", actor)) return; -#endif if (test & 1) A_Scream(actor); // A shortcut for the truly lazy. @@ -11847,10 +11670,9 @@ void A_FlickyCenter(mobj_t *actor) UINT16 flickytype = (locvar1 & 0xFFFF); UINT8 flickycolor = ((locvar1 >> 16) & 0xFF); UINT8 flickyflags = ((locvar1 >> 20) & 0xF); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyCenter", actor)) return; -#endif if (!actor->tracer) { @@ -11969,10 +11791,8 @@ void A_FlickyAim(mobj_t *actor) INT32 locvar2 = var2; boolean flickyhitwall = false; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FlickyAim", actor)) return; -#endif if ((actor->momx == actor->momy && actor->momy == 0) || (actor->target && P_IsFlickyCenter(actor->target->type) @@ -12070,10 +11890,10 @@ void A_FlickyFly(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyFly", actor)) return; -#endif + P_InternalFlickyFly(actor, locvar1, locvar2, FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK) ); @@ -12090,10 +11910,10 @@ void A_FlickySoar(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickySoar", actor)) return; -#endif + P_InternalFlickyFly(actor, locvar1, locvar2, 2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK))) ); @@ -12114,10 +11934,10 @@ void A_FlickyCoast(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyCoast", actor)) return; -#endif + if (actor->eflags & MFE_UNDERWATER) { actor->momx = (11*actor->momx)/12; @@ -12161,10 +11981,10 @@ void A_FlickyHop(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyHop", actor)) return; -#endif + P_InternalFlickyHop(actor, locvar1, locvar2, actor->angle); } @@ -12180,10 +12000,10 @@ void A_FlickyFlounder(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; angle_t hopangle; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyFlounder", actor)) return; -#endif + locvar1 *= (P_RandomKey(2) + 1); locvar2 *= (P_RandomKey(2) + 1); hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2); @@ -12202,10 +12022,10 @@ void A_FlickyCheck(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyCheck", actor)) return; -#endif + if (actor->target && P_IsFlickyCenter(actor->target->type) && (actor->target->flags & MF_GRENADEBOUNCE)) @@ -12239,10 +12059,10 @@ void A_FlickyHeightCheck(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyHeightCheck", actor)) return; -#endif + if (actor->target && P_IsFlickyCenter(actor->target->type) && (actor->target->flags & MF_GRENADEBOUNCE)) @@ -12274,10 +12094,10 @@ void A_FlickyFlutter(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyFlutter", actor)) return; -#endif + var1 = locvar1; var2 = locvar2; A_FlickyCheck(actor); @@ -12305,13 +12125,9 @@ void A_FlameParticle(mobj_t *actor) mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance); fixed_t rad, hei; mobj_t *particle; - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FlameParticle", actor)) return; -#endif if (!type) return; @@ -12337,12 +12153,9 @@ void A_FadeOverlay(mobj_t *actor) { mobj_t *fade; INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_FadeOverlay", actor)) return; -#endif fade = P_SpawnGhostMobj(actor); fade->frame = actor->frame; @@ -12382,10 +12195,8 @@ void A_Boss5Jump(mobj_t *actor) // INT32 locvar1 = var1; // INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss5Jump", actor)) return; -#endif if (!actor->tracer) return; // Don't even bother if we've got nothing to aim at. @@ -12461,10 +12272,8 @@ void A_LightBeamReset(mobj_t *actor) // INT32 locvar1 = var1; // INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_LightBeamReset", actor)) return; -#endif actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256; P_SetScale(actor, actor->destscale); @@ -12493,10 +12302,8 @@ void A_MineExplode(mobj_t *actor) // INT32 locvar1 = var1; // INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MineExplode", actor)) return; -#endif A_Scream(actor); actor->flags = MF_NOGRAVITY|MF_NOCLIP; @@ -12548,10 +12355,8 @@ void A_MineRange(mobj_t *actor) INT32 locvar1 = var1; // INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MineRange", actor)) return; -#endif if (!actor->target) return; @@ -12576,10 +12381,8 @@ void A_ConnectToGround(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_ConnectToGround", actor)) return; -#endif if (actor->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); @@ -12636,10 +12439,10 @@ void A_SpawnParticleRelative(mobj_t *actor) mobj_t *mo; INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnParticleRelative", actor)) return; -#endif + CONS_Debug(DBG_GAMELOGIC, "A_SpawnParticleRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -12674,10 +12477,9 @@ void A_MultiShotDist(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_MultiShotDist", actor)) return; -#endif { UINT8 i; @@ -12714,10 +12516,9 @@ void A_WhoCaresIfYourSonIsABee(mobj_t *actor) fixed_t foffsetx; fixed_t foffsety; mobj_t *son; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor)) return; -#endif A_FaceTarget(actor); @@ -12749,11 +12550,9 @@ void A_WhoCaresIfYourSonIsABee(mobj_t *actor) void A_ParentTriesToSleep(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ParentTriesToSleep", actor)) return; -#endif if (actor->extravalue1) { @@ -12780,12 +12579,8 @@ void A_ParentTriesToSleep(mobj_t *actor) // void A_CryingToMomma(mobj_t *actor) { - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_CryingToMomma", actor)) return; -#endif if (actor->tracer) actor->tracer->extravalue1++; @@ -12813,10 +12608,9 @@ void A_CheckFlags2(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckFlags2", actor)) return; -#endif if (actor->flags2 & locvar1) P_SetMobjState(actor, (statenum_t)locvar2); @@ -12832,14 +12626,12 @@ void A_CheckFlags2(mobj_t *actor) void A_Boss5FindWaypoint(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; boolean avoidcenter; UINT32 i; UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5FindWaypoint", actor)) return; -#endif avoidcenter = !actor->tracer || (actor->health == actor->info->damage+1); @@ -12901,8 +12693,8 @@ void A_Boss5FindWaypoint(mobj_t *actor) else // locvar1 == 0 { fixed_t hackoffset = P_MobjFlip(actor)*56*FRACUNIT; - INT32 numwaypoints = 0; - mobj_t **waypoints; + INT32 numfangwaypoints = 0; + mobj_t **fangwaypoints; INT32 key; actor->z += hackoffset; @@ -12927,7 +12719,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (!P_CheckSight(actor, mapthings[i].mobj)) continue; - numwaypoints++; + numfangwaypoints++; } // players also count as waypoints apparently @@ -12949,11 +12741,11 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (!P_CheckSight(actor, players[i].mo)) continue; - numwaypoints++; + numfangwaypoints++; } } - if (!numwaypoints) + if (!numfangwaypoints) { // restore z position actor->z -= hackoffset; @@ -12961,8 +12753,8 @@ void A_Boss5FindWaypoint(mobj_t *actor) } // allocate the table and reset count to zero - waypoints = Z_Calloc(sizeof(*waypoints)*numwaypoints, PU_STATIC, NULL); - numwaypoints = 0; + fangwaypoints = Z_Calloc(sizeof(*waypoints)*numfangwaypoints, PU_STATIC, NULL); + numfangwaypoints = 0; // now find them again and add them to the table! for (i = 0; i < nummapthings; i++) @@ -12987,7 +12779,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) } if (!P_CheckSight(actor, mapthings[i].mobj)) continue; - waypoints[numwaypoints++] = mapthings[i].mobj; + fangwaypoints[numfangwaypoints++] = mapthings[i].mobj; } if (actor->extravalue2 > 1) @@ -13008,25 +12800,25 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (!P_CheckSight(actor, players[i].mo)) continue; - waypoints[numwaypoints++] = players[i].mo; + fangwaypoints[numfangwaypoints++] = players[i].mo; } } // restore z position actor->z -= hackoffset; - if (!numwaypoints) + if (!numfangwaypoints) { - Z_Free(waypoints); // free table + Z_Free(fangwaypoints); // free table goto nowaypoints; // ??? } - key = P_RandomKey(numwaypoints); + key = P_RandomKey(numfangwaypoints); - P_SetTarget(&actor->tracer, waypoints[key]); + P_SetTarget(&actor->tracer, fangwaypoints[key]); if (actor->tracer->type == MT_FANGWAYPOINT) - actor->tracer->reactiontime = numwaypoints/4; // Monster Iestyn: is this how it should be? I count center waypoints as waypoints unlike the original Lua script - Z_Free(waypoints); // free table + actor->tracer->reactiontime = numfangwaypoints/4; // Monster Iestyn: is this how it should be? I count center waypoints as waypoints unlike the original Lua script + Z_Free(fangwaypoints); // free table } // now face the tracer you just set! @@ -13054,10 +12846,9 @@ void A_DoNPCSkid(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; fixed_t x, y, z; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_DoNPCSkid", actor)) return; -#endif x = actor->x; y = actor->y; @@ -13111,10 +12902,9 @@ void A_DoNPCPain(mobj_t *actor) INT32 locvar2 = var2; fixed_t vspeed = 0; fixed_t hspeed = FixedMul(4*FRACUNIT, actor->scale); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_DoNPCPain", actor)) return; -#endif actor->flags &= ~(MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT); @@ -13160,11 +12950,9 @@ void A_DoNPCPain(mobj_t *actor) void A_PrepareRepeat(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_PrepareRepeat", actor)) return; -#endif actor->extravalue2 = locvar1; } @@ -13183,10 +12971,9 @@ void A_Boss5ExtraRepeat(mobj_t *actor) INT32 calc; INT32 locspawn; INT32 lochealth; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5ExtraRepeat", actor)) return; -#endif if (actor->extravalue2 > 0 && !(actor->flags2 & MF2_FRET)) return; @@ -13217,10 +13004,9 @@ void A_Boss5ExtraRepeat(mobj_t *actor) // void A_Boss5Calm(mobj_t *actor) { -#ifdef HAVE_BLUA if (LUA_CallAction("A_Boss5Calm", actor)) return; -#endif + actor->flags |= MF_SHOOTABLE; actor->flags2 &= ~MF2_FRET; } @@ -13236,10 +13022,9 @@ void A_Boss5CheckOnGround(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5CheckOnGround", actor)) return; -#endif if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) || (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz)) @@ -13268,10 +13053,9 @@ void A_Boss5CheckFalling(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5CheckFalling", actor)) return; -#endif if (actor->health && actor->extravalue2 > 1) { @@ -13298,10 +13082,9 @@ void A_Boss5PinchShot(mobj_t *actor) INT32 locvar2 = var2; fixed_t zoffset; mobj_t *missile; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5PinchShot", actor)) return; -#endif if (actor->health > actor->info->damage) return; @@ -13334,10 +13117,9 @@ void A_Boss5MakeItRain(mobj_t *actor) INT32 locvar2 = var2; INT32 offset = (48 + locvar2)<<16; // upper 16 bits, not fixed_t! INT32 i; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5MakeItRain", actor)) return; -#endif actor->flags2 |= MF2_STRONGBOX; @@ -13371,10 +13153,9 @@ void A_Boss5MakeJunk(mobj_t *actor) mobj_t *broked = NULL; angle_t ang; INT32 i = ((locvar2 & 1) ? 8 : 1); -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5MakeJunk", actor)) return; -#endif if (locvar1 < 0 && (actor->flags2 & MF2_SLIDEPUSH)) // this entire action is a hack, don't judge me { @@ -13462,11 +13243,9 @@ void A_Boss5MakeJunk(mobj_t *actor) void A_LookForBetter(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_LookForBetter", actor)) return; -#endif P_LookForPlayers(actor, (locvar1 & 65535), false, FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)); A_FaceTarget(actor); @@ -13524,11 +13303,9 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi void A_Boss5BombExplode(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5BombExplode", actor)) return; -#endif // The original Lua script did not use |= to add flags but just set these flags exactly apparently? // (I may modify this later) @@ -13585,8 +13362,9 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) P_ResetPlayer(player); A_PlayActiveSound(dustdevil); } + player->powers[pw_carry] = CR_DUSTDEVIL; player->powers[pw_nocontrol] = 2; - player->drawangle += ANG20; + P_SetTarget(&thing->tracer, dustdevil); P_SetPlayerMobjState(thing, S_PLAY_PAIN); if (dist > dragamount) @@ -13606,7 +13384,9 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) P_ResetPlayer(player); thing->z = dustdevil->z + dustdevil->height; thrust = 20 * FRACUNIT; + player->powers[pw_carry] = CR_NONE; player->powers[pw_nocontrol] = 0; + P_SetTarget(&thing->tracer, NULL); S_StartSound(thing, sfx_wdjump); P_SetPlayerMobjState(thing, S_PLAY_FALL); } @@ -13631,10 +13411,8 @@ void A_DustDevilThink(mobj_t *actor) INT32 bx, by, xl, xh, yl, yh; fixed_t radius = actor->radius; -#ifdef HAVE_BLUA if (LUA_CallAction("A_DustDevilThink", actor)) return; -#endif //Chained thinker for the spiralling dust column. while (layer && !P_MobjWasRemoved(layer)) { @@ -13771,15 +13549,12 @@ static boolean PIT_TNTExplode(mobj_t *nearby) void A_TNTExplode(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; INT32 x, y; INT32 xl, xh, yl, yh; static mappoint_t epicenter = {0,0,0}; -#ifdef HAVE_BLUA if (LUA_CallAction("A_TNTExplode", actor)) return; -#endif if (actor->tracer) { @@ -13843,12 +13618,9 @@ void A_TNTExplode(mobj_t *actor) void A_DebrisRandom(mobj_t *actor) { INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_DebrisRandom", actor)) return; -#endif actor->frame |= P_RandomRange(0, locvar1); var1 = 0; @@ -13888,10 +13660,8 @@ void A_TrainCameo(mobj_t *actor) fixed_t span = locvar1*FRACUNIT; fixed_t len = locvar2*FRACUNIT; -#ifdef HAVE_BLUA if (LUA_CallAction("A_TrainCameo", actor)) return; -#endif //Spawn sides. P_TrainSeg(actor, x, y + span, z, ang, spr, 0); @@ -13928,10 +13698,8 @@ void A_TrainCameo2(mobj_t *actor) fixed_t span = locvar1*FRACUNIT; fixed_t len = locvar2*FRACUNIT; -#ifdef HAVE_BLUA if (LUA_CallAction("A_TrainCameo2", actor)) return; -#endif //Spawn sides. P_TrainSeg(actor, x, y + span, z, ang, spr, 0); @@ -13956,10 +13724,8 @@ void A_CanarivoreGas(mobj_t *actor) { INT32 locvar1 = var1; -#ifdef HAVE_BLUA if (LUA_CallAction("A_CanarivoreGas", actor)) return; -#endif P_DustRing(locvar1, 4, actor->x, actor->y, actor->z + actor->height / 5, 18, 0, FRACUNIT/10, actor->scale); P_DustRing(locvar1, 6, actor->x, actor->y, actor->z + actor->height / 5, 28, FRACUNIT, FRACUNIT/10, actor->scale); @@ -13979,10 +13745,8 @@ void A_KillSegments(mobj_t *actor) mobj_t *seg = actor->tracer; INT32 fuse = locvar1 ? locvar1 : TICRATE/2; -#ifdef HAVE_BLUA if (LUA_CallAction("A_KillSegments", actor)) return; -#endif while (seg) { @@ -14064,10 +13828,8 @@ void A_SnapperSpawn(mobj_t *actor) INT32 i; mobj_t *seg; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SnapperSpawn", actor)) return; -#endif // It spawns 1 head. seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, headtype); @@ -14116,10 +13878,8 @@ void A_SnapperThinker(mobj_t *actor) fixed_t dist; boolean chasing; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SnapperThinker", actor)) return; -#endif // We make a check just in case there's no spawnpoint. if (actor->spawnpoint) @@ -14239,10 +13999,8 @@ void A_SaloonDoorSpawn(mobj_t *actor) mobj_t *door; mobjflag2_t ambush = (actor->flags2 & MF2_AMBUSH); -#ifdef HAVE_BLUA if (LUA_CallAction("A_SaloonDoorSpawn", actor)) return; -#endif if (!locvar1) return; @@ -14278,10 +14036,8 @@ void A_MinecartSparkThink(mobj_t *actor) fixed_t dz, dm; UINT8 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_MinecartSparkThink", actor)) return; -#endif if (actor->momz == 0 && P_IsObjectOnGround(actor)) actor->momz = P_RandomRange(2, 4)*FRACUNIT; @@ -14313,10 +14069,9 @@ void A_ModuloToState(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; -#ifdef HAVE_BLUA + if (LUA_CallAction("A_ModuloToState", actor)) return; -#endif if ((modulothing % locvar1 == 0)) P_SetMobjState(actor, (locvar2)); @@ -14334,10 +14089,8 @@ 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) @@ -14367,10 +14120,8 @@ void A_LavafallLava(mobj_t *actor) mobj_t *lavafall; UINT8 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_LavafallLava", actor)) return; -#endif if ((40 - actor->fuse) % (2*(actor->scale >> FRACBITS))) return; @@ -14397,10 +14148,8 @@ void A_LavafallLava(mobj_t *actor) // 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)) { @@ -14424,10 +14173,8 @@ 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; @@ -14450,10 +14197,8 @@ void A_SpawnPterabytes(mobj_t *actor) UINT8 amount = 1; UINT8 i; -#ifdef HAVE_BLUA if (LUA_CallAction("A_SpawnPterabytes", actor)) return; -#endif if (actor->spawnpoint) amount = actor->spawnpoint->extrainfo + 1; @@ -14487,10 +14232,8 @@ 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; @@ -14511,10 +14254,8 @@ 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) @@ -14549,10 +14290,8 @@ void A_RolloutRock(mobj_t *actor) 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 @@ -14634,10 +14373,8 @@ void A_DragonbomberSpawn(mobj_t *actor) UINT8 i; mobj_t *mo = actor; - #ifdef HAVE_BLUA - if (LUA_CallAction("A_DragonbomberSpawn", actor)) - return; - #endif + if (LUA_CallAction("A_DragonbomberSpawn", actor)) + return; for (i = 0; i < var1; i++) // spawn tail segments { @@ -14672,10 +14409,8 @@ void A_DragonWing(mobj_t *actor) mobj_t *target = actor->target; fixed_t x, y; - #ifdef HAVE_BLUA - if (LUA_CallAction("A_DragonWing", actor)) - return; - #endif + if (LUA_CallAction("A_DragonWing", actor)) + return; if (target == NULL || !target->health) { @@ -14707,10 +14442,8 @@ void A_DragonSegment(mobj_t *actor) fixed_t ydist; fixed_t zdist; - #ifdef HAVE_BLUA - if (LUA_CallAction("A_DragonSegment", actor)) - return; - #endif + if (LUA_CallAction("A_DragonSegment", actor)) + return; if (target == NULL || !target->health) { @@ -14730,3 +14463,43 @@ void A_DragonSegment(mobj_t *actor) actor->angle = hangle; P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist); } + +// Function: A_ChangeHeight +// +// Description: Changes the actor's height by var1 +// +// var1 = height +// var2 = +// &1: height is absolute +// &2: scale with actor's scale +// +void A_ChangeHeight(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t height = locvar1; + boolean reverse; + + if (LUA_CallAction("A_ChangeHeight", actor)) + return; + + reverse = (actor->eflags & MFE_VERTICALFLIP) || (actor->flags2 & MF2_OBJECTFLIP); + + if (locvar2 & 2) + height = FixedMul(height, actor->scale); + + P_UnsetThingPosition(actor); + if (locvar2 & 1) + { + if (reverse) + actor->z += actor->height - locvar1; + actor->height = locvar1; + } + else + { + if (reverse) + actor->z -= locvar1; + actor->height += locvar1; + } + P_SetThingPosition(actor); +} diff --git a/src/p_floor.c b/src/p_floor.c index c23d469bc..a0f7edd9c 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,9 +15,7 @@ #include "doomstat.h" #include "m_random.h" #include "p_local.h" -#ifdef ESLOPE #include "p_slopes.h" -#endif #include "r_state.h" #include "s_sound.h" #include "z_zone.h" @@ -28,246 +26,129 @@ // FLOORS // ========================================================================== -// -// Mini-P_IsObjectOnGroundIn for T_MovePlane hack -// -static inline boolean P_MobjReadyToMove(mobj_t *mo, sector_t *sec, boolean sectorisffloor, boolean sectorisquicksand) -{ - if (sectorisquicksand) - return (mo->z > sec->floorheight && mo->z < sec->ceilingheight); - else if (!!(mo->flags & MF_SPAWNCEILING) ^ !!(mo->eflags & MFE_VERTICALFLIP)) - return ((sectorisffloor) ? (mo->z+mo->height != sec->floorheight) : (mo->z+mo->height != sec->ceilingheight)); - else - return ((sectorisffloor) ? (mo->z != sec->ceilingheight) : (mo->z != sec->floorheight)); -} - // // Move a plane (floor or ceiling) and check for crushing // result_e T_MovePlane(sector_t *sector, fixed_t speed, fixed_t dest, boolean crush, - INT32 floorOrCeiling, INT32 direction) + boolean ceiling, INT32 direction) { - boolean flag; fixed_t lastpos; fixed_t destheight; // used to keep floors/ceilings from moving through each other - // Stuff used for mobj hacks. - INT32 secnum = -1; - mobj_t *mo = NULL; - sector_t *sec = NULL; - ffloor_t *rover = NULL; - boolean sectorisffloor = false; - boolean sectorisquicksand = false; - sector->moved = true; - switch (floorOrCeiling) + if (ceiling) { - case 0: - // moving a floor - switch (direction) - { - case -1: - // Moving a floor down - if (sector->floorheight - speed < dest) - { - lastpos = sector->floorheight; - sector->floorheight = dest; - flag = P_CheckSector(sector, crush); - if (flag && sector->numattached) - { - sector->floorheight = lastpos; - P_CheckSector(sector, crush); - } - return pastdest; - } - else - { - lastpos = sector->floorheight; - sector->floorheight -= speed; - flag = P_CheckSector(sector, crush); - if (flag && sector->numattached) - { - sector->floorheight = lastpos; - P_CheckSector(sector, crush); - return crushed; - } - } - break; - - case 1: - // Moving a floor up - // keep floor from moving through ceilings - destheight = (dest < sector->ceilingheight) ? dest : sector->ceilingheight; - if (sector->floorheight + speed > destheight) - { - lastpos = sector->floorheight; - sector->floorheight = destheight; - flag = P_CheckSector(sector, crush); - if (flag) - { - sector->floorheight = lastpos; - P_CheckSector(sector, crush); - } - return pastdest; - } - else - { - // crushing is possible - lastpos = sector->floorheight; - sector->floorheight += speed; - flag = P_CheckSector(sector, crush); - if (flag) - { - sector->floorheight = lastpos; - P_CheckSector(sector, crush); - return crushed; - } - } - break; - } - break; - - case 1: - // moving a ceiling - switch (direction) - { - case -1: - // moving a ceiling down - // keep ceiling from moving through floors - destheight = (dest > sector->floorheight) ? dest : sector->floorheight; - if (sector->ceilingheight - speed < destheight) - { - lastpos = sector->ceilingheight; - sector->ceilingheight = destheight; - flag = P_CheckSector(sector, crush); - - if (flag) - { - sector->ceilingheight = lastpos; - P_CheckSector(sector, crush); - } - return pastdest; - } - else - { - // crushing is possible - lastpos = sector->ceilingheight; - sector->ceilingheight -= speed; - flag = P_CheckSector(sector, crush); - - if (flag) - { - sector->ceilingheight = lastpos; - P_CheckSector(sector, crush); - return crushed; - } - } - break; - - case 1: - // moving a ceiling up - if (sector->ceilingheight + speed > dest) - { - lastpos = sector->ceilingheight; - sector->ceilingheight = dest; - flag = P_CheckSector(sector, crush); - if (flag && sector->numattached) - { - sector->ceilingheight = lastpos; - P_CheckSector(sector, crush); - } - return pastdest; - } - else - { - lastpos = sector->ceilingheight; - sector->ceilingheight += speed; - flag = P_CheckSector(sector, crush); - if (flag && sector->numattached) - { - sector->ceilingheight = lastpos; - P_CheckSector(sector, crush); - return crushed; - } - } - break; - } - break; - } - - // Hack for buggy mobjs to move by gravity with moving planes. - if (sector->tagline) - sectorisffloor = true; - - // Optimization condition. If the sector is not an FOF, declare sec as the main sector outside of the loop. - if (!sectorisffloor) - sec = sector; - - // Optimization condition. Only run the logic if there is any Things in the sector. - if (sectorisffloor || sec->thinglist) - { - // If this is an FOF being checked, check all the affected sectors for moving mobjs. - while ((sectorisffloor ? (secnum = P_FindSectorFromLineTag(sector->tagline, secnum)) : (secnum = 1)) >= 0) + lastpos = sector->ceilingheight; + // moving a ceiling + switch (direction) { - if (sectorisffloor) - { - // Get actual sector from the list of sectors. - sec = §ors[secnum]; - - // Can't use P_InQuicksand because it will return the incorrect result - // because of checking for heights. - for (rover = sec->ffloors; rover; rover = rover->next) + case -1: + // moving a ceiling down + // keep ceiling from moving through floors + destheight = (dest > sector->floorheight) ? dest : sector->floorheight; + if (sector->ceilingheight - speed < destheight) { - if (rover->target == sec && (rover->flags & FF_QUICKSAND)) + sector->ceilingheight = destheight; + if (P_CheckSector(sector, crush)) { - sectorisquicksand = true; - break; + sector->ceilingheight = lastpos; + P_CheckSector(sector, crush); + } + return pastdest; + } + else + { + // crushing is possible + sector->ceilingheight -= speed; + if (P_CheckSector(sector, crush)) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector, crush); + return crushed; } } - } + break; - for (mo = sec->thinglist; mo; mo = mo->snext) - { - // The object should be ready to move as defined by this function. - if (!P_MobjReadyToMove(mo, sec, sectorisffloor, sectorisquicksand)) - continue; - - // The object should not be moving at all. - if (mo->momx || mo->momy || mo->momz) - continue; - - // These objects will be affected by this condition. - switch (mo->type) + case 1: + // moving a ceiling up + if (sector->ceilingheight + speed > dest) { - case MT_GOOP: // Egg Slimer's goop objects - case MT_SPINFIRE: // Elemental Shield flame balls - case MT_SPIKE: // Floor Spike - // Is the object hang from the ceiling? - // In that case, swap the planes used. - // verticalflip inverts - if (!!(mo->flags & MF_SPAWNCEILING) ^ !!(mo->eflags & MFE_VERTICALFLIP)) - { - if (sectorisffloor && !sectorisquicksand) - mo->z = mo->ceilingz - mo->height; - else - mo->z = mo->ceilingz = mo->subsector->sector->ceilingheight - mo->height; - } - else - { - if (sectorisffloor && !sectorisquicksand) - mo->z = mo->floorz; - else - mo->z = mo->floorz = mo->subsector->sector->floorheight; - } - break; - // Kill warnings... - default: - break; + sector->ceilingheight = dest; + if (P_CheckSector(sector, crush) && sector->numattached) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector, crush); + } + return pastdest; } - } + else + { + sector->ceilingheight += speed; + if (P_CheckSector(sector, crush) && sector->numattached) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector, crush); + return crushed; + } + } + break; + } + } + else + { + lastpos = sector->floorheight; + // moving a floor + switch (direction) + { + case -1: + // Moving a floor down + if (sector->floorheight - speed < dest) + { + sector->floorheight = dest; + if (P_CheckSector(sector, crush) && sector->numattached) + { + sector->floorheight = lastpos; + P_CheckSector(sector, crush); + } + return pastdest; + } + else + { + sector->floorheight -= speed; + if (P_CheckSector(sector, crush) && sector->numattached) + { + sector->floorheight = lastpos; + P_CheckSector(sector, crush); + return crushed; + } + } + break; - // Break from loop if there is no FOFs to check. - if (!sectorisffloor) + case 1: + // Moving a floor up + // keep floor from moving through ceilings + destheight = (dest < sector->ceilingheight) ? dest : sector->ceilingheight; + if (sector->floorheight + speed > destheight) + { + sector->floorheight = destheight; + if (P_CheckSector(sector, crush)) + { + sector->floorheight = lastpos; + P_CheckSector(sector, crush); + } + return pastdest; + } + else + { + // crushing is possible + sector->floorheight += speed; + if (P_CheckSector(sector, crush)) + { + sector->floorheight = lastpos; + P_CheckSector(sector, crush); + return crushed; + } + } break; } } @@ -292,7 +173,7 @@ void T_MoveFloor(floormove_t *movefloor) res = T_MovePlane(movefloor->sector, movefloor->speed, movefloor->floordestheight, - movefloor->crush, 0, movefloor->direction); + movefloor->crush, false, movefloor->direction); if (movefloor->type == bounceFloor) { @@ -485,7 +366,7 @@ void T_MoveElevator(elevator_t *elevator) elevator->speed, elevator->ceilingdestheight, elevator->distance, - 1, // move floor + true, // move ceiling elevator->direction ); @@ -495,7 +376,7 @@ void T_MoveElevator(elevator_t *elevator) elevator->speed, elevator->floordestheight, elevator->distance, - 0, // move ceiling + false, // move floor elevator->direction ); @@ -547,7 +428,7 @@ void T_MoveElevator(elevator_t *elevator) elevator->speed, elevator->floordestheight, elevator->distance, - 0, // move ceiling + false, // move floor elevator->direction ); @@ -559,7 +440,7 @@ void T_MoveElevator(elevator_t *elevator) elevator->speed, elevator->ceilingdestheight, elevator->distance, - 1, // move floor + true, // move ceiling elevator->direction ); } @@ -680,43 +561,18 @@ void T_MoveElevator(elevator_t *elevator) // // Useful for things like intermittent falling lava. // -void T_ContinuousFalling(levelspecthink_t *faller) +void T_ContinuousFalling(continuousfall_t *faller) { -#define speed vars[0] -#define direction vars[1] -#define floorwasheight vars[2] -#define ceilingwasheight vars[3] -#define floordestheight vars[4] -#define ceilingdestheight vars[5] - - if (faller->direction == -1) - { - faller->sector->ceilingheight -= faller->speed; - faller->sector->floorheight -= faller->speed; - } - else - { - faller->sector->ceilingheight += faller->speed; - faller->sector->floorheight += faller->speed; - } + faller->sector->ceilingheight += faller->speed*faller->direction; + faller->sector->floorheight += faller->speed*faller->direction; P_CheckSector(faller->sector, false); - if (faller->direction == -1) // Down + if ((faller->direction == -1 && faller->sector->ceilingheight <= faller->destheight) + || (faller->direction == 1 && faller->sector->floorheight >= faller->destheight)) { - if (faller->sector->ceilingheight <= faller->ceilingdestheight) // if destination height acheived - { - faller->sector->ceilingheight = faller->ceilingwasheight; - faller->sector->floorheight = faller->floorwasheight; - } - } - else // Up - { - if (faller->sector->floorheight >= faller->floordestheight) // if destination height acheived - { - faller->sector->ceilingheight = faller->ceilingwasheight; - faller->sector->floorheight = faller->floorwasheight; - } + faller->sector->ceilingheight = faller->ceilingstartheight; + faller->sector->floorheight = faller->floorstartheight; } P_CheckSector(faller->sector, false); // you might think this is irrelevant. you would be wrong @@ -724,12 +580,6 @@ void T_ContinuousFalling(levelspecthink_t *faller) faller->sector->floorspeed = faller->speed*faller->direction; faller->sector->ceilspeed = 42; faller->sector->moved = true; -#undef speed -#undef direction -#undef floorwasheight -#undef ceilingwasheight -#undef floordestheight -#undef ceilingdestheight } // @@ -775,23 +625,20 @@ static fixed_t P_SectorCheckWater(sector_t *analyzesector, ////////////////////////////////////////////////// // Bounces a floating cheese -void T_BounceCheese(levelspecthink_t *bouncer) +void T_BounceCheese(bouncecheese_t *bouncer) { -#define speed vars[0] -#define distance vars[1] -#define low vars[2] -#define ceilingwasheight vars[3] -#define floorwasheight vars[4] + fixed_t sectorheight; fixed_t halfheight; fixed_t waterheight; fixed_t floorheight; sector_t *actionsector; INT32 i; + boolean remove; - if (bouncer->sector->crumblestate == 4 || bouncer->sector->crumblestate == 1 - || bouncer->sector->crumblestate == 2) // Oops! Crumbler says to remove yourself! + if (bouncer->sector->crumblestate == CRUMBLE_RESTORE || bouncer->sector->crumblestate == CRUMBLE_WAIT + || bouncer->sector->crumblestate == CRUMBLE_ACTIVATED) // Oops! Crumbler says to remove yourself! { - bouncer->sector->crumblestate = 1; + bouncer->sector->crumblestate = CRUMBLE_WAIT; bouncer->sector->ceilingdata = NULL; bouncer->sector->ceilspeed = 0; bouncer->sector->floordata = NULL; @@ -806,43 +653,28 @@ void T_BounceCheese(levelspecthink_t *bouncer) actionsector = §ors[i]; actionsector->moved = true; - halfheight = abs(bouncer->sector->ceilingheight - bouncer->sector->floorheight) >> 1; + sectorheight = abs(bouncer->sector->ceilingheight - bouncer->sector->floorheight); + halfheight = sectorheight/2; waterheight = P_SectorCheckWater(actionsector, bouncer->sector); // sorts itself out if there's no suitable water in the sector - floorheight = P_FloorzAtPos(actionsector->soundorg.x, actionsector->soundorg.y, bouncer->sector->floorheight, halfheight << 1); + floorheight = P_FloorzAtPos(actionsector->soundorg.x, actionsector->soundorg.y, bouncer->sector->floorheight, sectorheight); + + remove = false; // Water level is up to the ceiling. if (waterheight > bouncer->sector->ceilingheight - halfheight && bouncer->sector->ceilingheight >= actionsector->ceilingheight) // Tails 01-08-2004 { bouncer->sector->ceilingheight = actionsector->ceilingheight; - bouncer->sector->floorheight = bouncer->sector->ceilingheight - (halfheight*2); - T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling - T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor - P_RecalcPrecipInSector(actionsector); - bouncer->sector->ceilingdata = NULL; - bouncer->sector->floordata = NULL; - bouncer->sector->floorspeed = 0; - bouncer->sector->ceilspeed = 0; - bouncer->sector->moved = true; - P_RemoveThinker(&bouncer->thinker); // remove bouncer from actives - return; + bouncer->sector->floorheight = actionsector->ceilingheight - sectorheight; + remove = true; } // Water level is too shallow. else if (waterheight < bouncer->sector->floorheight + halfheight && bouncer->sector->floorheight <= floorheight) { - bouncer->sector->ceilingheight = floorheight + (halfheight << 1); + bouncer->sector->ceilingheight = floorheight + sectorheight; bouncer->sector->floorheight = floorheight; - T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling - T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor - P_RecalcPrecipInSector(actionsector); - bouncer->sector->ceilingdata = NULL; - bouncer->sector->floordata = NULL; - bouncer->sector->floorspeed = 0; - bouncer->sector->ceilspeed = 0; - bouncer->sector->moved = true; - P_RemoveThinker(&bouncer->thinker); // remove bouncer from actives - return; + remove = true; } else { @@ -850,37 +682,47 @@ void T_BounceCheese(levelspecthink_t *bouncer) bouncer->floorwasheight = waterheight - halfheight; } - T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->ceilingheight - - 70*FRACUNIT, 0, 1, -1); // move ceiling - T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->floorheight - 70*FRACUNIT, - 0, 0, -1); // move floor + if (remove) + { + T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, false, true, -1); // update things on ceiling + T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, false, false, -1); // update things on floor + P_RecalcPrecipInSector(actionsector); + bouncer->sector->ceilingdata = NULL; + bouncer->sector->floordata = NULL; + bouncer->sector->floorspeed = 0; + bouncer->sector->ceilspeed = 0; + bouncer->sector->moved = true; + P_RemoveThinker(&bouncer->thinker); // remove bouncer from actives + return; + } + + if (bouncer->speed >= 0) // move floor first to fix height desync and any bizarre bugs following that + { + T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->floorheight - 70*FRACUNIT, + false, false, -1); // move floor + T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->ceilingheight - + 70*FRACUNIT, false, true, -1); // move ceiling + } + else + { + T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->ceilingheight - + 70*FRACUNIT, false, true, -1); // move ceiling + T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->floorheight - 70*FRACUNIT, + false, false, -1); // move floor + } bouncer->sector->floorspeed = -bouncer->speed/2; bouncer->sector->ceilspeed = 42; - if (bouncer->sector->ceilingheight < bouncer->ceilingwasheight && bouncer->low == 0) // Down + if ((bouncer->sector->ceilingheight < bouncer->ceilingwasheight && !bouncer->low) // Down + || (bouncer->sector->ceilingheight > bouncer->ceilingwasheight && bouncer->low)) // Up { if (abs(bouncer->speed) < 6*FRACUNIT) bouncer->speed -= bouncer->speed/3; else bouncer->speed -= bouncer->speed/2; - bouncer->low = 1; - if (abs(bouncer->speed) > 6*FRACUNIT) - { - mobj_t *mp = (void *)&actionsector->soundorg; - actionsector->soundorg.z = bouncer->sector->floorheight; - S_StartSound(mp, sfx_splash); - } - } - else if (bouncer->sector->ceilingheight > bouncer->ceilingwasheight && bouncer->low) // Up - { - if (abs(bouncer->speed) < 6*FRACUNIT) - bouncer->speed -= bouncer->speed/3; - else - bouncer->speed -= bouncer->speed/2; - - bouncer->low = 0; + bouncer->low = !bouncer->low; if (abs(bouncer->speed) > 6*FRACUNIT) { mobj_t *mp = (void *)&actionsector->soundorg; @@ -903,8 +745,8 @@ void T_BounceCheese(levelspecthink_t *bouncer) { bouncer->sector->floorheight = bouncer->floorwasheight; bouncer->sector->ceilingheight = bouncer->ceilingwasheight; - T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling - T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor + T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, false, true, -1); // update things on ceiling + T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, false, false, -1); // update things on floor bouncer->sector->ceilingdata = NULL; bouncer->sector->floordata = NULL; bouncer->sector->floorspeed = 0; @@ -919,27 +761,13 @@ void T_BounceCheese(levelspecthink_t *bouncer) if (actionsector) P_RecalcPrecipInSector(actionsector); } -#undef speed -#undef distance -#undef low -#undef ceilingwasheight -#undef floorwasheight } ////////////////////////////////////////////////// // T_StartCrumble //////////////////////////////// ////////////////////////////////////////////////// // Crumbling platform Tails 03-11-2002 -// -// DEFINITION OF THE 'CRUMBLESTATE'S: -// -// 0 - No crumble thinker -// 1 - Don't float on water because this is supposed to wait for a crumble -// 2 - Crumble thinker activated, but hasn't fallen yet -// 3 - Crumble thinker is falling -// 4 - Crumble thinker is about to restore to original position -// -void T_StartCrumble(elevator_t *elevator) +void T_StartCrumble(crumble_t *crumble) { ffloor_t *rover; sector_t *sector; @@ -947,84 +775,96 @@ void T_StartCrumble(elevator_t *elevator) // Once done, the no-return thinker just sits there, // constantly 'returning'... kind of an oxymoron, isn't it? - if (((elevator->floordestheight == 1 && elevator->direction == -1) - || (elevator->floordestheight == 0 && elevator->direction == 1)) - && elevator->type == elevateContinuous) // No return crumbler + if ((((crumble->flags & CF_REVERSE) && crumble->direction == -1) + || (!(crumble->flags & CF_REVERSE) && crumble->direction == 1)) + && !(crumble->flags & CF_RETURN)) { - elevator->sector->ceilspeed = 0; - elevator->sector->floorspeed = 0; + crumble->sector->ceilspeed = 0; + crumble->sector->floorspeed = 0; return; } - if (elevator->distance != 0) + if (crumble->timer != 0) { - if (elevator->distance > 0) // Count down the timer + if (crumble->timer > 0) // Count down the timer { - elevator->distance--; - if (elevator->distance <= 0) - elevator->distance = -15*TICRATE; // Timer until platform returns to original position. + if (--crumble->timer <= 0) + crumble->timer = -15*TICRATE; // Timer until platform returns to original position. else { // Timer isn't up yet, so just keep waiting. - elevator->sector->ceilspeed = 0; - elevator->sector->floorspeed = 0; + crumble->sector->ceilspeed = 0; + crumble->sector->floorspeed = 0; return; } } - else if (++elevator->distance == 0) // Reposition back to original spot + else if (++crumble->timer == 0) // Reposition back to original spot { - for (i = -1; (i = P_FindSectorFromTag(elevator->sourceline->tag, i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) { sector = §ors[i]; for (rover = sector->ffloors; rover; rover = rover->next) { - if (rover->flags & FF_CRUMBLE && rover->flags & FF_FLOATBOB - && rover->master == elevator->sourceline) - { - rover->alpha = elevator->origspeed; + if (!(rover->flags & FF_CRUMBLE)) + continue; - if (rover->alpha == 0xff) - rover->flags &= ~FF_TRANSLUCENT; - } + if (!(rover->flags & FF_FLOATBOB)) + continue; + + if (rover->master != crumble->sourceline) + continue; + + rover->alpha = crumble->origalpha; + + if (rover->alpha == 0xff) + rover->flags &= ~FF_TRANSLUCENT; } } // Up! - if (elevator->floordestheight == 1) - elevator->direction = -1; + if (crumble->flags & CF_REVERSE) + crumble->direction = -1; else - elevator->direction = 1; + crumble->direction = 1; - elevator->sector->ceilspeed = 0; - elevator->sector->floorspeed = 0; + crumble->sector->ceilspeed = 0; + crumble->sector->floorspeed = 0; return; } // Flash to indicate that the platform is about to return. - if (elevator->distance > -224 && (leveltime % ((abs(elevator->distance)/8) + 1) == 0)) + if (crumble->timer > -224 && (leveltime % ((abs(crumble->timer)/8) + 1) == 0)) { - for (i = -1; (i = P_FindSectorFromTag(elevator->sourceline->tag, i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) { sector = §ors[i]; for (rover = sector->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_NORETURN) && rover->flags & FF_CRUMBLE && rover->flags & FF_FLOATBOB - && rover->master == elevator->sourceline) - { - if (rover->alpha == elevator->origspeed) - { - rover->flags |= FF_TRANSLUCENT; - rover->alpha = 0x00; - } - else - { - if (elevator->origspeed == 0xff) - rover->flags &= ~FF_TRANSLUCENT; + if (rover->flags & FF_NORETURN) + continue; - rover->alpha = elevator->origspeed; - } + if (!(rover->flags & FF_CRUMBLE)) + continue; + + if (!(rover->flags & FF_FLOATBOB)) + continue; + + if (rover->master != crumble->sourceline) + continue; + + if (rover->alpha == crumble->origalpha) + { + rover->flags |= FF_TRANSLUCENT; + rover->alpha = 0x00; + } + else + { + rover->alpha = crumble->origalpha; + + if (rover->alpha == 0xff) + rover->flags &= ~FF_TRANSLUCENT; } } } @@ -1033,74 +873,62 @@ void T_StartCrumble(elevator_t *elevator) // We're about to go back to the original position, // so set this to let other thinkers know what is // about to happen. - if (elevator->distance < 0 && elevator->distance > -3) - elevator->sector->crumblestate = 4; // makes T_BounceCheese remove itself + if (crumble->timer < 0 && crumble->timer > -3) + crumble->sector->crumblestate = CRUMBLE_RESTORE; // makes T_BounceCheese remove itself } - if ((elevator->floordestheight == 0 && elevator->direction == -1) - || (elevator->floordestheight == 1 && elevator->direction == 1)) // Down + if ((!(crumble->flags & CF_REVERSE) && crumble->direction == -1) + || ((crumble->flags & CF_REVERSE) && crumble->direction == 1)) // Down { - elevator->sector->crumblestate = 3; // Allow floating now. + crumble->sector->crumblestate = CRUMBLE_FALL; // Allow floating now. // Only fall like this if it isn't meant to float on water - if (elevator->high != 42) + if (!(crumble->flags & CF_FLOATBOB)) { - elevator->speed += gravity; // Gain more and more speed + crumble->speed += gravity; // Gain more and more speed - if ((elevator->floordestheight == 0 && !(elevator->sector->ceilingheight < -16384*FRACUNIT)) - || (elevator->floordestheight == 1 && !(elevator->sector->ceilingheight > 16384*FRACUNIT))) + if ((!(crumble->flags & CF_REVERSE) && crumble->sector->ceilingheight >= -16384*FRACUNIT) + || ((crumble->flags & CF_REVERSE) && crumble->sector->ceilingheight <= 16384*FRACUNIT)) { - fixed_t dest; - - if (elevator->floordestheight == 1) - dest = elevator->sector->ceilingheight + (elevator->speed*2); - else - dest = elevator->sector->ceilingheight - (elevator->speed*2); - T_MovePlane //jff 4/7/98 reverse order of ceiling/floor ( - elevator->sector, - elevator->speed, - dest, - 0, - 1, // move floor - elevator->direction + crumble->sector, + crumble->speed, + crumble->sector->ceilingheight + crumble->direction*crumble->speed*2, + false, + true, // move ceiling + crumble->direction ); - if (elevator->floordestheight == 1) - dest = elevator->sector->floorheight + (elevator->speed*2); - else - dest = elevator->sector->floorheight - (elevator->speed*2); - - T_MovePlane - ( - elevator->sector, - elevator->speed, - dest, - 0, - 0, // move ceiling - elevator->direction + T_MovePlane + ( + crumble->sector, + crumble->speed, + crumble->sector->floorheight + crumble->direction*crumble->speed*2, + false, + false, // move floor + crumble->direction ); - elevator->sector->ceilspeed = 42; - elevator->sector->floorspeed = elevator->speed*elevator->direction; + crumble->sector->ceilspeed = 42; + crumble->sector->floorspeed = crumble->speed*crumble->direction; } } } else // Up (restore to original position) { - elevator->sector->crumblestate = 1; - elevator->sector->ceilingheight = elevator->ceilingwasheight; - elevator->sector->floorheight = elevator->floorwasheight; - elevator->sector->floordata = NULL; - elevator->sector->ceilingdata = NULL; - elevator->sector->ceilspeed = 0; - elevator->sector->floorspeed = 0; - elevator->sector->moved = true; - P_RemoveThinker(&elevator->thinker); + crumble->sector->crumblestate = CRUMBLE_WAIT; + crumble->sector->ceilingheight = crumble->ceilingwasheight; + crumble->sector->floorheight = crumble->floorwasheight; + crumble->sector->floordata = NULL; + crumble->sector->ceilingdata = NULL; + crumble->sector->ceilspeed = 0; + crumble->sector->floorspeed = 0; + crumble->sector->moved = true; + P_RemoveThinker(&crumble->thinker); } - for (i = -1; (i = P_FindSectorFromTag(elevator->sourceline->tag, i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) { sector = §ors[i]; sector->moved = true; @@ -1113,24 +941,17 @@ void T_StartCrumble(elevator_t *elevator) ////////////////////////////////////////////////// // Mario hits a block! // -void T_MarioBlock(levelspecthink_t *block) +void T_MarioBlock(mariothink_t *block) { INT32 i; -#define speed vars[1] -#define direction vars[2] -#define floorwasheight vars[3] -#define ceilingwasheight vars[4] -#define distance vars[5] -#define low vars[6] - T_MovePlane ( block->sector, block->speed, block->sector->ceilingheight + 70*FRACUNIT * block->direction, - 0, - 1, // move floor + false, + true, // move ceiling block->direction ); @@ -1139,17 +960,17 @@ void T_MarioBlock(levelspecthink_t *block) block->sector, block->speed, block->sector->floorheight + 70*FRACUNIT * block->direction, - 0, - 0, // move ceiling + false, + false, // move floor block->direction ); - if (block->sector->ceilingheight >= block->ceilingwasheight + 32*FRACUNIT) // Go back down now.. - block->direction = -block->direction; - else if (block->sector->ceilingheight <= block->ceilingwasheight) + if (block->sector->ceilingheight >= block->ceilingstartheight + 32*FRACUNIT) // Go back down now.. + block->direction *= -1; + else if (block->sector->ceilingheight <= block->ceilingstartheight) { - block->sector->ceilingheight = block->ceilingwasheight; - block->sector->floorheight = block->floorwasheight; + block->sector->ceilingheight = block->ceilingstartheight; + block->sector->floorheight = block->floorstartheight; P_RemoveThinker(&block->thinker); block->sector->floordata = NULL; block->sector->ceilingdata = NULL; @@ -1158,595 +979,41 @@ void T_MarioBlock(levelspecthink_t *block) block->direction = 0; } - for (i = -1; (i = P_FindSectorFromTag((INT16)block->vars[0], i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(block->tag, i)) >= 0 ;) P_RecalcPrecipInSector(§ors[i]); - -#undef speed -#undef direction -#undef floorwasheight -#undef ceilingwasheight -#undef distance -#undef low } -void T_SpikeSector(levelspecthink_t *spikes) -{ - mobj_t *thing; - msecnode_t *node; - boolean dothepain; - sector_t *affectsec; - - node = spikes->sector->touching_thinglist; // things touching this sector - - for (; node; node = node->m_thinglist_next) - { - thing = node->m_thing; - if (!thing->player) - continue; - - dothepain = false; - affectsec = §ors[spikes->vars[0]]; - - if (affectsec == spikes->sector) // Applied to an actual sector - { - fixed_t affectfloor = P_GetSpecialBottomZ(thing, affectsec, affectsec); - fixed_t affectceil = P_GetSpecialTopZ(thing, affectsec, affectsec); - - if (affectsec->flags & SF_FLIPSPECIAL_FLOOR) - { - if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0) - continue; - - if (thing->z == affectfloor) - dothepain = true; - } - - if (affectsec->flags & SF_FLIPSPECIAL_CEILING) - { - if ((thing->eflags & MFE_VERTICALFLIP) && thing->momz < 0) - continue; - - if (thing->z + thing->height == affectceil) - dothepain = true; - } - } - else - { - fixed_t affectfloor = P_GetSpecialBottomZ(thing, affectsec, spikes->sector); - fixed_t affectceil = P_GetSpecialTopZ(thing, affectsec, spikes->sector); - if (affectsec->flags & SF_FLIPSPECIAL_FLOOR) - { - if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0) - continue; - - if (thing->z == affectceil) - dothepain = true; - } - - if (affectsec->flags & SF_FLIPSPECIAL_CEILING) - { - if ((thing->eflags & MFE_VERTICALFLIP) && thing->momz < 0) - continue; - - if (thing->z + thing->height == affectfloor) - dothepain = true; - } - } - - if (dothepain) - { - P_DamageMobj(thing, NULL, NULL, 1, DMG_SPIKE); - break; - } - } -} - -void T_FloatSector(levelspecthink_t *floater) +void T_FloatSector(floatthink_t *floater) { fixed_t cheeseheight; + fixed_t waterheight; sector_t *actionsector; INT32 secnum; - cheeseheight = (floater->sector->ceilingheight + floater->sector->floorheight)>>1; - // Just find the first sector with the tag. // Doesn't work with multiple sectors that have different floor/ceiling heights. - secnum = P_FindSectorFromTag((INT16)floater->vars[0], -1); + secnum = P_FindSectorFromTag(floater->tag, -1); + if (secnum <= 0) + return; + actionsector = §ors[secnum]; - if (secnum > 0) - actionsector = §ors[secnum]; - else - actionsector = NULL; + cheeseheight = (floater->sector->ceilingheight + floater->sector->floorheight)>>1; - if (actionsector) - { - //boolean floatanyway = false; // Ignore the crumblestate setting. - fixed_t waterheight = P_SectorCheckWater(actionsector, floater->sector); // find the highest suitable water block around + //boolean floatanyway = false; // Ignore the crumblestate setting. + waterheight = P_SectorCheckWater(actionsector, floater->sector); // find the highest suitable water block around - if (waterheight == cheeseheight) // same height, no floating needed - ; - else if (floater->sector->floorheight == actionsector->floorheight && waterheight < cheeseheight) // too low - ; - else if (floater->sector->ceilingheight == actionsector->ceilingheight && waterheight > cheeseheight) // too high - ; - // we have something to float in! Or we're for some reason above the ground, let's fall anyway - else if (floater->sector->crumblestate == 0 || floater->sector->crumblestate >= 3/* || floatanyway*/) - EV_BounceSector(floater->sector, FRACUNIT, floater->sourceline); + if (waterheight == cheeseheight) // same height, no floating needed + return; - P_RecalcPrecipInSector(actionsector); - } -} + if (floater->sector->floorheight == actionsector->floorheight && waterheight < cheeseheight) // too low + return; -// -// T_BridgeThinker -// -// Kind of like T_RaiseSector, -// but spreads out across -// multiple FOFs at varying -// intensity. -// -void T_BridgeThinker(levelspecthink_t *bridge) -{ - msecnode_t *node; - mobj_t *thing; - sector_t *sector; - sector_t *controlsec = NULL; - INT32 i, k; + if (floater->sector->ceilingheight == actionsector->ceilingheight && waterheight > cheeseheight) // too high + return; - INT16 j; - boolean playeronme = false; - fixed_t ceilingdestination = 0, floordestination = 0; - result_e res = 0; - -#define ORIGFLOORHEIGHT (bridge->vars[0]) -#define ORIGCEILINGHEIGHT (bridge->vars[1]) -#define BASESPEED (bridge->vars[2]) -#define CURSPEED (bridge->vars[3]) -#define STARTTAG ((INT16)bridge->vars[4]) -#define ENDTAG ((INT16)bridge->vars[5]) -#define DIRECTION (bridge->vars[8]) -#define SAGAMT (8*FRACUNIT) - fixed_t lowceilheight = ORIGCEILINGHEIGHT - SAGAMT; - fixed_t lowfloorheight = ORIGFLOORHEIGHT - SAGAMT; -#define LOWCEILINGHEIGHT (lowceilheight) -#define LOWFLOORHEIGHT (lowfloorheight) -#define STARTCONTROLTAG (ENDTAG + 1) -#define ENDCONTROLTAG (ENDTAG + (ENDTAG - STARTTAG) + 1) - - // Is someone standing on it? - for (j = STARTTAG; j <= ENDTAG; j++) - { - for (i = -1; (i = P_FindSectorFromTag(j, i)) >= 0 ;) - { - sector = §ors[i]; - - // Nab the control sector that this sector belongs to. - k = P_FindSectorFromTag((INT16)(j + (ENDTAG-STARTTAG) + 1), -1); - - if (k == -1) - break; - - controlsec = §ors[k]; - - // Is a player standing on me? - for (node = sector->touching_thinglist; node; node = node->m_thinglist_next) - { - thing = node->m_thing; - - if (!thing->player) - continue; - - if (!(thing->z == controlsec->ceilingheight)) - continue; - - playeronme = true; - goto wegotit; // Just take the first one? - } - } - } -wegotit: - if (playeronme) - { - // Lower controlsec like a regular T_RaiseSector - // Set the heights of all the other control sectors to - // be a gradient of this height toward the edges - } - else - { - // Raise controlsec like a regular T_RaiseSector - // Set the heights of all the other control sectors to - // be a gradient of this height toward the edges. - } - - if (playeronme && controlsec) - { - INT32 dist; - - bridge->sector = controlsec; - CURSPEED = BASESPEED; - - { - // Translate tags to - 0 + range - /*so you have a number in [min, max]. - let range = max - min, subtract min - from your number to get [0, range]. - subtract range/2 to get [-range/2, range/2]. - take absolute value and get [0, range/2] where - lower number = closer to midpoint. divide by - range/2 to get [0, 1]. subtract that number - from 1 to get [0, 1] with higher number = closer - to midpoint. multiply this by max sag amount*/ - - INT32 midpoint = STARTCONTROLTAG + ((ENDCONTROLTAG-STARTCONTROLTAG) + 1)/2; -// INT32 tagstart = STARTTAG - midpoint; -// INT32 tagend = ENDTAG - midpoint; - -// CONS_Debug(DBG_GAMELOGIC, "tagstart is %d, tagend is %d\n", tagstart, tagend); - - // Sag is adjusted by how close you are to the center - dist = ((ENDCONTROLTAG - STARTCONTROLTAG))/2 - abs(bridge->sector->tag - midpoint); - -// CONS_Debug(DBG_GAMELOGIC, "Dist is %d\n", dist); - LOWCEILINGHEIGHT -= (SAGAMT) * dist; - LOWFLOORHEIGHT -= (SAGAMT) * dist; - } - - // go down - if (bridge->sector->ceilingheight <= LOWCEILINGHEIGHT) - { - bridge->sector->floorheight = LOWCEILINGHEIGHT - (bridge->sector->ceilingheight - bridge->sector->floorheight); - bridge->sector->ceilingheight = LOWCEILINGHEIGHT; - bridge->sector->ceilspeed = 0; - bridge->sector->floorspeed = 0; - goto dorest; - } - - DIRECTION = -1; - ceilingdestination = LOWCEILINGHEIGHT; - floordestination = LOWFLOORHEIGHT; - - if ((bridge->sector->ceilingheight - LOWCEILINGHEIGHT) - < (ORIGCEILINGHEIGHT - bridge->sector->ceilingheight)) - { - fixed_t origspeed = CURSPEED; - - // Slow down as you get closer to the bottom - CURSPEED = FixedMul(CURSPEED,FixedDiv(bridge->sector->ceilingheight - LOWCEILINGHEIGHT, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - else - { - fixed_t origspeed = CURSPEED; - // Slow down as you get closer to the top - CURSPEED = FixedMul(CURSPEED,FixedDiv(ORIGCEILINGHEIGHT - bridge->sector->ceilingheight, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - -// CONS_Debug(DBG_GAMELOGIC, "Curspeed is %d\n", CURSPEED>>FRACBITS); - - res = T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - ceilingdestination, // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - DIRECTION // direction - ); - - if (res == ok || res == pastdest) - T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - floordestination, // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - DIRECTION // direction - ); - - bridge->sector->ceilspeed = 42; - bridge->sector->floorspeed = CURSPEED*DIRECTION; - - dorest: - // Adjust joined sector heights - { - sector_t *sourcesec = bridge->sector; - - INT32 divisor = sourcesec->tag - ENDTAG + 1; - fixed_t heightdiff = ORIGCEILINGHEIGHT - sourcesec->ceilingheight; - fixed_t interval; - INT32 plusplusme = 0; - - if (divisor > 0) - { - interval = heightdiff/divisor; - -// CONS_Debug(DBG_GAMELOGIC, "interval is %d\n", interval>>FRACBITS); - - // TODO: Use T_MovePlane - - for (j = (INT16)(ENDTAG+1); j <= sourcesec->tag; j++, plusplusme++) - { - for (i = -1; (i = P_FindSectorFromTag(j, i)) >= 0 ;) - { - if (sectors[i].ceilingheight >= sourcesec->ceilingheight) - { - sectors[i].ceilingheight = ORIGCEILINGHEIGHT - (interval*plusplusme); - sectors[i].floorheight = ORIGFLOORHEIGHT - (interval*plusplusme); - } - else // Do the regular rise - { - bridge->sector = §ors[i]; - - CURSPEED = BASESPEED/2; - - // rise back up - if (bridge->sector->ceilingheight >= ORIGCEILINGHEIGHT) - { - bridge->sector->floorheight = ORIGCEILINGHEIGHT - (bridge->sector->ceilingheight - bridge->sector->floorheight); - bridge->sector->ceilingheight = ORIGCEILINGHEIGHT; - bridge->sector->ceilspeed = 0; - bridge->sector->floorspeed = 0; - continue; - } - - DIRECTION = 1; - ceilingdestination = ORIGCEILINGHEIGHT; - floordestination = ORIGFLOORHEIGHT; - -// CONS_Debug(DBG_GAMELOGIC, "ceildest: %d, floordest: %d\n", ceilingdestination>>FRACBITS, floordestination>>FRACBITS); - - if ((bridge->sector->ceilingheight - LOWCEILINGHEIGHT) - < (ORIGCEILINGHEIGHT - bridge->sector->ceilingheight)) - { - fixed_t origspeed = CURSPEED; - - // Slow down as you get closer to the bottom - CURSPEED = FixedMul(CURSPEED,FixedDiv(bridge->sector->ceilingheight - LOWCEILINGHEIGHT, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - else - { - fixed_t origspeed = CURSPEED; - // Slow down as you get closer to the top - CURSPEED = FixedMul(CURSPEED,FixedDiv(ORIGCEILINGHEIGHT - bridge->sector->ceilingheight, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - - res = T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - ceilingdestination, // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - DIRECTION // direction - ); - - if (res == ok || res == pastdest) - T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - floordestination, // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - DIRECTION // direction - ); - - bridge->sector->ceilspeed = 42; - bridge->sector->floorspeed = CURSPEED*DIRECTION; - } - } - } - } - - // Now the other side - divisor = ENDTAG + (ENDTAG-STARTTAG) + 1; - divisor -= sourcesec->tag; - - if (divisor > 0) - { - interval = heightdiff/divisor; - plusplusme = 0; - -// CONS_Debug(DBG_GAMELOGIC, "interval2 is %d\n", interval>>FRACBITS); - - for (j = (INT16)(sourcesec->tag+1); j <= ENDTAG + (ENDTAG-STARTTAG) + 1; j++, plusplusme++) - { - for (i = -1; (i = P_FindSectorFromTag(j, i)) >= 0 ;) - { - if (sectors[i].ceilingheight >= sourcesec->ceilingheight) - { - sectors[i].ceilingheight = sourcesec->ceilingheight + (interval*plusplusme); - sectors[i].floorheight = sourcesec->floorheight + (interval*plusplusme); - } - else // Do the regular rise - { - bridge->sector = §ors[i]; - - CURSPEED = BASESPEED/2; - - // rise back up - if (bridge->sector->ceilingheight >= ORIGCEILINGHEIGHT) - { - bridge->sector->floorheight = ORIGCEILINGHEIGHT - (bridge->sector->ceilingheight - bridge->sector->floorheight); - bridge->sector->ceilingheight = ORIGCEILINGHEIGHT; - bridge->sector->ceilspeed = 0; - bridge->sector->floorspeed = 0; - continue; - } - - DIRECTION = 1; - ceilingdestination = ORIGCEILINGHEIGHT; - floordestination = ORIGFLOORHEIGHT; - -// CONS_Debug(DBG_GAMELOGIC, "ceildest: %d, floordest: %d\n", ceilingdestination>>FRACBITS, floordestination>>FRACBITS); - - if ((bridge->sector->ceilingheight - LOWCEILINGHEIGHT) - < (ORIGCEILINGHEIGHT - bridge->sector->ceilingheight)) - { - fixed_t origspeed = CURSPEED; - - // Slow down as you get closer to the bottom - CURSPEED = FixedMul(CURSPEED,FixedDiv(bridge->sector->ceilingheight - LOWCEILINGHEIGHT, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - else - { - fixed_t origspeed = CURSPEED; - // Slow down as you get closer to the top - CURSPEED = FixedMul(CURSPEED,FixedDiv(ORIGCEILINGHEIGHT - bridge->sector->ceilingheight, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - - res = T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - ceilingdestination, // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - DIRECTION // direction - ); - - if (res == ok || res == pastdest) - T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - floordestination, // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - DIRECTION // direction - ); - - bridge->sector->ceilspeed = 42; - bridge->sector->floorspeed = CURSPEED*DIRECTION; - } - } - } - } - } - - // for (i = -1; (i = P_FindSectorFromTag(bridge->sourceline->tag, i)) >= 0 ;) - // P_RecalcPrecipInSector(§ors[i]); - } - else - { - // Iterate control sectors - for (j = (INT16)(ENDTAG+1); j <= (ENDTAG+(ENDTAG-STARTTAG)+1); j++) - { - for (i = -1; (i = P_FindSectorFromTag(j, i)) >= 0 ;) - { - bridge->sector = §ors[i]; - - CURSPEED = BASESPEED/2; - - // rise back up - if (bridge->sector->ceilingheight >= ORIGCEILINGHEIGHT) - { - bridge->sector->floorheight = ORIGCEILINGHEIGHT - (bridge->sector->ceilingheight - bridge->sector->floorheight); - bridge->sector->ceilingheight = ORIGCEILINGHEIGHT; - bridge->sector->ceilspeed = 0; - bridge->sector->floorspeed = 0; - continue; - } - - DIRECTION = 1; - ceilingdestination = ORIGCEILINGHEIGHT; - floordestination = ORIGFLOORHEIGHT; - -// CONS_Debug(DBG_GAMELOGIC, "ceildest: %d, floordest: %d\n", ceilingdestination>>FRACBITS, floordestination>>FRACBITS); - - if ((bridge->sector->ceilingheight - LOWCEILINGHEIGHT) - < (ORIGCEILINGHEIGHT - bridge->sector->ceilingheight)) - { - fixed_t origspeed = CURSPEED; - - // Slow down as you get closer to the bottom - CURSPEED = FixedMul(CURSPEED,FixedDiv(bridge->sector->ceilingheight - LOWCEILINGHEIGHT, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - else - { - fixed_t origspeed = CURSPEED; - // Slow down as you get closer to the top - CURSPEED = FixedMul(CURSPEED,FixedDiv(ORIGCEILINGHEIGHT - bridge->sector->ceilingheight, (ORIGCEILINGHEIGHT - LOWCEILINGHEIGHT)>>5)); - - if (CURSPEED <= origspeed/16) - CURSPEED = origspeed/16; - else if (CURSPEED > origspeed) - CURSPEED = origspeed; - } - - res = T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - ceilingdestination, // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - DIRECTION // direction - ); - - if (res == ok || res == pastdest) - T_MovePlane - ( - bridge->sector, // sector - CURSPEED, // speed - floordestination, // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - DIRECTION // direction - ); - - bridge->sector->ceilspeed = 42; - bridge->sector->floorspeed = CURSPEED*DIRECTION; - } - } - // Update precip - } - -#undef SAGAMT -#undef LOWFLOORHEIGHT -#undef LOWCEILINGHEIGHT -#undef ORIGFLOORHEIGHT -#undef ORIGCEILINGHEIGHT -#undef BASESPEED -#undef CURSPEED -#undef STARTTAG -#undef ENDTAG -#undef DIRECTION + // we have something to float in! Or we're for some reason above the ground, let's fall anyway + if (floater->sector->crumblestate == CRUMBLE_NONE || floater->sector->crumblestate >= CRUMBLE_FALL/* || floatanyway*/) + EV_BounceSector(floater->sector, FRACUNIT, floater->sourceline); } static mobj_t *SearchMarioNode(msecnode_t *node) @@ -1814,187 +1081,91 @@ static mobj_t *SearchMarioNode(msecnode_t *node) return thing; } -void T_MarioBlockChecker(levelspecthink_t *block) +void T_MarioBlockChecker(mariocheck_t *block) { line_t *masterline = block->sourceline; - if (block->vars[2] == 1) // Don't update the textures when the block's being bumped upwards. - return; if (SearchMarioNode(block->sector->touching_thinglist)) { sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture; // Update textures if (masterline->backsector) - { block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->ceilingpic; // Update flats to be backside's ceiling - } } else { sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].toptexture; if (masterline->backsector) - { block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->floorpic; // Update flats to be backside's floor - } } } +static boolean P_IsPlayerValid(size_t playernum) +{ + if (!playeringame[playernum]) + return false; + + if (!players[playernum].mo) + return false; + + if (players[playernum].mo->health <= 0) + return false; + + if (players[playernum].spectator) + return false; + + return true; +} + // This is the Thwomp's 'brain'. It looks around for players nearby, and if // it finds any, **SMASH**!!! Muahahhaa.... -void T_ThwompSector(levelspecthink_t *thwomp) +void T_ThwompSector(thwomp_t *thwomp) { -#define speed vars[1] -#define direction vars[2] -#define distance vars[3] -#define floorwasheight vars[4] -#define ceilingwasheight vars[5] fixed_t thwompx, thwompy; sector_t *actionsector; ffloor_t *rover = NULL; INT32 secnum; + fixed_t speed; // If you just crashed down, wait a second before coming back up. - if (--thwomp->distance > 0) - { - sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].bottomtexture; + if (--thwomp->delay > 0) return; - } // Just find the first sector with the tag. // Doesn't work with multiple sectors that have different floor/ceiling heights. - secnum = P_FindSectorFromTag((INT16)thwomp->vars[0], -1); + secnum = P_FindSectorFromTag(thwomp->tag, -1); - if (secnum > 0) - { - actionsector = §ors[secnum]; - - // Look for thwomp FFloor - for (rover = actionsector->ffloors; rover; rover = rover->next) - { - if (rover->master == thwomp->sourceline) - break; - } - } - else + if (secnum <= 0) return; // Bad bad bad! + actionsector = §ors[secnum]; + + // Look for thwomp FOF + for (rover = actionsector->ffloors; rover; rover = rover->next) + { + if (rover->master == thwomp->sourceline) + break; + } + + if (!rover) + return; // Didn't find any FOFs, so bail out + thwompx = actionsector->soundorg.x; thwompy = actionsector->soundorg.y; - if (thwomp->direction > 0) // Moving back up.. + if (thwomp->direction == 0) // Not going anywhere, so look for players. { - result_e res = 0; - - // Set the texture from the lower one (normal) - sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].bottomtexture; - /// \note this should only have to be done once, but is already done repeatedly, above - - if (thwomp->sourceline->flags & ML_EFFECT5) - thwomp->speed = thwomp->sourceline->dx/8; - else - thwomp->speed = 2*FRACUNIT; - - res = T_MovePlane - ( - thwomp->sector, // sector - thwomp->speed, // speed - thwomp->floorwasheight, // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - thwomp->direction // direction - ); - - if (res == ok || res == pastdest) - T_MovePlane - ( - thwomp->sector, // sector - thwomp->speed, // speed - thwomp->ceilingwasheight, // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - thwomp->direction // direction - ); - - if (res == pastdest) - thwomp->direction = 0; // stop moving - - thwomp->sector->ceilspeed = 42; - thwomp->sector->floorspeed = thwomp->speed*thwomp->direction; - } - else if (thwomp->direction < 0) // Crashing down! - { - result_e res = 0; - - // Set the texture from the upper one (angry) - sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].toptexture; - - if (thwomp->sourceline->flags & ML_EFFECT5) - thwomp->speed = thwomp->sourceline->dy/8; - else - thwomp->speed = 10*FRACUNIT; - - res = T_MovePlane - ( - thwomp->sector, // sector - thwomp->speed, // speed - P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight, - thwomp->sector->ceilingheight - thwomp->sector->floorheight), // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - thwomp->direction // direction - ); - - if (res == ok || res == pastdest) - T_MovePlane - ( - thwomp->sector, // sector - thwomp->speed, // speed - P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight, - thwomp->sector->ceilingheight - - (thwomp->sector->floorheight + thwomp->speed)) - + (thwomp->sector->ceilingheight - - (thwomp->sector->floorheight + thwomp->speed/2)), // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - thwomp->direction // direction - ); - - if (res == pastdest) - { - mobj_t *mp = (void *)&actionsector->soundorg; - - if (!rover || (rover->flags & FF_EXISTS)) - { - if (thwomp->sourceline->flags & ML_EFFECT4) - S_StartSound(mp, sides[thwomp->sourceline->sidenum[0]].textureoffset>>FRACBITS); - else - S_StartSound(mp, sfx_thwomp); - } - - thwomp->direction = 1; // start heading back up - thwomp->distance = TICRATE; // but only after a small delay - } - - thwomp->sector->ceilspeed = 42; - thwomp->sector->floorspeed = thwomp->speed*thwomp->direction; - } - else // Not going anywhere, so look for players. - { - if (!rover || (rover->flags & FF_EXISTS)) + if (rover->flags & FF_EXISTS) { UINT8 i; // scan the players to find victims! for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i]) - continue; - if (players[i].spectator) - continue; - if (!players[i].mo) - continue; - if (!players[i].mo->health) + if (!P_IsPlayerValid(i)) continue; + if (players[i].mo->z > thwomp->sector->ceilingheight) continue; - if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96 * FRACUNIT) + + if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96*FRACUNIT) continue; thwomp->direction = -1; @@ -2005,13 +1176,109 @@ void T_ThwompSector(levelspecthink_t *thwomp) thwomp->sector->ceilspeed = 0; thwomp->sector->floorspeed = 0; } + else + { + result_e res = 0; + + if (thwomp->direction > 0) //Moving back up.. + { + // Set the texture from the lower one (normal) + sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].bottomtexture; + + speed = thwomp->retractspeed; + + res = T_MovePlane + ( + thwomp->sector, // sector + speed, // speed + thwomp->floorstartheight, // dest + false, // crush + false, // ceiling? + thwomp->direction // direction + ); + + if (res == ok || res == pastdest) + T_MovePlane + ( + thwomp->sector, // sector + speed, // speed + thwomp->ceilingstartheight, // dest + false, // crush + true, // ceiling? + thwomp->direction // direction + ); + + if (res == pastdest) + thwomp->direction = 0; // stop moving + } + else // Crashing down! + { + // Set the texture from the upper one (angry) + sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].toptexture; + + speed = thwomp->crushspeed; + + res = T_MovePlane + ( + thwomp->sector, // sector + speed, // speed + P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight, + thwomp->sector->ceilingheight - thwomp->sector->floorheight), // dest + false, // crush + false, // ceiling? + thwomp->direction // direction + ); + + if (res == ok || res == pastdest) + T_MovePlane + ( + thwomp->sector, // sector + speed, // speed + P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight, + thwomp->sector->ceilingheight + - (thwomp->sector->floorheight + speed)) + + (thwomp->sector->ceilingheight + - (thwomp->sector->floorheight + speed/2)), // dest + false, // crush + true, // ceiling? + thwomp->direction // direction + ); + + if (res == pastdest) + { + if (rover->flags & FF_EXISTS) + S_StartSound((void *)&actionsector->soundorg, thwomp->sound); + + thwomp->direction = 1; // start heading back up + thwomp->delay = TICRATE; // but only after a small delay + } + } + + thwomp->sector->ceilspeed = 42; + thwomp->sector->floorspeed = speed*thwomp->direction; + } P_RecalcPrecipInSector(actionsector); -#undef speed -#undef direction -#undef distance -#undef floorwasheight -#undef ceilingwasheight +} + +static boolean T_SectorHasEnemies(sector_t *sec) +{ + msecnode_t *node = sec->touching_thinglist; // things touching this sector + mobj_t *mo; + while (node) + { + mo = node->m_thing; + + if ((mo->flags & (MF_ENEMY|MF_BOSS)) + && mo->health > 0 + && mo->z < sec->ceilingheight + && mo->z + mo->height > sec->floorheight) + return true; + + node = node->m_thinglist_next; + } + + return false; } // @@ -2020,18 +1287,14 @@ void T_ThwompSector(levelspecthink_t *thwomp) // Runs a linedef exec when no more MF_ENEMY/MF_BOSS objects with health are in the area // \sa P_AddNoEnemiesThinker // -void T_NoEnemiesSector(levelspecthink_t *nobaddies) +void T_NoEnemiesSector(noenemies_t *nobaddies) { size_t i; - fixed_t upperbound, lowerbound; sector_t *sec = NULL; - sector_t *targetsec = NULL; INT32 secnum = -1; - msecnode_t *node; - mobj_t *thing; boolean FOFsector = false; - while ((secnum = P_FindSectorFromLineTag(nobaddies->sourceline, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(nobaddies->sourceline->tag, secnum)) >= 0) { sec = §ors[secnum]; @@ -2047,42 +1310,15 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies) FOFsector = true; - while ((targetsecnum = P_FindSectorFromLineTag(sec->lines[i], targetsecnum)) >= 0) + while ((targetsecnum = P_FindSectorFromTag(sec->lines[i]->tag, targetsecnum)) >= 0) { - targetsec = §ors[targetsecnum]; - - upperbound = targetsec->ceilingheight; - lowerbound = targetsec->floorheight; - node = targetsec->touching_thinglist; // things touching this sector - while (node) - { - thing = node->m_thing; - - if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0 - && thing->z < upperbound && thing->z+thing->height > lowerbound) - return; - - node = node->m_thinglist_next; - } - } - } - - if (!FOFsector) - { - upperbound = sec->ceilingheight; - lowerbound = sec->floorheight; - node = sec->touching_thinglist; // things touching this sector - while (node) - { - thing = node->m_thing; - - if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0 - && thing->z < upperbound && thing->z+thing->height > lowerbound) + if (T_SectorHasEnemies(§ors[targetsecnum])) return; - - node = node->m_thinglist_next; } } + + if (!FOFsector && T_SectorHasEnemies(sec)) + return; } CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", nobaddies->sourceline->tag); @@ -2119,30 +1355,23 @@ static boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec) return false; } -// -// P_HavePlayersEnteredArea -// -// Helper function for T_EachTimeThinker -// -static INT32 P_HavePlayersEnteredArea(boolean *curPlayers, boolean *oldPlayers, boolean inAndOut) +static boolean P_IsMobjTouchingSector(mobj_t *mo, sector_t *sec) { - INT32 i; + msecnode_t *node; - // Easy check... nothing has changed - if (!memcmp(curPlayers, oldPlayers, sizeof(boolean)*MAXPLAYERS)) - return -1; + if (mo->subsector->sector == sec) + return true; - // Otherwise, we have to check if any new players have entered - for (i = 0; i < MAXPLAYERS; i++) + if (!(sec->flags & SF_TRIGGERSPECIAL_TOUCH)) + return false; + + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) { - if (inAndOut && !curPlayers[i] && oldPlayers[i]) - return i; - - if (curPlayers[i] && !oldPlayers[i]) - return i; + if (node->m_sector == sec) + return true; } - return -1; + return false; } // @@ -2153,47 +1382,30 @@ static INT32 P_HavePlayersEnteredArea(boolean *curPlayers, boolean *oldPlayers, // // \sa P_AddEachTimeThinker // -void T_EachTimeThinker(levelspecthink_t *eachtime) +void T_EachTimeThinker(eachtime_t *eachtime) { size_t i, j; sector_t *sec = NULL; sector_t *targetsec = NULL; - //sector_t *usesec = NULL; INT32 secnum = -1; - INT32 affectPlayer = 0; boolean oldPlayersInArea[MAXPLAYERS]; - boolean playersInArea[MAXPLAYERS]; boolean oldPlayersOnArea[MAXPLAYERS]; - boolean playersOnArea[MAXPLAYERS]; boolean *oldPlayersArea; boolean *playersArea; boolean FOFsector = false; - boolean inAndOut = false; boolean floortouch = false; fixed_t bottomheight, topheight; - msecnode_t *node; ffloor_t *rover; for (i = 0; i < MAXPLAYERS; i++) { - if (i & 1) - { - oldPlayersInArea[i] = eachtime->vars[i/2] & 65535; - oldPlayersOnArea[i] = eachtime->var2s[i/2] & 65535; - eachtime->vars[i/2] = 0; - eachtime->var2s[i/2] = 0; - } - else - { - oldPlayersInArea[i] = eachtime->vars[i/2] >> 16; - oldPlayersOnArea[i] = eachtime->var2s[i/2] >> 16; - } - - playersInArea[i] = false; - playersOnArea[i] = false; + oldPlayersInArea[i] = eachtime->playersInArea[i]; + oldPlayersOnArea[i] = eachtime->playersOnArea[i]; + eachtime->playersInArea[i] = false; + eachtime->playersOnArea[i] = false; } - while ((secnum = P_FindSectorFromLineTag(eachtime->sourceline, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(eachtime->sourceline->tag, secnum)) >= 0) { sec = §ors[secnum]; @@ -2216,7 +1428,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) FOFsector = true; - while ((targetsecnum = P_FindSectorFromLineTag(sec->lines[i], targetsecnum)) >= 0) + while ((targetsecnum = P_FindSectorFromTag(sec->lines[i]->tag, targetsecnum)) >= 0) { targetsec = §ors[targetsecnum]; @@ -2235,35 +1447,10 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) for (j = 0; j < MAXPLAYERS; j++) { - if (!playeringame[j]) + if (!P_IsPlayerValid(j)) continue; - if (!players[j].mo) - continue; - - if (players[j].mo->health <= 0) - continue; - - if ((netgame || multiplayer) && players[j].spectator) - continue; - - if (players[j].mo->subsector->sector == targetsec) - ; - else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH) - { - boolean insector = false; - for (node = players[j].mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (node->m_sector == targetsec) - { - insector = true; - break; - } - } - if (!insector) - continue; - } - else + if (!P_IsMobjTouchingSector(players[j].mo, targetsec)) continue; topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec); @@ -2275,24 +1462,10 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) if (players[j].mo->z + players[j].mo->height < bottomheight) continue; - if (floortouch == true && P_IsObjectOnGroundIn(players[j].mo, targetsec)) - { - if (j & 1) - eachtime->var2s[j/2] |= 1; - else - eachtime->var2s[j/2] |= 1 << 16; - - playersOnArea[j] = true; - } + if (floortouch && P_IsObjectOnGroundIn(players[j].mo, targetsec)) + eachtime->playersOnArea[j] = true; else - { - if (j & 1) - eachtime->vars[j/2] |= 1; - else - eachtime->vars[j/2] |= 1 << 16; - - playersInArea[j] = true; - } + eachtime->playersInArea[j] = true; } } } @@ -2301,102 +1474,61 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) { for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i]) + if (!P_IsPlayerValid(i)) continue; - if (!players[i].mo) - continue; - - if (players[i].mo->health <= 0) - continue; - - if ((netgame || multiplayer) && players[i].spectator) - continue; - - if (players[i].mo->subsector->sector == sec) - ; - else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH) - { - boolean insector = false; - for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (node->m_sector == sec) - { - insector = true; - break; - } - } - if (!insector) - continue; - } - else + if (!P_IsMobjTouchingSector(players[i].mo, sec)) continue; if (!(players[i].mo->subsector->sector == sec || P_PlayerTouchingSectorSpecial(&players[i], 2, (GETSECSPECIAL(sec->special, 2))) == sec)) continue; - if (floortouch == true && P_IsObjectOnRealGround(players[i].mo, sec)) - { - if (i & 1) - eachtime->var2s[i/2] |= 1; - else - eachtime->var2s[i/2] |= 1 << 16; - - playersOnArea[i] = true; - } + if (floortouch && P_IsObjectOnRealGround(players[i].mo, sec)) + eachtime->playersOnArea[i] = true; else - { - if (i & 1) - eachtime->vars[i/2] |= 1; - else - eachtime->vars[i/2] |= 1 << 16; - - playersInArea[i] = true; - } + eachtime->playersInArea[i] = true; } } } - if ((eachtime->sourceline->flags & ML_BOUNCY) == ML_BOUNCY) - inAndOut = true; - // Check if a new player entered. // If not, check if a player hit the floor. // If either condition is true, execute. - if (floortouch == true) + if (floortouch) { - playersArea = playersOnArea; + playersArea = eachtime->playersOnArea; oldPlayersArea = oldPlayersOnArea; } else { - playersArea = playersInArea; + playersArea = eachtime->playersInArea; oldPlayersArea = oldPlayersInArea; } - while ((affectPlayer = P_HavePlayersEnteredArea(playersArea, oldPlayersArea, inAndOut)) != -1) + // Easy check... nothing has changed + if (!memcmp(playersArea, oldPlayersArea, sizeof(boolean)*MAXPLAYERS)) + return; + + // If sector has an "all players" trigger type, all players need to be in area + if (GETSECSPECIAL(sec->special, 2) == 2 || GETSECSPECIAL(sec->special, 2) == 3) { - if (GETSECSPECIAL(sec->special, 2) == 2 || GETSECSPECIAL(sec->special, 2) == 3) + for (i = 0; i < MAXPLAYERS; i++) { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - if (!players[i].mo) - continue; - - if (players[i].mo->health <= 0) - continue; - - if ((netgame || multiplayer) && players[i].spectator) - continue; - - if (!playersArea[i]) - return; - } + if (P_IsPlayerValid(i) && playersArea[i]) + continue; } + } + + // Trigger for every player who has entered (and exited, if triggerOnExit) + for (i = 0; i < MAXPLAYERS; i++) + { + if (playersArea[i] == oldPlayersArea[i]) + continue; + + // If player has just left, check if still valid + if (!playersArea[i] && (!eachtime->triggerOnExit || !P_IsPlayerValid(i))) + continue; CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", eachtime->sourceline->tag); @@ -2404,12 +1536,10 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) // No more stupid hacks involving changing eachtime->sourceline's tag or special or whatever! // This should now run ONLY the stuff for eachtime->sourceline itself, instead of all trigger linedefs sharing the same tag. // Makes much more sense doing it this way, honestly. - P_RunTriggerLinedef(eachtime->sourceline, players[affectPlayer].mo, sec); + P_RunTriggerLinedef(eachtime->sourceline, players[i].mo, sec); if (!eachtime->sourceline->special) // this happens only for "Trigger on X calls" linedefs P_RemoveThinker(&eachtime->thinker); - - oldPlayersArea[affectPlayer]=playersArea[affectPlayer]; } } @@ -2419,20 +1549,24 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) // Rises up to its topmost position when a // player steps on it. Lowers otherwise. // -void T_RaiseSector(levelspecthink_t *raise) +void T_RaiseSector(raise_t *raise) { msecnode_t *node; mobj_t *thing; sector_t *sector; INT32 i; boolean playeronme = false, active = false; + boolean moveUp; fixed_t ceilingdestination, floordestination; + fixed_t speed, origspeed; + fixed_t distToNearestEndpoint; + INT32 direction; result_e res = 0; - if (raise->sector->crumblestate >= 3 || raise->sector->ceilingdata) + if (raise->sector->crumblestate >= CRUMBLE_FALL || raise->sector->ceilingdata) return; - for (i = -1; (i = P_FindSectorFromTag(raise->sourceline->tag, i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(raise->tag, i)) >= 0 ;) { sector = §ors[i]; @@ -2449,7 +1583,7 @@ void T_RaiseSector(levelspecthink_t *raise) continue; // Option to require spindashing. - if (raise->vars[1] && !(thing->player->pflags & PF_STARTDASH)) + if (raise->flags & RF_SPINDASH && !(thing->player->pflags & PF_STARTDASH)) continue; if (!(thing->z == P_GetSpecialTopZ(thing, raise->sector, sector))) @@ -2460,43 +1594,43 @@ void T_RaiseSector(levelspecthink_t *raise) } } - if (raise->vars[9]) // Dynamically Sinking Platform^tm + if (raise->flags & RF_DYNAMIC) // Dynamically Sinking Platform^tm { #define shaketime 10 - if (raise->vars[11] > shaketime) // State: moving + if (raise->shaketimer > shaketime) // State: moving { if (playeronme) // If player is standing on the platform, accelerate { - raise->vars[10] += (FRACUNIT >> 5); + raise->extraspeed += (FRACUNIT >> 5); } else // otherwise, decelerate until inflection { - raise->vars[10] -= FRACUNIT >> 3; - if (raise->vars[10] <= 0) // inflection! + raise->extraspeed -= FRACUNIT >> 3; + if (raise->extraspeed <= 0) // inflection! { - raise->vars[10] = 0; - raise->vars[11] = 0; // allow the shake to occur again (fucks over players attempting to jump-cheese) + raise->extraspeed = 0; + raise->shaketimer = 0; // allow the shake to occur again (fucks over players attempting to jump-cheese) } } - active = raise->vars[10] > 0; + active = raise->extraspeed > 0; } else // State: shaking { - if (playeronme || raise->vars[11]) + if (playeronme || raise->shaketimer) { active = true; - if (++raise->vars[11] > shaketime) + if (++raise->shaketimer > shaketime) { if (playeronme) - raise->vars[10] = FRACUNIT >> 5; + raise->extraspeed = FRACUNIT >> 5; else - raise->vars[10] = FRACUNIT << 1; + raise->extraspeed = 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; + raise->extraspeed = ((shaketime/2) - raise->shaketimer) << FRACBITS; + if (raise->extraspeed < -raise->basespeed/2) + raise->extraspeed = -raise->basespeed/2; } } } @@ -2505,127 +1639,61 @@ void T_RaiseSector(levelspecthink_t *raise) else // Air bobbing platform (not a Dynamically Sinking Platform^tm) active = playeronme; - if (active) + moveUp = active ^ (raise->flags & RF_REVERSE); + ceilingdestination = moveUp ? raise->ceilingtop : raise->ceilingbottom; + floordestination = ceilingdestination - (raise->sector->ceilingheight - raise->sector->floorheight); + + if ((moveUp && raise->sector->ceilingheight >= ceilingdestination) + || (!moveUp && raise->sector->ceilingheight <= ceilingdestination)) { - raise->vars[3] = raise->vars[2]; - - if (raise->vars[0] == 1) - { - if (raise->sector->ceilingheight <= raise->vars[7]) - { - raise->sector->floorheight = raise->vars[7] - (raise->sector->ceilingheight - raise->sector->floorheight); - raise->sector->ceilingheight = raise->vars[7]; - raise->sector->ceilspeed = 0; - raise->sector->floorspeed = 0; - return; - } - - raise->vars[8] = -1; - ceilingdestination = raise->vars[7]; - floordestination = raise->vars[6]; - } - else // elevateUp - { - if (raise->sector->ceilingheight >= raise->vars[5]) - { - raise->sector->floorheight = raise->vars[5] - (raise->sector->ceilingheight - raise->sector->floorheight); - raise->sector->ceilingheight = raise->vars[5]; - raise->sector->ceilspeed = 0; - raise->sector->floorspeed = 0; - return; - } - - raise->vars[8] = 1; - ceilingdestination = raise->vars[5]; - floordestination = raise->vars[4]; - } + raise->sector->floorheight = floordestination; + raise->sector->ceilingheight = ceilingdestination; + raise->sector->ceilspeed = 0; + raise->sector->floorspeed = 0; + return; } - else - { - raise->vars[3] = raise->vars[2]/2; + direction = moveUp ? 1 : -1; - if (raise->vars[0] == 1) - { - if (raise->sector->ceilingheight >= raise->vars[5]) - { - raise->sector->floorheight = raise->vars[5] - (raise->sector->ceilingheight - raise->sector->floorheight); - raise->sector->ceilingheight = raise->vars[5]; - raise->sector->ceilspeed = 0; - raise->sector->floorspeed = 0; - return; - } - raise->vars[8] = 1; - ceilingdestination = raise->vars[5]; - floordestination = raise->vars[4]; - } - else // elevateUp - { - if (raise->sector->ceilingheight <= raise->vars[7]) - { - raise->sector->floorheight = raise->vars[7] - (raise->sector->ceilingheight - raise->sector->floorheight); - raise->sector->ceilingheight = raise->vars[7]; - raise->sector->ceilspeed = 0; - raise->sector->floorspeed = 0; - return; - } - raise->vars[8] = -1; - ceilingdestination = raise->vars[7]; - floordestination = raise->vars[6]; - } - } + origspeed = raise->basespeed; + if (!active) + origspeed /= 2; - if ((raise->sector->ceilingheight - raise->vars[7]) - < (raise->vars[5] - raise->sector->ceilingheight)) - { - fixed_t origspeed = raise->vars[3]; + // Speed up as you get closer to the middle, then slow down again + distToNearestEndpoint = min(raise->sector->ceilingheight - raise->ceilingbottom, raise->ceilingtop - raise->sector->ceilingheight); + speed = FixedMul(origspeed, FixedDiv(distToNearestEndpoint, (raise->ceilingtop - raise->ceilingbottom) >> 5)); - // Slow down as you get closer to the bottom - raise->vars[3] = FixedMul(raise->vars[3],FixedDiv(raise->sector->ceilingheight - raise->vars[7], (raise->vars[5] - raise->vars[7])>>5)); + if (speed <= origspeed/16) + speed = origspeed/16; + else if (speed > origspeed) + speed = origspeed; - if (raise->vars[3] <= origspeed/16) - raise->vars[3] = origspeed/16; - else if (raise->vars[3] > origspeed) - raise->vars[3] = origspeed; - } - else - { - fixed_t origspeed = raise->vars[3]; - // Slow down as you get closer to the top - raise->vars[3] = FixedMul(raise->vars[3],FixedDiv(raise->vars[5] - raise->sector->ceilingheight, (raise->vars[5] - raise->vars[7])>>5)); - - if (raise->vars[3] <= origspeed/16) - raise->vars[3] = origspeed/16; - else if (raise->vars[3] > origspeed) - raise->vars[3] = origspeed; - } - - raise->vars[3] += raise->vars[10]; + speed += raise->extraspeed; res = T_MovePlane ( - raise->sector, // sector - raise->vars[3], // speed + raise->sector, // sector + speed, // speed ceilingdestination, // dest - 0, // crush - 1, // floor or ceiling (1 for ceiling) - raise->vars[8] // direction + false, // crush + true, // ceiling? + direction // direction ); if (res == ok || res == pastdest) T_MovePlane ( - raise->sector, // sector - raise->vars[3], // speed + raise->sector, // sector + speed, // speed floordestination, // dest - 0, // crush - 0, // floor or ceiling (0 for floor) - raise->vars[8] // direction + false, // crush + false, // ceiling? + direction // direction ); raise->sector->ceilspeed = 42; - raise->sector->floorspeed = raise->vars[3]*raise->vars[8]; + raise->sector->floorspeed = speed*direction; - for (i = -1; (i = P_FindSectorFromTag(raise->sourceline->tag, i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(raise->tag, i)) >= 0 ;) P_RecalcPrecipInSector(§ors[i]); } @@ -2720,9 +1788,9 @@ void T_PlaneDisplace(planedisplace_t *pd) } if (pd->type == pd_floor || pd->type == pd_both) - T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, 0, 0, direction); // move floor + T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, false, false, direction); // move floor if (pd->type == pd_ceiling || pd->type == pd_both) - T_MovePlane(target, INT32_MAX/2, target->ceilingheight+diff, 0, 1, direction); // move ceiling + T_MovePlane(target, INT32_MAX/2, target->ceilingheight+diff, false, true, direction); // move ceiling pd->last_height = control->floorheight; } @@ -2736,14 +1804,14 @@ void T_PlaneDisplace(planedisplace_t *pd) // (egg capsule button), P_PlayerInSpecialSector (buttons), // and P_SpawnSpecials (continuous floor movers and instant lower). // -INT32 EV_DoFloor(line_t *line, floor_e floortype) +void EV_DoFloor(line_t *line, floor_e floortype) { - INT32 rtn = 0, firstone = 1; + INT32 firstone = 1; INT32 secnum = -1; sector_t *sec; floormove_t *dofloor; - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { sec = §ors[secnum]; @@ -2751,7 +1819,6 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype) continue; // then don't add another one // new floor thinker - rtn = 1; dofloor = Z_Calloc(sizeof (*dofloor), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &dofloor->thinker); @@ -2941,8 +2008,6 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype) firstone = 0; } - - return rtn; } // SoM: Boom elevator support. @@ -2955,15 +2020,14 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype) // // jff 2/22/98 new type to move floor and ceiling in parallel // -INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) +void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) { INT32 secnum = -1; - INT32 rtn = 0; sector_t *sec; elevator_t *elevator; // act on all sectors with the same tag as the triggering linedef - while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) { sec = §ors[secnum]; @@ -2972,7 +2036,6 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) continue; // create and initialize new elevator thinker - rtn = 1; elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &elevator->thinker); sec->floordata = elevator; @@ -3074,7 +2137,6 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) break; } } - return rtn; } void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) @@ -3178,12 +2240,10 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) if (R_PointInSubsector(a, b)->sector == sec) { mobj_t *spawned = NULL; -#ifdef ESLOPE if (*rover->t_slope) - topz = P_GetZAt(*rover->t_slope, a, b) - (spacing>>1); + topz = P_GetSlopeZAt(*rover->t_slope, a, b) - (spacing>>1); if (*rover->b_slope) - bottomz = P_GetZAt(*rover->b_slope, a, b); -#endif + bottomz = P_GetSlopeZAt(*rover->b_slope, a, b); for (c = topz; c > bottomz; c -= spacing) { @@ -3209,16 +2269,13 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) } // Used for bobbing platforms on the water -INT32 EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline) +void EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline) { -#define speed vars[0] -#define distance vars[1] -#define low vars[2] - levelspecthink_t *bouncer; + bouncecheese_t *bouncer; // create and initialize new thinker if (sec->ceilingdata) // One at a time, ma'am. - return 0; + return; bouncer = Z_Calloc(sizeof (*bouncer), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &bouncer->thinker); @@ -3226,31 +2283,20 @@ INT32 EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline) bouncer->thinker.function.acp1 = (actionf_p1)T_BounceCheese; // set up the fields according to the type of elevator action + bouncer->sourceline = sourceline; bouncer->sector = sec; bouncer->speed = momz/2; - bouncer->sourceline = sourceline; bouncer->distance = FRACUNIT; - bouncer->low = 1; - - return 1; -#undef speed -#undef distance -#undef low + bouncer->low = true; } // For T_ContinuousFalling special -INT32 EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, boolean backwards) +void EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, boolean backwards) { -#define speed vars[0] -#define direction vars[1] -#define floorwasheight vars[2] -#define ceilingwasheight vars[3] -#define floordestheight vars[4] -#define ceilingdestheight vars[5] - levelspecthink_t *faller; + continuousfall_t *faller; // workaround for when there is no back sector - if (backsector == NULL) + if (!backsector) backsector = sec; // create and initialize new thinker @@ -3262,36 +2308,18 @@ INT32 EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, bool faller->sector = sec; faller->speed = spd; - faller->floorwasheight = sec->floorheight; - faller->ceilingwasheight = sec->ceilingheight; + faller->floorstartheight = sec->floorheight; + faller->ceilingstartheight = sec->ceilingheight; - if (backwards) - { - faller->ceilingdestheight = backsector->ceilingheight; - faller->floordestheight = faller->ceilingdestheight; - faller->direction = 1; // Up! - } - else - { - faller->floordestheight = backsector->floorheight; - faller->ceilingdestheight = faller->floordestheight; - faller->direction = -1; - } - - return 1; -#undef speed -#undef direction -#undef floorwasheight -#undef ceilingwasheight -#undef floordestheight -#undef ceilingdestheight + faller->destheight = backwards ? backsector->ceilingheight : backsector->floorheight; + faller->direction = backwards ? 1 : -1; } // Some other 3dfloor special things Tails 03-11-2002 (Search p_mobj.c for description) INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, player_t *player, fixed_t origalpha, boolean crumblereturn) { - elevator_t *elevator; + crumble_t *crumble; sector_t *foundsec; INT32 i; @@ -3299,68 +2327,58 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, if (sec->floordata) return 0; - if (sec->crumblestate > 1) + if (sec->crumblestate >= CRUMBLE_ACTIVATED) return 0; - // create and initialize new elevator thinker - elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL); - P_AddThinker(THINK_MAIN, &elevator->thinker); - elevator->thinker.function.acp1 = (actionf_p1)T_StartCrumble; + // create and initialize new crumble thinker + crumble = Z_Calloc(sizeof (*crumble), PU_LEVSPEC, NULL); + P_AddThinker(THINK_MAIN, &crumble->thinker); + crumble->thinker.function.acp1 = (actionf_p1)T_StartCrumble; - // Does this crumbler return? - if (crumblereturn) - elevator->type = elevateBounce; - else - elevator->type = elevateContinuous; - - // set up the fields according to the type of elevator action - elevator->sector = sec; - elevator->speed = 0; + // set up the fields + crumble->sector = sec; + crumble->speed = 0; if (player && player->mo && (player->mo->eflags & MFE_VERTICALFLIP)) { - elevator->direction = 1; // Up - elevator->floordestheight = 1; + crumble->direction = 1; // Up + crumble->flags |= CF_REVERSE; } else - { - elevator->direction = -1; // Down - elevator->floordestheight = 0; - } + crumble->direction = -1; // Down - elevator->floorwasheight = elevator->sector->floorheight; - elevator->ceilingwasheight = elevator->sector->ceilingheight; - elevator->distance = TICRATE; // Used for delay time - elevator->low = 0; - elevator->player = player; - elevator->origspeed = origalpha; + crumble->floorwasheight = crumble->sector->floorheight; + crumble->ceilingwasheight = crumble->sector->ceilingheight; + crumble->timer = TICRATE; + crumble->player = player; + crumble->origalpha = origalpha; - elevator->sourceline = rover->master; + crumble->sourceline = rover->master; - sec->floordata = elevator; + sec->floordata = crumble; + if (crumblereturn) + crumble->flags |= CF_RETURN; if (floating) - elevator->high = 42; - else - elevator->high = 0; + crumble->flags |= CF_FLOATBOB; - elevator->sector->crumblestate = 2; + crumble->sector->crumblestate = CRUMBLE_ACTIVATED; - for (i = -1; (i = P_FindSectorFromTag(elevator->sourceline->tag, i)) >= 0 ;) + for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) { foundsec = §ors[i]; - P_SpawnMobj(foundsec->soundorg.x, foundsec->soundorg.y, elevator->direction == 1 ? elevator->sector->floorheight : elevator->sector->ceilingheight, MT_CRUMBLEOBJ); + P_SpawnMobj(foundsec->soundorg.x, foundsec->soundorg.y, crumble->direction == 1 ? crumble->sector->floorheight : crumble->sector->ceilingheight, MT_CRUMBLEOBJ); } return 1; } -INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) +void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) { sector_t *roversec = rover->master->frontsector; fixed_t topheight = *rover->topheight; - levelspecthink_t *block; + mariothink_t *block; mobj_t *thing; fixed_t oldx = 0, oldy = 0, oldz = 0; @@ -3368,7 +2386,7 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) I_Assert(puncher->player != NULL); if (roversec->floordata || roversec->ceilingdata) - return 0; + return; if (!(rover->flags & FF_SOLID)) rover->flags |= (FF_SOLID|FF_RENDERALL|FF_CUTLEVEL); @@ -3376,8 +2394,9 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) // Find an item to pop out! thing = SearchMarioNode(roversec->touching_thinglist); - // Found something! - if (thing) + if (!thing) + S_StartSound(puncher, sfx_mario1); // "Thunk!" sound - puncher is "close enough". + else // Found something! { const boolean itsamonitor = (thing->flags & MF_MONITOR) == MF_MONITOR; // create and initialize new elevator thinker @@ -3390,13 +2409,11 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) // Set up the fields block->sector = roversec; - block->vars[0] = sector->tag; // actionsector - block->vars[1] = 4*FRACUNIT; // speed - block->vars[2] = 1; // Up // direction - block->vars[3] = block->sector->floorheight; // floorwasheight - block->vars[4] = block->sector->ceilingheight; // ceilingwasheight - block->vars[5] = FRACUNIT; // distance - block->vars[6] = 1; // low + block->speed = 4*FRACUNIT; + block->direction = 1; + block->floorstartheight = block->sector->floorheight; + block->ceilingstartheight = block->sector->ceilingheight; + block->tag = (INT16)sector->tag; if (itsamonitor) { @@ -3437,8 +2454,4 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) P_SetThingPosition(thing); } } - else - S_StartSound(puncher, sfx_mario1); // "Thunk!" sound - puncher is "close enough". - - return 1; } diff --git a/src/p_inter.c b/src/p_inter.c index 5fb9b3fe7..b01d40c00 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -365,10 +365,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->flags & (MF_ENEMY|MF_BOSS) && special->flags2 & MF2_FRET) return; -#ifdef HAVE_BLUA if (LUAh_TouchSpecial(special, toucher) || P_MobjWasRemoved(special)) return; -#endif // 0 = none, 1 = elemental pierce, 2 = bubble bounce elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY) @@ -635,7 +633,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (ALL7EMERALDS(emeralds)) // Got all 7 { - if (!(netgame || multiplayer)) + if (continuesInSession) { player->continues += 1; player->gotcontinue = true; @@ -645,7 +643,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) S_StartSound(toucher, sfx_chchng); } else + { + P_GiveCoopLives(player, 1, true); // if continues are disabled, a life is a reasonable substitute S_StartSound(toucher, sfx_chchng); + } } else { @@ -1142,10 +1143,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->angle = special->angle; - if (player == &players[consoleplayer]) - localangle = toucher->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = toucher->angle; + P_SetPlayerAngle(player, toucher->angle); P_ResetPlayer(player); @@ -1563,10 +1561,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) #if 0 // camera redirection - deemed unnecessary toucher->angle = special->angle; - if (player == &players[consoleplayer]) - localangle = toucher->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = toucher->angle; + P_SetPlayerAngle(player, toucher->angle); #endif S_StartSound(toucher, special->info->attacksound); // home run @@ -1919,10 +1914,8 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour if (!netgame) return; // Presumably it's obvious what's happening in splitscreen. -#ifdef HAVE_BLUA if (LUAh_HurtMsg(player, inflictor, source, damagetype)) return; -#endif deadtarget = (player->mo->health <= 0); @@ -2285,7 +2278,7 @@ void P_CheckSurvivors(void) if (!taggers) //If there are no taggers, pick a survivor at random to be it. { // Exception for hide and seek. If a round has started and the IT player leaves, end the round. - if (gametype == GT_HIDEANDSEEK && (leveltime >= (hidetime * TICRATE))) + if ((gametyperules & GTR_HIDEFROZEN) && (leveltime >= (hidetime * TICRATE))) { CONS_Printf(M_GetText("The IT player has left the game.\n")); if (server) @@ -2395,10 +2388,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->flags2 &= ~(MF2_SKULLFLY|MF2_NIGHTSPULL); target->health = 0; // This makes it easy to check if something's dead elsewhere. -#ifdef HAVE_BLUA if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) return; -#endif // Let EVERYONE know what happened to a player! 01-29-2002 Tails if (target->player && !target->player->spectator) @@ -2525,7 +2516,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } P_RestoreMusic(target->player); - if (gametype != GT_COOP) + if (!G_CoopGametype()) { HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); @@ -2603,7 +2594,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget // allow them to try again, rather than sitting the whole thing out. if (leveltime >= hidetime * TICRATE) { - if (gametype == GT_TAG)//suiciding in survivor makes you IT. + if (!(gametyperules & GTR_HIDEFROZEN))//suiciding in survivor makes you IT. { target->player->pflags |= PF_TAGIT; CONS_Printf(M_GetText("%s is now IT!\n"), player_names[target->player-players]); // Tell everyone who is it! @@ -3097,7 +3088,7 @@ static boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, IN P_AddPlayerScore(source->player, 100); //award points to tagger. P_HitDeathMessages(player, inflictor, source, 0); - if (gametype == GT_TAG) //survivor + if (!(gametyperules & GTR_HIDEFROZEN)) //survivor { player->pflags |= PF_TAGIT; //in survivor, the player becomes IT and helps hunt down the survivors. CONS_Printf(M_GetText("%s is now IT!\n"), player_names[player-players]); // Tell everyone who is it! @@ -3156,9 +3147,9 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou return false; // In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on - if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && (G_PlatformGametype())) + if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && (gametyperules & GTR_FRIENDLY)) { - if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only + if ((gametyperules & GTR_FRIENDLY) && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only { if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { @@ -3257,7 +3248,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) } // If the player was super, tell them he/she ain't so super nomore. - if (gametype != GT_COOP && player->powers[pw_super]) + if (!G_CoopGametype() && player->powers[pw_super]) { S_StartSound(NULL, sfx_s3k66); //let all players hear it. HU_SetCEchoFlags(0); @@ -3441,7 +3432,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) return; - if (!cv_friendlyfire.value) + if (!cv_friendlyfire.value && source && source->player) { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { @@ -3456,7 +3447,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) return; } - if (inflictor->type == MT_LHRT) + if (inflictor && inflictor->type == MT_LHRT) return; if (player->powers[pw_shield] || player->bot) //If One-Hit Shield @@ -3511,11 +3502,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { player_t *player; -#ifdef HAVE_BLUA boolean force = false; -#else - static const boolean force = false; -#endif if (objectplacing) return false; @@ -3533,7 +3520,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; } -#ifdef HAVE_BLUA // Everything above here can't be forced. if (!metalrecording) { @@ -3545,7 +3531,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da else if (shouldForce == 2) return false; } -#endif if (!force) { @@ -3579,10 +3564,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!force && target->flags2 & MF2_FRET) // Currently flashing from being hit return false; -#ifdef HAVE_BLUA if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) return true; -#endif if (target->health > 1) target->flags2 |= MF2_FRET; @@ -3627,14 +3610,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (source == target) return false; // Don't hit yourself with your own paraloop, baka if (source && source->player && !(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) - && (gametype == GT_COOP + && ((gametyperules & GTR_FRIENDLY) || (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam))) return false; // Don't run eachother over in special stages and team games and such } -#ifdef HAVE_BLUA if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) return true; -#endif P_NiGHTSDamage(target, source); // -5s :( return true; } @@ -3687,18 +3668,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (force || (inflictor && inflictor->flags & MF_MISSILE && inflictor->flags2 & MF2_SUPERFIRE)) // Super Sonic is stunned! { -#ifdef HAVE_BLUA if (!LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) -#endif P_SuperDamage(player, inflictor, source, damage); return true; } return false; } -#ifdef HAVE_BLUA else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) return true; -#endif else if (player->powers[pw_shield] || (player->bot && !ultimatemode)) //If One-Hit Shield { P_ShieldDamage(player, inflictor, source, damage, damagetype); diff --git a/src/p_lights.c b/src/p_lights.c index 7de6a4dc5..371077a30 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_local.h b/src/p_local.h index bc4a91ed1..e89343ca8 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -66,9 +66,7 @@ typedef enum THINK_POLYOBJ, THINK_MAIN, THINK_MOBJ, -#ifdef ESLOPE THINK_DYNSLOPE, -#endif THINK_PRECIP, NUM_THINKERLISTS } thinklistnum_t; /**< Thinker lists. */ @@ -140,6 +138,10 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor); void P_ResetPlayer(player_t *player); boolean P_PlayerCanDamage(player_t *player, mobj_t *thing); boolean P_IsLocalPlayer(player_t *player); +void P_SetPlayerAngle(player_t *player, angle_t angle); +angle_t P_GetLocalAngle(player_t *player); +void P_SetLocalAngle(player_t *player, angle_t angle); +void P_ForceLocalAngle(player_t *player, angle_t angle); boolean P_IsObjectInGoop(mobj_t *mo); boolean P_IsObjectOnGround(mobj_t *mo); @@ -169,7 +171,6 @@ boolean P_AutoPause(void); void P_DoJumpShield(player_t *player); void P_DoBubbleBounce(player_t *player); -boolean P_TryClimb(player_t *player, line_t *line); void P_DoAbilityBounce(player_t *player, boolean changemomz); void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type); void P_BlackOw(player_t *player); @@ -251,7 +252,7 @@ extern jingle_t jingleinfo[NUMJINGLES]; #define JINGLEPOSTFADE 1000 void P_PlayJingle(player_t *player, jingletype_t jingletype); -boolean P_EvaluateMusicStatus(UINT16 status); +boolean P_EvaluateMusicStatus(UINT16 status, const char *musname); void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status); // @@ -384,9 +385,7 @@ extern mobj_t *tmfloorthing, *tmhitthing, *tmthing; extern camera_t *mapcampointer; extern fixed_t tmx; extern fixed_t tmy; -#ifdef ESLOPE extern pslope_t *tmfloorslope, *tmceilingslope; -#endif /* cphipps 2004/08/30 */ extern void P_MapStart(void); diff --git a/src/p_map.c b/src/p_map.c index 4edf73ca8..18d6a1853 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -27,9 +27,7 @@ #include "r_splats.h" -#ifdef ESLOPE #include "p_slopes.h" -#endif #include "z_zone.h" @@ -53,9 +51,7 @@ static fixed_t tmdropoffz, tmdrpoffceilz; // drop-off floor/ceiling heights mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector mobj_t *tmhitthing; // the solid thing you bumped into (for collisions) ffloor_t *tmfloorrover, *tmceilingrover; -#ifdef ESLOPE pslope_t *tmfloorslope, *tmceilingslope; -#endif // keep track of the line that lowers the ceiling, // so missiles don't explode against sky hack walls @@ -262,9 +258,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (!vertispeed && !horizspeed) return false; -#ifdef ESLOPE object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. -#endif if (spring->eflags & MFE_VERTICALFLIP) vertispeed *= -1; @@ -378,12 +372,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->angle = object->player->drawangle = spring->angle; if (!demoplayback || P_ControlStyle(object->player) == CS_LMAOGALOG) - { - if (object->player == &players[consoleplayer]) - localangle = spring->angle; - else if (object->player == &players[secondarydisplayplayer]) - localangle2 = spring->angle; - } + P_SetPlayerAngle(object->player, spring->angle); } if (object->player->pflags & PF_GLIDING) @@ -439,9 +428,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_SetPlayerMobjState(object, S_PLAY_FALL); } -#ifdef ESLOPE object->standingslope = NULL; // And again. -#endif final = true; @@ -491,9 +478,7 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) zdist = object->z - spring->z; } -#ifdef ESLOPE object->standingslope = NULL; // No launching off at silly angles for you. -#endif switch (spring->type) { @@ -756,11 +741,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath -#ifdef HAVE_BLUA // REX HAS SEEN YOU if (!LUAh_SeenPlayer(tmthing->target->player, thing->player)) return false; -#endif seenplayer = thing->player; return false; @@ -948,7 +931,6 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // the line doesn't cross between either pair of opposite corners } -#ifdef HAVE_BLUA { UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) @@ -957,9 +939,8 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; // force collide else if (shouldCollide == 2) return true; // force no collide - } - { - UINT8 shouldCollide = LUAh_MobjMoveCollide(tmthing, thing); // checks hook for tmthing's type + + shouldCollide = LUAh_MobjMoveCollide(tmthing, thing); // checks hook for tmthing's type if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) return true; // one of them was removed??? if (shouldCollide == 1) @@ -967,7 +948,6 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (shouldCollide == 2) return true; // force no collide } -#endif if (tmthing->type == MT_LAVAFALL_LAVA && (thing->type == MT_RING || thing->type == MT_REDTEAMRING || thing->type == MT_BLUETEAMRING || thing->type == MT_FLINGRING)) { @@ -1325,12 +1305,7 @@ static boolean PIT_CheckThing(mobj_t *thing) thing->angle = tmthing->angle; if (!demoplayback || P_ControlStyle(thing->player) == CS_LMAOGALOG) - { - if (thing->player == &players[consoleplayer]) - localangle = thing->angle; - else if (thing->player == &players[secondarydisplayplayer]) - localangle2 = thing->angle; - } + P_SetPlayerAngle(thing->player, thing->angle); return true; } @@ -1613,7 +1588,7 @@ static boolean PIT_CheckThing(mobj_t *thing) } // Force solid players in hide and seek to avoid corner stacking. - if (cv_tailspickup.value && gametype != GT_HIDEANDSEEK) + if (cv_tailspickup.value && !(gametyperules & GTR_HIDEFROZEN)) { if (tmthing->player && thing->player) { @@ -1741,9 +1716,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { tmfloorz = thing->z + thing->height; tmfloorrover = NULL; -#ifdef ESLOPE tmfloorslope = NULL; -#endif } return true; } @@ -1762,18 +1735,14 @@ static boolean PIT_CheckThing(mobj_t *thing) tmfloorz = tmceilingz = topz; // block while in air tmceilingrover = NULL; -#ifdef ESLOPE tmceilingslope = NULL; -#endif tmfloorthing = thing; // needed for side collision } else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height) { tmceilingz = topz; tmceilingrover = NULL; -#ifdef ESLOPE tmceilingslope = NULL; -#endif tmfloorthing = thing; // thing we may stand on } } @@ -1788,9 +1757,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { tmceilingz = thing->z; tmceilingrover = NULL; -#ifdef ESLOPE tmceilingslope = NULL; -#endif } return true; } @@ -1809,18 +1776,14 @@ static boolean PIT_CheckThing(mobj_t *thing) tmfloorz = tmceilingz = topz; // block while in air tmfloorrover = NULL; -#ifdef ESLOPE tmfloorslope = NULL; -#endif tmfloorthing = thing; // needed for side collision } else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z) { tmfloorz = topz; tmfloorrover = NULL; -#ifdef ESLOPE tmfloorslope = NULL; -#endif tmfloorthing = thing; // thing we may stand on } } @@ -1946,7 +1909,6 @@ static boolean PIT_CheckLine(line_t *ld) // this line is out of the if so upper and lower textures can be hit by a splat blockingline = ld; -#ifdef HAVE_BLUA { UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, blockingline); // checks hook for thing's type if (P_MobjWasRemoved(tmthing)) @@ -1956,7 +1918,6 @@ static boolean PIT_CheckLine(line_t *ld) else if (shouldCollide == 2) return true; // force no collide } -#endif if (!ld->backsector) // one sided line { @@ -1983,18 +1944,14 @@ static boolean PIT_CheckLine(line_t *ld) tmceilingz = opentop; ceilingline = ld; tmceilingrover = openceilingrover; -#ifdef ESLOPE tmceilingslope = opentopslope; -#endif } if (openbottom > tmfloorz) { tmfloorz = openbottom; tmfloorrover = openfloorrover; -#ifdef ESLOPE tmfloorslope = openbottomslope; -#endif } if (highceiling > tmdrpoffceilz) @@ -2075,10 +2032,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) tmceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; tmfloorrover = NULL; tmceilingrover = NULL; -#ifdef ESLOPE tmfloorslope = newsubsec->sector->f_slope; tmceilingslope = newsubsec->sector->c_slope; -#endif // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. if (newsubsec->sector->ffloors) @@ -2119,9 +2074,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (tmfloorz < topheight - sinklevel) { tmfloorz = topheight - sinklevel; tmfloorrover = rover; -#ifdef ESLOPE tmfloorslope = *rover->t_slope; -#endif } } else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= bottomheight + sinklevel && thing->momz >= 0) @@ -2129,9 +2082,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (tmceilingz > bottomheight + sinklevel) { tmceilingz = bottomheight + sinklevel; tmceilingrover = rover; -#ifdef ESLOPE tmceilingslope = *rover->b_slope; -#endif } } } @@ -2154,9 +2105,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (tmfloorz < thing->z) { tmfloorz = thing->z; tmfloorrover = rover; -#ifdef ESLOPE tmfloorslope = NULL; -#endif } } // Quicksand blocks never change heights otherwise. @@ -2173,9 +2122,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { tmfloorz = tmdropoffz = topheight; tmfloorrover = rover; -#ifdef ESLOPE tmfloorslope = *rover->t_slope; -#endif } if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2) && !(rover->flags & FF_PLATFORM) @@ -2183,9 +2130,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { tmceilingz = tmdrpoffceilz = bottomheight; tmceilingrover = rover; -#ifdef ESLOPE tmceilingslope = *rover->b_slope; -#endif } } } @@ -2202,7 +2147,6 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) BMBOUNDFIX(xl, xh, yl, yh); -#ifdef POLYOBJECTS // Check polyobjects and see if tmfloorz/tmceilingz need to be altered { validcount++; @@ -2260,17 +2204,13 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (polytop > tmfloorz && abs(delta1) < abs(delta2)) { tmfloorz = tmdropoffz = polytop; -#ifdef ESLOPE tmfloorslope = NULL; -#endif tmfloorrover = NULL; } if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) { tmceilingz = tmdrpoffceilz = polybottom; -#ifdef ESLOPE tmceilingslope = NULL; -#endif tmceilingrover = NULL; } } @@ -2278,7 +2218,6 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) } } } -#endif // tmfloorthing is set when tmfloorz comes from a thing's top tmfloorthing = NULL; @@ -2436,7 +2375,6 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) BMBOUNDFIX(xl, xh, yl, yh); -#ifdef POLYOBJECTS // Check polyobjects and see if tmfloorz/tmceilingz need to be altered { validcount++; @@ -2507,7 +2445,6 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) } } } -#endif // check lines for (bx = xl; bx <= xh; bx++) @@ -2671,10 +2608,8 @@ boolean PIT_PushableMoved(mobj_t *thing) line_t *oldblockline = blockingline; ffloor_t *oldflrrover = tmfloorrover; ffloor_t *oldceilrover = tmceilingrover; -#ifdef ESLOPE pslope_t *oldfslope = tmfloorslope; pslope_t *oldcslope = tmceilingslope; -#endif // Move the player P_TryMove(thing, thing->x+stand->momx, thing->y+stand->momy, true); @@ -2689,10 +2624,8 @@ boolean PIT_PushableMoved(mobj_t *thing) blockingline = oldblockline; tmfloorrover = oldflrrover; tmceilingrover = oldceilrover; -#ifdef ESLOPE tmfloorslope = oldfslope; tmceilingslope = oldcslope; -#endif thing->momz = stand->momz; } else @@ -2714,9 +2647,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) fixed_t tryy = thing->y; fixed_t radius = thing->radius; fixed_t thingtop = thing->z + thing->height; -#ifdef ESLOPE fixed_t startingonground = P_IsObjectOnGround(thing); -#endif floatok = false; if (radius < MAXRADIUS/2) @@ -2802,14 +2733,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->ceilingrover = tmceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } -#ifdef ESLOPE else if (tmceilingz < thingtop && thingtop - tmceilingz <= maxstep) { thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height; thing->ceilingrover = tmceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } -#endif } else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep) { @@ -2817,14 +2746,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->floorrover = tmfloorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } -#ifdef ESLOPE else if (tmfloorz > thing->z && tmfloorz - thing->z <= maxstep) { thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } -#endif } if (thing->eflags & MFE_VERTICALFLIP) @@ -2888,7 +2815,6 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->floorrover = tmfloorrover; thing->ceilingrover = tmceilingrover; -#ifdef ESLOPE if (!(thing->flags & MF_NOCLIPHEIGHT)) { // Assign thing's standingslope if needed @@ -2909,7 +2835,6 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } else // don't set standingslope if you're not going to clip against it thing->standingslope = NULL; -#endif thing->x = x; thing->y = y; @@ -3260,8 +3185,219 @@ isblocking: } // -// PTR_SlideTraverse +// P_IsClimbingValid // +// Unlike P_DoClimbing, don't use when up against a one-sided linedef. +// +static boolean P_IsClimbingValid(player_t *player, angle_t angle) +{ + fixed_t platx, platy; + sector_t *glidesector; + fixed_t floorz, ceilingz; + mobj_t *mo = player->mo; + ffloor_t *rover; + + platx = P_ReturnThrustX(mo, angle, mo->radius + FixedMul(8*FRACUNIT, mo->scale)); + platy = P_ReturnThrustY(mo, angle, mo->radius + FixedMul(8*FRACUNIT, mo->scale)); + + glidesector = R_PointInSubsector(mo->x + platx, mo->y + platy)->sector; + + floorz = P_GetSectorFloorZAt (glidesector, mo->x, mo->y); + ceilingz = P_GetSectorCeilingZAt(glidesector, mo->x, mo->y); + + if (glidesector != mo->subsector->sector) + { + boolean floorclimb = false; + fixed_t topheight, bottomheight; + + for (rover = glidesector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) + continue; + + topheight = P_GetFFloorTopZAt (rover, mo->x, mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, mo->x, mo->y); + + floorclimb = true; + + if (mo->eflags & MFE_VERTICALFLIP) + { + if ((topheight < mo->z + mo->height) && ((mo->z + mo->height + mo->momz) < topheight)) + floorclimb = true; + if (topheight < mo->z) // Waaaay below the ledge. + floorclimb = false; + if (bottomheight > mo->z + mo->height - FixedMul(16*FRACUNIT,mo->scale)) + floorclimb = false; + } + else + { + if ((bottomheight > mo->z) && ((mo->z - mo->momz) > bottomheight)) + floorclimb = true; + if (bottomheight > mo->z + mo->height) // Waaaay below the ledge. + floorclimb = false; + if (topheight < mo->z + FixedMul(16*FRACUNIT,mo->scale)) + floorclimb = false; + } + + if (floorclimb) + break; + } + + if (mo->eflags & MFE_VERTICALFLIP) + { + if ((floorz <= mo->z + mo->height) + && ((mo->z + mo->height - mo->momz) <= floorz)) + floorclimb = true; + + if ((floorz > mo->z) + && glidesector->floorpic == skyflatnum) + return false; + + if ((mo->z + mo->height - FixedMul(16*FRACUNIT,mo->scale) > ceilingz) + || (mo->z + mo->height <= floorz)) + floorclimb = true; + } + else + { + if ((ceilingz >= mo->z) + && ((mo->z - mo->momz) >= ceilingz)) + floorclimb = true; + + if ((ceilingz < mo->z+mo->height) + && glidesector->ceilingpic == skyflatnum) + return false; + + if ((mo->z + FixedMul(16*FRACUNIT,mo->scale) < floorz) + || (mo->z >= ceilingz)) + floorclimb = true; + } + + if (!floorclimb) + return false; + + return true; + } + + return false; +} + +static boolean PTR_LineIsBlocking(line_t *li) +{ + // one-sided linedefs are always solid to sliding movement. + if (!li->backsector) + return !P_PointOnLineSide(slidemo->x, slidemo->y, li); + + if (!(slidemo->flags & MF_MISSILE)) + { + if (li->flags & ML_IMPASSIBLE) + return true; + + if ((slidemo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS) + return true; + } + + // set openrange, opentop, openbottom + P_LineOpening(li, slidemo); + + if (openrange < slidemo->height) + return true; // doesn't fit + + if (opentop - slidemo->z < slidemo->height) + return true; // mobj is too high + + if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, slidemo->scale)) + return true; // too big a step up + + return false; +} + +static void PTR_GlideClimbTraverse(line_t *li) +{ + line_t *checkline = li; + ffloor_t *rover; + fixed_t topheight, bottomheight; + boolean fofline = false; + sector_t *checksector = (li->backsector && !P_PointOnLineSide(slidemo->x, slidemo->y, li)) ? li->backsector : li->frontsector; + + if (checksector->ffloors) + { + for (rover = checksector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) + continue; + + topheight = P_GetFFloorTopZAt (rover, slidemo->x, slidemo->y); + bottomheight = P_GetFFloorBottomZAt(rover, slidemo->x, slidemo->y); + + if (topheight < slidemo->z) + continue; + + if (bottomheight > slidemo->z + slidemo->height) + continue; + + // Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this? + if (rover->master->flags & ML_TFERLINE) + { + size_t linenum = li-checksector->lines[0]; + checkline = rover->master->frontsector->lines[0] + linenum; + fofline = true; + } + + break; + } + } + + // see about climbing on the wall + if (!(checkline->flags & ML_NOCLIMB) && checkline->special != HORIZONSPECIAL) + { + boolean canclimb; + angle_t climbangle, climbline; + INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li); + + climbangle = climbline = R_PointToAngle2(li->v1->x, li->v1->y, li->v2->x, li->v2->y); + + if (whichside) // on second side? + climbline += ANGLE_180; + + climbangle += (ANGLE_90 * (whichside ? -1 : 1)); + + canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true); + + if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45) + || (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135)) + && canclimb) + { + slidemo->angle = climbangle; + /*if (!demoplayback || P_ControlStyle(slidemo->player) == CS_LMAOGALOG) + P_SetPlayerAngle(slidemo->player, slidemo->angle);*/ + + if (!slidemo->player->climbing) + { + S_StartSound(slidemo->player->mo, sfx_s3k4a); + slidemo->player->climbing = 5; + } + + slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED); + slidemo->player->glidetime = 0; + slidemo->player->secondjump = 0; + + if (slidemo->player->climbing > 1) + slidemo->momz = slidemo->momx = slidemo->momy = 0; + + if (fofline) + whichside = 0; + + if (!whichside) + { + slidemo->player->lastsidehit = checkline->sidenum[whichside]; + slidemo->player->lastlinehit = (INT16)(checkline - lines); + } + + P_Thrust(slidemo, slidemo->angle, FixedMul(5*FRACUNIT, slidemo->scale)); + } + } +} + static boolean PTR_SlideTraverse(intercept_t *in) { line_t *li; @@ -3270,49 +3406,20 @@ static boolean PTR_SlideTraverse(intercept_t *in) li = in->d.line; - // one-sided linedefs are always solid to sliding movement. - // one-sided linedef - if (!li->backsector) - { - if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) - return true; // don't hit the back side - goto isblocking; - } + if (!PTR_LineIsBlocking(li)) + return true; - if (!(slidemo->flags & MF_MISSILE)) - { - if (li->flags & ML_IMPASSIBLE) - goto isblocking; - - if ((slidemo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS) - goto isblocking; - } - - // set openrange, opentop, openbottom - P_LineOpening(li, slidemo); - - if (openrange < slidemo->height) - goto isblocking; // doesn't fit - - if (opentop - slidemo->z < slidemo->height) - goto isblocking; // mobj is too high - - if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, slidemo->scale)) - goto isblocking; // too big a step up - - // this line doesn't block movement - return true; - - // the line does block movement, + // the line blocks movement, // see if it is closer than best so far -isblocking: if (li->polyobj && slidemo->player) { if ((li->polyobj->lines[0]->backsector->flags & SF_TRIGGERSPECIAL_TOUCH) && !(li->polyobj->flags & POF_NOSPECIALS)) P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector); } - P_TryClimb(slidemo->player, li); + if (slidemo->player && slidemo->player->charability == CA_GLIDEANDCLIMB + && (slidemo->player->pflags & PF_GLIDING || slidemo->player->climbing)) + PTR_GlideClimbTraverse(li); if (in->frac < bestslidefrac && (!slidemo->player || !slidemo->player->climbing)) { @@ -3443,11 +3550,7 @@ static void P_CheckLavaWall(mobj_t *mo, sector_t *sec) 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; + topheight = P_GetFFloorTopZAt(rover, mo->x, mo->y); if (mo->eflags & MFE_VERTICALFLIP) { @@ -3460,11 +3563,7 @@ static void P_CheckLavaWall(mobj_t *mo, sector_t *sec) continue; } - bottomheight = -#ifdef ESLOPE - *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : -#endif - *rover->bottomheight; + bottomheight = P_GetFFloorBottomZAt(rover, mo->x, mo->y); if (mo->eflags & MFE_VERTICALFLIP) { @@ -4050,13 +4149,8 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) topheight = *rover->topheight; bottomheight = *rover->bottomheight; - -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, thing->x, thing->y); - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, thing->x, thing->y); -#endif*/ + //topheight = P_GetFFloorTopZAt (rover, thing->x, thing->y); + //bottomheight = P_GetFFloorBottomZAt(rover, thing->x, thing->y); delta1 = thing->z - (bottomheight + topheight)/2; delta2 = thingtop - (bottomheight + topheight)/2; @@ -4072,21 +4166,19 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) { //If the thing was crushed by a crumbling FOF, reward the player who made it crumble! thinker_t *think; - elevator_t *crumbler; + crumble_t *crumbler; for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next) { if (think->function.acp1 != (actionf_p1)T_StartCrumble) continue; - crumbler = (elevator_t *)think; + crumbler = (crumble_t *)think; if (crumbler->player && crumbler->player->mo && crumbler->player->mo != thing && crumbler->actionsector == thing->subsector->sector - && crumbler->sector == rover->master->frontsector - && (crumbler->type == elevateBounce - || crumbler->type == elevateContinuous)) + && crumbler->sector == rover->master->frontsector) { killer = crumbler->player->mo; } @@ -4835,12 +4927,7 @@ void P_MapEnd(void) fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) { sector_t *sec = R_PointInSubsector(x, y)->sector; - fixed_t floorz = sec->floorheight; - -#ifdef ESLOPE - if (sec->f_slope) - floorz = P_GetZAt(sec->f_slope, x, y); -#endif + fixed_t floorz = P_GetSectorFloorZAt(sec, x, y); // Intercept the stupid 'fall through 3dfloors' bug Tails 03-17-2002 if (sec->ffloors) @@ -4857,15 +4944,8 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE))) continue; - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, x, y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, x, y); -#endif + topheight = P_GetFFloorTopZAt (rover, x, y); + bottomheight = P_GetFFloorBottomZAt(rover, x, y); if (rover->flags & FF_QUICKSAND) { diff --git a/src/p_maputl.c b/src/p_maputl.c index b4043d643..c6e064d18 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -277,9 +277,7 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1) // OPTIMIZE: keep this precalculated // fixed_t opentop, openbottom, openrange, lowfloor, highceiling; -#ifdef ESLOPE pslope_t *opentopslope, *openbottomslope; -#endif ffloor_t *openfloorrover, *openceilingrover; // P_CameraLineOpening @@ -305,53 +303,33 @@ void P_CameraLineOpening(line_t *linedef) // If you can see through it, why not move the camera through it too? if (front->camsec >= 0) { - frontfloor = sectors[front->camsec].floorheight; - frontceiling = sectors[front->camsec].ceilingheight; -#ifdef ESLOPE - if (sectors[front->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[front->camsec].f_slope, camera.x, camera.y); - if (sectors[front->camsec].c_slope) - frontceiling = P_GetZAt(sectors[front->camsec].c_slope, camera.x, camera.y); -#endif + // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) + frontfloor = P_GetSectorFloorZAt (§ors[front->camsec], camera.x, camera.y); + frontceiling = P_GetSectorCeilingZAt(§ors[front->camsec], camera.x, camera.y); } else if (front->heightsec >= 0) { - frontfloor = sectors[front->heightsec].floorheight; - frontceiling = sectors[front->heightsec].ceilingheight; -#ifdef ESLOPE - if (sectors[front->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[front->heightsec].f_slope, camera.x, camera.y); - if (sectors[front->heightsec].c_slope) - frontceiling = P_GetZAt(sectors[front->heightsec].c_slope, camera.x, camera.y); -#endif + // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) + frontfloor = P_GetSectorFloorZAt (§ors[front->heightsec], camera.x, camera.y); + frontceiling = P_GetSectorCeilingZAt(§ors[front->heightsec], camera.x, camera.y); } else { - frontfloor = P_CameraGetFloorZ(mapcampointer, front, tmx, tmy, linedef); + frontfloor = P_CameraGetFloorZ (mapcampointer, front, tmx, tmy, linedef); frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tmx, tmy, linedef); } if (back->camsec >= 0) { - backfloor = sectors[back->camsec].floorheight; - backceiling = sectors[back->camsec].ceilingheight; -#ifdef ESLOPE - if (sectors[back->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[back->camsec].f_slope, camera.x, camera.y); - if (sectors[back->camsec].c_slope) - frontceiling = P_GetZAt(sectors[back->camsec].c_slope, camera.x, camera.y); -#endif + // SRB2CBTODO: ESLOPE (sectors[back->heightsec].f_slope) + backfloor = P_GetSectorFloorZAt (§ors[back->camsec], camera.x, camera.y); + backceiling = P_GetSectorCeilingZAt(§ors[back->camsec], camera.x, camera.y); } else if (back->heightsec >= 0) { - backfloor = sectors[back->heightsec].floorheight; - backceiling = sectors[back->heightsec].ceilingheight; -#ifdef ESLOPE - if (sectors[back->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope) - frontfloor = P_GetZAt(sectors[back->heightsec].f_slope, camera.x, camera.y); - if (sectors[back->heightsec].c_slope) - frontceiling = P_GetZAt(sectors[back->heightsec].c_slope, camera.x, camera.y); -#endif + // SRB2CBTODO: ESLOPE (sectors[back->heightsec].f_slope) + backfloor = P_GetSectorFloorZAt (§ors[back->heightsec], camera.x, camera.y); + backceiling = P_GetSectorCeilingZAt(§ors[back->heightsec], camera.x, camera.y); } else { @@ -461,7 +439,6 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) I_Assert(back != NULL); openfloorrover = openceilingrover = NULL; -#ifdef POLYOBJECTS if (linedef->polyobj) { // set these defaults so that polyobjects don't interfere with collision above or below them @@ -469,12 +446,9 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) openbottom = INT32_MIN; highceiling = INT32_MIN; lowfloor = INT32_MAX; -#ifdef ESLOPE opentopslope = openbottomslope = NULL; -#endif } else -#endif { // Set open and high/low values here fixed_t frontheight, backheight; @@ -485,17 +459,13 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) { opentop = frontheight; highceiling = backheight; -#ifdef ESLOPE opentopslope = front->c_slope; -#endif } else { opentop = backheight; highceiling = frontheight; -#ifdef ESLOPE opentopslope = back->c_slope; -#endif } frontheight = P_GetFloorZ(mobj, front, tmx, tmy, linedef); @@ -505,17 +475,13 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) { openbottom = frontheight; lowfloor = backheight; -#ifdef ESLOPE openbottomslope = front->f_slope; -#endif } else { openbottom = backheight; lowfloor = frontheight; -#ifdef ESLOPE openbottomslope = back->f_slope; -#endif } } @@ -537,7 +503,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) texheight = textures[texnum]->height << FRACBITS; // Set texbottom and textop to the Z coordinates of the texture's boundaries -#if 0 // #ifdef POLYOBJECTS +#if 0 // don't remove this code unless solid midtextures // on non-solid polyobjects should NEVER happen in the future if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) { @@ -580,7 +546,6 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) } } } -#ifdef POLYOBJECTS if (linedef->polyobj) { // Treat polyobj's backsector like a 3D Floor @@ -617,102 +582,95 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) // otherwise don't do anything special, pretend there's nothing else there } else -#endif - // Check for fake floors in the sector. - if (front->ffloors || back->ffloors) { - ffloor_t *rover; - fixed_t delta1, delta2; - - // Check for frontsector's fake floors - for (rover = front->ffloors; rover; rover = rover->next) + // Check for fake floors in the sector. + if (front->ffloors || back->ffloors) { - fixed_t topheight, bottomheight; - if (!(rover->flags & FF_EXISTS)) - continue; + ffloor_t *rover; + fixed_t delta1, delta2; - 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))) - continue; - - topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef); - bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef); - - delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); - delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - - if (delta1 >= delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_PLATFORM) // thing is below FOF + // Check for frontsector's fake floors + for (rover = front->ffloors; rover; rover = rover->next) { - if (bottomheight < opentop) { - opentop = bottomheight; -#ifdef ESLOPE - opentopslope = *rover->b_slope; -#endif - openceilingrover = rover; + fixed_t topheight, bottomheight; + if (!(rover->flags & FF_EXISTS)) + continue; + + 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))) + continue; + + topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef); + bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef); + + delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); + + if (delta1 >= delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_PLATFORM) // thing is below FOF + { + if (bottomheight < opentop) { + opentop = bottomheight; + opentopslope = *rover->b_slope; + openceilingrover = rover; + } + else if (bottomheight < highceiling) + highceiling = bottomheight; + } + + if (delta1 < delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF + { + if (topheight > openbottom) { + openbottom = topheight; + openbottomslope = *rover->t_slope; + openfloorrover = rover; + } + else if (topheight > lowfloor) + lowfloor = topheight; } - else if (bottomheight < highceiling) - highceiling = bottomheight; } - if (delta1 < delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF + // Check for backsectors fake floors + for (rover = back->ffloors; rover; rover = rover->next) { - if (topheight > openbottom) { - openbottom = topheight; -#ifdef ESLOPE - openbottomslope = *rover->t_slope; -#endif - openfloorrover = rover; + fixed_t topheight, bottomheight; + if (!(rover->flags & FF_EXISTS)) + continue; + + 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))) + continue; + + topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef); + bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef); + + delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); + delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); + + if (delta1 >= delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_PLATFORM) // thing is below FOF + { + if (bottomheight < opentop) { + opentop = bottomheight; + opentopslope = *rover->b_slope; + openceilingrover = rover; + } + else if (bottomheight < highceiling) + highceiling = bottomheight; } - else if (topheight > lowfloor) - lowfloor = topheight; - } - } - // Check for backsectors fake floors - for (rover = back->ffloors; rover; rover = rover->next) - { - fixed_t topheight, bottomheight; - if (!(rover->flags & FF_EXISTS)) - continue; - - 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))) - continue; - - topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef); - bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef); - - delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); - delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); - - if (delta1 >= delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_PLATFORM) // thing is below FOF - { - if (bottomheight < opentop) { - opentop = bottomheight; -#ifdef ESLOPE - opentopslope = *rover->b_slope; -#endif - openceilingrover = rover; + if (delta1 < delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF + { + if (topheight > openbottom) { + openbottom = topheight; + openbottomslope = *rover->t_slope; + openfloorrover = rover; + } + else if (topheight > lowfloor) + lowfloor = topheight; } - else if (bottomheight < highceiling) - highceiling = bottomheight; - } - - if (delta1 < delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF - { - if (topheight > openbottom) { - openbottom = topheight; -#ifdef ESLOPE - openbottomslope = *rover->t_slope; -#endif - openfloorrover = rover; - } - else if (topheight > lowfloor) - lowfloor = topheight; } } } @@ -962,9 +920,7 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) { INT32 offset; const INT32 *list; // Big blockmap -#ifdef POLYOBJECTS polymaplink_t *plink; // haleyjd 02/22/06 -#endif line_t *ld; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) @@ -972,7 +928,6 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) offset = y*bmapwidth + x; -#ifdef POLYOBJECTS // haleyjd 02/22/06: consider polyobject lines plink = polyblocklinks[offset]; @@ -996,7 +951,6 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) } plink = (polymaplink_t *)(plink->link.next); } -#endif offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x]; diff --git a/src/p_maputl.h b/src/p_maputl.h index 16cfc834e..08b606833 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -55,9 +55,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y); boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y); extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling; -#ifdef ESLOPE extern pslope_t *opentopslope, *openbottomslope; -#endif extern ffloor_t *openfloorrover, *openceilingrover; void P_LineOpening(line_t *plinedef, mobj_t *mobj); diff --git a/src/p_mobj.c b/src/p_mobj.c index d9d0f2b56..40d0755b3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -19,7 +19,7 @@ #include "p_local.h" #include "p_setup.h" #include "r_main.h" -#include "r_things.h" +#include "r_skins.h" #include "r_sky.h" #include "r_splats.h" #include "s_sound.h" @@ -31,9 +31,7 @@ #include "i_video.h" #include "lua_hook.h" #include "b_bot.h" -#ifdef ESLOPE #include "p_slopes.h" -#endif #include "f_finale.h" #include "m_cond.h" @@ -62,9 +60,7 @@ void P_RunCachedActions(void) { var1 = states[ac->statenum].var1; var2 = states[ac->statenum].var2; -#ifdef HAVE_BLUA astate = &states[ac->statenum]; -#endif if (ac->mobj && !P_MobjWasRemoved(ac->mobj)) // just in case... states[ac->statenum].action.acp1(ac->mobj); next = ac->next; @@ -445,7 +441,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) mobj->sprite2 = spr2; mobj->frame = frame|(st->frame&~FF_FRAMEMASK); - if (mobj->color >= MAXSKINCOLORS && mobj->color < MAXTRANSLATIONS) // Super colours? Super bright! + if (mobj->color >= FIRSTSUPERCOLOR && mobj->color < numskincolors) // Super colours? Super bright! mobj->frame |= FF_FULLBRIGHT; } // Regular sprites @@ -464,9 +460,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) { var1 = st->var1; var2 = st->var2; -#ifdef HAVE_BLUA astate = st; -#endif st->action.acp1(mobj); // woah. a player was removed by an action. @@ -590,9 +584,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) { var1 = st->var1; var2 = st->var2; -#ifdef HAVE_BLUA astate = st; -#endif st->action.acp1(mobj); if (P_MobjWasRemoved(mobj)) return false; @@ -939,15 +931,8 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover) || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) return false; - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y); -#endif + topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); + bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); if (mobj->z > topheight) return false; @@ -958,7 +943,6 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover) return true; } -#ifdef ESLOPE // P_GetFloorZ (and its ceiling counterpart) // Gets the floor height (or ceiling height) of the mobj's contact point in sector, assuming object's center if moved to [x, y] // If line is supplied, it's a divider line on the sector. Set it to NULL if you're not checking for collision with a line @@ -979,12 +963,12 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, /*CONS_Printf("BEFORE: v1 = %f %f %f\n", FIXED_TO_FLOAT(v1.x), FIXED_TO_FLOAT(v1.y), - FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y)) + FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v1.x, v1.y)) ); CONS_Printf(" v2 = %f %f %f\n", FIXED_TO_FLOAT(v2.x), FIXED_TO_FLOAT(v2.y), - FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y)) + FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v2.x, v2.y)) );*/ if (abs(v1.x-x) > radius) { @@ -1042,35 +1026,32 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, /*CONS_Printf("AFTER: v1 = %f %f %f\n", FIXED_TO_FLOAT(v1.x), FIXED_TO_FLOAT(v1.y), - FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y)) + FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v1.x, v1.y)) ); CONS_Printf(" v2 = %f %f %f\n", FIXED_TO_FLOAT(v2.x), FIXED_TO_FLOAT(v2.y), - FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y)) + FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v2.x, v2.y)) );*/ // Return the higher of the two points if (actuallylowest) return min( - P_GetZAt(slope, v1.x, v1.y), - P_GetZAt(slope, v2.x, v2.y) + P_GetSlopeZAt(slope, v1.x, v1.y), + P_GetSlopeZAt(slope, v2.x, v2.y) ); else return max( - P_GetZAt(slope, v1.x, v1.y), - P_GetZAt(slope, v2.x, v2.y) + P_GetSlopeZAt(slope, v1.x, v1.y), + P_GetSlopeZAt(slope, v2.x, v2.y) ); } -#endif fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) { -#ifdef ESLOPE I_Assert(mobj != NULL); -#endif I_Assert(sector != NULL); -#ifdef ESLOPE + if (sector->f_slope) { fixed_t testx, testy; pslope_t *slope = sector->f_slope; @@ -1096,7 +1077,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t // If the highest point is in the sector, then we have it easy! Just get the Z at that point if (R_PointInSubsector(testx, testy)->sector == (boundsec ? boundsec : sector)) - return P_GetZAt(slope, testx, testy); + return P_GetSlopeZAt(slope, testx, testy); // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point if (perfect) { @@ -1136,29 +1117,18 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t // If we're just testing for base sector location (no collision line), just go for the center's spot... // It'll get fixed when we test for collision anyway, and the final result can't be lower than this if (line == NULL) - return P_GetZAt(slope, x, y); + return P_GetSlopeZAt(slope, x, y); return HighestOnLine(mobj->radius, x, y, line, slope, lowest); } else // Well, that makes it easy. Just get the floor height -#else - (void)mobj; - (void)boundsec; - (void)x; - (void)y; - (void)line; - (void)lowest; - (void)perfect; -#endif return sector->floorheight; } fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) { -#ifdef ESLOPE I_Assert(mobj != NULL); -#endif I_Assert(sector != NULL); -#ifdef ESLOPE + if (sector->c_slope) { fixed_t testx, testy; pslope_t *slope = sector->c_slope; @@ -1184,7 +1154,7 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed // If the highest point is in the sector, then we have it easy! Just get the Z at that point if (R_PointInSubsector(testx, testy)->sector == (boundsec ? boundsec : sector)) - return P_GetZAt(slope, testx, testy); + return P_GetSlopeZAt(slope, testx, testy); // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point if (perfect) { @@ -1224,30 +1194,19 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed // If we're just testing for base sector location (no collision line), just go for the center's spot... // It'll get fixed when we test for collision anyway, and the final result can't be lower than this if (line == NULL) - return P_GetZAt(slope, x, y); + return P_GetSlopeZAt(slope, x, y); return HighestOnLine(mobj->radius, x, y, line, slope, lowest); } else // Well, that makes it easy. Just get the ceiling height -#else - (void)mobj; - (void)boundsec; - (void)x; - (void)y; - (void)line; - (void)lowest; - (void)perfect; -#endif return sector->ceilingheight; } // Now do the same as all above, but for cameras because apparently cameras are special? fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) { -#ifdef ESLOPE I_Assert(mobj != NULL); -#endif I_Assert(sector != NULL); -#ifdef ESLOPE + if (sector->f_slope) { fixed_t testx, testy; pslope_t *slope = sector->f_slope; @@ -1273,7 +1232,7 @@ fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fix // If the highest point is in the sector, then we have it easy! Just get the Z at that point if (R_PointInSubsector(testx, testy)->sector == (boundsec ? boundsec : sector)) - return P_GetZAt(slope, testx, testy); + return P_GetSlopeZAt(slope, testx, testy); // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point if (perfect) { @@ -1313,29 +1272,18 @@ fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fix // If we're just testing for base sector location (no collision line), just go for the center's spot... // It'll get fixed when we test for collision anyway, and the final result can't be lower than this if (line == NULL) - return P_GetZAt(slope, x, y); + return P_GetSlopeZAt(slope, x, y); return HighestOnLine(mobj->radius, x, y, line, slope, lowest); } else // Well, that makes it easy. Just get the floor height -#else - (void)mobj; - (void)boundsec; - (void)x; - (void)y; - (void)line; - (void)lowest; - (void)perfect; -#endif return sector->floorheight; } fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect) { -#ifdef ESLOPE I_Assert(mobj != NULL); -#endif I_Assert(sector != NULL); -#ifdef ESLOPE + if (sector->c_slope) { fixed_t testx, testy; pslope_t *slope = sector->c_slope; @@ -1361,7 +1309,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f // If the highest point is in the sector, then we have it easy! Just get the Z at that point if (R_PointInSubsector(testx, testy)->sector == (boundsec ? boundsec : sector)) - return P_GetZAt(slope, testx, testy); + return P_GetSlopeZAt(slope, testx, testy); // If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point if (perfect) { @@ -1401,19 +1349,10 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f // If we're just testing for base sector location (no collision line), just go for the center's spot... // It'll get fixed when we test for collision anyway, and the final result can't be lower than this if (line == NULL) - return P_GetZAt(slope, x, y); + return P_GetSlopeZAt(slope, x, y); return HighestOnLine(mobj->radius, x, y, line, slope, lowest); } else // Well, that makes it easy. Just get the ceiling height -#else - (void)mobj; - (void)boundsec; - (void)x; - (void)y; - (void)line; - (void)lowest; - (void)perfect; -#endif return sector->ceilingheight; } static void P_PlayerFlip(mobj_t *mo) @@ -1685,10 +1624,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale) && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale) && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING)) -#ifdef ESLOPE - && !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)) -#endif - ) + && !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2))) { // if in a walking frame, stop moving if (player->panim == PA_WALK) @@ -1738,70 +1674,74 @@ static void P_PushableCheckBustables(mobj_t *mo) for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) { + ffloor_t *rover; + fixed_t topheight, bottomheight; + if (!node->m_sector) break; - if (node->m_sector->ffloors) + if (!node->m_sector->ffloors) + continue; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - ffloor_t *rover; - fixed_t topheight, bottomheight; + if (!(rover->flags & FF_EXISTS)) + continue; - for (rover = node->m_sector->ffloors; rover; rover = rover->next) + if (!(rover->flags & FF_BUSTUP)) + continue; + + // Needs ML_EFFECT4 flag for pushables to break it + if (!(rover->master->flags & ML_EFFECT4)) + continue; + + if (rover->master->frontsector->crumblestate != CRUMBLE_NONE) + continue; + + 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); + + // Height checks + if (rover->flags & FF_SHATTERBOTTOM) { - if (!(rover->flags & FF_EXISTS)) continue; + if (mo->z + mo->momz + mo->height < bottomheight) + continue; - if (!(rover->flags & FF_BUSTUP)) continue; - - // Needs ML_EFFECT4 flag for pushables to break it - if (!(rover->master->flags & ML_EFFECT4)) continue; - - if (!rover->master->frontsector->crumblestate) - { - 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); - // Height checks - if (rover->flags & FF_SHATTERBOTTOM) - { - if (mo->z+mo->momz + mo->height < bottomheight) - continue; - - if (mo->z+mo->height > bottomheight) - continue; - } - else if (rover->flags & FF_SPINBUST) - { - if (mo->z+mo->momz > topheight) - continue; - - if (mo->z+mo->height < bottomheight) - continue; - } - else if (rover->flags & FF_SHATTER) - { - if (mo->z+mo->momz > topheight) - continue; - - if (mo->z+mo->momz + mo->height < bottomheight) - continue; - } - else - { - if (mo->z >= topheight) - continue; - - if (mo->z+mo->height < bottomheight) - continue; - } - - EV_CrumbleChain(NULL, rover); // node->m_sector - - // Run a linedef executor?? - if (rover->master->flags & ML_EFFECT5) - P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), mo, node->m_sector); - - goto bustupdone; - } + if (mo->z + mo->height > bottomheight) + continue; } + else if (rover->flags & FF_SPINBUST) + { + if (mo->z + mo->momz > topheight) + continue; + + if (mo->z + mo->height < bottomheight) + continue; + } + else if (rover->flags & FF_SHATTER) + { + if (mo->z + mo->momz > topheight) + continue; + + if (mo->z + mo->momz + mo->height < bottomheight) + continue; + } + else + { + if (mo->z >= topheight) + continue; + + if (mo->z + mo->height < bottomheight) + continue; + } + + EV_CrumbleChain(NULL, rover); // node->m_sector + + // Run a linedef executor?? + if (rover->master->flags & ML_EFFECT5) + P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), mo, node->m_sector); + + goto bustupdone; } } bustupdone: @@ -1835,11 +1775,9 @@ void P_XYMovement(mobj_t *mo) fixed_t xmove, ymove; fixed_t oldx, oldy; // reducing bobbing/momentum on ice when up against walls boolean moved; -#ifdef ESLOPE pslope_t *oldslope = NULL; - vector3_t slopemom; + vector3_t slopemom = {0,0,0}; fixed_t predictedz = 0; -#endif I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1869,7 +1807,6 @@ void P_XYMovement(mobj_t *mo) oldx = mo->x; oldy = mo->y; -#ifdef ESLOPE if (mo->flags & MF_NOCLIPHEIGHT) mo->standingslope = NULL; @@ -1894,7 +1831,6 @@ void P_XYMovement(mobj_t *mo) } } else if (P_IsObjectOnGround(mo) && !mo->momz) predictedz = mo->z; -#endif // Pushables can break some blocks if (CheckForBustableBlocks && ((mo->flags & MF_PUSHABLE) || ((mo->info->flags & MF_PUSHABLE) && mo->fuse))) @@ -1911,15 +1847,12 @@ void P_XYMovement(mobj_t *mo) B_MoveBlocked(player); } -#ifdef HAVE_BLUA if (LUAh_MobjMoveBlocked(mo)) { if (P_MobjWasRemoved(mo)) return; } - else -#endif - if (P_MobjWasRemoved(mo)) + else if (P_MobjWasRemoved(mo)) return; else if (mo->flags & MF_BOUNCE) { @@ -1970,7 +1903,6 @@ void P_XYMovement(mobj_t *mo) } else if (player || mo->flags & (MF_SLIDEME|MF_PUSHABLE)) { // try to slide along it -#ifdef ESLOPE // Wall transfer part 1. pslope_t *transferslope = NULL; fixed_t transfermomz = 0; @@ -1980,14 +1912,12 @@ void P_XYMovement(mobj_t *mo) if (((transferslope->zangle < ANGLE_180) ? transferslope->zangle : InvAngle(transferslope->zangle)) >= ANGLE_45) // Prevent some weird stuff going on on shallow slopes. transfermomz = P_GetWallTransferMomZ(mo, transferslope); } -#endif P_SlideMove(mo); if (player) player->powers[pw_pushing] = 3; xmove = ymove = 0; -#ifdef ESLOPE // Wall transfer part 2. if (transfermomz && transferslope) // Are we "transferring onto the wall" (really just a disguised vertical launch)? { @@ -2010,7 +1940,6 @@ void P_XYMovement(mobj_t *mo) } } } -#endif } else if (mo->type == MT_SPINFIRE) { @@ -2066,7 +1995,6 @@ void P_XYMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; return; -#ifdef ESLOPE if (moved && oldslope && !(mo->flags & MF_NOCLIPHEIGHT)) { // Check to see if we ran off if (oldslope != mo->standingslope) { // First, compare different slopes @@ -2112,7 +2040,6 @@ void P_XYMovement(mobj_t *mo) //CONS_Printf("Launched off of flat surface running into downward slope\n"); } } -#endif // Check the gravity status. P_CheckGravity(mo, false); @@ -2163,11 +2090,9 @@ void P_XYMovement(mobj_t *mo) if (player && player->powers[pw_carry] == CR_NIGHTSMODE) return; // no friction for NiGHTS players -#ifdef ESLOPE if ((mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED) && (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8)) // Special exception for tumbleweeds on slopes return; -#endif if (((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz)) && !(player && player->pflags & PF_SLIDING)) @@ -2435,7 +2360,6 @@ static boolean P_ZMovement(mobj_t *mo) mo->z += mo->momz; onground = P_IsObjectOnGround(mo); -#ifdef ESLOPE if (mo->standingslope) { if (mo->flags & MF_NOCLIPHEIGHT) @@ -2443,7 +2367,6 @@ static boolean P_ZMovement(mobj_t *mo) else if (!onground) P_SlopeLaunch(mo); } -#endif switch (mo->type) { @@ -2645,7 +2568,6 @@ static boolean P_ZMovement(mobj_t *mo) else mo->z = mo->floorz; -#ifdef ESLOPE if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here? { mo->momz = 0; @@ -2658,7 +2580,6 @@ static boolean P_ZMovement(mobj_t *mo) mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); } -#endif // hit the floor if (mo->type == MT_FIREBALL) // special case for the fireball @@ -2758,13 +2679,11 @@ static boolean P_ZMovement(mobj_t *mo) else mom.y -= FixedMul(6*FRACUNIT, mo->scale); } -#ifdef ESLOPE else if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) { // Pop the object up a bit to encourage bounciness //mom.z = P_MobjFlip(mo)*mo->scale; } -#endif else { mom.x = mom.y = mom.z = 0; @@ -2804,11 +2723,9 @@ static boolean P_ZMovement(mobj_t *mo) else if (tmfloorthing) mom.z = tmfloorthing->momz; -#ifdef ESLOPE if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above. P_QuantizeMomentumToSlope(&mom, mo->standingslope); } -#endif mo->momx = mom.x; mo->momy = mom.y; @@ -2885,6 +2802,94 @@ static boolean P_ZMovement(mobj_t *mo) return true; } +// Check for "Mario" blocks to hit and bounce them +static void P_CheckMarioBlocks(mobj_t *mo) +{ + msecnode_t *node; + + if (netgame && mo->player->spectator) + return; + + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + ffloor_t *rover; + + if (!node->m_sector->ffloors) + continue; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!(rover->flags & FF_MARIO)) + continue; + + if (mo->eflags & MFE_VERTICALFLIP) + continue; // if you were flipped, your head isn't actually hitting your ceilingz is it? + + if (*rover->bottomheight != mo->ceilingz) + continue; + + if (rover->flags & FF_SHATTERBOTTOM) // Brick block! + EV_CrumbleChain(node->m_sector, rover); + else // Question block! + EV_MarioBlock(rover, node->m_sector, mo); + } + } +} + +// Check if we're on a polyobject that triggers a linedef executor. +static boolean P_PlayerPolyObjectZMovement(mobj_t *mo) +{ + msecnode_t *node; + boolean stopmovecut = false; + + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + sector_t *sec = node->m_sector; + subsector_t *newsubsec; + size_t i; + + for (i = 0; i < numsubsectors; i++) + { + polyobj_t *po; + sector_t *polysec; + newsubsec = &subsectors[i]; + + if (newsubsec->sector != sec) + continue; + + for (po = newsubsec->polyList; po; po = (polyobj_t *)(po->link.next)) + { + if (!(po->flags & POF_SOLID)) + continue; + + if (!P_MobjInsidePolyobj(po, mo)) + continue; + + polysec = po->lines[0]->backsector; + + // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red + if ((mo->z == polysec->ceilingheight || mo->z + mo->height == polysec->floorheight) && po->thinker) + stopmovecut = true; + + if (!(po->flags & POF_LDEXEC)) + continue; + + if (mo->z != polysec->ceilingheight) + continue; + + // We're landing on a PO, so check for a linedef executor. + // Trigger tags are 32000 + the PO's ID number. + P_LinedefExecute((INT16)(32000 + po->id), mo, NULL); + } + } + } + + return stopmovecut; +} + static void P_PlayerZMovement(mobj_t *mo) { boolean onground; @@ -2930,7 +2935,6 @@ static void P_PlayerZMovement(mobj_t *mo) || mo->player->playerstate == PST_REBORN) return; -#ifdef ESLOPE if (mo->standingslope) { if (mo->flags & MF_NOCLIPHEIGHT) @@ -2938,7 +2942,6 @@ static void P_PlayerZMovement(mobj_t *mo) else if (!onground) P_SlopeLaunch(mo); } -#endif // clip movement if (onground && !(mo->flags & MF_NOCLIPHEIGHT)) @@ -2966,12 +2969,10 @@ static void P_PlayerZMovement(mobj_t *mo) if (mo->player->panim == PA_PAIN) P_SetPlayerMobjState(mo, S_PLAY_WALK); -#ifdef ESLOPE if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) { // Handle landing on slope during Z movement P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)); } -#endif if (P_MobjFlip(mo)*mo->momz < 0) // falling { @@ -2985,69 +2986,10 @@ static void P_PlayerZMovement(mobj_t *mo) mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack + clipmomz = P_PlayerHitFloor(mo->player, true); + + if (!P_PlayerPolyObjectZMovement(mo)) { -#ifdef POLYOBJECTS - // Check if we're on a polyobject - // that triggers a linedef executor. - msecnode_t *node; - boolean stopmovecut = false; - - for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - sector_t *sec = node->m_sector; - subsector_t *newsubsec; - size_t i; - - for (i = 0; i < numsubsectors; i++) - { - newsubsec = &subsectors[i]; - - if (newsubsec->sector != sec) - continue; - - if (newsubsec->polyList) - { - polyobj_t *po = newsubsec->polyList; - sector_t *polysec; - - while(po) - { - if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - // We're inside it! Yess... - polysec = po->lines[0]->backsector; - - // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red - if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && po->thinker) - stopmovecut = true; - - if (!(po->flags & POF_LDEXEC)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - if (mo->z == polysec->ceilingheight) - { - // We're landing on a PO, so check for - // a linedef executor. - // Trigger tags are 32000 + the PO's ID number. - P_LinedefExecute((INT16)(32000 + po->id), mo, NULL); - } - - po = (polyobj_t *)(po->link.next); - } - } - } - } - - if (!stopmovecut) -#endif - // Cut momentum in half when you hit the ground and // aren't pressing any controls. if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING)) @@ -3057,8 +2999,6 @@ static void P_PlayerZMovement(mobj_t *mo) } } - clipmomz = P_PlayerHitFloor(mo->player, true); - if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE) mo->player->pflags &= ~PF_STARTDASH; @@ -3113,39 +3053,10 @@ nightsdone: } } - // Check for "Mario" blocks to hit and bounce them if (P_MobjFlip(mo)*mo->momz > 0) { - msecnode_t *node; - - if (CheckForMarioBlocks && !(netgame && mo->player->spectator)) // Only let the player punch - { - // Search the touching sectors, from side-to-side... - for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - ffloor_t *rover; - if (!node->m_sector->ffloors) - continue; - - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS)) - continue; - - // Come on, it's time to go... - if (rover->flags & FF_MARIO - && !(mo->eflags & MFE_VERTICALFLIP) // if you were flipped, your head isn't actually hitting your ceilingz is it? - && *rover->bottomheight == mo->ceilingz) // The player's head hit the bottom! - { - // DO THE MARIO! - if (rover->flags & FF_SHATTERBOTTOM) // Brick block! - EV_CrumbleChain(node->m_sector, rover); - else // Question block! - EV_MarioBlock(rover, node->m_sector, mo); - } - } - } // Ugly ugly billions of braces! Argh! - } + if (CheckForMarioBlocks) + P_CheckMarioBlocks(mo); // hit the ceiling if (mariomode) @@ -3304,11 +3215,7 @@ static boolean P_SceneryZMovement(mobj_t *mo) // boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) { - fixed_t topheight = -#ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : -#endif - *rover->topheight; + fixed_t topheight = P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); if (!player->powers[pw_carry] && !player->homing && ((player->powers[pw_super] || player->charflags & SF_RUNONWATER || player->dashmode >= DASHMODE_THRESHOLD) && player->mo->ceilingz-topheight >= player->mo->height) @@ -3351,16 +3258,8 @@ void P_MobjCheckWater(mobj_t *mobj) || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) continue; - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y); - - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y); -#endif + topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); + bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); if (mobj->eflags & MFE_VERTICALFLIP) { @@ -3607,16 +3506,8 @@ static void P_SceneryCheckWater(mobj_t *mobj) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS) continue; - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y); - - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y); -#endif + topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); + bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); if (topheight <= mobj->z || bottomheight > (mobj->z + (mobj->height>>1))) @@ -3661,15 +3552,9 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) if (!(rover->flags & FF_EXISTS)) continue; - if (halfheight >= ( -#ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, thiscam->x, thiscam->y) : -#endif - *rover->topheight) || halfheight <= ( -#ifdef ESLOPE - *rover->b_slope ? P_GetZAt(*rover->b_slope, thiscam->x, thiscam->y) : -#endif - *rover->bottomheight)) + if (halfheight >= P_GetFFloorTopZAt(rover, thiscam->x, thiscam->y)) + continue; + if (halfheight <= P_GetFFloorBottomZAt(rover, thiscam->x, thiscam->y)) continue; if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) @@ -3697,15 +3582,9 @@ static boolean P_CameraCheckWater(camera_t *thiscam) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS) continue; - if (halfheight >= ( -#ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, thiscam->x, thiscam->y) : -#endif - *rover->topheight) || halfheight <= ( -#ifdef ESLOPE - *rover->b_slope ? P_GetZAt(*rover->b_slope, thiscam->x, thiscam->y) : -#endif - *rover->bottomheight)) + if (halfheight >= P_GetFFloorTopZAt(rover, thiscam->x, thiscam->y)) + continue; + if (halfheight <= P_GetFFloorBottomZAt(rover, thiscam->x, thiscam->y)) continue; return true; @@ -3881,22 +3760,121 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled return false; } -// -// P_PlayerMobjThinker -// -static void P_PlayerMobjThinker(mobj_t *mobj) +static void P_CheckCrumblingPlatforms(mobj_t *mobj) { msecnode_t *node; + if (netgame && mobj->player->spectator) + return; + + for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) + { + ffloor_t *rover; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!(rover->flags & FF_CRUMBLE)) + continue; + + if (mobj->eflags & MFE_VERTICALFLIP) + { + if (P_GetSpecialBottomZ(mobj, sectors + rover->secnum, node->m_sector) != mobj->z + mobj->height) + continue; + } + else + { + if (P_GetSpecialTopZ(mobj, sectors + rover->secnum, node->m_sector) != mobj->z) + continue; + } + + EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), mobj->player, rover->alpha, !(rover->flags & FF_NORETURN)); + } + } +} + +static boolean P_MobjTouchesSectorWithWater(mobj_t *mobj) +{ + msecnode_t *node; + + for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) + { + ffloor_t *rover; + + if (!node->m_sector->ffloors) + continue; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!(rover->flags & FF_SWIMMABLE)) + continue; + + return true; + } + } + + return false; +} + +// Check for floating water platforms and bounce them +static void P_CheckFloatbobPlatforms(mobj_t *mobj) +{ + msecnode_t *node; + + // Can't land on anything if you're not moving downwards + if (P_MobjFlip(mobj)*mobj->momz >= 0) + return; + + if (!P_MobjTouchesSectorWithWater(mobj)) + return; + + for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) + { + ffloor_t *rover; + + if (!node->m_sector->ffloors) + continue; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!(rover->flags & FF_FLOATBOB)) + continue; + + + if (mobj->eflags & MFE_VERTICALFLIP) + { + if (abs(*rover->bottomheight - (mobj->z + mobj->height)) > abs(mobj->momz)) + continue; + } + else + { + if (abs(*rover->topheight - mobj->z) > abs(mobj->momz)) + continue; + } + + // Initiate a 'bouncy' elevator function which slowly diminishes. + EV_BounceSector(rover->master->frontsector, -mobj->momz, rover->master); + } + } +} + +static void P_PlayerMobjThinker(mobj_t *mobj) +{ I_Assert(mobj != NULL); I_Assert(mobj->player != NULL); I_Assert(!P_MobjWasRemoved(mobj)); P_MobjCheckWater(mobj); -#ifdef ESLOPE P_ButteredSlope(mobj); -#endif // momentum movement mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN; @@ -3942,77 +3920,10 @@ static void P_PlayerMobjThinker(mobj_t *mobj) else P_TryMove(mobj, mobj->x, mobj->y, true); - if (!(netgame && mobj->player->spectator)) - { - // Crumbling platforms - for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) - { - fixed_t topheight, bottomheight; - ffloor_t *rover; + P_CheckCrumblingPlatforms(mobj); - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_CRUMBLE)) - continue; - - topheight = P_GetSpecialTopZ(mobj, sectors + rover->secnum, node->m_sector); - bottomheight = P_GetSpecialBottomZ(mobj, sectors + rover->secnum, node->m_sector); - - if ((topheight == mobj->z && !(mobj->eflags & MFE_VERTICALFLIP)) - || (bottomheight == mobj->z + mobj->height && mobj->eflags & MFE_VERTICALFLIP)) // You nut. - EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), mobj->player, rover->alpha, !(rover->flags & FF_NORETURN)); - } - } - } - - // Check for floating water platforms and bounce them - if (CheckForFloatBob && P_MobjFlip(mobj)*mobj->momz < 0) - { - boolean thereiswater = false; - - for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (node->m_sector->ffloors) - { - ffloor_t *rover; - // Get water boundaries first - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS)) - continue; - - if (rover->flags & FF_SWIMMABLE) // Is there water? - { - thereiswater = true; - break; - } - } - } - } - if (thereiswater) - { - for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (node->m_sector->ffloors) - { - ffloor_t *rover; - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_FLOATBOB)) - continue; - - if ((!(mobj->eflags & MFE_VERTICALFLIP) && abs(*rover->topheight-mobj->z) <= abs(mobj->momz)) // The player is landing on the cheese! - || (mobj->eflags & MFE_VERTICALFLIP && abs(*rover->bottomheight-(mobj->z+mobj->height)) <= abs(mobj->momz))) - { - // Initiate a 'bouncy' elevator function - // which slowly diminishes. - EV_BounceSector(rover->master->frontsector, -mobj->momz, rover->master); - } - } - } - } - } // Ugly ugly billions of braces! Argh! - } + if (CheckForFloatBob) + P_CheckFloatbobPlatforms(mobj); // always do the gravity bit now, that's simpler // BUT CheckPosition only if wasn't done before. @@ -4055,11 +3966,7 @@ static void CalculatePrecipFloor(precipmobj_t *mobj) mobjsecsubsec = mobj->subsector->sector; else return; - mobj->floorz = -#ifdef ESLOPE - mobjsecsubsec->f_slope ? P_GetZAt(mobjsecsubsec->f_slope, mobj->x, mobj->y) : -#endif - mobjsecsubsec->floorheight; + mobj->floorz = P_GetSectorFloorZAt(mobjsecsubsec, mobj->x, mobj->y); if (mobjsecsubsec->ffloors) { ffloor_t *rover; @@ -4074,13 +3981,7 @@ static void CalculatePrecipFloor(precipmobj_t *mobj) if (!(rover->flags & FF_BLOCKOTHERS) && !(rover->flags & FF_SWIMMABLE)) continue; -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y); - else -#endif - topheight = *rover->topheight; - + topheight = P_GetFFloorTopZAt(rover, mobj->x, mobj->y); if (topheight > mobj->floorz) mobj->floorz = topheight; } @@ -7166,8 +7067,7 @@ static void P_MobjScaleThink(mobj_t *mobj) fixed_t oldheight = mobj->height; UINT8 correctionType = 0; // Don't correct Z position, just gain height - if ((mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz)) - && mobj->type != MT_EGGMOBILE_FIRE) + if (mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz)) correctionType = 1; // Correct Z position by centering else if (mobj->eflags & MFE_VERTICALFLIP) correctionType = 2; // Correct Z position by moving down @@ -7188,10 +7088,6 @@ static void P_MobjScaleThink(mobj_t *mobj) /// \todo Lua hook for "reached destscale"? switch (mobj->type) { - case MT_EGGMOBILE_FIRE: - mobj->destscale = FRACUNIT; - mobj->scalespeed = FRACUNIT>>4; - break; default: break; } @@ -7648,12 +7544,10 @@ static void P_RosySceneryThink(mobj_t *mobj) static void P_MobjSceneryThink(mobj_t *mobj) { -#ifdef HAVE_BLUA if (LUAh_MobjThinker(mobj)) return; if (P_MobjWasRemoved(mobj)) return; -#endif if ((mobj->flags2 & MF2_SHIELD) && !P_AddShield(mobj)) return; @@ -7998,16 +7892,15 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (!mobj->fuse) { -#ifdef HAVE_BLUA if (!LUAh_MobjFuse(mobj)) -#endif P_RemoveMobj(mobj); return; } if (mobj->fuse < 0) return; - if ((--mobj->fuse) < 6) + if (mobj->fuse < 6) mobj->frame = (mobj->frame & ~FF_TRANSMASK) | ((10 - (mobj->fuse*2)) << (FF_TRANSSHIFT)); + mobj->fuse--; } break; case MT_FINISHFLAG: @@ -8058,9 +7951,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->fuse--; if (!mobj->fuse) { -#ifdef HAVE_BLUA if (!LUAh_MobjFuse(mobj)) -#endif P_RemoveMobj(mobj); return; } @@ -8089,7 +7980,6 @@ static boolean P_MobjPushableThink(mobj_t *mobj) static boolean P_MobjBossThink(mobj_t *mobj) { -#ifdef HAVE_BLUA if (LUAh_BossThinker(mobj)) { if (P_MobjWasRemoved(mobj)) @@ -8098,7 +7988,6 @@ static boolean P_MobjBossThink(mobj_t *mobj) else if (P_MobjWasRemoved(mobj)) return false; else -#endif switch (mobj->type) { case MT_EGGMOBILE: @@ -8374,6 +8263,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj) // See Linedef Exec 457 (Track mobj angle to point) static void P_TracerAngleThink(mobj_t *mobj) { + angle_t looking; angle_t ang; if (!mobj->tracer) @@ -8388,7 +8278,12 @@ static void P_TracerAngleThink(mobj_t *mobj) // mobj->cvval - Allowable failure delay // mobj->cvmem - Failure timer - ang = mobj->angle - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); + if (mobj->player) + looking = ( mobj->player->cmd.angleturn << 16 );/* fixes CS_LMAOGALOG */ + else + looking = mobj->angle; + + ang = looking - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); // \todo account for distance between mobj and tracer // Because closer mobjs can be facing beyond the angle tolerance @@ -9397,8 +9292,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius*16) { + var1 = mobj->info->speed; + var2 = 1; + // Home in on the target. - P_HomingAttack(mobj, mobj->tracer); + A_HomingChase(mobj); if (mobj->z < mobj->floorz) mobj->z = mobj->floorz; @@ -9575,7 +9473,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_BOSSFLYPOINT: return false; case MT_NIGHTSCORE: - mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE); + mobj->color = (UINT16)(leveltime % SKINCOLOR_WHITE); break; case MT_JETFUME1: if (!P_JetFume1Think(mobj)) @@ -10008,113 +9906,110 @@ static boolean P_FuseThink(mobj_t *mobj) if (mobj->fuse) return true; -#ifdef HAVE_BLUA if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj)) ; - else -#endif - if (mobj->info->flags & MF_MONITOR) + else if (mobj->info->flags & MF_MONITOR) + { + P_MonitorFuseThink(mobj); + return false; + } + else switch (mobj->type) + { + // gargoyle and snowman handled in P_PushableThinker, not here + case MT_THROWNGRENADE: + case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: + P_SetMobjState(mobj, mobj->info->deathstate); + break; + case MT_LHRT: + P_KillMobj(mobj, NULL, NULL, 0); + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + P_FlagFuseThink(mobj); + P_RemoveMobj(mobj); + return false; + case MT_FANG: + if (mobj->flags2 & MF2_SLIDEPUSH) { - P_MonitorFuseThink(mobj); + var1 = 0; + var2 = 0; + A_BossDeath(mobj); return false; } - else switch (mobj->type) + P_SetMobjState(mobj, mobj->state->nextstate); + if (P_MobjWasRemoved(mobj)) + return false; + break; + case MT_METALSONIC_BATTLE: + break; // don't remove + case MT_SPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += mobj->spawnpoint->angle; + break; + case MT_WALLSPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += (mobj->spawnpoint->angle / 360); + break; + case MT_NIGHTSCORE: + P_RemoveMobj(mobj); + return false; + case MT_LAVAFALL: + if (mobj->state - states == S_LAVAFALL_DORMANT) { - // gargoyle and snowman handled in P_PushableThinker, not here - case MT_THROWNGRENADE: - case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: - P_SetMobjState(mobj, mobj->info->deathstate); + 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 false; + case MT_PYREFLY: + if (mobj->health <= 0) break; - case MT_LHRT: - P_KillMobj(mobj, NULL, NULL, 0); - break; - case MT_BLUEFLAG: - case MT_REDFLAG: - P_FlagFuseThink(mobj); - P_RemoveMobj(mobj); - return false; - case MT_FANG: - if (mobj->flags2 & MF2_SLIDEPUSH) - { - var1 = 0; - var2 = 0; - A_BossDeath(mobj); - return false; - } - P_SetMobjState(mobj, mobj->state->nextstate); - if (P_MobjWasRemoved(mobj)) - return false; - break; - case MT_METALSONIC_BATTLE: - break; // don't remove - case MT_SPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += mobj->spawnpoint->angle; - break; - case MT_WALLSPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += (mobj->spawnpoint->angle / 360); - break; - case MT_NIGHTSCORE: - P_RemoveMobj(mobj); - return false; - 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 false; - 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 false; - case MT_PLAYER: - break; // don't remove - default: - P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. - break; - // Looking for monitors? They moved to a special condition above. + 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 false; + case MT_PLAYER: + break; // don't remove + default: + P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. + break; + // Looking for monitors? They moved to a special condition above. + } return !P_MobjWasRemoved(mobj); } @@ -10183,7 +10078,6 @@ void P_MobjThinker(mobj_t *mobj) return; } -#ifdef HAVE_BLUA // Check for a Lua thinker first if (!mobj->player) { @@ -10197,7 +10091,7 @@ void P_MobjThinker(mobj_t *mobj) if (P_MobjWasRemoved(mobj)) return; } -#endif + // if it's pushable, or if it would be pushable other than temporary disablement, use the // separate thinker if (mobj->flags & MF_PUSHABLE || (mobj->info->flags & MF_PUSHABLE && mobj->fuse)) @@ -10266,7 +10160,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->eflags &= ~MFE_JUSTHITFLOOR; } -#ifdef ESLOPE // Sliding physics for slidey mobjs! + // Sliding physics for slidey mobjs! if (mobj->type == MT_FLINGRING || mobj->type == MT_FLINGCOIN || mobj->type == MT_FLINGBLUESPHERE @@ -10281,7 +10175,6 @@ void P_MobjThinker(mobj_t *mobj) //if (mobj->standingslope) CONS_Printf("slope physics on mobj\n"); P_ButteredSlope(mobj); } -#endif if (mobj->flags & (MF_ENEMY|MF_BOSS) && mobj->health && P_CheckDeathPitCollide(mobj)) // extra pit check in case these didn't have momz @@ -10615,16 +10508,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Make sure scale matches destscale immediately when spawned P_SetScale(mobj, mobj->destscale); - mobj->floorz = -#ifdef ESLOPE - mobj->subsector->sector->f_slope ? P_GetZAt(mobj->subsector->sector->f_slope, x, y) : -#endif - mobj->subsector->sector->floorheight; - mobj->ceilingz = -#ifdef ESLOPE - mobj->subsector->sector->c_slope ? P_GetZAt(mobj->subsector->sector->c_slope, x, y) : -#endif - mobj->subsector->sector->ceilingheight; + mobj->floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y); + mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y); mobj->floorrover = NULL; mobj->ceilingrover = NULL; @@ -10660,7 +10545,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Set shadowscale here, before spawn hook so that Lua can change it mobj->shadowscale = P_DefaultMobjShadowScale(mobj); -#ifdef HAVE_BLUA // DANGER! This can cause P_SpawnMobj to return NULL! // Avoid using P_RemoveMobj on the newly created mobj in "MobjSpawn" Lua hooks! if (LUAh_MobjSpawn(mobj)) @@ -10671,7 +10555,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) else if (P_MobjWasRemoved(mobj)) return NULL; else -#endif switch (mobj->type) { case MT_ALTVIEWMAN: @@ -10797,7 +10680,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_EGGROBO1: mobj->movecount = P_RandomKey(13); - mobj->color = SKINCOLOR_RUBY + P_RandomKey(MAXSKINCOLORS - SKINCOLOR_RUBY); + mobj->color = SKINCOLOR_RUBY + P_RandomKey(numskincolors - SKINCOLOR_RUBY); break; case MT_HIVEELEMENTAL: mobj->extravalue1 = 5; @@ -10941,9 +10824,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { var1 = st->var1; var2 = st->var2; -#ifdef HAVE_BLUA astate = st; -#endif st->action.acp1(mobj); // DANGER! This can cause P_SpawnMobj to return NULL! // Avoid using MF_RUNSPAWNFUNC on mobjs whose spawn state expects target or tracer to already be set! @@ -10981,16 +10862,8 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype // set subsector and/or block links P_SetPrecipitationThingPosition(mobj); - mobj->floorz = starting_floorz = -#ifdef ESLOPE - mobj->subsector->sector->f_slope ? P_GetZAt(mobj->subsector->sector->f_slope, x, y) : -#endif - mobj->subsector->sector->floorheight; - mobj->ceilingz = -#ifdef ESLOPE - mobj->subsector->sector->c_slope ? P_GetZAt(mobj->subsector->sector->c_slope, x, y) : -#endif - mobj->subsector->sector->ceilingheight; + mobj->floorz = starting_floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y); + mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y); mobj->floorrover = NULL; mobj->ceilingrover = NULL; @@ -11041,16 +10914,12 @@ size_t iquehead, iquetail; void P_RemoveMobj(mobj_t *mobj) { I_Assert(mobj != NULL); -#ifdef HAVE_BLUA if (P_MobjWasRemoved(mobj)) return; // something already removing this mobj. mobj->thinker.function.acp1 = (actionf_p1)P_RemoveThinkerDelayed; // shh. no recursing. LUAh_MobjRemoved(mobj); mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; // needed for P_UnsetThingPosition, etc. to work. -#else - I_Assert(!P_MobjWasRemoved(mobj)); -#endif // Rings only, please! if (mobj->spawnpoint && @@ -11445,7 +11314,7 @@ void P_SpawnPlayer(INT32 playernum) if (!G_GametypeHasSpectators()) { p->spectator = p->outofcoop = - (((multiplayer || netgame) && gametype == GT_COOP) // only question status in coop + (((multiplayer || netgame) && G_CoopGametype()) // only question status in coop && ((leveltime > 0 && ((G_IsSpecialStage(gamemap)) // late join special stage || (cv_coopstarposts.value == 2 && (p->jointime < 1 || p->outofcoop)))) // late join or die in new coop @@ -11525,6 +11394,14 @@ void P_SpawnPlayer(INT32 playernum) p->realtime = leveltime; p->followitem = skins[p->skin].followitem; + // Make sure player's stats are reset if they were in dashmode! + if (p->dashmode) + { + p->dashmode = 0; + p->normalspeed = skins[p->skin].normalspeed; + p->jumpfactor = skins[p->skin].jumpfactor; + } + //awayview stuff p->awayviewmobj = NULL; p->awayviewtics = 0; @@ -11563,10 +11440,7 @@ void P_AfterPlayerSpawn(INT32 playernum) player_t *p = &players[playernum]; mobj_t *mobj = p->mo; - if (playernum == consoleplayer) - localangle = mobj->angle; - else if (playernum == secondarydisplayplayer) - localangle2 = mobj->angle; + P_SetPlayerAngle(p, mobj->angle); p->viewheight = 41*p->height/48; @@ -11583,7 +11457,6 @@ void P_AfterPlayerSpawn(INT32 playernum) HU_Start(); } - SV_SpawnPlayer(playernum, mobj->x, mobj->y, mobj->angle); p->drawangle = mobj->angle; if (camera.chase) @@ -11599,7 +11472,7 @@ void P_AfterPlayerSpawn(INT32 playernum) if (CheckForReverseGravity) P_CheckGravity(mobj, false); - + if (p->pflags & PF_FINISHED) P_GiveFinishFlags(p); } @@ -11629,16 +11502,8 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) // set Z height sector = R_PointInSubsector(x, y)->sector; - floor = -#ifdef ESLOPE - sector->f_slope ? P_GetZAt(sector->f_slope, x, y) : -#endif - sector->floorheight; - ceiling = -#ifdef ESLOPE - sector->c_slope ? P_GetZAt(sector->c_slope, x, y) : -#endif - sector->ceilingheight; + floor = P_GetSectorFloorZAt (sector, x, y); + ceiling = P_GetSectorCeilingZAt(sector, x, y); ceilingspawn = ceiling - mobjinfo[MT_PLAYER].height; if (mthing) @@ -11708,16 +11573,8 @@ void P_MovePlayerToStarpost(INT32 playernum) P_SetThingPosition(mobj); sector = R_PointInSubsector(mobj->x, mobj->y)->sector; - floor = -#ifdef ESLOPE - sector->f_slope ? P_GetZAt(sector->f_slope, mobj->x, mobj->y) : -#endif - sector->floorheight; - ceiling = -#ifdef ESLOPE - sector->c_slope ? P_GetZAt(sector->c_slope, mobj->x, mobj->y) : -#endif - sector->ceilingheight; + floor = P_GetSectorFloorZAt (sector, mobj->x, mobj->y); + ceiling = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y); z = p->starpostz << FRACBITS; @@ -11756,7 +11613,7 @@ void P_MovePlayerToStarpost(INT32 playernum) mapthing_t *huntemeralds[MAXHUNTEMERALDS]; INT32 numhuntemeralds; -static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t offset, const boolean flip) +fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t offset, const boolean flip) { const subsector_t *ss = R_PointInSubsector(x, y); @@ -11766,20 +11623,12 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, // Establish height. if (flip) - return ( -#ifdef ESLOPE - ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : -#endif - ss->sector->ceilingheight) - offset - mobjinfo[mobjtype].height; + return P_GetSectorCeilingZAt(ss->sector, x, y) - offset - mobjinfo[mobjtype].height; else - return ( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : -#endif - ss->sector->floorheight) + offset; + return P_GetSectorFloorZAt(ss->sector, x, y) + offset; } -static fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y) +fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y) { fixed_t offset = mthing->z << FRACBITS; boolean flip = (!!(mobjinfo[mobjtype].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); @@ -11819,6 +11668,7 @@ static fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthin // Ring-like items, may float additional units with MTF_AMBUSH. case MT_SPIKEBALL: + case MT_EMERHUNT: case MT_EMERALDSPAWN: case MT_TOKEN: case MT_EMBLEM: @@ -11923,7 +11773,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) case MT_EMERALD5: case MT_EMERALD6: case MT_EMERALD7: - if (gametype != GT_COOP) // Don't place emeralds in non-coop modes + if (!G_CoopGametype()) // Don't place emeralds in non-coop modes return false; if (metalrecording) @@ -11943,7 +11793,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) runemeraldmanager = true; break; case MT_ROSY: - if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA))) + if (!(G_CoopGametype() || (mthing->options & MTF_EXTRA))) return false; // she doesn't hang out here if (!mariomode && !(netgame || multiplayer) && players[consoleplayer].skin == 3) @@ -12058,7 +11908,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) } } // Set powerup boxes to user settings for other netplay modes - else if (gametype != GT_COOP) + else if (!G_CoopGametype()) { switch (cv_matchboxes.value) { @@ -12114,7 +11964,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) { INT32 j; emblem_t* emblem = M_GetLevelEmblems(gamemap); - skincolors_t emcolor; + skincolornum_t emcolor; while (emblem) { @@ -12137,7 +11987,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) mobj->health = j + 1; emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting - mobj->color = (UINT8)emcolor; + mobj->color = (UINT16)emcolor; if (emblemlocations[j].collected || (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin)) @@ -12714,7 +12564,6 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) { -#ifdef HAVE_BLUA boolean override = LUAh_MapThingSpawn(mobj, mthing); if (P_MobjWasRemoved(mobj)) @@ -12722,7 +12571,6 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (override) return true; -#endif switch (mobj->type) { @@ -12778,7 +12626,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; case MT_BALLOON: if (mthing->angle > 0) - mobj->color = ((mthing->angle - 1) % (MAXSKINCOLORS - 1)) + 1; + mobj->color = ((mthing->angle - 1) % (numskincolors - 1)) + 1; break; #define makesoftwarecorona(mo, h) \ corona = P_SpawnMobjFromMobj(mo, 0, 0, h<threshold = min(mthing->extrainfo, 7); break; case MT_TUBEWAYPOINT: - mobj->health = mthing->angle & 255; - mobj->threshold = mthing->angle >> 8; + { + UINT8 sequence = mthing->angle >> 8; + UINT8 id = mthing->angle & 255; + mobj->health = id; + mobj->threshold = sequence; + P_AddWaypoint(sequence, id, mobj); break; + } case MT_IDEYAANCHOR: mobj->health = mthing->extrainfo; break; diff --git a/src/p_mobj.h b/src/p_mobj.h index fd0c95a56..dae8c8a86 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -312,7 +312,7 @@ typedef struct mobj_s void *skin; // overrides 'sprite' when non-NULL (for player bodies to 'remember' the skin) // Player and mobj sprites in multiplayer modes are modified // using an internal color lookup table for re-indexing. - UINT8 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation). + UINT16 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation). // Interaction info, by BLOCKMAP. // Links in blocks (if needed). @@ -370,9 +370,7 @@ typedef struct mobj_s INT32 cusval; INT32 cvmem; -#ifdef ESLOPE struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) -#endif boolean colorized; // Whether the mobj uses the rainbow colormap fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius @@ -453,6 +451,9 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing); void P_MovePlayerToStarpost(INT32 playernum); void P_AfterPlayerSpawn(INT32 playernum); +fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t offset, const boolean flip); +fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y); + mobj_t *P_SpawnMapThing(mapthing_t *mthing); void P_SpawnHoop(mapthing_t *mthing); void P_SetBonusTime(mobj_t *mobj); diff --git a/src/p_polyobj.c b/src/p_polyobj.c index a206d0171..ccf8519f6 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by James Haley -// Copyright (C) 2006-2019 by Sonic Team Junior. +// Copyright (C) 2006-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,12 +28,6 @@ #include "r_state.h" #include "r_defs.h" - -#define POLYOBJECTS - - -#ifdef POLYOBJECTS - /* Theory behind Polyobjects: @@ -146,11 +140,6 @@ FUNCINLINE static ATTRINLINE void Polyobj_vecSub2(vertex_t *dst, vertex_t *v1, v dst->y = v1->y - v2->y; } -// -// P_PointInsidePolyobj -// -// Returns TRUE if the XY point is inside the polyobject -// boolean P_PointInsidePolyobj(polyobj_t *po, fixed_t x, fixed_t y) { size_t i; @@ -164,11 +153,6 @@ boolean P_PointInsidePolyobj(polyobj_t *po, fixed_t x, fixed_t y) return true; } -// -// P_MobjTouchingPolyobj -// -// Returns TRUE if the mobj is touching the edge of a polyobject -// boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo) { fixed_t mbbox[4]; @@ -188,11 +172,6 @@ boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo) return false; } -// -// P_MobjInsidePolyobj -// -// Returns TRUE if the mobj is inside the polyobject -// boolean P_MobjInsidePolyobj(polyobj_t *po, mobj_t *mo) { fixed_t mbbox[4]; @@ -212,11 +191,6 @@ boolean P_MobjInsidePolyobj(polyobj_t *po, mobj_t *mo) return true; } -// -// P_BBoxInsidePolyobj -// -// Returns TRUE if the bbox is inside the polyobject -// boolean P_BBoxInsidePolyobj(polyobj_t *po, fixed_t *bbox) { size_t i; @@ -230,55 +204,56 @@ boolean P_BBoxInsidePolyobj(polyobj_t *po, fixed_t *bbox) return true; } -// -// Polyobj_GetInfo -// // Finds the 'polyobject settings' linedef for a polyobject // the polyobject's id should be set as its tag -// -void Polyobj_GetInfo(INT16 poid, INT32 *poflags, INT32 *parentID, INT32 *potrans) +static void Polyobj_GetInfo(polyobj_t *po) { - INT32 i = P_FindSpecialLineFromTag(POLYINFO_SPECIALNUM, poid, -1); + INT32 i = P_FindSpecialLineFromTag(POLYINFO_SPECIALNUM, po->id, -1); + + po->flags = POF_SOLID|POF_TESTHEIGHT|POF_RENDERSIDES; if (i == -1) return; // no extra settings to apply, let's leave it - if (parentID) - *parentID = lines[i].frontsector->special; + po->parent = lines[i].frontsector->special; + if (po->parent == po->id) // do not allow a self-reference + po->parent = -1; - if (potrans) - *potrans = (lines[i].frontsector->floorheight>>FRACBITS) / 100; + po->translucency = (lines[i].flags & ML_DONTPEGTOP) + ? (sides[lines[i].sidenum[0]].textureoffset>>FRACBITS) + : ((lines[i].frontsector->floorheight>>FRACBITS) / 100); + + po->translucency = max(min(po->translucency, NUMTRANSMAPS), 0); if (lines[i].flags & ML_EFFECT1) - *poflags |= POF_ONESIDE; + po->flags |= POF_ONESIDE; if (lines[i].flags & ML_EFFECT2) - *poflags &= ~POF_SOLID; + po->flags &= ~POF_SOLID; if (lines[i].flags & ML_EFFECT3) - *poflags |= POF_PUSHABLESTOP; + po->flags |= POF_PUSHABLESTOP; if (lines[i].flags & ML_EFFECT4) - *poflags |= POF_RENDERPLANES; + po->flags |= POF_RENDERPLANES; /*if (lines[i].flags & ML_EFFECT5) - *poflags &= ~POF_CLIPPLANES;*/ + po->flags &= ~POF_CLIPPLANES;*/ + + if (lines[i].flags & ML_EFFECT6) + po->flags |= POF_SPLAT; if (lines[i].flags & ML_NOCLIMB) // Has a linedef executor - *poflags |= POF_LDEXEC; + po->flags |= POF_LDEXEC; } // Reallocating array maintenance -// -// Polyobj_addVertex -// // Adds a vertex to a polyobject's reallocating vertex arrays, provided // that such a vertex isn't already in the array. Each vertex must only // be translated once during polyobject movement. Keeping track of them // this way results in much more clear and efficient code than what // Hexen used. -// static void Polyobj_addVertex(polyobj_t *po, vertex_t *v) { size_t i; @@ -314,14 +289,10 @@ static void Polyobj_addVertex(polyobj_t *po, vertex_t *v) po->numVertices++; } -// -// Polyobj_addLine -// // Adds a linedef to a polyobject's reallocating linedefs array, provided // that such a linedef isn't already in the array. Each linedef must only // be adjusted once during polyobject movement. Keeping track of them // this way provides the same benefits as for vertices. -// static void Polyobj_addLine(polyobj_t *po, line_t *l) { size_t i; @@ -346,14 +317,10 @@ static void Polyobj_addLine(polyobj_t *po, line_t *l) po->lines[po->numLines++] = l; } -// -// Polyobj_addSeg -// // Adds a single seg to a polyobject's reallocating seg pointer array. // Most polyobjects will have between 4 and 16 segs, so the array size // begins much smaller than usual. Calls Polyobj_addVertex and Polyobj_addLine // to add those respective structures for this seg, as well. -// static void Polyobj_addSeg(polyobj_t *po, seg_t *seg) { if (po->segCount >= po->numSegsAlloc) @@ -379,14 +346,10 @@ static void Polyobj_addSeg(polyobj_t *po, seg_t *seg) // Seg-finding functions -// -// Polyobj_findSegs -// // This method adds segs to a polyobject by following segs from vertex to // vertex. The process stops when the original starting point is reached // or if a particular search ends unexpectedly (ie, the polyobject is not // closed). -// static void Polyobj_findSegs(polyobj_t *po, seg_t *seg) { fixed_t startx, starty; @@ -400,25 +363,29 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg) // Find backfacings for (s = 0; s < numsegs; s++) { + size_t r; + if (segs[s].glseg) continue; - if (segs[s].linedef == seg->linedef - && segs[s].side == 1) + + if (segs[s].linedef != seg->linedef) + continue; + + if (segs[s].side != 1) + continue; + + for (r = 0; r < po->segCount; r++) { - size_t r; - for (r = 0; r < po->segCount; r++) - { - if (po->segs[r] == &segs[s]) - break; - } - - if (r != po->segCount) - continue; - - segs[s].dontrenderme = true; - - Polyobj_addSeg(po, &segs[s]); + if (po->segs[r] == &segs[s]) + break; } + + if (r != po->segCount) + continue; + + segs[s].dontrenderme = true; + + Polyobj_addSeg(po, &segs[s]); } } @@ -438,56 +405,60 @@ newseg: // seg's ending vertex. for (i = 0; i < numsegs; ++i) { + size_t q; + if (segs[i].glseg) continue; if (segs[i].side != 0) // needs to be frontfacing continue; - if (segs[i].v1->x == seg->v2->x && segs[i].v1->y == seg->v2->y) + if (segs[i].v1->x != seg->v2->x) + continue; + if (segs[i].v1->y != seg->v2->y) + continue; + + // Make sure you didn't already add this seg... + for (q = 0; q < po->segCount; q++) { - // Make sure you didn't already add this seg... - size_t q; - for (q = 0; q < po->segCount; q++) - { - if (po->segs[q] == &segs[i]) - break; - } - - if (q != po->segCount) - continue; - - // add the new seg and recurse - Polyobj_addSeg(po, &segs[i]); - seg = &segs[i]; - - if (!(po->flags & POF_ONESIDE)) - { - // Find backfacings - for (q = 0; q < numsegs; q++) - { - if (segs[q].glseg) - continue; - - if (segs[q].linedef == segs[i].linedef - && segs[q].side == 1) - { - size_t r; - for (r=0; r < po->segCount; r++) - { - if (po->segs[r] == &segs[q]) - break; - } - - if (r != po->segCount) - continue; - - segs[q].dontrenderme = true; - Polyobj_addSeg(po, &segs[q]); - } - } - } - - goto newseg; + if (po->segs[q] == &segs[i]) + break; } + + if (q != po->segCount) + continue; + + // add the new seg and recurse + Polyobj_addSeg(po, &segs[i]); + seg = &segs[i]; + + if (!(po->flags & POF_ONESIDE)) + { + // Find backfacings + for (q = 0; q < numsegs; q++) + { + size_t r; + + if (segs[q].glseg) + continue; + if (segs[q].linedef != segs[i].linedef) + continue; + if (segs[q].side != 1) + continue; + + for (r = 0; r < po->segCount; r++) + { + if (po->segs[r] == &segs[q]) + break; + } + + if (r != po->segCount) + continue; + + segs[q].dontrenderme = true; + Polyobj_addSeg(po, &segs[q]); + } + } + + goto newseg; } // error: if we reach here, the seg search never found another seg to @@ -496,91 +467,8 @@ newseg: CONS_Debug(DBG_POLYOBJ, "Polyobject %d is not closed\n", po->id); } -/* -// structure used to store segs during explicit search process -typedef struct segitem_s -{ - seg_t *seg; - INT32 num; -} segitem_t; - -// -// Polyobj_segCompare -// -// Callback for qsort that compares two segitems. -// -static int Polyobj_segCompare(const void *s1, const void *s2) -{ - const segitem_t *si1 = s1; - const segitem_t *si2 = s2; - - return si2->num - si1->num; -} - -// -// Polyobj_findExplicit -// -// Searches for segs to put into a polyobject in an explicitly provided order. -// -static void Polyobj_findExplicit(polyobj_t *po) -{ - // temporary dynamic seg array - segitem_t *segitems = NULL; - size_t numSegItems = 0; - size_t numSegItemsAlloc = 0; - - size_t i; - - // first loop: save off all segs with polyobject's id number - for (i = 0; i < numsegs; ++i) - { - INT32 polyID, parentID; - - if (segs[i].linedef->special != POLYOBJ_EXPLICIT_LINE) - continue; - - Polyobj_GetInfo(segs[i].linedef->tag, &polyID, &parentID, NULL); - - if (polyID == po->id && parentID > 0) - { - if (numSegItems >= numSegItemsAlloc) - { - numSegItemsAlloc = numSegItemsAlloc ? numSegItemsAlloc*2 : 4; - segitems = Z_Realloc(segitems, numSegItemsAlloc*sizeof(segitem_t), PU_STATIC, NULL); - } - segitems[numSegItems].seg = &segs[i]; - segitems[numSegItems].num = parentID; - ++numSegItems; - } - } - - // make sure array isn't empty - if (numSegItems == 0) - { - po->isBad = true; - CONS_Debug(DBG_POLYOBJ, "Polyobject %d is empty\n", po->id); - return; - } - - // sort the array if necessary - if (numSegItems >= 2) - qsort(segitems, numSegItems, sizeof(segitem_t), Polyobj_segCompare); - - // second loop: put the sorted segs into the polyobject - for (i = 0; i < numSegItems; ++i) - Polyobj_addSeg(po, segitems[i].seg); - - // free the temporary array - Z_Free(segitems); -}*/ - // Setup functions -// -// Polyobj_spawnPolyObj -// -// Sets up a Polyobject. -// static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) { size_t i; @@ -604,14 +492,12 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) po->thrust = FRACUNIT; po->spawnflags = po->flags = 0; - // 1. Search segs for "line start" special with tag matching this - // polyobject's id number. If found, iterate through segs which - // share common vertices and record them into the polyobject. + // Search segs for "line start" special with tag matching this + // polyobject's id number. If found, iterate through segs which + // share common vertices and record them into the polyobject. for (i = 0; i < numsegs; ++i) { seg_t *seg = &segs[i]; - INT32 poflags = POF_SOLID|POF_TESTHEIGHT|POF_RENDERSIDES; - INT32 parentID = 0, potrans = 0; if (seg->glseg) continue; @@ -625,17 +511,13 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) if (seg->linedef->tag != po->id) continue; - Polyobj_GetInfo(po->id, &poflags, &parentID, &potrans); // apply extra settings if they exist! + Polyobj_GetInfo(po); // apply extra settings if they exist! // save original flags and translucency to reference later for netgames! - po->spawnflags = po->flags = poflags; - po->spawntrans = po->translucency = potrans; + po->spawnflags = po->flags; + po->spawntrans = po->translucency; Polyobj_findSegs(po, seg); - po->parent = parentID; - if (po->parent == po->id) // do not allow a self-reference - po->parent = -1; - // TODO: sound sequence is in args[2] break; } @@ -645,29 +527,7 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) if (po->isBad) return; - /* - // 2. If no such line existed in the first step, look for a seg with the - // "explicit" special with tag matching this polyobject's id number. If - // found, continue to search for all such lines, storing them in a - // temporary list of segs which is then copied into the polyobject in - // sorted order. - if (po->segCount == 0) - { - UINT16 parent; - Polyobj_findExplicit(po); - // if an error occurred above, quit processing this object - if (po->isBad) - return; - - Polyobj_GetInfo(po->segs[0]->linedef->tag, NULL, NULL, &parent); - po->parent = parent; - if (po->parent == po->id) // do not allow a self-reference - po->parent = -1; - // TODO: sound sequence is in args[3] - }*/ - // make sure array isn't empty - // since Polyobj_findExplicit is disabled currently, we have to do things here instead now! if (po->segCount == 0) { po->isBad = true; @@ -696,12 +556,8 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) static void Polyobj_attachToSubsec(polyobj_t *po); -// -// Polyobj_moveToSpawnSpot -// // Translates the polyobject's vertices with respect to the difference between // the anchor and spawn spots. Updates linedef bounding boxes as well. -// static void Polyobj_moveToSpawnSpot(mapthing_t *anchor) { polyobj_t *po; @@ -748,11 +604,7 @@ static void Polyobj_moveToSpawnSpot(mapthing_t *anchor) Polyobj_attachToSubsec(po); } -// -// Polyobj_attachToSubsec -// // Attaches a polyobject to its appropriate subsector. -// static void Polyobj_attachToSubsec(polyobj_t *po) { subsector_t *ss; @@ -787,11 +639,7 @@ static void Polyobj_attachToSubsec(polyobj_t *po) po->attached = true; } -// -// Polyobj_removeFromSubsec -// // Removes a polyobject from the subsector to which it is attached. -// static void Polyobj_removeFromSubsec(polyobj_t *po) { if (po->attached) @@ -803,11 +651,7 @@ static void Polyobj_removeFromSubsec(polyobj_t *po) // Blockmap Functions -// -// Polyobj_getLink -// // Retrieves a polymaplink object from the free list or creates a new one. -// static polymaplink_t *Polyobj_getLink(void) { polymaplink_t *l; @@ -826,11 +670,7 @@ static polymaplink_t *Polyobj_getLink(void) return l; } -// -// Polyobj_putLink -// // Puts a polymaplink object into the free list. -// static void Polyobj_putLink(polymaplink_t *l) { memset(l, 0, sizeof(*l)); @@ -838,14 +678,10 @@ static void Polyobj_putLink(polymaplink_t *l) bmap_freelist = l; } -// -// Polyobj_linkToBlockmap -// // Inserts a polyobject into the polyobject blockmap. Unlike, mobj_t's, // polyobjects need to be linked into every blockmap cell which their // bounding box intersects. This ensures the accurate level of clipping // which is present with linedefs but absent from most mobj interactions. -// static void Polyobj_linkToBlockmap(polyobj_t *po) { fixed_t *blockbox = po->blockbox; @@ -890,12 +726,8 @@ static void Polyobj_linkToBlockmap(polyobj_t *po) po->linked = true; } -// -// Polyobj_removeFromBlockmap -// // Unlinks a polyobject from all blockmap cells it intersects and returns // its polymaplink objects to the free list. -// static void Polyobj_removeFromBlockmap(polyobj_t *po) { polymaplink_t *rover; @@ -934,13 +766,9 @@ static void Polyobj_removeFromBlockmap(polyobj_t *po) // Movement functions -// -// Polyobj_untouched -// // A version of Lee's routine from p_maputl.c that accepts an mobj pointer // argument instead of using tmthing. Returns true if the line isn't contacted // and false otherwise. -// static inline boolean Polyobj_untouched(line_t *ld, mobj_t *mo) { fixed_t x, y, ptmbbox[4]; @@ -953,13 +781,9 @@ static inline boolean Polyobj_untouched(line_t *ld, mobj_t *mo) P_BoxOnLineSide(ptmbbox, ld) != -1; } -// -// Polyobj_pushThing -// // Inflicts thrust and possibly damage on a thing which has been found to be // blocking the motion of a polyobject. The default thrust amount is only one // unit, but the motion of the polyobject can be used to change this. -// static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) { angle_t lineangle; @@ -994,11 +818,7 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) } } -// -// Polyobj_slideThing -// // Moves an object resting on top of a polyobject by (x, y). Template function to make alteration easier. -// static void Polyobj_slideThing(mobj_t *mo, fixed_t dx, fixed_t dy) { if (mo->player) { // Finally this doesn't suck eggs -fickle @@ -1046,11 +866,7 @@ static void Polyobj_slideThing(mobj_t *mo, fixed_t dx, fixed_t dy) P_TryMove(mo, mo->x+dx, mo->y+dy, true); } -// -// Polyobj_carryThings -// // Causes objects resting on top of the polyobject to 'ride' with its movement. -// static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy) { static INT32 pomovecount = 0; @@ -1102,12 +918,8 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy) } } -// -// Polyobj_clipThings -// // Checks for things that are in the way of a polyobject line move. // Returns true if something was hit. -// static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line) { INT32 hitflags = 0; @@ -1169,11 +981,8 @@ static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line) return hitflags; } -// -// Polyobj_moveXY -// + // Moves a polyobject on the x-y plane. -// static boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs) { size_t i; @@ -1229,15 +1038,11 @@ static boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean check return !(hitflags & 2); } -// -// Polyobj_rotatePoint -// // Rotates a point and then translates it relative to point c. // The formula for this can be found here: // http://www.inversereality.org/tutorials/graphics%20programming/2dtransformations.html // It is, of course, just a vector-matrix multiplication. -// -static inline void Polyobj_rotatePoint(vertex_t *v, const vertex_t *c, angle_t ang) +static inline void Polyobj_rotatePoint(vertex_t *v, const vector2_t *c, angle_t ang) { vertex_t tmp = *v; @@ -1248,12 +1053,8 @@ static inline void Polyobj_rotatePoint(vertex_t *v, const vertex_t *c, angle_t a v->y += c->y; } -// -// Polyobj_rotateLine -// // Taken from P_LoadLineDefs; simply updates the linedef's dx, dy, slopetype, // and bounding box to be consistent with its vertices. -// static void Polyobj_rotateLine(line_t *ld) { vertex_t *v1, *v2; @@ -1293,12 +1094,8 @@ static void Polyobj_rotateLine(line_t *ld) } } -// -// Polyobj_rotateThings -// // Causes objects resting on top of the rotating polyobject to 'ride' with its movement. -// -static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, UINT8 turnthings) +static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, UINT8 turnthings) { static INT32 pomovecount = 10000; INT32 x, y; @@ -1362,10 +1159,8 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, if (turnthings == 2 || (turnthings == 1 && !mo->player)) { mo->angle += delta; - if (mo->player == &players[consoleplayer]) - localangle += delta; - else if (mo->player == &players[secondarydisplayplayer]) - localangle2 += delta; + if (mo->player) + P_SetPlayerAngle(mo->player, (angle_t)(mo->player->angleturn << 16) + delta); } } } @@ -1373,16 +1168,12 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, } } -// -// Polyobj_rotate -// // Rotates a polyobject around its start point. -// static boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean checkmobjs) { size_t i; angle_t angle; - vertex_t origin; + vector2_t origin; INT32 hitflags = 0; // don't move bad polyobjects @@ -1451,12 +1242,8 @@ static boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, bo // Global Functions // -// -// Polyobj_GetForNum -// // Retrieves a polyobject by its numeric id using hashing. // Returns NULL if no such polyobject exists. -// polyobj_t *Polyobj_GetForNum(INT32 id) { INT32 curidx = PolyObjects[id % numPolyObjects].first; @@ -1467,12 +1254,9 @@ polyobj_t *Polyobj_GetForNum(INT32 id) return curidx == numPolyObjects ? NULL : &PolyObjects[curidx]; } -// -// Polyobj_GetParent -// + // Retrieves the parenting polyobject if one exists. Returns NULL // otherwise. -// #if 0 //unused function static polyobj_t *Polyobj_GetParent(polyobj_t *po) { @@ -1480,12 +1264,8 @@ static polyobj_t *Polyobj_GetParent(polyobj_t *po) } #endif -// -// Polyobj_GetChild -// // Iteratively retrieves the children POs of a parent, // sorta like P_FindSectorSpecialFromTag. -// static polyobj_t *Polyobj_GetChild(polyobj_t *po, INT32 *start) { for (; *start < numPolyObjects; (*start)++) @@ -1504,12 +1284,8 @@ typedef struct mobjqitem_s mobj_t *mo; } mobjqitem_t; -// -// Polyobj_InitLevel -// // Called at the beginning of each map after all other line and thing // processing is finished. -// void Polyobj_InitLevel(void) { thinker_t *th; @@ -1628,9 +1404,6 @@ void Polyobj_InitLevel(void) M_QueueFree(&anchorqueue); } -// -// Polyobj_MoveOnLoad -// // Called when a savegame is being loaded. Rotates and translates an // existing polyobject to its position when the game was saved. // @@ -1655,11 +1428,7 @@ void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y) // Thinker Functions -// -// T_PolyObjRotate -// // Thinker function for PolyObject rotation. -// void T_PolyObjRotate(polyrotate_t *th) { polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); @@ -1720,11 +1489,7 @@ void T_PolyObjRotate(polyrotate_t *th) } } -// -// Polyobj_componentSpeed -// // Calculates the speed components from the desired resultant velocity. -// FUNCINLINE static ATTRINLINE void Polyobj_componentSpeed(INT32 resVel, INT32 angle, fixed_t *xVel, fixed_t *yVel) { @@ -1805,22 +1570,39 @@ void T_PolyObjMove(polymove_t *th) } } -// -// T_PolyObjWaypoint -// -// Kinda like 'Zoom Tubes for PolyObjects' -// +static void T_MovePolyObj(polyobj_t *po, fixed_t distx, fixed_t disty, fixed_t distz) +{ + polyobj_t *child; + INT32 start; + + Polyobj_moveXY(po, distx, disty, true); + // TODO: use T_MovePlane + po->lines[0]->backsector->floorheight += distz; + po->lines[0]->backsector->ceilingheight += distz; + // Sal: Remember to check your sectors! + // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap + // updating objects in the front one too just added teleporting to ground bugs + P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); + // Apply action to mirroring polyobjects as well + start = 0; + while ((child = Polyobj_GetChild(po, &start))) + { + if (child->isBad) + continue; + + Polyobj_moveXY(child, distx, disty, true); + // TODO: use T_MovePlane + child->lines[0]->backsector->floorheight += distz; + child->lines[0]->backsector->ceilingheight += distz; + P_CheckSector(child->lines[0]->backsector, (boolean)(child->damage)); + } +} + void T_PolyObjWaypoint(polywaypoint_t *th) { - mobj_t *mo2; mobj_t *target = NULL; - mobj_t *waypoint = NULL; - thinker_t *wp; - fixed_t adjustx, adjusty, adjustz; - fixed_t momx, momy, momz, dist; - INT32 start; polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); - polyobj_t *oldpo = po; + fixed_t speed = th->speed; if (!po) #ifdef RANGECHECK @@ -1834,31 +1616,10 @@ void T_PolyObjWaypoint(polywaypoint_t *th) #endif // check for displacement due to override and reattach when possible - if (po->thinker == NULL) + if (!po->thinker) po->thinker = &th->thinker; -/* - // Find out target first. - // We redo this each tic to make savegame compatibility easier. - for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) - { - if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == th->sequence && mo2->health == th->pointnum) - { - target = mo2; - break; - } - } -*/ - - target = th->target; + target = waypoints[th->sequence][th->pointnum]; if (!target) { @@ -1866,240 +1627,93 @@ void T_PolyObjWaypoint(polywaypoint_t *th) return; } - // Compensate for position offset - adjustx = po->centerPt.x + th->diffx; - adjusty = po->centerPt.y + th->diffy; - adjustz = po->lines[0]->backsector->floorheight + (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2 + th->diffz; - - dist = P_AproxDistance(P_AproxDistance(target->x - adjustx, target->y - adjusty), target->z - adjustz); - - if (dist < 1) - dist = 1; - - momx = FixedMul(FixedDiv(target->x - adjustx, dist), (th->speed)); - momy = FixedMul(FixedDiv(target->y - adjusty, dist), (th->speed)); - momz = FixedMul(FixedDiv(target->z - adjustz, dist), (th->speed)); - - // Calculate the distance between the polyobject and the waypoint - // 'dist' already equals this. - - // Will the polyobject be FURTHER away if the momx/momy/momz is added to - // its current coordinates, or closer? (shift down to fracunits to avoid approximation errors) - if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(target->x - adjustx - momx, target->y - adjusty - momy), target->z - adjustz - momz)>>FRACBITS) + // Move along the waypoint sequence until speed for the current tic is exhausted + while (speed > 0) { - // If further away, set XYZ of polyobject to waypoint location - fixed_t amtx, amty, amtz; - fixed_t diffz; - amtx = (target->x - th->diffx) - po->centerPt.x; - amty = (target->y - th->diffy) - po->centerPt.y; - Polyobj_moveXY(po, amtx, amty, true); - // TODO: use T_MovePlane - amtz = (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2; - diffz = po->lines[0]->backsector->floorheight - (target->z - amtz); - po->lines[0]->backsector->floorheight = target->z - amtz; - po->lines[0]->backsector->ceilingheight = target->z + amtz; - // Sal: Remember to check your sectors! - // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap - // updating objects in the front one too just added teleporting to ground bugs - P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); - // Apply action to mirroring polyobjects as well - start = 0; - while ((po = Polyobj_GetChild(oldpo, &start))) + mobj_t *waypoint = NULL; + fixed_t pox, poy, poz; + fixed_t distx, disty, distz, dist; + + // Current position of polyobject + pox = po->centerPt.x; + poy = po->centerPt.y; + poz = (po->lines[0]->backsector->floorheight + po->lines[0]->backsector->ceilingheight)/2; + + // Calculate the distance between the polyobject and the waypoint + distx = target->x - pox; + disty = target->y - poy; + distz = target->z - poz; + dist = P_AproxDistance(P_AproxDistance(distx, disty), distz); + + if (dist < 1) + dist = 1; + + // Will the polyobject overshoot its target? + if (speed < dist) { - if (po->isBad) - continue; + // No. Move towards waypoint + fixed_t momx, momy, momz; - Polyobj_moveXY(po, amtx, amty, true); - // TODO: use T_MovePlane - po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did - po->lines[0]->backsector->ceilingheight += diffz; - // Sal: Remember to check your sectors! - // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap - // updating objects in the front one too just added teleporting to ground bugs - P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); - } - - po = oldpo; - - if (!th->stophere) - { - CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n"); - - // Find next waypoint - for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) - { - if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != th->sequence) - continue; - - if (th->direction == -1) - { - if (mo2->health == target->health - 1) - { - waypoint = mo2; - break; - } - } - else - { - if (mo2->health == target->health + 1) - { - waypoint = mo2; - break; - } - } - } - - if (!waypoint && th->wrap) // If specified, wrap waypoints - { - if (!th->continuous) - { - th->wrap = 0; - th->stophere = true; - } - - for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) - { - if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != th->sequence) - continue; - - if (th->direction == -1) - { - if (waypoint == NULL) - waypoint = mo2; - else if (mo2->health > waypoint->health) - waypoint = mo2; - } - else - { - if (mo2->health == 0) - { - waypoint = mo2; - break; - } - } - } - } - else if (!waypoint && th->comeback) // Come back to the start - { - th->direction = -th->direction; - - if (!th->continuous) - th->comeback = false; - - for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) - { - if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != th->sequence) - continue; - - if (th->direction == -1) - { - if (mo2->health == target->health - 1) - { - waypoint = mo2; - break; - } - } - else - { - if (mo2->health == target->health + 1) - { - waypoint = mo2; - break; - } - } - } - } - } - - if (waypoint) - { - CONS_Debug(DBG_POLYOBJ, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health); - - target = waypoint; - th->pointnum = target->health; - // Set the mobj as your target! -- Monster Iestyn 27/12/19 - P_SetTarget(&th->target, target); - - // calculate MOMX/MOMY/MOMZ for next waypoint - // change slope - dist = P_AproxDistance(P_AproxDistance(target->x - adjustx, target->y - adjusty), target->z - adjustz); - - if (dist < 1) - dist = 1; - - momx = FixedMul(FixedDiv(target->x - adjustx, dist), (th->speed)); - momy = FixedMul(FixedDiv(target->y - adjusty, dist), (th->speed)); - momz = FixedMul(FixedDiv(target->z - adjustz, dist), (th->speed)); + momx = FixedMul(FixedDiv(target->x - pox, dist), speed); + momy = FixedMul(FixedDiv(target->y - poy, dist), speed); + momz = FixedMul(FixedDiv(target->z - poz, dist), speed); + T_MovePolyObj(po, momx, momy, momz); + return; } else { - momx = momy = momz = 0; + // Yes. Teleport to waypoint and look for the next one + T_MovePolyObj(po, distx, disty, distz); if (!th->stophere) - CONS_Debug(DBG_POLYOBJ, "Next waypoint not found!\n"); + { + CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n"); + waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false); - if (po->thinker == &th->thinker) - po->thinker = NULL; + if (!waypoint && th->returnbehavior == PWR_WRAP) // If specified, wrap waypoints + { + if (!th->continuous) + { + th->returnbehavior = PWR_STOP; + th->stophere = true; + } - P_RemoveThinker(&th->thinker); - return; + waypoint = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence); + } + else if (!waypoint && th->returnbehavior == PWR_COMEBACK) // Come back to the start + { + th->direction = -th->direction; + + if (!th->continuous) + th->returnbehavior = PWR_STOP; + + waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false); + } + } + + if (waypoint) + { + CONS_Debug(DBG_POLYOBJ, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health); + + target = waypoint; + th->pointnum = target->health; + + // Calculate remaining speed + speed -= dist; + } + else + { + if (!th->stophere) + CONS_Debug(DBG_POLYOBJ, "Next waypoint not found!\n"); + + if (po->thinker == &th->thinker) + po->thinker = NULL; + + P_RemoveThinker(&th->thinker); + return; + } } } - else - { - // momx/momy/momz already equals the right speed - } - - // Move the polyobject - Polyobj_moveXY(po, momx, momy, true); - // TODO: use T_MovePlane - po->lines[0]->backsector->floorheight += momz; - po->lines[0]->backsector->ceilingheight += momz; - // Sal: Remember to check your sectors! - // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap - // updating objects in the front one too just added teleporting to ground bugs - P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); - - // Apply action to mirroring polyobjects as well - start = 0; - while ((po = Polyobj_GetChild(oldpo, &start))) - { - if (po->isBad) - continue; - - Polyobj_moveXY(po, momx, momy, true); - // TODO: use T_MovePlane - po->lines[0]->backsector->floorheight += momz; - po->lines[0]->backsector->ceilingheight += momz; - // Sal: Remember to check your sectors! - // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap - // updating objects in the front one too just added teleporting to ground bugs - P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); - } } void T_PolyDoorSlide(polyslidedoor_t *th) @@ -2303,7 +1917,7 @@ void T_PolyDoorSwing(polyswingdoor_t *th) } } -// T_PolyObjDisplace: shift a polyobject based on a control sector's heights. +// Shift a polyobject based on a control sector's heights. void T_PolyObjDisplace(polydisplace_t *th) { polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); @@ -2343,7 +1957,7 @@ void T_PolyObjDisplace(polydisplace_t *th) th->oldHeights = newheights; } -// T_PolyObjRotDisplace: rotate a polyobject based on a control sector's heights. +// Rotate a polyobject based on a control sector's heights. void T_PolyObjRotDisplace(polyrotdisplace_t *th) { polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); @@ -2389,7 +2003,7 @@ static inline INT32 Polyobj_AngSpeed(INT32 speed) // Linedef Handlers -INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata) +boolean EV_DoPolyObjRotate(polyrotdata_t *prdata) { polyobj_t *po; polyobj_t *oldpo; @@ -2399,16 +2013,16 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata) if (!(po = Polyobj_GetForNum(prdata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjRotate: bad polyobj %d\n", prdata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects if (po->isBad) - return 0; + return false; // check for override if this polyobj already has a thinker if (po->thinker && !prdata->overRide) - return 0; + return false; // create a new thinker th = Z_Malloc(sizeof(polyrotate_t), PU_LEVSPEC, NULL); @@ -2451,10 +2065,10 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata) } // action was successful - return 1; + return true; } -INT32 EV_DoPolyObjMove(polymovedata_t *pmdata) +boolean EV_DoPolyObjMove(polymovedata_t *pmdata) { polyobj_t *po; polyobj_t *oldpo; @@ -2464,16 +2078,16 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata) if (!(po = Polyobj_GetForNum(pmdata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjMove: bad polyobj %d\n", pmdata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects if (po->isBad) - return 0; + return false; // check for override if this polyobj already has a thinker if (po->thinker && !pmdata->overRide) - return 0; + return false; // create a new thinker th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL); @@ -2510,31 +2124,27 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata) } // action was successful - return 1; + return true; } -INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) +boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) { polyobj_t *po; polywaypoint_t *th; - mobj_t *mo2; mobj_t *first = NULL; - mobj_t *last = NULL; - mobj_t *target = NULL; - thinker_t *wp; if (!(po = Polyobj_GetForNum(pwdata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: bad polyobj %d\n", pwdata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects if (po->isBad) - return 0; + return false; if (po->thinker) // Don't crowd out another thinker. - return 0; + return false; // create a new thinker th = Z_Malloc(sizeof(polywaypoint_t), PU_LEVSPEC, NULL); @@ -2545,137 +2155,36 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) // set fields th->polyObjNum = pwdata->polyObjNum; th->speed = pwdata->speed; - th->sequence = pwdata->sequence; // Used to specify sequence # - if (pwdata->reverse) - th->direction = -1; - else - th->direction = 1; + th->sequence = pwdata->sequence; + th->direction = (pwdata->flags & PWF_REVERSE) ? -1 : 1; - th->comeback = pwdata->comeback; - th->continuous = pwdata->continuous; - th->wrap = pwdata->wrap; + th->returnbehavior = pwdata->returnbehavior; + if (pwdata->flags & PWF_LOOP) + th->continuous = true; th->stophere = false; // Find the first waypoint we need to use - for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) - { - if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != th->sequence) - continue; - - if (th->direction == -1) // highest waypoint # - { - if (mo2->health == 0) - last = mo2; - else - { - if (first == NULL) - first = mo2; - else if (mo2->health > first->health) - first = mo2; - } - } - else // waypoint 0 - { - if (mo2->health == 0) - first = mo2; - else - { - if (last == NULL) - last = mo2; - else if (mo2->health > last->health) - last = mo2; - } - } - } + first = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence); if (!first) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: Missing starting waypoint!\n"); po->thinker = NULL; P_RemoveThinker(&th->thinker); - return 0; + return false; } - // Hotfix to not crash on single-waypoint sequences -Red - if (!last) - last = first; - - // Set diffx, diffy, diffz - // Put these at 0 for now...might not be needed after all. - th->diffx = 0;//first->x - po->centerPt.x; - th->diffy = 0;//first->y - po->centerPt.y; - th->diffz = 0;//first->z - (po->lines[0]->backsector->floorheight + (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2); - - if (last->x == po->centerPt.x - && last->y == po->centerPt.y - && last->z == (po->lines[0]->backsector->floorheight + (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2)) + // Sanity check: If all waypoints are in the same location, + // don't allow the movement to be continuous so we don't get stuck in an infinite loop. + if (th->continuous && P_IsDegeneratedWaypointSequence(th->sequence)) { - // Already at the destination point... - if (!th->wrap) - { - po->thinker = NULL; - P_RemoveThinker(&th->thinker); - } + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: All waypoints are in the same location!\n"); + th->continuous = false; } - // Find the actual target movement waypoint - target = first; - /*for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) - { - if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + th->pointnum = first->health; - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != th->sequence) - continue; - - if (th->direction == -1) // highest waypoint # - { - if (mo2->health == first->health - 1) - { - target = mo2; - break; - } - } - else // waypoint 0 - { - if (mo2->health == first->health + 1) - { - target = mo2; - break; - } - } - }*/ - - if (!target) - { - CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: Missing target waypoint!\n"); - po->thinker = NULL; - P_RemoveThinker(&th->thinker); - return 0; - } - - // Set pointnum - th->pointnum = target->health; - th->target = NULL; // set to NULL first so the below doesn't go wrong - // Set the mobj as your target! -- Monster Iestyn 27/12/19 - P_SetTarget(&th->target, target); - - // We don't deal with the mirror crap here, we'll - // handle that in the T_Thinker function. - return 1; + return true; } static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata) @@ -2767,20 +2276,20 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata) Polyobj_doSwingDoor(po, doordata); } -INT32 EV_DoPolyDoor(polydoordata_t *doordata) +boolean EV_DoPolyDoor(polydoordata_t *doordata) { polyobj_t *po; if (!(po = Polyobj_GetForNum(doordata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyDoor: bad polyobj %d\n", doordata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects; // polyobject doors don't allow action overrides if (po->isBad || po->thinker) - return 0; + return false; switch (doordata->doorType) { @@ -2792,13 +2301,13 @@ INT32 EV_DoPolyDoor(polydoordata_t *doordata) break; default: CONS_Debug(DBG_POLYOBJ, "EV_DoPolyDoor: unknown door type %d", doordata->doorType); - return 0; + return false; } - return 1; + return true; } -INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata) +boolean EV_DoPolyObjDisplace(polydisplacedata_t *prdata) { polyobj_t *po; polyobj_t *oldpo; @@ -2808,12 +2317,12 @@ INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata) if (!(po = Polyobj_GetForNum(prdata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjRotate: bad polyobj %d\n", prdata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects if (po->isBad) - return 0; + return false; // create a new thinker th = Z_Malloc(sizeof(polydisplace_t), PU_LEVSPEC, NULL); @@ -2841,10 +2350,10 @@ INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata) } // action was successful - return 1; + return true; } -INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata) +boolean EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata) { polyobj_t *po; polyobj_t *oldpo; @@ -2854,12 +2363,12 @@ INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata) if (!(po = Polyobj_GetForNum(prdata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjRotate: bad polyobj %d\n", prdata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects if (po->isBad) - return 0; + return false; // create a new thinker th = Z_Malloc(sizeof(polyrotdisplace_t), PU_LEVSPEC, NULL); @@ -2887,7 +2396,7 @@ INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata) } // action was successful - return 1; + return true; } void T_PolyObjFlag(polymove_t *th) @@ -2936,7 +2445,7 @@ void T_PolyObjFlag(polymove_t *th) Polyobj_attachToSubsec(po); // relink to subsector } -INT32 EV_DoPolyObjFlag(line_t *pfdata) +boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) { polyobj_t *po; polyobj_t *oldpo; @@ -2944,22 +2453,22 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata) size_t i; INT32 start; - if (!(po = Polyobj_GetForNum(pfdata->tag))) + if (!(po = Polyobj_GetForNum(pfdata->polyObjNum))) { - CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: bad polyobj %d\n", pfdata->tag); - return 0; + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: bad polyobj %d\n", pfdata->polyObjNum); + return false; } // don't allow line actions to affect bad polyobjects, // polyobject doors don't allow action overrides if (po->isBad || po->thinker) - return 0; + return false; // Must have even # of vertices if (po->numVertices & 1) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: Polyobject has odd # of vertices!\n"); - return 0; + return false; } // create a new thinker @@ -2969,11 +2478,11 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata) po->thinker = &th->thinker; // set fields - th->polyObjNum = pfdata->tag; + th->polyObjNum = pfdata->polyObjNum; th->distance = 0; - th->speed = P_AproxDistance(pfdata->dx, pfdata->dy)>>FRACBITS; - th->angle = R_PointToAngle2(pfdata->v1->x, pfdata->v1->y, pfdata->v2->x, pfdata->v2->y)>>ANGLETOFINESHIFT; - th->momx = sides[pfdata->sidenum[0]].textureoffset>>FRACBITS; + th->speed = pfdata->speed; + th->angle = pfdata->angle; + th->momx = pfdata->momx; // save current positions for (i = 0; i < po->numVertices; ++i) @@ -2985,12 +2494,12 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata) start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) { - pfdata->tag = po->id; + pfdata->polyObjNum = po->id; EV_DoPolyObjFlag(pfdata); } // action was successful - return 1; + return true; } void T_PolyObjFade(polyfade_t *th) @@ -3088,7 +2597,7 @@ void T_PolyObjFade(polyfade_t *th) } } -INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata) +boolean EV_DoPolyObjFade(polyfadedata_t *pfdata) { polyobj_t *po; polyobj_t *oldpo; @@ -3098,16 +2607,16 @@ INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata) if (!(po = Polyobj_GetForNum(pfdata->polyObjNum))) { CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjFade: bad polyobj %d\n", pfdata->polyObjNum); - return 0; + return false; } // don't allow line actions to affect bad polyobjects if (po->isBad) - return 0; + return false; // already equal, nothing to do if (po->translucency == pfdata->destvalue) - return 1; + return true; if (po->thinker && po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade) P_RemoveThinker(po->thinker); @@ -3149,9 +2658,7 @@ INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata) } // action was successful - return 1; + return true; } -#endif // ifdef POLYOBJECTS - // EOF diff --git a/src/p_polyobj.h b/src/p_polyobj.h index 339390c0a..c6ae716f4 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by James Haley -// Copyright (C) 2006-2019 by Sonic Team Junior. +// Copyright (C) 2006-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -18,8 +18,6 @@ #include "p_mobj.h" #include "r_defs.h" -// haleyjd: temporary define -#ifdef POLYOBJECTS // // Defines // @@ -31,7 +29,6 @@ #define POLYOBJ_SPAWNCRUSH_DOOMEDNUM 762 // todo: REMOVE #define POLYOBJ_START_LINE 20 -#define POLYOBJ_EXPLICIT_LINE 21 #define POLYINFO_SPECIALNUM 22 typedef enum @@ -41,7 +38,7 @@ typedef enum POF_SOLID = 0x3, ///< Clips things. POF_TESTHEIGHT = 0x4, ///< Test line collision with heights POF_RENDERSIDES = 0x8, ///< Renders the sides. - POF_RENDERTOP = 0x10, ///< Renders the top.. + POF_RENDERTOP = 0x10, ///< Renders the top. POF_RENDERBOTTOM = 0x20, ///< Renders the bottom. POF_RENDERPLANES = 0x30, ///< Renders top and bottom. POF_RENDERALL = 0x38, ///< Renders everything. @@ -52,6 +49,7 @@ typedef enum POF_LDEXEC = 0x400, ///< This PO triggers a linedef executor. POF_ONESIDE = 0x800, ///< Only use the first side of the linedef. POF_NOSPECIALS = 0x1000, ///< Don't apply sector specials. + POF_SPLAT = 0x2000, ///< Use splat flat renderer (treat cyan pixels as invisible). } polyobjflags_e; // @@ -143,26 +141,26 @@ typedef struct polymove_s UINT32 angle; // angle along which to move } polymove_t; +// PolyObject waypoint movement return behavior +typedef enum +{ + PWR_STOP, // Stop after reaching last waypoint + PWR_WRAP, // Wrap back to first waypoint + PWR_COMEBACK, // Repeat sequence in reverse +} polywaypointreturn_e; + typedef struct polywaypoint_s { thinker_t thinker; // must be first - INT32 polyObjNum; // numeric id of polyobject - INT32 speed; // resultant velocity - INT32 sequence; // waypoint sequence # - INT32 pointnum; // waypoint # - INT32 direction; // 1 for normal, -1 for backwards - UINT8 comeback; // reverses and comes back when the end is reached - UINT8 wrap; // Wrap around waypoints - UINT8 continuous; // continuously move - used with COMEBACK or WRAP - UINT8 stophere; // Will stop after it reaches the next waypoint - - // Difference between location of PO and location of waypoint (offset) - fixed_t diffx; - fixed_t diffy; - fixed_t diffz; - - mobj_t *target; // next waypoint mobj + INT32 polyObjNum; // numeric id of polyobject + INT32 speed; // resultant velocity + INT32 sequence; // waypoint sequence # + INT32 pointnum; // waypoint # + INT32 direction; // 1 for normal, -1 for backwards + UINT8 returnbehavior; // behavior after reaching the last waypoint + UINT8 continuous; // continuously move - used with PWR_WRAP or PWR_COMEBACK + UINT8 stophere; // Will stop after it reaches the next waypoint } polywaypoint_t; typedef struct polyslidedoor_s @@ -257,15 +255,19 @@ typedef struct polymovedata_s UINT8 overRide; // if true, will override any action on the object } polymovedata_t; +typedef enum +{ + PWF_REVERSE = 1, // Move through waypoints in reverse order + PWF_LOOP = 1<<1, // Loop movement (used with PWR_WRAP or PWR_COMEBACK) +} polywaypointflags_e; + typedef struct polywaypointdata_s { - INT32 polyObjNum; // numeric id of polyobject to affect - INT32 sequence; // waypoint sequence # - fixed_t speed; // linear speed - UINT8 reverse; // if true, will go in reverse waypoint order - UINT8 comeback; // reverses and comes back when the end is reached - UINT8 wrap; // Wrap around waypoints - UINT8 continuous; // continuously move - used with COMEBACK or WRAP + INT32 polyObjNum; // numeric id of polyobject to affect + INT32 sequence; // waypoint sequence # + fixed_t speed; // linear speed + UINT8 returnbehavior; // behavior after reaching the last waypoint + UINT8 flags; // PWF_ flags } polywaypointdata_t; // polyobject door types @@ -301,6 +303,14 @@ typedef struct polyrotdisplacedata_s UINT8 turnobjs; } polyrotdisplacedata_t; +typedef struct polyflagdata_s +{ + INT32 polyObjNum; + INT32 speed; + UINT32 angle; + fixed_t momx; +} polyflagdata_t; + typedef struct polyfadedata_s { INT32 polyObjNum; @@ -322,7 +332,6 @@ boolean P_PointInsidePolyobj(polyobj_t *po, fixed_t x, fixed_t y); boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo); boolean P_MobjInsidePolyobj(polyobj_t *po, mobj_t *mo); boolean P_BBoxInsidePolyobj(polyobj_t *po, fixed_t *bbox); -void Polyobj_GetInfo(INT16 poid, INT32 *poflags, INT32 *parentID, INT32 *potrans); // thinkers (needed in p_saveg.c) void T_PolyObjRotate(polyrotate_t *); @@ -335,14 +344,14 @@ void T_PolyObjRotDisplace (polyrotdisplace_t *); void T_PolyObjFlag (polymove_t *); void T_PolyObjFade (polyfade_t *); -INT32 EV_DoPolyDoor(polydoordata_t *); -INT32 EV_DoPolyObjMove(polymovedata_t *); -INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *); -INT32 EV_DoPolyObjRotate(polyrotdata_t *); -INT32 EV_DoPolyObjDisplace(polydisplacedata_t *); -INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *); -INT32 EV_DoPolyObjFlag(struct line_s *); -INT32 EV_DoPolyObjFade(polyfadedata_t *); +boolean EV_DoPolyDoor(polydoordata_t *); +boolean EV_DoPolyObjMove(polymovedata_t *); +boolean EV_DoPolyObjWaypoint(polywaypointdata_t *); +boolean EV_DoPolyObjRotate(polyrotdata_t *); +boolean EV_DoPolyObjDisplace(polydisplacedata_t *); +boolean EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *); +boolean EV_DoPolyObjFlag(polyflagdata_t *); +boolean EV_DoPolyObjFade(polyfadedata_t *); // @@ -353,8 +362,6 @@ extern polyobj_t *PolyObjects; extern INT32 numPolyObjects; extern polymaplink_t **polyblocklinks; // polyobject blockmap -#endif // ifdef POLYOBJECTS - #endif // EOF diff --git a/src/p_pspr.h b/src/p_pspr.h index a7545bc3e..3c10e9be4 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_saveg.c b/src/p_saveg.c index f0106863b..6f5446795 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,7 +22,7 @@ #include "p_setup.h" #include "p_saveg.h" #include "r_data.h" -#include "r_things.h" +#include "r_skins.h" #include "r_state.h" #include "w_wad.h" #include "y_inter.h" @@ -31,9 +31,7 @@ #include "r_sky.h" #include "p_polyobj.h" #include "lua_script.h" -#ifdef ESLOPE #include "p_slopes.h" -#endif savedata_t savedata; UINT8 *save_p; @@ -61,9 +59,6 @@ typedef enum DRONE = 0x80, } player_saveflags; -// -// P_ArchivePlayer -// static inline void P_ArchivePlayer(void) { const player_t *player = &players[consoleplayer]; @@ -79,9 +74,6 @@ static inline void P_ArchivePlayer(void) WRITEINT32(save_p, player->continues); } -// -// P_UnArchivePlayer -// static inline void P_UnArchivePlayer(void) { INT16 skininfo = READUINT16(save_p); @@ -94,9 +86,6 @@ static inline void P_UnArchivePlayer(void) savedata.continues = READINT32(save_p); } -// -// P_NetArchivePlayers -// static void P_NetArchivePlayers(void) { INT32 i, j; @@ -114,6 +103,8 @@ static void P_NetArchivePlayers(void) // no longer send ticcmds, player name, skin, or color + WRITEINT16(save_p, players[i].angleturn); + WRITEINT16(save_p, players[i].oldrelangleturn); WRITEANGLE(save_p, players[i].aiming); WRITEANGLE(save_p, players[i].drawangle); WRITEANGLE(save_p, players[i].viewrollangle); @@ -302,9 +293,6 @@ static void P_NetArchivePlayers(void) } } -// -// P_NetUnArchivePlayers -// static void P_NetUnArchivePlayers(void) { INT32 i, j; @@ -325,6 +313,8 @@ static void P_NetUnArchivePlayers(void) // sending player names, skin and color should not be necessary at all! // (that data is handled in the server config now) + players[i].angleturn = READINT16(save_p); + players[i].oldrelangleturn = READINT16(save_p); players[i].aiming = READANGLE(save_p); players[i].drawangle = READANGLE(save_p); players[i].viewrollangle = READANGLE(save_p); @@ -731,6 +721,34 @@ static void P_NetUnArchiveColormaps(void) net_colormaps = NULL; } +static void P_NetArchiveWaypoints(void) +{ + INT32 i, j; + + for (i = 0; i < NUMWAYPOINTSEQUENCES; i++) + { + WRITEUINT16(save_p, numwaypoints[i]); + for (j = 0; j < numwaypoints[i]; j++) + WRITEUINT32(save_p, waypoints[i][j] ? waypoints[i][j]->mobjnum : 0); + } +} + +static void P_NetUnArchiveWaypoints(void) +{ + INT32 i, j; + UINT32 mobjnum; + + for (i = 0; i < NUMWAYPOINTSEQUENCES; i++) + { + numwaypoints[i] = READUINT16(save_p); + for (j = 0; j < numwaypoints[i]; j++) + { + mobjnum = READUINT32(save_p); + waypoints[i][j] = (mobjnum == 0) ? NULL : P_FindNewPosition(mobjnum); + } + } +} + /// /// World Archiving /// @@ -757,6 +775,7 @@ static void P_NetUnArchiveColormaps(void) // diff3 flags #define SD_TAGLIST 0x01 #define SD_COLORMAP 0x02 +#define SD_CRUMBLESTATE 0x04 #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 @@ -773,29 +792,102 @@ static void P_NetUnArchiveColormaps(void) #define LD_S2BOTTEX 0x04 #define LD_S2MIDTEX 0x08 -// -// P_NetArchiveWorld -// -static void P_NetArchiveWorld(void) +#define FD_FLAGS 0x01 +#define FD_ALPHA 0x02 + +// Check if any of the sector's FOFs differ from how they spawned +static boolean CheckFFloorDiff(const sector_t *ss) +{ + ffloor_t *rover; + + for (rover = ss->ffloors; rover; rover = rover->next) + { + if (rover->flags != rover->spawnflags + || rover->alpha != rover->spawnalpha) + { + return true; // we found an FOF that changed! + // don't bother checking for more, we do that later + } + } + return false; +} + +// Special case: save the stats of all modified ffloors along with their ffloor "number"s +// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed +static void ArchiveFFloors(const sector_t *ss) +{ + size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc + ffloor_t *rover; + UINT8 fflr_diff; + for (rover = ss->ffloors; rover; rover = rover->next) + { + fflr_diff = 0; // reset diff flags + if (rover->flags != rover->spawnflags) + fflr_diff |= FD_FLAGS; + if (rover->alpha != rover->spawnalpha) + fflr_diff |= FD_ALPHA; + + if (fflr_diff) + { + WRITEUINT16(save_p, j); // save ffloor "number" + WRITEUINT8(save_p, fflr_diff); + if (fflr_diff & FD_FLAGS) + WRITEUINT32(save_p, rover->flags); + if (fflr_diff & FD_ALPHA) + WRITEINT16(save_p, rover->alpha); + } + j++; + } + WRITEUINT16(save_p, 0xffff); +} + +static void UnArchiveFFloors(const sector_t *ss) +{ + UINT16 j = 0; // number of current ffloor in loop + UINT16 fflr_i; // saved ffloor "number" of next modified ffloor + UINT16 fflr_diff; // saved ffloor diff + ffloor_t *rover; + + rover = ss->ffloors; + if (!rover) // it is assumed sectors[i].ffloors actually exists, but just in case... + I_Error("Sector does not have any ffloors!"); + + fflr_i = READUINT16(save_p); // get first modified ffloor's number ready + for (;;) // for some reason the usual for (rover = x; ...) thing doesn't work here? + { + if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already + break; + // should NEVER need to be checked + //if (rover == NULL) + //break; + if (j != fflr_i) // this ffloor was not modified + { + j++; + rover = rover->next; + continue; + } + + fflr_diff = READUINT8(save_p); + + if (fflr_diff & FD_FLAGS) + rover->flags = READUINT32(save_p); + if (fflr_diff & FD_ALPHA) + rover->alpha = READINT16(save_p); + + fflr_i = READUINT16(save_p); // get next ffloor "number" ready + + j++; + rover = rover->next; + } +} + +static void ArchiveSectors(void) { size_t i; - INT32 statsec = 0, statline = 0; - const line_t *li = lines; - const line_t *spawnli = spawnlines; - const side_t *si; - const side_t *spawnsi; - UINT8 *put; - const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; UINT8 diff, diff2, diff3; - // initialize colormap vars because paranoia - ClearNetColormaps(); - - WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); - put = save_p; - for (i = 0; i < numsectors; i++, ss++, spawnss++) { diff = diff2 = diff3 = 0; @@ -836,21 +928,11 @@ static void P_NetArchiveWorld(void) if (ss->extra_colormap != spawnss->extra_colormap) diff3 |= SD_COLORMAP; + if (ss->crumblestate) + diff3 |= SD_CRUMBLESTATE; - // Check if any of the sector's FOFs differ from how they spawned - if (ss->ffloors) - { - ffloor_t *rover; - for (rover = ss->ffloors; rover; rover = rover->next) - { - if (rover->flags != rover->spawnflags - || rover->alpha != rover->spawnalpha) - { - diff |= SD_FFLOORS; // we found an FOF that changed! - break; // don't bother checking for more, we do that later - } - } - } + if (ss->ffloors && CheckFFloorDiff(ss)) + diff |= SD_FFLOORS; if (diff3) diff2 |= SD_DIFF3; @@ -860,87 +942,142 @@ static void P_NetArchiveWorld(void) if (diff) { - statsec++; - - WRITEUINT16(put, i); - WRITEUINT8(put, diff); + WRITEUINT16(save_p, i); + WRITEUINT8(save_p, diff); if (diff & SD_DIFF2) - WRITEUINT8(put, diff2); + WRITEUINT8(save_p, diff2); if (diff2 & SD_DIFF3) - WRITEUINT8(put, diff3); + WRITEUINT8(save_p, diff3); if (diff & SD_FLOORHT) - WRITEFIXED(put, ss->floorheight); + WRITEFIXED(save_p, ss->floorheight); if (diff & SD_CEILHT) - WRITEFIXED(put, ss->ceilingheight); + WRITEFIXED(save_p, ss->ceilingheight); if (diff & SD_FLOORPIC) - WRITEMEM(put, levelflats[ss->floorpic].name, 8); + WRITEMEM(save_p, levelflats[ss->floorpic].name, 8); if (diff & SD_CEILPIC) - WRITEMEM(put, levelflats[ss->ceilingpic].name, 8); + WRITEMEM(save_p, levelflats[ss->ceilingpic].name, 8); if (diff & SD_LIGHT) - WRITEINT16(put, ss->lightlevel); + WRITEINT16(save_p, ss->lightlevel); if (diff & SD_SPECIAL) - WRITEINT16(put, ss->special); + WRITEINT16(save_p, ss->special); if (diff2 & SD_FXOFFS) - WRITEFIXED(put, ss->floor_xoffs); + WRITEFIXED(save_p, ss->floor_xoffs); if (diff2 & SD_FYOFFS) - WRITEFIXED(put, ss->floor_yoffs); + WRITEFIXED(save_p, ss->floor_yoffs); if (diff2 & SD_CXOFFS) - WRITEFIXED(put, ss->ceiling_xoffs); + WRITEFIXED(save_p, ss->ceiling_xoffs); if (diff2 & SD_CYOFFS) - WRITEFIXED(put, ss->ceiling_yoffs); + WRITEFIXED(save_p, ss->ceiling_yoffs); if (diff2 & SD_FLOORANG) - WRITEANGLE(put, ss->floorpic_angle); + WRITEANGLE(save_p, ss->floorpic_angle); if (diff2 & SD_CEILANG) - WRITEANGLE(put, ss->ceilingpic_angle); + WRITEANGLE(save_p, ss->ceilingpic_angle); if (diff2 & SD_TAG) // save only the tag - WRITEINT16(put, ss->tag); + WRITEINT16(save_p, ss->tag); if (diff3 & SD_TAGLIST) // save both firsttag and nexttag { // either of these could be changed even if tag isn't - WRITEINT32(put, ss->firsttag); - WRITEINT32(put, ss->nexttag); + WRITEINT32(save_p, ss->firsttag); + WRITEINT32(save_p, ss->nexttag); } if (diff3 & SD_COLORMAP) - WRITEUINT32(put, CheckAddNetColormapToList(ss->extra_colormap)); + WRITEUINT32(save_p, CheckAddNetColormapToList(ss->extra_colormap)); // returns existing index if already added, or appends to net_colormaps and returns new index - - // Special case: save the stats of all modified ffloors along with their ffloor "number"s - // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed + if (diff3 & SD_CRUMBLESTATE) + WRITEINT32(save_p, ss->crumblestate); if (diff & SD_FFLOORS) - { - size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc - ffloor_t *rover; - UINT8 fflr_diff; - for (rover = ss->ffloors; rover; rover = rover->next) - { - fflr_diff = 0; // reset diff flags - if (rover->flags != rover->spawnflags) - fflr_diff |= 1; - if (rover->alpha != rover->spawnalpha) - fflr_diff |= 2; - - if (fflr_diff) - { - WRITEUINT16(put, j); // save ffloor "number" - WRITEUINT8(put, fflr_diff); - if (fflr_diff & 1) - WRITEUINT32(put, rover->flags); - if (fflr_diff & 2) - WRITEINT16(put, rover->alpha); - } - j++; - } - WRITEUINT16(put, 0xffff); - } + ArchiveFFloors(ss); } } - WRITEUINT16(put, 0xffff); + WRITEUINT16(save_p, 0xffff); +} + +static void UnArchiveSectors(void) +{ + UINT16 i; + UINT8 diff, diff2, diff3; + for (;;) + { + i = READUINT16(save_p); + + if (i == 0xffff) + break; + + if (i > numsectors) + I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(numsectors)); + + diff = READUINT8(save_p); + if (diff & SD_DIFF2) + diff2 = READUINT8(save_p); + else + diff2 = 0; + if (diff2 & SD_DIFF3) + diff3 = READUINT8(save_p); + else + diff3 = 0; + + if (diff & SD_FLOORHT) + sectors[i].floorheight = READFIXED(save_p); + if (diff & SD_CEILHT) + sectors[i].ceilingheight = READFIXED(save_p); + if (diff & SD_FLOORPIC) + { + sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save_p); + save_p += 8; + } + if (diff & SD_CEILPIC) + { + sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save_p); + save_p += 8; + } + if (diff & SD_LIGHT) + sectors[i].lightlevel = READINT16(save_p); + if (diff & SD_SPECIAL) + sectors[i].special = READINT16(save_p); + + if (diff2 & SD_FXOFFS) + sectors[i].floor_xoffs = READFIXED(save_p); + if (diff2 & SD_FYOFFS) + sectors[i].floor_yoffs = READFIXED(save_p); + if (diff2 & SD_CXOFFS) + sectors[i].ceiling_xoffs = READFIXED(save_p); + if (diff2 & SD_CYOFFS) + sectors[i].ceiling_yoffs = READFIXED(save_p); + if (diff2 & SD_FLOORANG) + sectors[i].floorpic_angle = READANGLE(save_p); + if (diff2 & SD_CEILANG) + sectors[i].ceilingpic_angle = READANGLE(save_p); + if (diff2 & SD_TAG) + sectors[i].tag = READINT16(save_p); // DON'T use P_ChangeSectorTag + if (diff3 & SD_TAGLIST) + { + sectors[i].firsttag = READINT32(save_p); + sectors[i].nexttag = READINT32(save_p); + } + + if (diff3 & SD_COLORMAP) + sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); + if (diff3 & SD_CRUMBLESTATE) + sectors[i].crumblestate = READINT32(save_p); + + if (diff & SD_FFLOORS) + UnArchiveFFloors(§ors[i]); + } +} + +static void ArchiveLines(void) +{ + size_t i; + const line_t *li = lines; + const line_t *spawnli = spawnlines; + const side_t *si; + const side_t *spawnsi; + UINT8 diff, diff2; // no diff3 - // do lines for (i = 0; i < numlines; i++, spawnli++, li++) { - diff = diff2 = diff3 = 0; + diff = diff2 = 0; if (li->special != spawnli->special) diff |= LD_SPECIAL; @@ -980,55 +1117,109 @@ static void P_NetArchiveWorld(void) if (diff) { - statline++; - WRITEINT16(put, i); - WRITEUINT8(put, diff); + WRITEINT16(save_p, i); + WRITEUINT8(save_p, diff); if (diff & LD_DIFF2) - WRITEUINT8(put, diff2); + WRITEUINT8(save_p, diff2); if (diff & LD_FLAG) - WRITEINT16(put, li->flags); + WRITEINT16(save_p, li->flags); if (diff & LD_SPECIAL) - WRITEINT16(put, li->special); + WRITEINT16(save_p, li->special); if (diff & LD_CLLCOUNT) - WRITEINT16(put, li->callcount); + WRITEINT16(save_p, li->callcount); si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) - WRITEFIXED(put, si->textureoffset); + WRITEFIXED(save_p, si->textureoffset); if (diff & LD_S1TOPTEX) - WRITEINT32(put, si->toptexture); + WRITEINT32(save_p, si->toptexture); if (diff & LD_S1BOTTEX) - WRITEINT32(put, si->bottomtexture); + WRITEINT32(save_p, si->bottomtexture); if (diff & LD_S1MIDTEX) - WRITEINT32(put, si->midtexture); + WRITEINT32(save_p, si->midtexture); si = &sides[li->sidenum[1]]; if (diff2 & LD_S2TEXOFF) - WRITEFIXED(put, si->textureoffset); + WRITEFIXED(save_p, si->textureoffset); if (diff2 & LD_S2TOPTEX) - WRITEINT32(put, si->toptexture); + WRITEINT32(save_p, si->toptexture); if (diff2 & LD_S2BOTTEX) - WRITEINT32(put, si->bottomtexture); + WRITEINT32(save_p, si->bottomtexture); if (diff2 & LD_S2MIDTEX) - WRITEINT32(put, si->midtexture); + WRITEINT32(save_p, si->midtexture); } } - WRITEUINT16(put, 0xffff); - R_ClearTextureNumCache(false); - - save_p = put; + WRITEUINT16(save_p, 0xffff); } -// -// P_NetUnArchiveWorld -// -static void P_NetUnArchiveWorld(void) +static void UnArchiveLines(void) { UINT16 i; line_t *li; side_t *si; - UINT8 *get; - UINT8 diff, diff2, diff3; + UINT8 diff, diff2; // no diff3 + + for (;;) + { + i = READUINT16(save_p); + + if (i == 0xffff) + break; + if (i > numlines) + I_Error("Invalid line number %u from server", i); + + diff = READUINT8(save_p); + li = &lines[i]; + + if (diff & LD_DIFF2) + diff2 = READUINT8(save_p); + else + diff2 = 0; + + if (diff & LD_FLAG) + li->flags = READINT16(save_p); + if (diff & LD_SPECIAL) + li->special = READINT16(save_p); + if (diff & LD_CLLCOUNT) + li->callcount = READINT16(save_p); + + si = &sides[li->sidenum[0]]; + if (diff & LD_S1TEXOFF) + si->textureoffset = READFIXED(save_p); + if (diff & LD_S1TOPTEX) + si->toptexture = READINT32(save_p); + if (diff & LD_S1BOTTEX) + si->bottomtexture = READINT32(save_p); + if (diff & LD_S1MIDTEX) + si->midtexture = READINT32(save_p); + + si = &sides[li->sidenum[1]]; + if (diff2 & LD_S2TEXOFF) + si->textureoffset = READFIXED(save_p); + if (diff2 & LD_S2TOPTEX) + si->toptexture = READINT32(save_p); + if (diff2 & LD_S2BOTTEX) + si->bottomtexture = READINT32(save_p); + if (diff2 & LD_S2MIDTEX) + si->midtexture = READINT32(save_p); + } +} + +static void P_NetArchiveWorld(void) +{ + // initialize colormap vars because paranoia + ClearNetColormaps(); + + WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); + + ArchiveSectors(); + ArchiveLines(); + R_ClearTextureNumCache(false); +} + +static void P_NetUnArchiveWorld(void) +{ + UINT16 i; if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD) I_Error("Bad $$$.sav at archive block World"); @@ -1044,159 +1235,8 @@ static void P_NetUnArchiveWorld(void) num_ffloors++; } - get = save_p; - - for (;;) - { - i = READUINT16(get); - - if (i == 0xffff) - break; - - if (i > numsectors) - I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(numsectors)); - - diff = READUINT8(get); - if (diff & SD_DIFF2) - diff2 = READUINT8(get); - else - diff2 = 0; - if (diff2 & SD_DIFF3) - diff3 = READUINT8(get); - else - diff3 = 0; - - if (diff & SD_FLOORHT) - sectors[i].floorheight = READFIXED(get); - if (diff & SD_CEILHT) - sectors[i].ceilingheight = READFIXED(get); - if (diff & SD_FLOORPIC) - { - sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get); - get += 8; - } - if (diff & SD_CEILPIC) - { - sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get); - get += 8; - } - if (diff & SD_LIGHT) - sectors[i].lightlevel = READINT16(get); - if (diff & SD_SPECIAL) - sectors[i].special = READINT16(get); - - if (diff2 & SD_FXOFFS) - sectors[i].floor_xoffs = READFIXED(get); - if (diff2 & SD_FYOFFS) - sectors[i].floor_yoffs = READFIXED(get); - if (diff2 & SD_CXOFFS) - sectors[i].ceiling_xoffs = READFIXED(get); - if (diff2 & SD_CYOFFS) - sectors[i].ceiling_yoffs = READFIXED(get); - if (diff2 & SD_FLOORANG) - sectors[i].floorpic_angle = READANGLE(get); - if (diff2 & SD_CEILANG) - sectors[i].ceilingpic_angle = READANGLE(get); - if (diff2 & SD_TAG) - sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag - if (diff3 & SD_TAGLIST) - { - sectors[i].firsttag = READINT32(get); - sectors[i].nexttag = READINT32(get); - } - - if (diff3 & SD_COLORMAP) - sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(get)); - - if (diff & SD_FFLOORS) - { - UINT16 j = 0; // number of current ffloor in loop - UINT16 fflr_i; // saved ffloor "number" of next modified ffloor - UINT16 fflr_diff; // saved ffloor diff - ffloor_t *rover; - - rover = sectors[i].ffloors; - if (!rover) // it is assumed sectors[i].ffloors actually exists, but just in case... - I_Error("Sector does not have any ffloors!"); - - fflr_i = READUINT16(get); // get first modified ffloor's number ready - for (;;) // for some reason the usual for (rover = x; ...) thing doesn't work here? - { - if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already - break; - // should NEVER need to be checked - //if (rover == NULL) - //break; - if (j != fflr_i) // this ffloor was not modified - { - j++; - rover = rover->next; - continue; - } - - fflr_diff = READUINT8(get); - - if (fflr_diff & 1) - rover->flags = READUINT32(get); - if (fflr_diff & 2) - rover->alpha = READINT16(get); - - fflr_i = READUINT16(get); // get next ffloor "number" ready - - j++; - rover = rover->next; - } - } - } - - for (;;) - { - i = READUINT16(get); - - if (i == 0xffff) - break; - if (i > numlines) - I_Error("Invalid line number %u from server", i); - - diff = READUINT8(get); - li = &lines[i]; - - if (diff & LD_DIFF2) - diff2 = READUINT8(get); - else - diff2 = 0; - - diff3 = 0; - - if (diff & LD_FLAG) - li->flags = READINT16(get); - if (diff & LD_SPECIAL) - li->special = READINT16(get); - if (diff & LD_CLLCOUNT) - li->callcount = READINT16(get); - - si = &sides[li->sidenum[0]]; - if (diff & LD_S1TEXOFF) - si->textureoffset = READFIXED(get); - if (diff & LD_S1TOPTEX) - si->toptexture = READINT32(get); - if (diff & LD_S1BOTTEX) - si->bottomtexture = READINT32(get); - if (diff & LD_S1MIDTEX) - si->midtexture = READINT32(get); - - si = &sides[li->sidenum[1]]; - if (diff2 & LD_S2TEXOFF) - si->textureoffset = READFIXED(get); - if (diff2 & LD_S2TOPTEX) - si->toptexture = READINT32(get); - if (diff2 & LD_S2BOTTEX) - si->bottomtexture = READINT32(get); - if (diff2 & LD_S2MIDTEX) - si->midtexture = READINT32(get); - } - - save_p = get; + UnArchiveSectors(); + UnArchiveLines(); } // @@ -1252,9 +1292,7 @@ typedef enum MD2_HPREV = 1<<8, MD2_FLOORROVER = 1<<9, MD2_CEILINGROVER = 1<<10, -#ifdef ESLOPE MD2_SLOPE = 1<<11, -#endif MD2_COLORIZED = 1<<12, MD2_ROLLANGLE = 1<<13, MD2_SHADOWSCALE = 1<<14, @@ -1277,9 +1315,7 @@ typedef enum tc_startcrumble, tc_marioblock, tc_marioblockchecker, - tc_spikesector, tc_floatsector, - tc_bridgethinker, tc_crushceiling, tc_scroll, tc_friction, @@ -1294,11 +1330,8 @@ typedef enum tc_fade, tc_fadecolormap, tc_planedisplace, -#ifdef ESLOPE tc_dynslopeline, tc_dynslopevert, -#endif // ESLOPE -#ifdef POLYOBJECTS tc_polyrotate, // haleyjd 03/26/06: polyobjects tc_polymove, tc_polywaypoint, @@ -1308,7 +1341,6 @@ typedef enum tc_polydisplace, tc_polyrotdisplace, tc_polyfade, -#endif tc_end } specials_e; @@ -1336,19 +1368,12 @@ static inline UINT32 SavePlayer(const player_t *player) return 0xFFFFFFFF; } -#ifdef ESLOPE static UINT32 SaveSlope(const pslope_t *slope) { if (slope) return (UINT32)(slope->id); return 0xFFFFFFFF; } -#endif // ESLOPE -// -// SaveMobjThinker -// -// Saves a mobj_t thinker -// static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { const mobj_t *mobj = (const mobj_t *)th; @@ -1406,7 +1431,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff |= MD_TICS; if (mobj->sprite != mobj->state->sprite) diff |= MD_SPRITE; - if (mobj->sprite == SPR_PLAY && mobj->sprite2 != 0) + if (mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK)) diff |= MD_SPRITE; if (mobj->frame != mobj->state->frame) diff |= MD_FRAME; @@ -1471,10 +1496,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_FLOORROVER; if (mobj->ceilingrover) diff2 |= MD2_CEILINGROVER; -#ifdef ESLOPE if (mobj->standingslope) diff2 |= MD2_SLOPE; -#endif if (mobj->colorized) diff2 |= MD2_COLORIZED; if (mobj->rollangle) @@ -1502,42 +1525,14 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) if (diff2 & MD2_FLOORROVER) { - ffloor_t *rover; - size_t i = 0; - UINT32 roverindex = 0; - - for (rover = mobj->floorrover->target->ffloors; rover; rover = rover->next) - { - if (rover == mobj->floorrover) - { - roverindex = i; - break; - } - i++; - } - - WRITEUINT32(save_p, (UINT32)(mobj->floorrover->target - sectors)); - WRITEUINT32(save_p, rover ? roverindex : i); // store max index to denote invalid ffloor ref + WRITEUINT32(save_p, SaveSector(mobj->floorrover->target)); + WRITEUINT16(save_p, P_GetFFloorID(mobj->floorrover)); } if (diff2 & MD2_CEILINGROVER) { - ffloor_t *rover; - size_t i = 0; - UINT32 roverindex = 0; - - for (rover = mobj->ceilingrover->target->ffloors; rover; rover = rover->next) - { - if (rover == mobj->ceilingrover) - { - roverindex = i; - break; - } - i++; - } - - WRITEUINT32(save_p, (UINT32)(mobj->ceilingrover->target - sectors)); - WRITEUINT32(save_p, rover ? roverindex : i); // store max index to denote invalid ffloor ref + WRITEUINT32(save_p, SaveSector(mobj->ceilingrover->target)); + WRITEUINT16(save_p, P_GetFFloorID(mobj->ceilingrover)); } if (diff & MD_SPAWNPOINT) @@ -1630,7 +1625,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) if (diff2 & MD2_SKIN) WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins)); if (diff2 & MD2_COLOR) - WRITEUINT8(save_p, mobj->color); + WRITEUINT16(save_p, mobj->color); if (diff2 & MD2_EXTVAL1) WRITEINT32(save_p, mobj->extravalue1); if (diff2 & MD2_EXTVAL2) @@ -1639,10 +1634,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT32(save_p, mobj->hnext->mobjnum); if (diff2 & MD2_HPREV) WRITEUINT32(save_p, mobj->hprev->mobjnum); -#ifdef ESLOPE if (diff2 & MD2_SLOPE) WRITEUINT16(save_p, mobj->standingslope->id); -#endif if (diff2 & MD2_COLORIZED) WRITEUINT8(save_p, mobj->colorized); if (diff2 & MD2_ROLLANGLE) @@ -1653,30 +1646,111 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT32(save_p, mobj->mobjnum); } -// -// SaveSpecialLevelThinker -// -// Saves a levelspecthink_t thinker -// -static void SaveSpecialLevelThinker(const thinker_t *th, const UINT8 type) +static void SaveNoEnemiesThinker(const thinker_t *th, const UINT8 type) { - const levelspecthink_t *ht = (const void *)th; - size_t i; + const noenemies_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveLine(ht->sourceline)); +} + +static void SaveBounceCheeseThinker(const thinker_t *th, const UINT8 type) +{ + const bouncecheese_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEFIXED(save_p, ht->speed); + WRITEFIXED(save_p, ht->distance); + WRITEFIXED(save_p, ht->floorwasheight); + WRITEFIXED(save_p, ht->ceilingwasheight); + WRITECHAR(save_p, ht->low); +} + +static void SaveContinuousFallThinker(const thinker_t *th, const UINT8 type) +{ + const continuousfall_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEFIXED(save_p, ht->speed); + WRITEINT32(save_p, ht->direction); + WRITEFIXED(save_p, ht->floorstartheight); + WRITEFIXED(save_p, ht->ceilingstartheight); + WRITEFIXED(save_p, ht->destheight); +} + +static void SaveMarioBlockThinker(const thinker_t *th, const UINT8 type) +{ + const mariothink_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEFIXED(save_p, ht->speed); + WRITEINT32(save_p, ht->direction); + WRITEFIXED(save_p, ht->floorstartheight); + WRITEFIXED(save_p, ht->ceilingstartheight); + WRITEINT16(save_p, ht->tag); +} + +static void SaveMarioCheckThinker(const thinker_t *th, const UINT8 type) +{ + const mariocheck_t *ht = (const void *)th; WRITEUINT8(save_p, type); - for (i = 0; i < 16; i++) - { - WRITEFIXED(save_p, ht->vars[i]); //var[16] - WRITEFIXED(save_p, ht->var2s[i]); //var[16] - } WRITEUINT32(save_p, SaveLine(ht->sourceline)); WRITEUINT32(save_p, SaveSector(ht->sector)); } -// -// SaveCeilingThinker -// -// Saves a ceiling_t thinker -// +static void SaveThwompThinker(const thinker_t *th, const UINT8 type) +{ + const thwomp_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEFIXED(save_p, ht->crushspeed); + WRITEFIXED(save_p, ht->retractspeed); + WRITEINT32(save_p, ht->direction); + WRITEFIXED(save_p, ht->floorstartheight); + WRITEFIXED(save_p, ht->ceilingstartheight); + WRITEINT32(save_p, ht->delay); + WRITEINT16(save_p, ht->tag); + WRITEUINT16(save_p, ht->sound); +} + +static void SaveFloatThinker(const thinker_t *th, const UINT8 type) +{ + const floatthink_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEINT16(save_p, ht->tag); +} + +static void SaveEachTimeThinker(const thinker_t *th, const UINT8 type) +{ + const eachtime_t *ht = (const void *)th; + size_t i; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveLine(ht->sourceline)); + for (i = 0; i < MAXPLAYERS; i++) + { + WRITECHAR(save_p, ht->playersInArea[i]); + WRITECHAR(save_p, ht->playersOnArea[i]); + } + WRITECHAR(save_p, ht->triggerOnExit); +} + +static void SaveRaiseThinker(const thinker_t *th, const UINT8 type) +{ + const raise_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEINT16(save_p, ht->tag); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEFIXED(save_p, ht->ceilingbottom); + WRITEFIXED(save_p, ht->ceilingtop); + WRITEFIXED(save_p, ht->basespeed); + WRITEFIXED(save_p, ht->extraspeed); + WRITEUINT8(save_p, ht->shaketimer); + WRITEUINT8(save_p, ht->flags); +} + static void SaveCeilingThinker(const thinker_t *th, const UINT8 type) { const ceiling_t *ht = (const void *)th; @@ -1698,11 +1772,6 @@ static void SaveCeilingThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->sourceline); } -// -// SaveFloormoveThinker -// -// Saves a floormove_t thinker -// static void SaveFloormoveThinker(const thinker_t *th, const UINT8 type) { const floormove_t *ht = (const void *)th; @@ -1719,11 +1788,6 @@ static void SaveFloormoveThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->delaytimer); } -// -// SaveLightflashThinker -// -// Saves a lightflash_t thinker -// static void SaveLightflashThinker(const thinker_t *th, const UINT8 type) { const lightflash_t *ht = (const void *)th; @@ -1733,11 +1797,6 @@ static void SaveLightflashThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->minlight); } -// -// SaveStrobeThinker -// -// Saves a strobe_t thinker -// static void SaveStrobeThinker(const thinker_t *th, const UINT8 type) { const strobe_t *ht = (const void *)th; @@ -1750,11 +1809,6 @@ static void SaveStrobeThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->brighttime); } -// -// SaveGlowThinker -// -// Saves a glow_t thinker -// static void SaveGlowThinker(const thinker_t *th, const UINT8 type) { const glow_t *ht = (const void *)th; @@ -1765,11 +1819,7 @@ static void SaveGlowThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->direction); WRITEINT32(save_p, ht->speed); } -// -// SaveFireflickerThinker -// -// Saves a fireflicker_t thinker -// + static inline void SaveFireflickerThinker(const thinker_t *th, const UINT8 type) { const fireflicker_t *ht = (const void *)th; @@ -1780,11 +1830,7 @@ static inline void SaveFireflickerThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->maxlight); WRITEINT32(save_p, ht->minlight); } -// -// SaveElevatorThinker -// -// Saves a elevator_t thinker -// + static void SaveElevatorThinker(const thinker_t *th, const UINT8 type) { const elevator_t *ht = (const void *)th; @@ -1804,15 +1850,26 @@ static void SaveElevatorThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->delaytimer); WRITEFIXED(save_p, ht->floorwasheight); WRITEFIXED(save_p, ht->ceilingwasheight); - WRITEUINT32(save_p, SavePlayer(ht->player)); // was dummy WRITEUINT32(save_p, SaveLine(ht->sourceline)); } -// -// SaveScrollThinker -// -// Saves a scroll_t thinker -// +static void SaveCrumbleThinker(const thinker_t *th, const UINT8 type) +{ + const crumble_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEUINT32(save_p, SaveSector(ht->actionsector)); + WRITEUINT32(save_p, SavePlayer(ht->player)); // was dummy + WRITEINT32(save_p, ht->direction); + WRITEINT32(save_p, ht->origalpha); + WRITEINT32(save_p, ht->timer); + WRITEFIXED(save_p, ht->speed); + WRITEFIXED(save_p, ht->floorwasheight); + WRITEFIXED(save_p, ht->ceilingwasheight); + WRITEUINT8(save_p, ht->flags); +} + static inline void SaveScrollThinker(const thinker_t *th, const UINT8 type) { const scroll_t *ht = (const void *)th; @@ -1829,11 +1886,6 @@ static inline void SaveScrollThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, ht->type); } -// -// SaveFrictionThinker -// -// Saves a friction_t thinker -// static inline void SaveFrictionThinker(const thinker_t *th, const UINT8 type) { const friction_t *ht = (const void *)th; @@ -1845,11 +1897,6 @@ static inline void SaveFrictionThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, ht->roverfriction); } -// -// SavePusherThinker -// -// Saves a pusher_t thinker -// static inline void SavePusherThinker(const thinker_t *th, const UINT8 type) { const pusher_t *ht = (const void *)th; @@ -1869,25 +1916,15 @@ static inline void SavePusherThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->slider); } -// -// SaveLaserThinker -// -// Saves a laserthink_t thinker -// static void SaveLaserThinker(const thinker_t *th, const UINT8 type) { const laserthink_t *ht = (const void *)th; WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEUINT32(save_p, SaveSector(ht->sec)); + WRITEINT16(save_p, ht->tag); WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT8(save_p, ht->nobosses); } -// -// SaveLightlevelThinker -// -// Saves a lightlevel_t thinker -// static void SaveLightlevelThinker(const thinker_t *th, const UINT8 type) { const lightlevel_t *ht = (const void *)th; @@ -1900,11 +1937,6 @@ static void SaveLightlevelThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->timer); } -// -// SaveExecutorThinker -// -// Saves a executor_t thinker -// static void SaveExecutorThinker(const thinker_t *th, const UINT8 type) { const executor_t *ht = (const void *)th; @@ -1915,11 +1947,6 @@ static void SaveExecutorThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->timer); } -// -// SaveDisappearThinker -// -// Saves a disappear_t thinker -// static void SaveDisappearThinker(const thinker_t *th, const UINT8 type) { const disappear_t *ht = (const void *)th; @@ -1933,11 +1960,6 @@ static void SaveDisappearThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->exists); } -// -// SaveFadeThinker -// -// Saves a fade_t thinker -// static void SaveFadeThinker(const thinker_t *th, const UINT8 type) { const fade_t *ht = (const void *)th; @@ -1961,11 +1983,6 @@ static void SaveFadeThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, ht->exactalpha); } -// -// SaveFadeColormapThinker -// -// Saves a fadecolormap_t thinker -// static void SaveFadeColormapThinker(const thinker_t *th, const UINT8 type) { const fadecolormap_t *ht = (const void *)th; @@ -1978,11 +1995,6 @@ static void SaveFadeColormapThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->timer); } -// -// SavePlaneDisplaceThinker -// -// Saves a planedisplace_t thinker -// static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type) { const planedisplace_t *ht = (const void *)th; @@ -1993,8 +2005,7 @@ static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->speed); WRITEUINT8(save_p, ht->type); } -#ifdef ESLOPE -/// Save a dynamic slope thinker. + static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type) { const dynplanethink_t* ht = (const void*)th; @@ -2008,15 +2019,7 @@ static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type WRITEMEM(save_p, ht->tags, sizeof(ht->tags)); WRITEMEM(save_p, ht->vex, sizeof(ht->vex)); } -#endif // ESLOPE -#ifdef POLYOBJECTS - -// -// SavePolyrotateThinker -// -// Saves a polyrotate_t thinker -// static inline void SavePolyrotatetThinker(const thinker_t *th, const UINT8 type) { const polyrotate_t *ht = (const void *)th; @@ -2024,13 +2027,9 @@ static inline void SavePolyrotatetThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->polyObjNum); WRITEINT32(save_p, ht->speed); WRITEINT32(save_p, ht->distance); + WRITEUINT8(save_p, ht->turnobjs); } -// -// SavePolymoveThinker -// -// Saves a polymovet_t thinker -// static void SavePolymoveThinker(const thinker_t *th, const UINT8 type) { const polymove_t *ht = (const void *)th; @@ -2043,11 +2042,6 @@ static void SavePolymoveThinker(const thinker_t *th, const UINT8 type) WRITEANGLE(save_p, ht->angle); } -// -// SavePolywaypointThinker -// -// Saves a polywaypoint_t thinker -// static void SavePolywaypointThinker(const thinker_t *th, UINT8 type) { const polywaypoint_t *ht = (const void *)th; @@ -2057,21 +2051,11 @@ static void SavePolywaypointThinker(const thinker_t *th, UINT8 type) WRITEINT32(save_p, ht->sequence); WRITEINT32(save_p, ht->pointnum); WRITEINT32(save_p, ht->direction); - WRITEUINT8(save_p, ht->comeback); - WRITEUINT8(save_p, ht->wrap); + WRITEUINT8(save_p, ht->returnbehavior); WRITEUINT8(save_p, ht->continuous); WRITEUINT8(save_p, ht->stophere); - WRITEFIXED(save_p, ht->diffx); - WRITEFIXED(save_p, ht->diffy); - WRITEFIXED(save_p, ht->diffz); - WRITEUINT32(save_p, SaveMobjnum(ht->target)); } -// -// SavePolyslidedoorThinker -// -// Saves a polyslidedoor_t thinker -// static void SavePolyslidedoorThinker(const thinker_t *th, const UINT8 type) { const polyslidedoor_t *ht = (const void *)th; @@ -2091,11 +2075,6 @@ static void SavePolyslidedoorThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, ht->closing); } -// -// SavePolyswingdoorThinker -// -// Saves a polyswingdoor_t thinker -// static void SavePolyswingdoorThinker(const thinker_t *th, const UINT8 type) { const polyswingdoor_t *ht = (const void *)th; @@ -2146,24 +2125,6 @@ static void SavePolyfadeThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->timer); } -#endif -/* -// -// SaveWhatThinker -// -// Saves a what_t thinker -// -static inline void SaveWhatThinker(const thinker_t *th, const UINT8 type) -{ - const what_t *ht = (const void *)th; - WRITEUINT8(save_p, type); -} -*/ - -// -// P_NetArchiveThinkers -// -// static void P_NetArchiveThinkers(void) { const thinker_t *th; @@ -2231,27 +2192,27 @@ static void P_NetArchiveThinkers(void) } else if (th->function.acp1 == (actionf_p1)T_ContinuousFalling) { - SaveSpecialLevelThinker(th, tc_continuousfalling); + SaveContinuousFallThinker(th, tc_continuousfalling); continue; } else if (th->function.acp1 == (actionf_p1)T_ThwompSector) { - SaveSpecialLevelThinker(th, tc_thwomp); + SaveThwompThinker(th, tc_thwomp); continue; } else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector) { - SaveSpecialLevelThinker(th, tc_noenemies); + SaveNoEnemiesThinker(th, tc_noenemies); continue; } else if (th->function.acp1 == (actionf_p1)T_EachTimeThinker) { - SaveSpecialLevelThinker(th, tc_eachtime); + SaveEachTimeThinker(th, tc_eachtime); continue; } else if (th->function.acp1 == (actionf_p1)T_RaiseSector) { - SaveSpecialLevelThinker(th, tc_raisesector); + SaveRaiseThinker(th, tc_raisesector); continue; } else if (th->function.acp1 == (actionf_p1)T_CameraScanner) @@ -2276,37 +2237,27 @@ static void P_NetArchiveThinkers(void) } else if (th->function.acp1 == (actionf_p1)T_BounceCheese) { - SaveSpecialLevelThinker(th, tc_bouncecheese); + SaveBounceCheeseThinker(th, tc_bouncecheese); continue; } else if (th->function.acp1 == (actionf_p1)T_StartCrumble) { - SaveElevatorThinker(th, tc_startcrumble); + SaveCrumbleThinker(th, tc_startcrumble); continue; } else if (th->function.acp1 == (actionf_p1)T_MarioBlock) { - SaveSpecialLevelThinker(th, tc_marioblock); + SaveMarioBlockThinker(th, tc_marioblock); continue; } else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker) { - SaveSpecialLevelThinker(th, tc_marioblockchecker); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_SpikeSector) - { - SaveSpecialLevelThinker(th, tc_spikesector); + SaveMarioCheckThinker(th, tc_marioblockchecker); continue; } else if (th->function.acp1 == (actionf_p1)T_FloatSector) { - SaveSpecialLevelThinker(th, tc_floatsector); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_BridgeThinker) - { - SaveSpecialLevelThinker(th, tc_bridgethinker); + SaveFloatThinker(th, tc_floatsector); continue; } else if (th->function.acp1 == (actionf_p1)T_LaserFlash) @@ -2344,7 +2295,6 @@ static void P_NetArchiveThinkers(void) SavePlaneDisplaceThinker(th, tc_planedisplace); continue; } -#ifdef POLYOBJECTS else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate) { SavePolyrotatetThinker(th, tc_polyrotate); @@ -2390,8 +2340,6 @@ static void P_NetArchiveThinkers(void) SavePolyfadeThinker(th, tc_polyfade); continue; } -#endif -#ifdef ESLOPE else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine) { SaveDynamicSlopeThinker(th, tc_dynslopeline); @@ -2402,7 +2350,6 @@ static void P_NetArchiveThinkers(void) SaveDynamicSlopeThinker(th, tc_dynslopevert); continue; } -#endif // ESLOPE #ifdef PARANOIA else if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed) // wait garbage collection I_Error("unknown thinker type %p", th->function.acp1); @@ -2463,7 +2410,6 @@ static inline player_t *LoadPlayer(UINT32 player) return &players[player]; } -#ifdef ESLOPE static inline pslope_t *LoadSlope(UINT32 slopeid) { pslope_t *p = slopelist; @@ -2475,13 +2421,7 @@ static inline pslope_t *LoadSlope(UINT32 slopeid) } while ((p = p->next)); return NULL; } -#endif // ESLOPE -// -// LoadMobjThinker -// -// Loads a mobj_t from a save game -// static thinker_t* LoadMobjThinker(actionf_p1 thinker) { thinker_t *next; @@ -2506,34 +2446,16 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (diff2 & MD2_FLOORROVER) { - size_t floor_sectornum = (size_t)READUINT32(save_p); - size_t floor_rovernum = (size_t)READUINT32(save_p); - ffloor_t *rover = NULL; - size_t rovernum = 0; - - for (rover = sectors[floor_sectornum].ffloors; rover; rover = rover->next) - { - if (rovernum == floor_rovernum) - break; - rovernum++; - } - floorrover = rover; + sector_t *sec = LoadSector(READUINT32(save_p)); + UINT16 id = READUINT16(save_p); + floorrover = P_GetFFloorByID(sec, id); } if (diff2 & MD2_CEILINGROVER) { - size_t ceiling_sectornum = (size_t)READUINT32(save_p); - size_t ceiling_rovernum = (size_t)READUINT32(save_p); - ffloor_t *rover = NULL; - size_t rovernum = 0; - - for (rover = sectors[ceiling_sectornum].ffloors; rover; rover = rover->next) - { - if (rovernum == ceiling_rovernum) - break; - rovernum++; - } - ceilingrover = rover; + sector_t *sec = LoadSector(READUINT32(save_p)); + UINT16 id = READUINT16(save_p); + ceilingrover = P_GetFFloorByID(sec, id); } if (diff & MD_SPAWNPOINT) @@ -2658,11 +2580,6 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) i = READUINT8(save_p); mobj->player = &players[i]; mobj->player->mo = mobj; - // added for angle prediction - if (consoleplayer == i) - localangle = mobj->angle; - if (secondarydisplayplayer == i) - localangle2 = mobj->angle; } if (diff & MD_MOVEDIR) mobj->movedir = READANGLE(save_p); @@ -2711,7 +2628,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (diff2 & MD2_SKIN) mobj->skin = &skins[READUINT8(save_p)]; if (diff2 & MD2_COLOR) - mobj->color = READUINT8(save_p); + mobj->color = READUINT16(save_p); if (diff2 & MD2_EXTVAL1) mobj->extravalue1 = READINT32(save_p); if (diff2 & MD2_EXTVAL2) @@ -2720,10 +2637,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p); if (diff2 & MD2_HPREV) mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p); -#ifdef ESLOPE if (diff2 & MD2_SLOPE) mobj->standingslope = P_SlopeById(READUINT16(save_p)); -#endif if (diff2 & MD2_COLORIZED) mobj->colorized = READUINT8(save_p); if (diff2 & MD2_ROLLANGLE) @@ -2760,46 +2675,145 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) return &mobj->thinker; } -// -// LoadSpecialLevelThinker -// -// Loads a levelspecthink_t from a save game -// -// floorOrCeiling: -// 0 - Don't set -// 1 - Floor Only -// 2 - Ceiling Only -// 3 - Both -// -static thinker_t* LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling) +static thinker_t* LoadNoEnemiesThinker(actionf_p1 thinker) { - levelspecthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - size_t i; + noenemies_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sourceline = LoadLine(READUINT32(save_p)); + return &ht->thinker; +} + +static thinker_t* LoadBounceCheeseThinker(actionf_p1 thinker) +{ + bouncecheese_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - for (i = 0; i < 16; i++) - { - ht->vars[i] = READFIXED(save_p); //var[16] - ht->var2s[i] = READFIXED(save_p); //var[16] - } ht->sourceline = LoadLine(READUINT32(save_p)); ht->sector = LoadSector(READUINT32(save_p)); + ht->speed = READFIXED(save_p); + ht->distance = READFIXED(save_p); + ht->floorwasheight = READFIXED(save_p); + ht->ceilingwasheight = READFIXED(save_p); + ht->low = READCHAR(save_p); + + if (ht->sector) + ht->sector->ceilingdata = ht; + + return &ht->thinker; +} + +static thinker_t* LoadContinuousFallThinker(actionf_p1 thinker) +{ + continuousfall_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sector = LoadSector(READUINT32(save_p)); + ht->speed = READFIXED(save_p); + ht->direction = READINT32(save_p); + ht->floorstartheight = READFIXED(save_p); + ht->ceilingstartheight = READFIXED(save_p); + ht->destheight = READFIXED(save_p); if (ht->sector) { - if (floorOrCeiling & 2) - ht->sector->ceilingdata = ht; - if (floorOrCeiling & 1) - ht->sector->floordata = ht; + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; } return &ht->thinker; } -// -// LoadCeilingThinker -// -// Loads a ceiling_t from a save game -// +static thinker_t* LoadMarioBlockThinker(actionf_p1 thinker) +{ + mariothink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sector = LoadSector(READUINT32(save_p)); + ht->speed = READFIXED(save_p); + ht->direction = READINT32(save_p); + ht->floorstartheight = READFIXED(save_p); + ht->ceilingstartheight = READFIXED(save_p); + ht->tag = READINT16(save_p); + + if (ht->sector) + { + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; + } + + return &ht->thinker; +} + +static thinker_t* LoadMarioCheckThinker(actionf_p1 thinker) +{ + mariocheck_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sourceline = LoadLine(READUINT32(save_p)); + ht->sector = LoadSector(READUINT32(save_p)); + return &ht->thinker; +} + +static thinker_t* LoadThwompThinker(actionf_p1 thinker) +{ + thwomp_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sourceline = LoadLine(READUINT32(save_p)); + ht->sector = LoadSector(READUINT32(save_p)); + ht->crushspeed = READFIXED(save_p); + ht->retractspeed = READFIXED(save_p); + ht->direction = READINT32(save_p); + ht->floorstartheight = READFIXED(save_p); + ht->ceilingstartheight = READFIXED(save_p); + ht->delay = READINT32(save_p); + ht->tag = READINT16(save_p); + ht->sound = READUINT16(save_p); + + if (ht->sector) + { + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; + } + + return &ht->thinker; +} + +static thinker_t* LoadFloatThinker(actionf_p1 thinker) +{ + floatthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sourceline = LoadLine(READUINT32(save_p)); + ht->sector = LoadSector(READUINT32(save_p)); + ht->tag = READINT16(save_p); + return &ht->thinker; +} + +static thinker_t* LoadEachTimeThinker(actionf_p1 thinker) +{ + size_t i; + eachtime_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sourceline = LoadLine(READUINT32(save_p)); + for (i = 0; i < MAXPLAYERS; i++) + { + ht->playersInArea[i] = READCHAR(save_p); + ht->playersOnArea[i] = READCHAR(save_p); + } + ht->triggerOnExit = READCHAR(save_p); + return &ht->thinker; +} + +static thinker_t* LoadRaiseThinker(actionf_p1 thinker) +{ + raise_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->tag = READINT16(save_p); + ht->sector = LoadSector(READUINT32(save_p)); + ht->ceilingbottom = READFIXED(save_p); + ht->ceilingtop = READFIXED(save_p); + ht->basespeed = READFIXED(save_p); + ht->extraspeed = READFIXED(save_p); + ht->shaketimer = READUINT8(save_p); + ht->flags = READUINT8(save_p); + return &ht->thinker; +} + static thinker_t* LoadCeilingThinker(actionf_p1 thinker) { ceiling_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2824,11 +2838,6 @@ static thinker_t* LoadCeilingThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadFloormoveThinker -// -// Loads a floormove_t from a save game -// static thinker_t* LoadFloormoveThinker(actionf_p1 thinker) { floormove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2848,11 +2857,6 @@ static thinker_t* LoadFloormoveThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadLightflashThinker -// -// Loads a lightflash_t from a save game -// static thinker_t* LoadLightflashThinker(actionf_p1 thinker) { lightflash_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2865,11 +2869,6 @@ static thinker_t* LoadLightflashThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadStrobeThinker -// -// Loads a strobe_t from a save game -// static thinker_t* LoadStrobeThinker(actionf_p1 thinker) { strobe_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2885,11 +2884,6 @@ static thinker_t* LoadStrobeThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadGlowThinker -// -// Loads a glow_t from a save game -// static thinker_t* LoadGlowThinker(actionf_p1 thinker) { glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2903,11 +2897,7 @@ static thinker_t* LoadGlowThinker(actionf_p1 thinker) ht->sector->lightingdata = ht; return &ht->thinker; } -// -// LoadFireflickerThinker -// -// Loads a fireflicker_t from a save game -// + static thinker_t* LoadFireflickerThinker(actionf_p1 thinker) { fireflicker_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2921,12 +2911,8 @@ static thinker_t* LoadFireflickerThinker(actionf_p1 thinker) ht->sector->lightingdata = ht; return &ht->thinker; } -// -// LoadElevatorThinker -// -// Loads a elevator_t from a save game -// -static thinker_t* LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling) + +static thinker_t* LoadElevatorThinker(actionf_p1 thinker, boolean setplanedata) { elevator_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; @@ -2945,25 +2931,39 @@ static thinker_t* LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling) ht->delaytimer = READFIXED(save_p); ht->floorwasheight = READFIXED(save_p); ht->ceilingwasheight = READFIXED(save_p); - ht->player = LoadPlayer(READUINT32(save_p)); // was dummy ht->sourceline = LoadLine(READUINT32(save_p)); - if (ht->sector) + if (ht->sector && setplanedata) { - if (floorOrCeiling & 2) - ht->sector->ceilingdata = ht; - if (floorOrCeiling & 1) - ht->sector->floordata = ht; + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; } return &ht->thinker; } -// -// LoadScrollThinker -// -// Loads a scroll_t from a save game -// +static thinker_t* LoadCrumbleThinker(actionf_p1 thinker) +{ + crumble_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sourceline = LoadLine(READUINT32(save_p)); + ht->sector = LoadSector(READUINT32(save_p)); + ht->actionsector = LoadSector(READUINT32(save_p)); + ht->player = LoadPlayer(READUINT32(save_p)); + ht->direction = READINT32(save_p); + ht->origalpha = READINT32(save_p); + ht->timer = READINT32(save_p); + ht->speed = READFIXED(save_p); + ht->floorwasheight = READFIXED(save_p); + ht->ceilingwasheight = READFIXED(save_p); + ht->flags = READUINT8(save_p); + + if (ht->sector) + ht->sector->floordata = ht; + + return &ht->thinker; +} + static thinker_t* LoadScrollThinker(actionf_p1 thinker) { scroll_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2981,11 +2981,6 @@ static thinker_t* LoadScrollThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadFrictionThinker -// -// Loads a friction_t from a save game -// static inline thinker_t* LoadFrictionThinker(actionf_p1 thinker) { friction_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -2998,11 +2993,6 @@ static inline thinker_t* LoadFrictionThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadPusherThinker -// -// Loads a pusher_t from a save game -// static thinker_t* LoadPusherThinker(actionf_p1 thinker) { pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3024,31 +3014,16 @@ static thinker_t* LoadPusherThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadLaserThinker -// -// Loads a laserthink_t from a save game -// static inline thinker_t* LoadLaserThinker(actionf_p1 thinker) { laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ffloor_t *rover = NULL; ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->sec = LoadSector(READUINT32(save_p)); + ht->tag = READINT16(save_p); ht->sourceline = LoadLine(READUINT32(save_p)); - for (rover = ht->sector->ffloors; rover; rover = rover->next) - if (rover->secnum == (size_t)(ht->sec - sectors) - && rover->master == ht->sourceline) - ht->ffloor = rover; + ht->nobosses = READUINT8(save_p); return &ht->thinker; } -// -// LoadLightlevelThinker -// -// Loads a lightlevel_t from a save game -// static inline thinker_t* LoadLightlevelThinker(actionf_p1 thinker) { lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3064,11 +3039,6 @@ static inline thinker_t* LoadLightlevelThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadExecutorThinker -// -// Loads a executor_t from a save game -// static inline thinker_t* LoadExecutorThinker(actionf_p1 thinker) { executor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3080,11 +3050,6 @@ static inline thinker_t* LoadExecutorThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadDisappearThinker -// -// Loads a disappear_t thinker -// static inline thinker_t* LoadDisappearThinker(actionf_p1 thinker) { disappear_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3099,11 +3064,6 @@ static inline thinker_t* LoadDisappearThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadFadeThinker -// -// Loads a fade_t thinker -// static inline thinker_t* LoadFadeThinker(actionf_p1 thinker) { sector_t *ss; @@ -3146,10 +3106,6 @@ static inline thinker_t* LoadFadeThinker(actionf_p1 thinker) return &ht->thinker; } -// LoadFadeColormapThinker -// -// Loads a fadecolormap_t from a save game -// static inline thinker_t* LoadFadeColormapThinker(actionf_p1 thinker) { fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3165,11 +3121,6 @@ static inline thinker_t* LoadFadeColormapThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadPlaneDisplaceThinker -// -// Loads a planedisplace_t thinker -// static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker) { planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3183,8 +3134,6 @@ static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker) return &ht->thinker; } -#ifdef ESLOPE -/// Save a dynamic slope thinker. static inline thinker_t* LoadDynamicSlopeThinker(actionf_p1 thinker) { dynplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); @@ -3198,15 +3147,7 @@ static inline thinker_t* LoadDynamicSlopeThinker(actionf_p1 thinker) READMEM(save_p, ht->vex, sizeof(ht->vex)); return &ht->thinker; } -#endif // ESLOPE -#ifdef POLYOBJECTS - -// -// LoadPolyrotateThinker -// -// Loads a polyrotate_t thinker -// static inline thinker_t* LoadPolyrotatetThinker(actionf_p1 thinker) { polyrotate_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3214,14 +3155,10 @@ static inline thinker_t* LoadPolyrotatetThinker(actionf_p1 thinker) ht->polyObjNum = READINT32(save_p); ht->speed = READINT32(save_p); ht->distance = READINT32(save_p); + ht->turnobjs = READUINT8(save_p); return &ht->thinker; } -// -// LoadPolymoveThinker -// -// Loads a polymovet_t thinker -// static thinker_t* LoadPolymoveThinker(actionf_p1 thinker) { polymove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3235,11 +3172,6 @@ static thinker_t* LoadPolymoveThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadPolywaypointThinker -// -// Loads a polywaypoint_t thinker -// static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker) { polywaypoint_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3249,22 +3181,12 @@ static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker) ht->sequence = READINT32(save_p); ht->pointnum = READINT32(save_p); ht->direction = READINT32(save_p); - ht->comeback = READUINT8(save_p); - ht->wrap = READUINT8(save_p); + ht->returnbehavior = READUINT8(save_p); ht->continuous = READUINT8(save_p); ht->stophere = READUINT8(save_p); - ht->diffx = READFIXED(save_p); - ht->diffy = READFIXED(save_p); - ht->diffz = READFIXED(save_p); - ht->target = LoadMobj(READUINT32(save_p)); return &ht->thinker; } -// -// LoadPolyslidedoorThinker -// -// loads a polyslidedoor_t thinker -// static inline thinker_t* LoadPolyslidedoorThinker(actionf_p1 thinker) { polyslidedoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3285,11 +3207,6 @@ static inline thinker_t* LoadPolyslidedoorThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadPolyswingdoorThinker -// -// Loads a polyswingdoor_t thinker -// static inline thinker_t* LoadPolyswingdoorThinker(actionf_p1 thinker) { polyswingdoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3305,11 +3222,6 @@ static inline thinker_t* LoadPolyswingdoorThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadPolydisplaceThinker -// -// Loads a polydisplace_t thinker -// static inline thinker_t* LoadPolydisplaceThinker(actionf_p1 thinker) { polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3334,11 +3246,6 @@ static inline thinker_t* LoadPolyrotdisplaceThinker(actionf_p1 thinker) return &ht->thinker; } -// -// LoadPolyfadeThinker -// -// Loads a polyfadet_t thinker -// static thinker_t* LoadPolyfadeThinker(actionf_p1 thinker) { polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); @@ -3353,24 +3260,7 @@ static thinker_t* LoadPolyfadeThinker(actionf_p1 thinker) ht->timer = READINT32(save_p); return &ht->thinker; } -#endif -/* -// -// LoadWhatThinker -// -// load a what_t thinker -// -static inline void LoadWhatThinker(actionf_p1 thinker) -{ - what_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; -} -*/ - -// -// P_NetUnArchiveThinkers -// static void P_NetUnArchiveThinkers(void) { thinker_t *currentthinker; @@ -3455,61 +3345,51 @@ static void P_NetUnArchiveThinkers(void) break; case tc_elevator: - th = LoadElevatorThinker((actionf_p1)T_MoveElevator, 3); + th = LoadElevatorThinker((actionf_p1)T_MoveElevator, true); break; case tc_continuousfalling: - th = LoadSpecialLevelThinker((actionf_p1)T_ContinuousFalling, 3); + th = LoadContinuousFallThinker((actionf_p1)T_ContinuousFalling); break; case tc_thwomp: - th = LoadSpecialLevelThinker((actionf_p1)T_ThwompSector, 3); + th = LoadThwompThinker((actionf_p1)T_ThwompSector); break; case tc_noenemies: - th = LoadSpecialLevelThinker((actionf_p1)T_NoEnemiesSector, 0); + th = LoadNoEnemiesThinker((actionf_p1)T_NoEnemiesSector); break; case tc_eachtime: - th = LoadSpecialLevelThinker((actionf_p1)T_EachTimeThinker, 0); + th = LoadEachTimeThinker((actionf_p1)T_EachTimeThinker); break; case tc_raisesector: - th = LoadSpecialLevelThinker((actionf_p1)T_RaiseSector, 0); + th = LoadRaiseThinker((actionf_p1)T_RaiseSector); break; - /// \todo rewrite all the code that uses an elevator_t but isn't an elevator - /// \note working on it! case tc_camerascanner: - th = LoadElevatorThinker((actionf_p1)T_CameraScanner, 0); + th = LoadElevatorThinker((actionf_p1)T_CameraScanner, false); break; case tc_bouncecheese: - th = LoadSpecialLevelThinker((actionf_p1)T_BounceCheese, 2); + th = LoadBounceCheeseThinker((actionf_p1)T_BounceCheese); break; case tc_startcrumble: - th = LoadElevatorThinker((actionf_p1)T_StartCrumble, 1); + th = LoadCrumbleThinker((actionf_p1)T_StartCrumble); break; case tc_marioblock: - th = LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3); + th = LoadMarioBlockThinker((actionf_p1)T_MarioBlock); break; case tc_marioblockchecker: - th = LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0); - break; - - case tc_spikesector: - th = LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0); + th = LoadMarioCheckThinker((actionf_p1)T_MarioBlockChecker); break; case tc_floatsector: - th = LoadSpecialLevelThinker((actionf_p1)T_FloatSector, 0); - break; - - case tc_bridgethinker: - th = LoadSpecialLevelThinker((actionf_p1)T_BridgeThinker, 3); + th = LoadFloatThinker((actionf_p1)T_FloatSector); break; case tc_laserflash: @@ -3540,7 +3420,6 @@ static void P_NetUnArchiveThinkers(void) case tc_planedisplace: th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace); break; -#ifdef POLYOBJECTS case tc_polyrotate: th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate); break; @@ -3551,7 +3430,6 @@ static void P_NetUnArchiveThinkers(void) case tc_polywaypoint: th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint); - restoreNum = true; break; case tc_polyslidedoor: @@ -3577,8 +3455,7 @@ static void P_NetUnArchiveThinkers(void) case tc_polyfade: th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade); break; -#endif -#ifdef ESLOPE + case tc_dynslopeline: th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeLine); break; @@ -3586,7 +3463,6 @@ static void P_NetUnArchiveThinkers(void) case tc_dynslopevert: th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeVert); break; -#endif // ESLOPE case tc_scroll: th = LoadScrollThinker((actionf_p1)T_Scroll); @@ -3613,7 +3489,6 @@ static void P_NetUnArchiveThinkers(void) if (restoreNum) { executor_t *delay = NULL; - polywaypoint_t *polywp = NULL; UINT32 mobjnum; for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next) { @@ -3624,15 +3499,6 @@ static void P_NetUnArchiveThinkers(void) continue; delay->caller = P_FindNewPosition(mobjnum); } - for (currentthinker = thlist[THINK_POLYOBJ].next; currentthinker != &thlist[THINK_POLYOBJ]; currentthinker = currentthinker->next) - { - if (currentthinker->function.acp1 != (actionf_p1)T_PolyObjWaypoint) - continue; - polywp = (void *)currentthinker; - if (!(mobjnum = (UINT32)(size_t)polywp->target)) - continue; - polywp->target = P_FindNewPosition(mobjnum); - } } } @@ -3640,7 +3506,6 @@ static void P_NetUnArchiveThinkers(void) // // haleyjd 03/26/06: PolyObject saving code // -#ifdef POLYOBJECTS #define PD_FLAGS 0x01 #define PD_TRANS 0x02 @@ -3729,10 +3594,7 @@ static inline void P_UnArchivePolyObjects(void) for (i = 0; i < numSavedPolys; ++i) P_UnArchivePolyObj(&PolyObjects[i]); } -#endif -// -// P_FinishMobjs -// + static inline void P_FinishMobjs(void) { thinker_t *currentthinker; @@ -3841,9 +3703,6 @@ static void P_RelinkPointers(void) } } -// -// P_NetArchiveSpecials -// static inline void P_NetArchiveSpecials(void) { size_t i, z; @@ -3884,9 +3743,6 @@ static inline void P_NetArchiveSpecials(void) WRITEUINT8(save_p, 0x00); } -// -// P_NetUnArchiveSpecials -// static void P_NetUnArchiveSpecials(void) { size_t i; @@ -3929,16 +3785,15 @@ static void P_NetUnArchiveSpecials(void) // ======================================================================= // Misc // ======================================================================= -static inline void P_ArchiveMisc(void) +static inline void P_ArchiveMisc(INT16 mapnum) { + //lastmapsaved = mapnum; + lastmaploaded = mapnum; + if (gamecomplete) - WRITEINT16(save_p, gamemap | 8192); - else - WRITEINT16(save_p, gamemap); - - //lastmapsaved = gamemap; - lastmaploaded = gamemap; + mapnum |= 8192; + WRITEINT16(save_p, mapnum); WRITEUINT16(save_p, emeralds+357); WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder)); } @@ -3952,10 +3807,10 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) if (mapoverride != 0) { gamemap = mapoverride; - gamecomplete = true; + gamecomplete = 1; } else - gamecomplete = false; + gamecomplete = 0; // gamemap changed; we assume that its map header is always valid, // so make it so @@ -4179,12 +4034,10 @@ static inline boolean P_UnArchiveLuabanksAndConsistency(void) return true; } -void P_SaveGame(void) +void P_SaveGame(INT16 mapnum) { - P_ArchiveMisc(); + P_ArchiveMisc(mapnum); P_ArchivePlayer(); - - // yes, even in non HAVE_BLUA P_ArchiveLuabanksAndConsistency(); } @@ -4213,16 +4066,13 @@ void P_SaveNetGame(void) if (gamestate == GS_LEVEL) { P_NetArchiveWorld(); -#ifdef POLYOBJECTS P_ArchivePolyObjects(); -#endif P_NetArchiveThinkers(); P_NetArchiveSpecials(); P_NetArchiveColormaps(); + P_NetArchiveWaypoints(); } -#ifdef HAVE_BLUA LUA_Archive(); -#endif P_ArchiveLuabanksAndConsistency(); } @@ -4255,18 +4105,15 @@ boolean P_LoadNetGame(void) if (gamestate == GS_LEVEL) { P_NetUnArchiveWorld(); -#ifdef POLYOBJECTS P_UnArchivePolyObjects(); -#endif P_NetUnArchiveThinkers(); P_NetUnArchiveSpecials(); P_NetUnArchiveColormaps(); + P_NetUnArchiveWaypoints(); P_RelinkPointers(); P_FinishMobjs(); } -#ifdef HAVE_BLUA LUA_UnArchive(); -#endif // This is stupid and hacky, but maybe it'll work! P_SetRandSeed(P_GetInitSeed()); diff --git a/src/p_saveg.h b/src/p_saveg.h index 16d47bea8..d8756a7a9 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -21,7 +21,7 @@ // Persistent storage/archiving. // These are the load / save game routines. -void P_SaveGame(void); +void P_SaveGame(INT16 mapnum); void P_SaveNetGame(void); boolean P_LoadGame(INT16 mapoverride); boolean P_LoadNetGame(void); diff --git a/src/p_setup.c b/src/p_setup.c index dcc28bae1..f86de5ad4 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -27,7 +27,7 @@ #include "i_system.h" #include "r_data.h" -#include "r_things.h" +#include "r_things.h" // for R_AddSpriteDefs #include "r_patch.h" #include "r_sky.h" #include "r_draw.h" @@ -57,9 +57,7 @@ #include "filesrch.h" // refreshdirmenu -#ifdef HAVE_BLUA #include "lua_hud.h" // level title -#endif #include "f_finale.h" // wipes @@ -79,9 +77,7 @@ #include "hardware/hw_model.h" #endif -#ifdef ESLOPE #include "p_slopes.h" -#endif #include "fastcmp.h" // textmap parsing @@ -148,6 +144,133 @@ mapthing_t *playerstarts[MAXPLAYERS]; mapthing_t *bluectfstarts[MAXPLAYERS]; mapthing_t *redctfstarts[MAXPLAYERS]; +// Maintain waypoints +mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE]; +UINT16 numwaypoints[NUMWAYPOINTSEQUENCES]; + +void P_AddWaypoint(UINT8 sequence, UINT8 id, mobj_t *waypoint) +{ + waypoints[sequence][id] = waypoint; + if (id >= numwaypoints[sequence]) + numwaypoints[sequence] = id + 1; +} + +static void P_ResetWaypoints(void) +{ + UINT16 sequence, id; + for (sequence = 0; sequence < NUMWAYPOINTSEQUENCES; sequence++) + { + for (id = 0; id < numwaypoints[sequence]; id++) + waypoints[sequence][id] = NULL; + + numwaypoints[sequence] = 0; + } +} + +mobj_t *P_GetFirstWaypoint(UINT8 sequence) +{ + return waypoints[sequence][0]; +} + +mobj_t *P_GetLastWaypoint(UINT8 sequence) +{ + return waypoints[sequence][numwaypoints[sequence] - 1]; +} + +mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap) +{ + UINT8 sequence = current->threshold; + UINT8 id = current->health; + + if (id == 0) + { + if (!wrap) + return NULL; + + id = numwaypoints[sequence] - 1; + } + else + id--; + + return waypoints[sequence][id]; +} + +mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap) +{ + UINT8 sequence = current->threshold; + UINT8 id = current->health; + + if (id == numwaypoints[sequence] - 1) + { + if (!wrap) + return NULL; + + id = 0; + } + else + id++; + + return waypoints[sequence][id]; +} + +mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo) +{ + UINT8 wp; + mobj_t *mo2, *result = NULL; + fixed_t bestdist = 0; + fixed_t curdist; + + for (wp = 0; wp < numwaypoints[sequence]; wp++) + { + mo2 = waypoints[sequence][wp]; + + if (!mo2) + continue; + + curdist = P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z); + + if (result && curdist > bestdist) + continue; + + result = mo2; + bestdist = curdist; + } + + return result; +} + +// Return true if all waypoints are in the same location +boolean P_IsDegeneratedWaypointSequence(UINT8 sequence) +{ + mobj_t *first, *waypoint; + UINT8 wp; + + if (numwaypoints[sequence] <= 1) + return true; + + first = waypoints[sequence][0]; + + for (wp = 1; wp < numwaypoints[sequence]; wp++) + { + waypoint = waypoints[sequence][wp]; + + if (!waypoint) + continue; + + if (waypoint->x != first->x) + return false; + + if (waypoint->y != first->y) + return false; + + if (waypoint->z != first->z) + return false; + } + + return true; +} + + /** Logs an error about a map being corrupt, then terminate. * This allows reporting highly technical errors for usefulness, without * confusing a novice map designer who simply needs to run ZenNode. @@ -221,7 +344,11 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; mapheaderinfo[num]->nextlevel = (INT16)(i + 1); + mapheaderinfo[num]->marathonnext = 0; mapheaderinfo[num]->startrings = 0; + mapheaderinfo[num]->sstimer = 90; + mapheaderinfo[num]->ssspheres = 1; + mapheaderinfo[num]->gravity = FRACUNIT/2; mapheaderinfo[num]->keywords[0] = '\0'; snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i)); mapheaderinfo[num]->musname[6] = 0; @@ -697,47 +824,27 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) static void P_SpawnEmeraldHunt(void) { - INT32 emer1, emer2, emer3; - INT32 timeout = 0; // keeps from getting stuck + INT32 emer[3], num[MAXHUNTEMERALDS], i, randomkey; + fixed_t x, y, z; - emer1 = emer2 = emer3 = 0; + for (i = 0; i < numhuntemeralds; i++) + num[i] = i; - //increment spawn numbers because zero is valid. - emer1 = (P_RandomKey(numhuntemeralds)) + 1; - while (timeout++ < 100) + for (i = 0; i < 3; i++) { - emer2 = (P_RandomKey(numhuntemeralds)) + 1; + // generate random index, shuffle afterwards + randomkey = P_RandomKey(numhuntemeralds--); + emer[i] = num[randomkey]; + num[randomkey] = num[numhuntemeralds]; + num[numhuntemeralds] = emer[i]; - if (emer2 != emer1) - break; + // spawn emerald + x = huntemeralds[emer[i]]->x<y<x<y<z<x<y<z<x<y<z<camsec = -1; ss->floorlightsec = ss->ceilinglightsec = -1; - ss->crumblestate = 0; + ss->crumblestate = CRUMBLE_NONE; ss->touching_thinglist = NULL; ss->linecount = 0; ss->lines = NULL; - ss->tagline = NULL; ss->ffloors = NULL; ss->attached = NULL; @@ -911,11 +1017,9 @@ static void P_InitializeSector(sector_t *ss) ss->preciplist = NULL; ss->touching_preciplist = NULL; -#ifdef ESLOPE ss->f_slope = NULL; ss->c_slope = NULL; ss->hasslope = false; -#endif ss->spawn_lightlevel = ss->lightlevel; @@ -980,9 +1084,7 @@ static void P_InitializeLinedef(line_t *ld) ld->splats = NULL; #endif ld->firsttag = ld->nexttag = -1; -#ifdef POLYOBJECTS ld->polyobj = NULL; -#endif ld->text = NULL; ld->callcount = 0; @@ -1187,10 +1289,14 @@ static void P_LoadSidedefs(UINT8 *data) case 9: // Mace parameters case 14: // Bustable block parameters case 15: // Fan particle spawner parameters + case 334: // Trigger linedef executor: Object dye - Continuous + case 335: // Trigger linedef executor: Object dye - Each time + case 336: // Trigger linedef executor: Object dye - Once case 425: // Calls P_SetMobjState on calling mobj case 434: // Custom Power case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors case 461: // Spawns an object on the map based on texture offsets + case 463: // Colorizes an object { char process[8*3+1]; memset(process,0,8*3+1); @@ -1892,10 +1998,8 @@ static void P_InitializeSeg(seg_t *seg) seg->numlights = 0; seg->rlights = NULL; -#ifdef POLYOBJECTS seg->polyseg = NULL; seg->dontrenderme = false; -#endif } static void P_LoadSegs(UINT8 *data) @@ -2258,11 +2362,9 @@ static boolean P_LoadBlockMap(UINT8 *data, size_t count) blocklinks = Z_Calloc(count, PU_LEVEL, NULL); blockmap = blockmaplump+4; -#ifdef POLYOBJECTS // haleyjd 2/22/06: setup polyobject blockmap count = sizeof(*polyblocklinks) * bmapwidth * bmapheight; polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL); -#endif return true; } @@ -2513,11 +2615,9 @@ static void P_CreateBlockMap(void) blocklinks = Z_Calloc(count, PU_LEVEL, NULL); blockmap = blockmaplump + 4; -#ifdef POLYOBJECTS // haleyjd 2/22/06: setup polyobject blockmap count = sizeof(*polyblocklinks) * bmapwidth * bmapheight; polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL); -#endif } } @@ -3096,7 +3196,7 @@ static void P_InitTagGametype(void) //Also, you'd never have to loop through all 32 players slots to find anything ever again. for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && !(players[i].spectator && players[i].quittime)) + if (playeringame[i] && !(players[i].spectator || players[i].quittime)) { playersactive[realnumplayers] = i; //stores the player's node in the array. realnumplayers++; @@ -3197,21 +3297,6 @@ static void P_InitCamera(void) } } -static boolean CanSaveLevel(INT32 mapnum) -{ - if (ultimatemode) // never save in ultimate (probably redundant with cursaveslot also being checked) - return false; - - if (G_IsSpecialStage(mapnum) // don't save in special stages - || mapnum == lastmaploaded) // don't save if the last map loaded was this one - return false; - - // Any levels that have the savegame flag can save normally. - // If the game is complete for this save slot, then any level can save! - // On the other side of the spectrum, if lastmaploaded is 0, then the save file has only just been created and needs to save ASAP! - return (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME || gamecomplete || !lastmaploaded); -} - static void P_RunSpecialStageWipe(void) { tic_t starttime = I_GetTime(); @@ -3374,7 +3459,7 @@ static void P_InitGametype(void) if (G_TagGametype()) P_InitTagGametype(); - else if (gametype == GT_RACE && server) + else if (((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) && server) CV_StealthSetValue(&cv_numlaps, (cv_basenumlaps.value) ? cv_basenumlaps.value @@ -3526,9 +3611,7 @@ boolean P_LoadLevel(boolean fromnetsave) // Close text prompt before freeing the old level F_EndTextPrompt(false, true); -#ifdef HAVE_BLUA LUA_InvalidateLevel(); -#endif for (ss = sectors; sectors+numsectors != ss; ss++) { @@ -3575,6 +3658,8 @@ boolean P_LoadLevel(boolean fromnetsave) P_ResetSpawnpoints(); + P_ResetWaypoints(); + P_MapStart(); if (!P_LoadMapFromFile()) @@ -3584,9 +3669,7 @@ boolean P_LoadLevel(boolean fromnetsave) // anything that P_SpawnSlopes/P_LoadThings needs to know P_InitSpecials(); -#ifdef ESLOPE P_SpawnSlopes(fromnetsave); -#endif P_SpawnMapThings(!fromnetsave); skyboxmo[0] = skyboxviewpnts[0]; @@ -3650,11 +3733,19 @@ boolean P_LoadLevel(boolean fromnetsave) P_RunCachedActions(); - if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || players[consoleplayer].lives <= 0) - && (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(gamemap)) - G_SaveGame((UINT32)cursaveslot); - - lastmaploaded = gamemap; // HAS to be set after saving!! + // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... + if (!titlemapinaction) + { + if (!lastmaploaded) // Start a new game? + { + // I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020 + if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) + && (!modifiedgame || savemoddata) && cursaveslot > 0) + G_SaveGame((UINT32)cursaveslot, gamemap); + // If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted. + } + lastmaploaded = gamemap; // HAS to be set after saving!! + } if (!fromnetsave) // uglier hack { // to make a newly loaded level start on the second frame. @@ -3665,9 +3756,7 @@ boolean P_LoadLevel(boolean fromnetsave) G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); } P_PreTicker(2); -#ifdef HAVE_BLUA LUAh_MapLoad(); -#endif } // No render mode, stop here. @@ -3786,12 +3875,12 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l { UINT16 numlumps = *pnumlumps; size_t i = *pi; - if (!stricmp(lumpinfo->name2, folName)) + if (!stricmp(lumpinfo->fullname, folName)) { lumpinfo++; *start = ++i; for (; i < numlumps; i++, lumpinfo++) - if (strnicmp(lumpinfo->name2, folName, strlen(folName))) + if (strnicmp(lumpinfo->fullname, folName, strlen(folName))) break; lumpinfo--; *end = i-- - *start; @@ -3859,10 +3948,8 @@ boolean P_AddWadFile(const char *wadfilename) // Update the detected resources. // Note: ALWAYS load Lua scripts first, SOCs right after, and the remaining resources afterwards. -#ifdef HAVE_BLUA // if (luaNum) // Lua scripts. // P_LoadLuaScrRange(wadnum, luaPos, luaNum); -#endif // if (socNum) // SOCs. // P_LoadDehackRange(wadnum, socPos, socNum); if (sfxNum) // Sounds. TODO: Function currently only updates already existing sounds, the rest is handled somewhere else. diff --git a/src/p_setup.h b/src/p_setup.h index d7e2d8861..e7150c0ae 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_sight.c b/src/p_sight.c index 07dfabbc1..2e1e49997 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -100,7 +100,6 @@ static fixed_t P_InterceptVector2(divline_t *v2, divline_t *v1) return frac; } -#ifdef POLYOBJECTS static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los) { size_t i; @@ -169,7 +168,6 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los) return true; } -#endif // // P_CrossSubsector @@ -180,9 +178,7 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) { seg_t *seg; INT32 count; -#ifdef POLYOBJECTS polyobj_t *po; // haleyjd 02/23/06 -#endif #ifdef RANGECHECK if (num >= numsubsectors) @@ -192,7 +188,6 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) // haleyjd 02/23/06: this assignment should be after the above check seg = segs + subsectors[num].firstline; -#ifdef POLYOBJECTS // haleyjd 02/23/06: check polyobject lines if ((po = subsectors[num].polyList)) { @@ -207,7 +202,6 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) po = (polyobj_t *)(po->link.next); } } -#endif for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines { @@ -218,9 +212,7 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) const vertex_t *v1,*v2; fixed_t frac; fixed_t frontf, backf, frontc, backc; -#ifdef ESLOPE fixed_t fracx, fracy; -#endif if (seg->glseg) continue; @@ -263,21 +255,14 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) front = seg->frontsector; back = seg->backsector; -#ifdef ESLOPE // calculate position at intercept fracx = los->strace.x + FixedMul(los->strace.dx, frac); fracy = los->strace.y + FixedMul(los->strace.dy, frac); // calculate sector heights - frontf = (front->f_slope) ? P_GetZAt(front->f_slope, fracx, fracy) : front->floorheight; - frontc = (front->c_slope) ? P_GetZAt(front->c_slope, fracx, fracy) : front->ceilingheight; - backf = (back->f_slope) ? P_GetZAt(back->f_slope, fracx, fracy) : back->floorheight; - backc = (back->c_slope) ? P_GetZAt(back->c_slope, fracx, fracy) : back->ceilingheight; -#else - frontf = front->floorheight; - frontc = front->ceilingheight; - backf = back->floorheight; - backc = back->ceilingheight; -#endif + frontf = P_GetSectorFloorZAt (front, fracx, fracy); + frontc = P_GetSectorCeilingZAt(front, fracx, fracy); + backf = P_GetSectorFloorZAt (back , fracx, fracy); + backc = P_GetSectorCeilingZAt(back , fracx, fracy); // crosses a two sided line // no wall to block sight with? if (frontf == backf && frontc == backc @@ -327,15 +312,10 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) continue; } -#ifdef ESLOPE - topz = (*rover->t_slope) ? P_GetZAt(*rover->t_slope, fracx, fracy) : *rover->topheight; - bottomz = (*rover->b_slope) ? P_GetZAt(*rover->b_slope, fracx, fracy) : *rover->bottomheight; -#else - topz = *rover->topheight; - bottomz = *rover->bottomheight; -#endif - topslope = FixedDiv(topz - los->sightzstart , frac); - bottomslope = FixedDiv(bottomz - los->sightzstart , frac); + topz = P_GetFFloorTopZAt (rover, fracx, fracy); + bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy); + topslope = FixedDiv( topz - los->sightzstart, frac); + bottomslope = FixedDiv(bottomz - los->sightzstart, frac); if (topslope >= los->topslope && bottomslope <= los->bottomslope) return false; // view completely blocked } @@ -348,15 +328,10 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) continue; } -#ifdef ESLOPE - topz = (*rover->t_slope) ? P_GetZAt(*rover->t_slope, fracx, fracy) : *rover->topheight; - bottomz = (*rover->b_slope) ? P_GetZAt(*rover->b_slope, fracx, fracy) : *rover->bottomheight; -#else - topz = *rover->topheight; - bottomz = *rover->bottomheight; -#endif - topslope = FixedDiv(topz - los->sightzstart , frac); - bottomslope = FixedDiv(bottomz - los->sightzstart , frac); + topz = P_GetFFloorTopZAt (rover, fracx, fracy); + bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy); + topslope = FixedDiv( topz - los->sightzstart, frac); + bottomslope = FixedDiv(bottomz - los->sightzstart, frac); if (topslope >= los->topslope && bottomslope <= los->bottomslope) return false; // view completely blocked } @@ -432,15 +407,10 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) // killough 11/98: shortcut for melee situations // same subsector? obviously visible -#ifndef POLYOBJECTS - if (t1->subsector == t2->subsector) - return true; -#else // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec if (!t1->subsector->polyList && t1->subsector == t2->subsector) return true; -#endif // An unobstructed LOS is possible. // Now look from eyes of t1 to any part of t2. @@ -487,26 +457,10 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) continue; } -#ifdef ESLOPE - if (*rover->t_slope) - { - topz1 = P_GetZAt(*rover->t_slope, t1->x, t1->y); - topz2 = P_GetZAt(*rover->t_slope, t2->x, t2->y); - } - else - topz1 = topz2 = *rover->topheight; - - if (*rover->b_slope) - { - bottomz1 = P_GetZAt(*rover->b_slope, t1->x, t1->y); - bottomz2 = P_GetZAt(*rover->b_slope, t2->x, t2->y); - } - else - bottomz1 = bottomz2 = *rover->bottomheight; -#else - topz1 = topz2 = *rover->topheight; - bottomz1 = bottomz2 = *rover->bottomheight; -#endif + topz1 = P_GetFFloorTopZAt (rover, t1->x, t1->y); + topz2 = P_GetFFloorTopZAt (rover, t2->x, t2->y); + bottomz1 = P_GetFFloorBottomZAt(rover, t1->x, t1->y); + bottomz2 = P_GetFFloorBottomZAt(rover, t2->x, t2->y); // Check for blocking floors here. if ((los.sightzstart < bottomz1 && t2->z >= topz2) @@ -519,7 +473,7 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) if (rover->flags & FF_SOLID) continue; // shortcut since neither mobj can be inside the 3dfloor - if (!(rover->flags & FF_INVERTPLANES)) + if (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES)) { if (los.sightzstart >= topz1 && t2->z + t2->height < topz2) return false; // blocked by upper outside plane @@ -528,7 +482,7 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) return false; // blocked by lower outside plane } - if (rover->flags & FF_INVERTPLANES || rover->flags & FF_BOTHPLANES) + if (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES) { if (los.sightzstart < topz1 && t2->z >= topz2) return false; // blocked by upper inside plane diff --git a/src/p_slopes.c b/src/p_slopes.c index 6d5930882..6aeb1b025 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2004 by Stephen McGranahan -// Copyright (C) 2015-2019 by Sonic Team Junior. +// Copyright (C) 2015-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -23,8 +23,6 @@ #include "p_maputl.h" #include "w_wad.h" -#ifdef ESLOPE - pslope_t *slopelist = NULL; UINT16 slopecount = 0; @@ -568,7 +566,7 @@ void P_CopySectorSlope(line_t *line) int i, special = line->special; // Check for copy linedefs - for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) + for (i = -1; (i = P_FindSectorFromTag(line->tag, i)) >= 0;) { sector_t *srcsec = sectors + i; @@ -657,17 +655,49 @@ void P_SpawnSlopes(const boolean fromsave) { // Various utilities related to slopes // -// -// P_GetZAt -// // Returns the height of the sloped plane at (x, y) as a fixed_t -// -fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y) +fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y) { - fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) + - FixedMul(y - slope->o.y, slope->d.y); + fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) + + FixedMul(y - slope->o.y, slope->d.y); - return slope->o.z + FixedMul(dist, slope->zdelta); + return slope->o.z + FixedMul(dist, slope->zdelta); +} + +// Like P_GetSlopeZAt but falls back to z if slope is NULL +fixed_t P_GetZAt(const pslope_t *slope, fixed_t x, fixed_t y, fixed_t z) +{ + return slope ? P_GetSlopeZAt(slope, x, y) : z; +} + +// Returns the height of the sector floor at (x, y) +fixed_t P_GetSectorFloorZAt(const sector_t *sector, fixed_t x, fixed_t y) +{ + return sector->f_slope ? P_GetSlopeZAt(sector->f_slope, x, y) : sector->floorheight; +} + +// Returns the height of the sector ceiling at (x, y) +fixed_t P_GetSectorCeilingZAt(const sector_t *sector, fixed_t x, fixed_t y) +{ + return sector->c_slope ? P_GetSlopeZAt(sector->c_slope, x, y) : sector->ceilingheight; +} + +// Returns the height of the FOF top at (x, y) +fixed_t P_GetFFloorTopZAt(const ffloor_t *ffloor, fixed_t x, fixed_t y) +{ + return *ffloor->t_slope ? P_GetSlopeZAt(*ffloor->t_slope, x, y) : *ffloor->topheight; +} + +// Returns the height of the FOF bottom at (x, y) +fixed_t P_GetFFloorBottomZAt(const ffloor_t *ffloor, fixed_t x, fixed_t y) +{ + return *ffloor->b_slope ? P_GetSlopeZAt(*ffloor->b_slope, x, y) : *ffloor->bottomheight; +} + +// Returns the height of the light list at (x, y) +fixed_t P_GetLightZAt(const lightlist_t *light, fixed_t x, fixed_t y) +{ + return light->slope ? P_GetSlopeZAt(light->slope, x, y) : light->height; } @@ -844,6 +874,3 @@ void P_ButteredSlope(mobj_t *mo) P_Thrust(mo, mo->standingslope->xydirection, thrust); } - -// EOF -#endif // #ifdef ESLOPE diff --git a/src/p_slopes.h b/src/p_slopes.h index 0bf03f26d..06d900b66 100644 --- a/src/p_slopes.h +++ b/src/p_slopes.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2004 by Stephen McGranahan -// Copyright (C) 2015-2019 by Sonic Team Junior. +// Copyright (C) 2015-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,8 +15,6 @@ #include "m_fixed.h" // Vectors -#ifdef ESLOPE - extern pslope_t *slopelist; extern UINT16 slopecount; @@ -35,7 +33,21 @@ void P_CopySectorSlope(line_t *line); pslope_t *P_SlopeById(UINT16 id); // Returns the height of the sloped plane at (x, y) as a fixed_t -fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y); +fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y); + +// Like P_GetSlopeZAt but falls back to z if slope is NULL +fixed_t P_GetZAt(const pslope_t *slope, fixed_t x, fixed_t y, fixed_t z); + +// Returns the height of the sector at (x, y) +fixed_t P_GetSectorFloorZAt (const sector_t *sector, fixed_t x, fixed_t y); +fixed_t P_GetSectorCeilingZAt(const sector_t *sector, fixed_t x, fixed_t y); + +// Returns the height of the FOF at (x, y) +fixed_t P_GetFFloorTopZAt (const ffloor_t *ffloor, fixed_t x, fixed_t y); +fixed_t P_GetFFloorBottomZAt(const ffloor_t *ffloor, fixed_t x, fixed_t y); + +// Returns the height of the light list at (x, y) +fixed_t P_GetLightZAt(const lightlist_t *light, fixed_t x, fixed_t y); // Lots of physics-based bullshit void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope); @@ -74,5 +86,4 @@ typedef struct void T_DynamicSlopeLine (dynplanethink_t* th); void T_DynamicSlopeVert (dynplanethink_t* th); -#endif // #ifdef ESLOPE #endif // #ifndef P_SLOPES_H__ diff --git a/src/p_spec.c b/src/p_spec.c index 28d48d5d8..499efd899 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -36,7 +36,7 @@ #include "m_cond.h" //unlock triggers #include "lua_hook.h" // LUAh_LinedefExecute #include "f_finale.h" // control text prompt -#include "r_things.h" // skins +#include "r_skins.h" // skins #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -114,12 +114,11 @@ static void P_ResetColormapFader(sector_t *sector); static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, extracolormap_t *dest_exc, boolean ticbased, INT32 duration); static void P_AddBlockThinker(sector_t *sec, line_t *sourceline); -static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline); +static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline); //static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec); static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers); static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec); static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer); -static void P_AddSpikeThinker(sector_t *sec, INT32 referrer); static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee, UINT8 reverse); @@ -988,42 +987,12 @@ static sector_t *P_FindModelCeilingSector(fixed_t ceildestheight, INT32 secnum) } #endif -/** Searches the tag lists for the next sector tagged to a line. - * - * \param line Tagged line used as a reference. - * \param start -1 to start at the beginning, or the result of a previous call - * to keep searching. - * \return Number of the next tagged sector found. - * \sa P_FindSectorFromTag, P_FindLineFromLineTag - */ -INT32 P_FindSectorFromLineTag(line_t *line, INT32 start) -{ - if (line->tag == -1) - { - start++; - - if (start >= (INT32)numsectors) - return -1; - - return start; - } - else - { - start = start >= 0 ? sectors[start].nexttag : - sectors[(unsigned)line->tag % numsectors].firsttag; - while (start >= 0 && sectors[start].tag != line->tag) - start = sectors[start].nexttag; - return start; - } -} - /** Searches the tag lists for the next sector with a given tag. * * \param tag Tag number to look for. * \param start -1 to start anew, or the result of a previous call to keep * searching. * \return Number of the next tagged sector found. - * \sa P_FindSectorFromLineTag */ INT32 P_FindSectorFromTag(INT16 tag, INT32 start) { @@ -1046,42 +1015,12 @@ INT32 P_FindSectorFromTag(INT16 tag, INT32 start) } } -/** Searches the tag lists for the next line tagged to a line. - * - * \param line Tagged line used as a reference. - * \param start -1 to start anew, or the result of a previous call to keep - * searching. - * \return Number of the next tagged line found. - * \sa P_FindSectorFromLineTag - */ -static INT32 P_FindLineFromLineTag(const line_t *line, INT32 start) -{ - if (line->tag == -1) - { - start++; - - if (start >= (INT32)numlines) - return -1; - - return start; - } - else - { - start = start >= 0 ? lines[start].nexttag : - lines[(unsigned)line->tag % numlines].firsttag; - while (start >= 0 && lines[start].tag != line->tag) - start = lines[start].nexttag; - return start; - } -} -#if 0 /** Searches the tag lists for the next line with a given tag and special. * * \param tag Tag number. * \param start -1 to start anew, or the result of a previous call to keep * searching. * \return Number of next suitable line found. - * \sa P_FindLineFromLineTag * \author Graue */ static INT32 P_FindLineFromTag(INT32 tag, INT32 start) @@ -1090,7 +1029,7 @@ static INT32 P_FindLineFromTag(INT32 tag, INT32 start) { start++; - if (start >= numlines) + if (start >= (INT32)numlines) return -1; return start; @@ -1104,10 +1043,7 @@ static INT32 P_FindLineFromTag(INT32 tag, INT32 start) return start; } } -#endif -// -// P_FindSpecialLineFromTag -// + INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) { if (tag == -1) @@ -1137,14 +1073,8 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) } } -// haleyjd: temporary define -#ifdef POLYOBJECTS -// -// PolyDoor -// // Parses arguments for parameterized polyobject door types -// static boolean PolyDoor(line_t *line) { polydoordata_t pdd; @@ -1181,11 +1111,7 @@ static boolean PolyDoor(line_t *line) return EV_DoPolyDoor(&pdd); } -// -// PolyMove -// // Parses arguments for parameterized polyobject move specials -// static boolean PolyMove(line_t *line) { polymovedata_t pmd; @@ -1200,12 +1126,8 @@ static boolean PolyMove(line_t *line) return EV_DoPolyObjMove(&pmd); } -// -// PolyInvisible -// // Makes a polyobject invisible and intangible // If NOCLIMB is ticked, the polyobject will still be tangible, just not visible. -// static void PolyInvisible(line_t *line) { INT32 polyObjNum = line->tag; @@ -1228,12 +1150,8 @@ static void PolyInvisible(line_t *line) po->flags &= ~POF_RENDERALL; } -// -// PolyVisible -// // Makes a polyobject visible and tangible // If NOCLIMB is ticked, the polyobject will not be tangible, just visible. -// static void PolyVisible(line_t *line) { INT32 polyObjNum = line->tag; @@ -1256,16 +1174,14 @@ static void PolyVisible(line_t *line) po->flags |= (po->spawnflags & POF_RENDERALL); } -// -// PolyTranslucency -// + // Sets the translucency of a polyobject // Frontsector floor / 100 = translevel -// static void PolyTranslucency(line_t *line) { INT32 polyObjNum = line->tag; polyobj_t *po; + INT32 value; if (!(po = Polyobj_GetForNum(polyObjNum))) { @@ -1277,37 +1193,28 @@ static void PolyTranslucency(line_t *line) if (po->isBad) return; - // if DONTPEGBOTTOM, specify raw translucency value in Front X Offset - // else, take it out of 1000. If Front X Offset is specified, use that. Else, use floorheight. + // If Front X Offset is specified, use that. Else, use floorheight. + value = (sides[line->sidenum[0]].textureoffset ? sides[line->sidenum[0]].textureoffset : line->frontsector->floorheight) >> FRACBITS; + + // If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000. + if (!(line->flags & ML_DONTPEGBOTTOM)) + value /= 100; + if (line->flags & ML_EFFECT3) // relative calc - po->translucency = max(min(po->translucency + ((line->flags & ML_DONTPEGBOTTOM) ? - (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS) - : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS)) - : (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), -1000) / 100 - : max(min(line->frontsector->floorheight>>FRACBITS, 1000), -1000) / 100)), - NUMTRANSMAPS), 0); + po->translucency += value; else - po->translucency = (line->flags & ML_DONTPEGBOTTOM) ? - (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), 0) - : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), 0)) - : (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), 0) / 100 - : max(min(line->frontsector->floorheight>>FRACBITS, 1000), 0) / 100); + po->translucency = value; + + po->translucency = max(min(po->translucency, NUMTRANSMAPS), 0); } -// -// PolyFade -// // Makes a polyobject translucency fade and applies tangibility -// static boolean PolyFade(line_t *line) { INT32 polyObjNum = line->tag; polyobj_t *po; polyfadedata_t pfd; + INT32 value; if (!(po = Polyobj_GetForNum(polyObjNum))) { @@ -1330,25 +1237,19 @@ static boolean PolyFade(line_t *line) pfd.polyObjNum = polyObjNum; - // if DONTPEGBOTTOM, specify raw translucency value in Front X Offset - // else, take it out of 1000. If Front X Offset is specified, use that. Else, use floorheight. + // If Front X Offset is specified, use that. Else, use floorheight. + value = (sides[line->sidenum[0]].textureoffset ? sides[line->sidenum[0]].textureoffset : line->frontsector->floorheight) >> FRACBITS; + + // If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000. + if (!(line->flags & ML_DONTPEGBOTTOM)) + value /= 100; + if (line->flags & ML_EFFECT3) // relative calc - pfd.destvalue = max(min(po->translucency + ((line->flags & ML_DONTPEGBOTTOM) ? - (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS) - : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS)) - : (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), -1000) / 100 - : max(min(line->frontsector->floorheight>>FRACBITS, 1000), -1000) / 100)), - NUMTRANSMAPS), 0); + pfd.destvalue = po->translucency + value; else - pfd.destvalue = (line->flags & ML_DONTPEGBOTTOM) ? - (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), 0) - : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), 0)) - : (sides[line->sidenum[0]].textureoffset ? - max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), 0) / 100 - : max(min(line->frontsector->floorheight>>FRACBITS, 1000), 0) / 100); + pfd.destvalue = value; + + pfd.destvalue = max(min(pfd.destvalue, NUMTRANSMAPS), 0); // already equal, nothing to do if (po->translucency == pfd.destvalue) @@ -1367,11 +1268,7 @@ static boolean PolyFade(line_t *line) return EV_DoPolyObjFade(&pfd); } -// -// PolyWaypoint -// // Parses arguments for parameterized polyobject waypoint movement -// static boolean PolyWaypoint(line_t *line) { polywaypointdata_t pwd; @@ -1379,19 +1276,26 @@ static boolean PolyWaypoint(line_t *line) pwd.polyObjNum = line->tag; pwd.speed = sides[line->sidenum[0]].textureoffset / 8; pwd.sequence = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Sequence # - pwd.reverse = (line->flags & ML_EFFECT1) == ML_EFFECT1; // Reverse? - pwd.comeback = (line->flags & ML_EFFECT2) == ML_EFFECT2; // Return when reaching end? - pwd.wrap = (line->flags & ML_EFFECT3) == ML_EFFECT3; // Wrap around waypoints - pwd.continuous = (line->flags & ML_EFFECT4) == ML_EFFECT4; // Continuously move - used with COMEBACK or WRAP + + // Behavior after reaching the last waypoint? + if (line->flags & ML_EFFECT3) + pwd.returnbehavior = PWR_WRAP; // Wrap back to first waypoint + else if (line->flags & ML_EFFECT2) + pwd.returnbehavior = PWR_COMEBACK; // Go through sequence in reverse + else + pwd.returnbehavior = PWR_STOP; // Stop + + // Flags + pwd.flags = 0; + if (line->flags & ML_EFFECT1) + pwd.flags |= PWF_REVERSE; + if (line->flags & ML_EFFECT4) + pwd.flags |= PWF_LOOP; return EV_DoPolyObjWaypoint(&pwd); } -// -// PolyRotate -// // Parses arguments for parameterized polyobject rotate specials -// static boolean PolyRotate(line_t *line) { polyrotdata_t prd; @@ -1416,11 +1320,20 @@ static boolean PolyRotate(line_t *line) return EV_DoPolyObjRotate(&prd); } -// -// PolyDisplace -// +// Parses arguments for polyobject flag waving special +static boolean PolyFlag(line_t *line) +{ + polyflagdata_t pfd; + + pfd.polyObjNum = line->tag; + pfd.speed = P_AproxDistance(line->dx, line->dy) >> FRACBITS; + pfd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y) >> ANGLETOFINESHIFT; + pfd.momx = sides[line->sidenum[0]].textureoffset >> FRACBITS; + + return EV_DoPolyObjFlag(&pfd); +} + // Parses arguments for parameterized polyobject move-by-sector-heights specials -// static boolean PolyDisplace(line_t *line) { polydisplacedata_t pdd; @@ -1435,8 +1348,7 @@ static boolean PolyDisplace(line_t *line) } -/** Similar to PolyDisplace(). - */ +// Parses arguments for parameterized polyobject rotate-by-sector-heights specials static boolean PolyRotDisplace(line_t *line) { polyrotdisplacedata_t pdd; @@ -1462,8 +1374,6 @@ static boolean PolyRotDisplace(line_t *line) return EV_DoPolyObjRotDisplace(&pdd); } -#endif // ifdef POLYOBJECTS - /** Changes a sector's tag. * Used by the linedef executor tag changer and by crumblers. * @@ -2034,6 +1944,17 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!(actor && actor->player && ((stricmp(triggerline->text, skins[actor->player->skin].name) == 0) ^ ((triggerline->flags & ML_NOCLIMB) == ML_NOCLIMB)))) return false; break; + case 334: // object dye - continuous + case 335: // object dye - each time + case 336: // object dye - once + { + INT32 triggercolor = (INT32)sides[triggerline->sidenum[0]].toptexture; + UINT8 color = (actor->player ? actor->player->powers[pw_dye] : actor->color); + boolean invert = (triggerline->flags & ML_NOCLIMB ? true : false); + + if (invert ^ (triggercolor != color)) + return false; + } default: break; } @@ -2167,6 +2088,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller || specialtype == 328 // Nights lap - Once || specialtype == 330 // Nights Bonus Time - Once || specialtype == 333 // Skin - Once + || specialtype == 336 // Dye - Once || specialtype == 399) // Level Load triggerline->special = 0; // Clear it out @@ -2208,7 +2130,8 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) || lines[masterline].special == 310 // CTF Red team - Each time || lines[masterline].special == 312 // CTF Blue team - Each time || lines[masterline].special == 322 // Trigger on X calls - Each Time - || lines[masterline].special == 332)// Skin - Each time + || lines[masterline].special == 332 // Skin - Each time + || lines[masterline].special == 335)// Dye - Each time continue; if (lines[masterline].special < 300 @@ -2488,7 +2411,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) newceilinglightsec = line->frontsector->ceilinglightsec; // act on all sectors with the same tag as the triggering linedef - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { if (sectors[secnum].lightingdata) { @@ -2543,7 +2466,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 409: // Change tagged sectors' tag // (formerly "Change calling sectors' tag", but behavior was changed) { - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) P_ChangeSectorTag(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; } @@ -2553,7 +2476,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 411: // Stop floor/ceiling movement in tagged sector(s) - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { if (sectors[secnum].floordata) { @@ -2623,7 +2546,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } else { - if ((secnum = P_FindSectorFromLineTag(line, -1)) < 0) + if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) return; dest = P_GetObjectTypeInSectorNum(MT_TELEPORTMAN, secnum); @@ -2738,7 +2661,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Additionally play the sound from tagged sectors' soundorgs sector_t *sec; - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { sec = §ors[secnum]; S_StartSound(&sec->soundorg, sfxnum); @@ -2853,7 +2776,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 416: // Spawn adjustable fire flicker - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2887,7 +2810,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 417: // Spawn adjustable glowing light - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2921,7 +2844,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 418: // Spawn adjustable strobe flash (unsynchronized) - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2955,7 +2878,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 419: // Spawn adjustable strobe flash (synchronized) - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -3003,7 +2926,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 421: // Stop lighting effect in tagged sectors - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) if (sectors[secnum].lightingdata) { P_RemoveThinker(&((elevator_t *)sectors[secnum].lightingdata)->thinker); @@ -3018,7 +2941,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens return; - if ((secnum = P_FindSectorFromLineTag(line, -1)) < 0) + if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) return; altview = P_GetObjectTypeInSectorNum(MT_ALTVIEWMAN, secnum); @@ -3337,7 +3260,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->sidenum[1] != 0xffff) state = (statenum_t)sides[line->sidenum[1]].toptexture; - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) { boolean tryagain; sec = sectors + secnum; @@ -3366,14 +3289,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } case 443: // Calls a named Lua function -#ifdef HAVE_BLUA if (line->text) LUAh_LinedefExecute(line, mo, callsec); else CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(line-lines)); -#else - CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n"); -#endif break; case 444: // Earthquake camera @@ -3496,7 +3415,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Except it is activated by linedef executor, not level load // This could even override existing colormaps I believe // -- Monster Iestyn 14/06/18 - for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;) + for (secnum = -1; (secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0 ;) { P_ResetColormapFader(§ors[secnum]); @@ -3824,7 +3743,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } case 455: // Fade colormap - for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;) + for (secnum = -1; (secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0 ;) { extracolormap_t *source_exc, *dest_exc, *exc; INT32 speed = (INT32)((line->flags & ML_DONTPEGBOTTOM) || !sides[line->sidenum[0]].rowoffset) && line->sidenum[1] != 0xFFFF ? @@ -3913,7 +3832,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 456: // Stop fade colormap - for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;) + for (secnum = -1; (secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0 ;) P_ResetColormapFader(§ors[secnum]); break; @@ -3927,7 +3846,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean persist = (line->flags & ML_EFFECT2); mobj_t *anchormo; - if ((secnum = P_FindSectorFromLineTag(line, -1)) < 0) + if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) return; anchormo = P_GetObjectTypeInSectorNum(MT_ANGLEMAN, secnum); @@ -4018,7 +3937,11 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) mobj = P_SpawnMobj(x, y, z, type); if (mobj) + { + if (line->flags & ML_EFFECT1) + mobj->angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); CONS_Debug(DBG_GAMELOGIC, "Linedef Type %d - Spawn Object: %d spawned at (%d, %d, %d)\n", line->special, mobj->type, mobj->x>>FRACBITS, mobj->y>>FRACBITS, mobj->z>>FRACBITS); //TODO: Convert mobj->type to a string somehow. + } else CONS_Alert(CONS_ERROR,"Linedef Type %d - Spawn Object: Object did not spawn!\n", line->special); } @@ -4042,7 +3965,63 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; -#ifdef POLYOBJECTS + case 463: // Dye object + { + INT32 color = sides[line->sidenum[0]].toptexture; + + if (mo) + { + if (color < 0 || color >= numskincolors) + return; + + var1 = 0; + var2 = color; + A_Dye(mo); + } + } + break; + + case 464: // Trigger Egg Capsule + { + thinker_t *th; + mobj_t *mo2; + + // Find the center of the Eggtrap and release all the pretty animals! + // The chimps are my friends.. heeheeheheehehee..... - LouisJM + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_EGGTRAP) + continue; + + if (!mo2->spawnpoint) + continue; + + if (mo2->spawnpoint->angle != line->tag) + continue; + + P_KillMobj(mo2, NULL, mo, 0); + } + + if (!(line->flags & ML_NOCLIMB)) + { + INT32 i; + + // Mark all players with the time to exit thingy! + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + P_DoPlayerExit(&players[i]); + } + } + } + break; + case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing PolyDoor(line); @@ -4072,7 +4051,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 492: PolyFade(line); break; -#endif default: break; @@ -4100,7 +4078,7 @@ void P_SetupSignExit(player_t *player) if (!numfound && !(player->mo->target && player->mo->target->type == MT_SIGN) - && !(gametype == GT_COOP && (netgame || multiplayer) && cv_exitmove.value)) + && !((gametyperules & GTR_FRIENDLY) && (netgame || multiplayer) && cv_exitmove.value)) P_SetTarget(&player->mo->target, thing); if (thing->state != &states[thing->info->spawnstate]) @@ -4131,7 +4109,7 @@ void P_SetupSignExit(player_t *player) if (!numfound && !(player->mo->target && player->mo->target->type == MT_SIGN) - && !(gametype == GT_COOP && (netgame || multiplayer) && cv_exitmove.value)) + && !((gametyperules & GTR_FRIENDLY) && (netgame || multiplayer) && cv_exitmove.value)) P_SetTarget(&player->mo->target, thing); if (thing->state != &states[thing->info->spawnstate]) @@ -4421,7 +4399,8 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers P_DamageMobj(player->mo, NULL, NULL, 1, DMG_ELECTRIC); break; case 5: // Spikes - // Don't do anything. In Soviet Russia, spikes find you. + if (roversector || P_MobjReadyToTrigger(player->mo, sector)) + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_SPIKE); break; case 6: // Death Pit (Camera Mod) case 7: // Death Pit (No Camera Mod) @@ -4486,7 +4465,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers continue; if (players[i].bot) continue; - if (gametype == GT_COOP && players[i].lives <= 0) + if (G_CoopGametype() && players[i].lives <= 0) continue; if (roversector) { @@ -4623,12 +4602,7 @@ DoneSection2: player->mo->angle = player->drawangle = lineangle; if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - { - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - } + P_SetPlayerAngle(player, player->mo->angle); if (!(lines[i].flags & ML_EFFECT4)) { @@ -4717,7 +4691,7 @@ DoneSection2: // FOF custom exits not to work. lineindex = P_FindSpecialLineFromTag(2, sector->tag, -1); - if (gametype == GT_COOP && lineindex != -1) // Custom exit! + if (G_CoopGametype() && lineindex != -1) // Custom exit! { // Special goodies with the block monsters flag depending on emeralds collected if ((lines[lineindex].flags & ML_BLOCKMONSTERS) && ALL7EMERALDS(emeralds)) @@ -4831,9 +4805,7 @@ DoneSection2: INT32 sequence; fixed_t speed; INT32 lineindex; - thinker_t *th; mobj_t *waypoint = NULL; - mobj_t *mo2; angle_t an; if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ZOOMTUBE) @@ -4858,25 +4830,7 @@ DoneSection2: break; } - // scan the thinkers - // to find the first waypoint - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - if (mo2->threshold != sequence) - continue; - if (mo2->health != 0) - continue; - - waypoint = mo2; - break; - } + waypoint = P_GetFirstWaypoint(sequence); if (!waypoint) { @@ -4913,9 +4867,7 @@ DoneSection2: INT32 sequence; fixed_t speed; INT32 lineindex; - thinker_t *th; mobj_t *waypoint = NULL; - mobj_t *mo2; angle_t an; if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ZOOMTUBE) @@ -4940,25 +4892,7 @@ DoneSection2: break; } - // scan the thinkers - // to find the last waypoint - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - if (mo2->threshold != sequence) - continue; - - if (!waypoint) - waypoint = mo2; - else if (mo2->health > waypoint->health) - waypoint = mo2; - } + waypoint = P_GetLastWaypoint(sequence); if (!waypoint) { @@ -4991,7 +4925,7 @@ DoneSection2: break; case 10: // Finish Line - if (gametype == GT_RACE && !player->exiting) + if (((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) && !player->exiting) { if (player->starpostnum == numstarposts) // Must have touched all the starposts { @@ -5040,14 +4974,11 @@ DoneSection2: INT32 sequence; fixed_t speed; INT32 lineindex; - thinker_t *th; mobj_t *waypointmid = NULL; mobj_t *waypointhigh = NULL; mobj_t *waypointlow = NULL; - mobj_t *mo2; mobj_t *closest = NULL; vector3_t p, line[2], resulthigh, resultlow; - mobj_t *highest = NULL; if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ROPEHANG) break; @@ -5093,98 +5024,16 @@ DoneSection2: // Determine the closest spot on the line between the three waypoints // Put player at that location. - // scan the thinkers - // to find the first waypoint - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + waypointmid = P_GetClosestWaypoint(sequence, player->mo); - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (!highest) - highest = mo2; - else if (mo2->health > highest->health) // Find the highest waypoint # in case we wrap - highest = mo2; - - if (closest && P_AproxDistance(P_AproxDistance(player->mo->x-mo2->x, player->mo->y-mo2->y), - player->mo->z-mo2->z) > P_AproxDistance(P_AproxDistance(player->mo->x-closest->x, - player->mo->y-closest->y), player->mo->z-closest->z)) - continue; - - // Found a target - closest = mo2; - } - - waypointmid = closest; - - closest = NULL; - - if (waypointmid == NULL) + if (!waypointmid) { CONS_Debug(DBG_GAMELOGIC, "ERROR: WAYPOINT(S) IN SEQUENCE %d NOT FOUND.\n", sequence); break; } - // Find waypoint before this one (waypointlow) - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (waypointmid->health == 0) - { - if (mo2->health != highest->health) - continue; - } - else if (mo2->health != waypointmid->health - 1) - continue; - - // Found a target - waypointlow = mo2; - break; - } - - // Find waypoint after this one (waypointhigh) - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (waypointmid->health == highest->health) - { - if (mo2->health != 0) - continue; - } - else if (mo2->health != waypointmid->health + 1) - continue; - - // Found a target - waypointhigh = mo2; - break; - } + waypointlow = P_GetPreviousWaypoint(waypointmid, true); + waypointhigh = P_GetNextWaypoint(waypointmid, true); CONS_Debug(DBG_GAMELOGIC, "WaypointMid: %d; WaypointLow: %d; WaypointHigh: %d\n", waypointmid->health, waypointlow ? waypointlow->health : -1, waypointhigh ? waypointhigh->health : -1); @@ -5231,6 +5080,7 @@ DoneSection2: if (lines[lineindex].flags & ML_EFFECT1) // Don't wrap { + mobj_t *highest = P_GetLastWaypoint(sequence); highest->flags |= MF_SLIDEME; } @@ -5242,7 +5092,7 @@ DoneSection2: player->mo->y = resulthigh.y; player->mo->z = resulthigh.z - P_GetPlayerHeight(player); } - else if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == highest->health) + else if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == numwaypoints[sequence] - 1) { closest = waypointmid; player->mo->x = resultlow.x; @@ -5649,6 +5499,35 @@ void P_UpdateSpecials(void) } } +// +// Floor over floors (FOFs), 3Dfloors, 3Dblocks, fake floors (ffloors), rovers, or whatever you want to call them +// + +/** Gets the ID number for a 3Dfloor in its target sector. + * + * \param fflr The 3Dfloor we want an ID for. + * \return ID of 3Dfloor in target sector. Note that the first FOF's ID is 0. UINT16_MAX is given if invalid. + * \sa P_GetFFloorByID + */ +UINT16 P_GetFFloorID(ffloor_t *fflr) +{ + ffloor_t *rover; + sector_t *sec; + UINT16 i = 0; + + if (!fflr) + return UINT16_MAX; + + sec = fflr->target; + + if (!sec->ffloors) + return UINT16_MAX; + for (rover = sec->ffloors; rover; rover = rover->next, i++) + if (rover == fflr) + return i; + return UINT16_MAX; +} + /** Gets a 3Dfloor by control sector. * * \param sec Target sector. @@ -5673,7 +5552,7 @@ static inline ffloor_t *P_GetFFloorBySec(sector_t *sec, sector_t *sec2) * \param sec Target sector. * \param id ID of 3Dfloor in target sector. Note that the first FOF's ID is 0. * \return Pointer to found 3Dfloor, or NULL. - * \sa P_GetFFloorBySec + * \sa P_GetFFloorBySec, P_GetFFloorID */ ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id) { @@ -5729,7 +5608,6 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f thinker_t *th; friction_t *f; pusher_t *p; - levelspecthink_t *lst; size_t sec2num; size_t i; @@ -5747,8 +5625,6 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f sec2->floorheight = tempceiling; } - sec2->tagline = master; - if (sec2->numattached == 0) { sec2->attached = Z_Malloc(sizeof (*sec2->attached) * sec2->maxattached, PU_STATIC, NULL); @@ -5792,7 +5668,6 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f fflr->topyoffs = &sec2->ceiling_yoffs; fflr->topangle = &sec2->ceilingpic_angle; -#ifdef ESLOPE // Add slopes fflr->t_slope = &sec2->c_slope; fflr->b_slope = &sec2->f_slope; @@ -5800,7 +5675,6 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f // (this fixes FOF slopes glitching initially at level load in software mode) if (sec2->hasslope) sec->hasslope = true; -#endif if ((flags & FF_SOLID) && (master->flags & ML_EFFECT1)) // Block player only flags &= ~FF_BLOCKOTHERS; @@ -5834,16 +5708,8 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f else if (th == &thlist[THINK_MAIN]) break; - // Should this FOF have spikeness? - if (th->function.acp1 == (actionf_p1)T_SpikeSector) - { - lst = (levelspecthink_t *)th; - - if (lst->sector == sec2) - P_AddSpikeThinker(sec, (INT32)sec2num); - } // Should this FOF have friction? - else if(th->function.acp1 == (actionf_p1)T_Friction) + if(th->function.acp1 == (actionf_p1)T_Friction) { f = (friction_t *)th; @@ -5890,7 +5756,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f } if ((flags & FF_CRUMBLE)) - sec2->crumblestate = 1; + sec2->crumblestate = CRUMBLE_WAIT; if ((flags & FF_FLOATBOB)) { @@ -5907,28 +5773,6 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f // SPECIAL SPAWNING // -/** Adds a spike thinker. - * Sector type Section1:5 will result in this effect. - * - * \param sec Sector in which to add the thinker. - * \param referrer If != sec, then we're dealing with a FOF - * \sa P_SpawnSpecials, T_SpikeSector - * \author SSNTails - */ -static void P_AddSpikeThinker(sector_t *sec, INT32 referrer) -{ - levelspecthink_t *spikes; - - // create and initialize new thinker - spikes = Z_Calloc(sizeof (*spikes), PU_LEVSPEC, NULL); - P_AddThinker(THINK_MAIN, &spikes->thinker); - - spikes->thinker.function.acp1 = (actionf_p1)T_SpikeSector; - - spikes->sector = sec; - spikes->vars[0] = referrer; -} - /** Adds a float thinker. * Float thinkers cause solid 3Dfloors to float on water. * @@ -5937,9 +5781,9 @@ static void P_AddSpikeThinker(sector_t *sec, INT32 referrer) * \sa P_SpawnSpecials, T_FloatSector * \author SSNTails */ -static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline) +static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline) { - levelspecthink_t *floater; + floatthink_t *floater; // create and initialize new thinker floater = Z_Calloc(sizeof (*floater), PU_LEVSPEC, NULL); @@ -5948,43 +5792,10 @@ static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline) floater->thinker.function.acp1 = (actionf_p1)T_FloatSector; floater->sector = sec; - floater->vars[0] = tag; + floater->tag = (INT16)tag; floater->sourceline = sourceline; } -/** Adds a bridge thinker. - * Bridge thinkers cause a group of FOFs to behave like - * a bridge made up of pieces, that bows under weight. - * - * \param sec Control sector. - * \sa P_SpawnSpecials, T_BridgeThinker - * \author SSNTails - */ -/* -static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec) -{ - levelspecthink_t *bridge; - - // create an initialize new thinker - bridge = Z_Calloc(sizeof (*bridge), PU_LEVSPEC, NULL); - P_AddThinker(THINK_MAIN, &bridge->thinker); - - bridge->thinker.function.acp1 = (actionf_p1)T_BridgeThinker; - - bridge->sector = sec; - bridge->vars[0] = sourceline->frontsector->floorheight; - bridge->vars[1] = sourceline->frontsector->ceilingheight; - bridge->vars[2] = P_AproxDistance(sourceline->dx, sourceline->dy); // Speed - bridge->vars[2] = FixedDiv(bridge->vars[2], 16*FRACUNIT); - bridge->vars[3] = bridge->vars[2]; - - // Start tag and end tag are TARGET SECTORS, not CONTROL SECTORS - // Control sector tags should be End_Tag + (End_Tag - Start_Tag) - bridge->vars[4] = sourceline->tag; // Start tag - bridge->vars[5] = (sides[sourceline->sidenum[0]].textureoffset>>FRACBITS); // End tag -} -*/ - /** * Adds a plane displacement thinker. * Whenever the "control" sector moves, @@ -6026,7 +5837,7 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, */ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline) { - levelspecthink_t *block; + mariocheck_t *block; // create and initialize new elevator thinker block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL); @@ -6047,109 +5858,67 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline) * there already. * * \param sec Control sector. - * \param actionsector Target sector. - * \param sourceline Control linedef. * \sa P_SpawnSpecials, T_RaiseSector * \author SSNTails */ -static void P_AddRaiseThinker(sector_t *sec, line_t *sourceline) +static void P_AddRaiseThinker(sector_t *sec, INT16 tag, fixed_t speed, fixed_t ceilingtop, fixed_t ceilingbottom, boolean lower, boolean spindash) { - levelspecthink_t *raise; + raise_t *raise; raise = Z_Calloc(sizeof (*raise), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &raise->thinker); raise->thinker.function.acp1 = (actionf_p1)T_RaiseSector; - if (sourceline->flags & ML_BLOCKMONSTERS) - raise->vars[0] = 1; - else - raise->vars[0] = 0; - - // set up the fields + raise->tag = tag; raise->sector = sec; - // Require a spindash to activate - if (sourceline->flags & ML_NOCLIMB) - raise->vars[1] = 1; - else - raise->vars[1] = 0; + raise->ceilingtop = ceilingtop; + raise->ceilingbottom = ceilingbottom; - raise->vars[2] = P_AproxDistance(sourceline->dx, sourceline->dy); - raise->vars[2] = FixedDiv(raise->vars[2], 4*FRACUNIT); - raise->vars[3] = raise->vars[2]; + raise->basespeed = speed; - raise->vars[5] = P_FindHighestCeilingSurrounding(sec); - raise->vars[4] = raise->vars[5] - - (sec->ceilingheight - sec->floorheight); - - raise->vars[7] = P_FindLowestCeilingSurrounding(sec); - raise->vars[6] = raise->vars[7] - - (sec->ceilingheight - sec->floorheight); - - raise->sourceline = sourceline; + if (lower) + raise->flags |= RF_REVERSE; + if (spindash) + raise->flags |= RF_SPINDASH; } -static void P_AddAirbob(sector_t *sec, line_t *sourceline, boolean noadjust, boolean dynamic) +static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, boolean spindash, boolean dynamic) { - levelspecthink_t *airbob; + raise_t *airbob; airbob = Z_Calloc(sizeof (*airbob), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &airbob->thinker); airbob->thinker.function.acp1 = (actionf_p1)T_RaiseSector; - // set up the fields + airbob->tag = tag; airbob->sector = sec; - // Require a spindash to activate - if (sourceline->flags & ML_NOCLIMB) - airbob->vars[1] = 1; - else - airbob->vars[1] = 0; + airbob->ceilingtop = sec->ceilingheight; + airbob->ceilingbottom = sec->ceilingheight - dist; - airbob->vars[2] = FRACUNIT; + airbob->basespeed = FRACUNIT; - if (noadjust) - airbob->vars[7] = airbob->sector->ceilingheight-16*FRACUNIT; - else - airbob->vars[7] = airbob->sector->ceilingheight - P_AproxDistance(sourceline->dx, sourceline->dy); - airbob->vars[6] = airbob->vars[7] - - (sec->ceilingheight - sec->floorheight); - - airbob->vars[3] = airbob->vars[2]; - - if (sourceline->flags & ML_BLOCKMONSTERS) - airbob->vars[0] = 1; - else - airbob->vars[0] = 0; - - airbob->vars[5] = sec->ceilingheight; - airbob->vars[4] = airbob->vars[5] - - (sec->ceilingheight - sec->floorheight); - - airbob->vars[9] = dynamic ? 1 : 0; - - airbob->sourceline = sourceline; + if (!raise) + airbob->flags |= RF_REVERSE; + if (spindash) + airbob->flags |= RF_SPINDASH; + if (dynamic) + airbob->flags |= RF_DYNAMIC; } /** Adds a thwomp thinker. * Even thwomps need to think! * * \param sec Control sector. - * \param actionsector Target sector. - * \param sourceline Control linedef. * \sa P_SpawnSpecials, T_ThwompSector * \author SSNTails */ -static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, line_t *sourceline) +static inline void P_AddThwompThinker(sector_t *sec, INT16 tag, line_t *sourceline, fixed_t crushspeed, fixed_t retractspeed, UINT16 sound) { -#define speed vars[1] -#define direction vars[2] -#define distance vars[3] -#define floorwasheight vars[4] -#define ceilingwasheight vars[5] - levelspecthink_t *thwomp; + thwomp_t *thwomp; // You *probably* already have a thwomp in this sector. If you've combined it with something // else that uses the floordata/ceilingdata, you must be weird. @@ -6163,34 +5932,33 @@ static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, lin thwomp->thinker.function.acp1 = (actionf_p1)T_ThwompSector; // set up the fields according to the type of elevator action - thwomp->sector = sec; - thwomp->vars[0] = actionsector->tag; - thwomp->floorwasheight = thwomp->sector->floorheight; - thwomp->ceilingwasheight = thwomp->sector->ceilingheight; - thwomp->direction = 0; - thwomp->distance = 1; thwomp->sourceline = sourceline; - thwomp->sector->floordata = thwomp; - thwomp->sector->ceilingdata = thwomp; - return; -#undef speed -#undef direction -#undef distance -#undef floorwasheight -#undef ceilingwasheight + thwomp->sector = sec; + thwomp->crushspeed = crushspeed; + thwomp->retractspeed = retractspeed; + thwomp->direction = 0; + thwomp->floorstartheight = sec->floorheight; + thwomp->ceilingstartheight = sec->ceilingheight; + thwomp->delay = 1; + thwomp->tag = tag; + thwomp->sound = sound; + + sec->floordata = thwomp; + sec->ceilingdata = thwomp; + // Start with 'resting' texture + sides[sourceline->sidenum[0]].midtexture = sides[sourceline->sidenum[0]].bottomtexture; } /** Adds a thinker which checks if any MF_ENEMY objects with health are in the defined area. * If not, a linedef executor is run once. * - * \param sec Control sector. * \param sourceline Control linedef. * \sa P_SpawnSpecials, T_NoEnemiesSector * \author SSNTails */ -static inline void P_AddNoEnemiesThinker(sector_t *sec, line_t *sourceline) +static inline void P_AddNoEnemiesThinker(line_t *sourceline) { - levelspecthink_t *nobaddies; + noenemies_t *nobaddies; // create and initialize new thinker nobaddies = Z_Calloc(sizeof (*nobaddies), PU_LEVSPEC, NULL); @@ -6198,21 +5966,19 @@ static inline void P_AddNoEnemiesThinker(sector_t *sec, line_t *sourceline) nobaddies->thinker.function.acp1 = (actionf_p1)T_NoEnemiesSector; - nobaddies->sector = sec; nobaddies->sourceline = sourceline; } /** Adds a thinker for Each-Time linedef executors. A linedef executor is run * only when a player enters the area and doesn't run again until they re-enter. * - * \param sec Control sector that contains the lines of executors we will want to run. * \param sourceline Control linedef. * \sa P_SpawnSpecials, T_EachTimeThinker * \author SSNTails */ -static void P_AddEachTimeThinker(sector_t *sec, line_t *sourceline) +static void P_AddEachTimeThinker(line_t *sourceline) { - levelspecthink_t *eachtime; + eachtime_t *eachtime; // create and initialize new thinker eachtime = Z_Calloc(sizeof (*eachtime), PU_LEVSPEC, NULL); @@ -6220,8 +5986,8 @@ static void P_AddEachTimeThinker(sector_t *sec, line_t *sourceline) eachtime->thinker.function.acp1 = (actionf_p1)T_EachTimeThinker; - eachtime->sector = sec; eachtime->sourceline = sourceline; + eachtime->triggerOnExit = !!(sourceline->flags & ML_BOUNCY); } /** Adds a camera scanner. @@ -6236,6 +6002,8 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto { elevator_t *elevator; // Why not? LOL + CONS_Alert(CONS_WARNING, M_GetText("Detected a camera scanner effect (linedef type 5). This effect is deprecated and will be removed in the future!\n")); + // create and initialize new elevator thinker elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &elevator->thinker); @@ -6249,98 +6017,85 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto elevator->distance = FixedInt(AngleFixed(angle)); } -static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT; - /** Flashes a laser block. * * \param flash Thinker structure for this laser. - * \sa EV_AddLaserThinker + * \sa P_AddLaserThinker * \author SSNTails */ void T_LaserFlash(laserthink_t *flash) { msecnode_t *node; mobj_t *thing; - sector_t *sourcesec; - ffloor_t *fflr = flash->ffloor; - sector_t *sector = flash->sector; + INT32 s; + ffloor_t *fflr; + sector_t *sector; + sector_t *sourcesec = flash->sourceline->frontsector; fixed_t top, bottom; - if (!fflr || !(fflr->flags & FF_EXISTS)) - return; - - if (leveltime & 2) - //fflr->flags |= FF_RENDERALL; - fflr->alpha = 0xB0; - else - //fflr->flags &= ~FF_RENDERALL; - fflr->alpha = 0x90; - - sourcesec = fflr->master->frontsector; // Less to type! - -#ifdef ESLOPE - top = (*fflr->t_slope) ? P_GetZAt(*fflr->t_slope, sector->soundorg.x, sector->soundorg.y) - : *fflr->topheight; - bottom = (*fflr->b_slope) ? P_GetZAt(*fflr->b_slope, sector->soundorg.x, sector->soundorg.y) - : *fflr->bottomheight; - sector->soundorg.z = (top + bottom)/2; -#else - sector->soundorg.z = (*fflr->topheight + *fflr->bottomheight)/2; -#endif - S_StartSound(§or->soundorg, sfx_laser); - - // Seek out objects to DESTROY! MUAHAHHAHAHAA!!!*cough* - for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_thinglist_next) + for (s = -1; (s = P_FindSectorFromTag(flash->tag, s)) >= 0 ;) { - thing = node->m_thing; + sector = §ors[s]; + for (fflr = sector->ffloors; fflr; fflr = fflr->next) + { + if (fflr->master != flash->sourceline) + continue; - if ((fflr->master->flags & ML_EFFECT1) - && thing->flags & MF_BOSS) - continue; // Don't hurt bosses + if (!(fflr->flags & FF_EXISTS)) + break; - // Don't endlessly kill egg guard shields (or anything else for that matter) - if (thing->health <= 0) - continue; + if (leveltime & 2) + //fflr->flags |= FF_RENDERALL; + fflr->alpha = 0xB0; + else + //fflr->flags &= ~FF_RENDERALL; + fflr->alpha = 0x90; - top = P_GetSpecialTopZ(thing, sourcesec, sector); - bottom = P_GetSpecialBottomZ(thing, sourcesec, sector); + top = P_GetFFloorTopZAt (fflr, sector->soundorg.x, sector->soundorg.y); + bottom = P_GetFFloorBottomZAt(fflr, sector->soundorg.x, sector->soundorg.y); + sector->soundorg.z = (top + bottom)/2; + S_StartSound(§or->soundorg, sfx_laser); - if (thing->z >= top - || thing->z + thing->height <= bottom) - continue; + // Seek out objects to DESTROY! MUAHAHHAHAHAA!!!*cough* + for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_thinglist_next) + { + thing = node->m_thing; - if (thing->flags & MF_SHOOTABLE) - P_DamageMobj(thing, NULL, NULL, 1, 0); - else if (thing->type == MT_EGGSHIELD) - P_KillMobj(thing, NULL, NULL, 0); + if (flash->nobosses && thing->flags & MF_BOSS) + continue; // Don't hurt bosses + + // Don't endlessly kill egg guard shields (or anything else for that matter) + if (thing->health <= 0) + continue; + + top = P_GetSpecialTopZ(thing, sourcesec, sector); + bottom = P_GetSpecialBottomZ(thing, sourcesec, sector); + + if (thing->z >= top + || thing->z + thing->height <= bottom) + continue; + + if (thing->flags & MF_SHOOTABLE) + P_DamageMobj(thing, NULL, NULL, 1, 0); + else if (thing->type == MT_EGGSHIELD) + P_KillMobj(thing, NULL, NULL, 0); + } + + break; + } } } -/** Adds a laser thinker to a 3Dfloor. - * - * \param fflr 3Dfloor to turn into a laser block. - * \param sector Target sector. - * \param secthkiners Lists of thinkers sorted by sector. May be NULL. - * \sa T_LaserFlash - * \author SSNTails - */ -static inline void EV_AddLaserThinker(sector_t *sec, sector_t *sec2, line_t *line, thinkerlist_t *secthinkers) +static inline void P_AddLaserThinker(INT16 tag, line_t *line, boolean nobosses) { - laserthink_t *flash; - ffloor_t *fflr = P_AddFakeFloor(sec, sec2, line, laserflags, secthinkers); - - if (!fflr) - return; - - flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL); + laserthink_t *flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &flash->thinker); flash->thinker.function.acp1 = (actionf_p1)T_LaserFlash; - flash->ffloor = fflr; - flash->sector = sec; // For finding mobjs - flash->sec = sec2; + flash->tag = tag; flash->sourceline = line; + flash->nobosses = nobosses; } // @@ -6370,11 +6125,11 @@ static void P_RunLevelLoadExecutors(void) void P_InitSpecials(void) { // Set the default gravity. Custom gravity overrides this setting. - gravity = FRACUNIT/2; + gravity = mapheaderinfo[gamemap-1]->gravity; // Defaults in case levels don't have them set. - sstimer = 90*TICRATE + 6; - ssspheres = 1; + sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6; + ssspheres = mapheaderinfo[gamemap-1]->ssspheres; CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; @@ -6452,9 +6207,11 @@ void P_SpawnSpecials(boolean fromnetsave) switch(GETSECSPECIAL(sector->special, 1)) { case 5: // Spikes - P_AddSpikeThinker(sector, (INT32)(sector-sectors)); + //Terrible hack to replace an even worse hack: + //Spike damage automatically sets SF_TRIGGERSPECIAL_TOUCH. + //Yes, this also affects other specials on the same sector. Sorry. + sector->flags |= SF_TRIGGERSPECIAL_TOUCH; break; - case 15: // Bouncy sector CheckForBouncySector = true; break; @@ -6483,7 +6240,7 @@ void P_SpawnSpecials(boolean fromnetsave) switch(GETSECSPECIAL(sector->special, 4)) { case 10: // Circuit finish line - if (gametype == GT_RACE) + if ((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) circuitmap = true; break; } @@ -6500,9 +6257,7 @@ void P_SpawnSpecials(boolean fromnetsave) // Firstly, find out how many there are in each sector for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next) { - if (th->function.acp1 == (actionf_p1)T_SpikeSector) - secthinkers[((levelspecthink_t *)th)->sector - sectors].count++; - else if (th->function.acp1 == (actionf_p1)T_Friction) + if (th->function.acp1 == (actionf_p1)T_Friction) secthinkers[((friction_t *)th)->affectee].count++; else if (th->function.acp1 == (actionf_p1)T_Pusher) secthinkers[((pusher_t *)th)->affectee].count++; @@ -6522,9 +6277,7 @@ void P_SpawnSpecials(boolean fromnetsave) { size_t secnum = (size_t)-1; - if (th->function.acp1 == (actionf_p1)T_SpikeSector) - secnum = ((levelspecthink_t *)th)->sector - sectors; - else if (th->function.acp1 == (actionf_p1)T_Friction) + if (th->function.acp1 == (actionf_p1)T_Friction) secnum = ((friction_t *)th)->affectee; else if (th->function.acp1 == (actionf_p1)T_Pusher) secnum = ((pusher_t *)th)->affectee; @@ -6563,7 +6316,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 1: // Definable gravity per sector sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) { sectors[s].gravity = §ors[sec].floorheight; // This allows it to change in realtime! @@ -6587,7 +6340,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 5: // Change camera info sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_AddCameraScanner(§ors[sec], §ors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)); break; @@ -6614,7 +6367,7 @@ void P_SpawnSpecials(boolean fromnetsave) P_ApplyFlatAlignment(lines + i, lines[i].frontsector, flatangle, xoffs, yoffs); else { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0;) P_ApplyFlatAlignment(lines + i, sectors + s, flatangle, xoffs, yoffs); } } @@ -6625,7 +6378,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 8: // Sector Parameters - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) { if (lines[i].flags & ML_NOCLIMB) { @@ -6653,7 +6406,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 10: // Vertical culling plane for sprites and FOFs sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) sectors[s].cullheight = &lines[i]; // This allows it to change in realtime! break; @@ -6714,18 +6467,18 @@ void P_SpawnSpecials(boolean fromnetsave) case 63: // support for drawn heights coming from different sector sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) sectors[s].heightsec = (INT32)sec; break; case 64: // Appearing/Disappearing FOF option if (lines[i].flags & ML_BLOCKMONSTERS) { // Find FOFs by control sector tag - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) for (j = 0; (unsigned)j < sectors[s].linecount; j++) if (sectors[s].lines[j]->special >= 100 && sectors[s].lines[j]->special < 300) Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), (INT32)(sectors[s].lines[j]-lines), (INT32)i); } else // Find FOFs by effect sector tag - for (s = -1; (s = P_FindLineFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindLineFromTag(lines[i].tag, s)) >= 0 ;) { if ((size_t)s == i) continue; @@ -6734,23 +6487,16 @@ void P_SpawnSpecials(boolean fromnetsave) } break; - case 65: // Bridge Thinker - /* - // Disable this until it's working right! - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - P_AddBridgeThinker(&lines[i], §ors[s]);*/ - break; - case 66: // Displace floor by front sector - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; case 67: // Displace ceiling by front sector - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; case 68: // Displace both floor AND ceiling by front sector - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; @@ -6944,18 +6690,19 @@ void P_SpawnSpecials(boolean fromnetsave) case 150: // Air bobbing platform case 151: // Adjustable air bobbing platform + { + fixed_t dist = (lines[i].special == 150) ? 16*FRACUNIT : P_AproxDistance(lines[i].dx, lines[i].dy); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - lines[i].flags |= ML_BLOCKMONSTERS; - P_AddAirbob(lines[i].frontsector, lines + i, (lines[i].special != 151), false); + P_AddAirbob(lines[i].frontsector, lines[i].tag, dist, false, !!(lines[i].flags & ML_NOCLIMB), false); break; + } case 152: // Adjustable air bobbing platform in reverse P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines + i, true, false); + P_AddAirbob(lines[i].frontsector, lines[i].tag, P_AproxDistance(lines[i].dx, lines[i].dy), true, !!(lines[i].flags & ML_NOCLIMB), 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); + P_AddAirbob(lines[i].frontsector, lines[i].tag, P_AproxDistance(lines[i].dx, lines[i].dy), false, !!(lines[i].flags & ML_NOCLIMB), true); break; case 160: // Float/bob platform @@ -7005,15 +6752,13 @@ void P_SpawnSpecials(boolean 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_AddAirbob(lines[i].frontsector, lines + i, true, false); + P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), 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_AddAirbob(lines[i].frontsector, lines + i, true, false); + P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 178: // Crumbling platform that will float when it hits water @@ -7026,49 +6771,36 @@ void P_SpawnSpecials(boolean 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_AddAirbob(lines[i].frontsector, lines + i, true, false); + P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 190: // Rising Platform FOF (solid, opaque, shadows) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, &lines[i]); - break; - case 191: // Rising Platform FOF (solid, opaque, no shadows) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_NOSHADE|FF_CUTLEVEL, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, &lines[i]); - break; - case 192: // Rising Platform TL block: FOF (solid, translucent) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_NOSHADE|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, &lines[i]); - break; - case 193: // Rising Platform FOF (solid, invisible) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_NOSHADE, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, &lines[i]); - break; - case 194: // Rising Platform 'Platform' - You can jump up through it - // If line has no-climb set, don't give it shadows, otherwise do - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_PLATFORM|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, &lines[i]); - break; - case 195: // Rising Platform Translucent "platform" - // If line has no-climb set, don't give it shadows, otherwise do - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_PLATFORM|FF_TRANSLUCENT|FF_BOTHPLANES|FF_ALLSIDES|FF_EXTRA|FF_CUTEXTRA; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_NOSHADE; + { + fixed_t speed = FixedDiv(P_AproxDistance(lines[i].dx, lines[i].dy), 4*FRACUNIT); + fixed_t ceilingtop = P_FindHighestCeilingSurrounding(lines[i].frontsector); + fixed_t ceilingbottom = P_FindLowestCeilingSurrounding(lines[i].frontsector); + ffloorflags = FF_EXISTS|FF_SOLID; + if (lines[i].special != 193) + ffloorflags |= FF_RENDERALL; + if (lines[i].special <= 191) + ffloorflags |= FF_CUTLEVEL; + if (lines[i].special == 192 || lines[i].special == 195) + ffloorflags |= FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA; + if (lines[i].special >= 194) + ffloorflags |= FF_PLATFORM|FF_BOTHPLANES|FF_ALLSIDES; + if (lines[i].special != 190 && (lines[i].special <= 193 || lines[i].flags & ML_NOCLIMB)) + ffloorflags |= FF_NOSHADE; P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, &lines[i]); + + P_AddRaiseThinker(lines[i].frontsector, lines[i].tag, speed, ceilingtop, ceilingbottom, !!(lines[i].flags & ML_BLOCKMONSTERS), !!(lines[i].flags & ML_NOCLIMB)); break; + } case 200: // Double light effect P_AddFakeFloorsByLine(i, FF_EXISTS|FF_CUTSPRITES|FF_DOUBLESHADOW, secthinkers); @@ -7079,7 +6811,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 202: // Fog - ffloorflags = FF_EXISTS|FF_RENDERALL|FF_FOG|FF_BOTHPLANES|FF_INVERTPLANES|FF_ALLSIDES|FF_INVERTSIDES|FF_CUTEXTRA|FF_EXTRA|FF_DOUBLESHADOW|FF_CUTSPRITES; + ffloorflags = FF_EXISTS|FF_RENDERALL|FF_FOG|FF_INVERTPLANES|FF_INVERTSIDES|FF_CUTEXTRA|FF_EXTRA|FF_DOUBLESHADOW|FF_CUTSPRITES; sec = sides[*lines[i].sidenum].sector - sectors; // SoM: Because it's fog, check for an extra colormap and set the fog flag... if (sectors[sec].extra_colormap) @@ -7124,14 +6856,14 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 251: // A THWOMP! - sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - { - P_AddThwompThinker(§ors[sec], §ors[s], &lines[i]); - P_AddFakeFloor(§ors[s], §ors[sec], lines + i, - FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - } + { + fixed_t crushspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dy >> 3 : 10*FRACUNIT; + fixed_t retractspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dx >> 3 : 2*FRACUNIT; + UINT16 sound = (lines[i].flags & ML_EFFECT4) ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : sfx_thwomp; + P_AddThwompThinker(lines[i].frontsector, lines[i].tag, &lines[i], crushspeed, retractspeed, sound); + P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); break; + } case 252: // Shatter block (breaks when touched) ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER; @@ -7170,11 +6902,8 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 258: // Laser block - sec = sides[*lines[i].sidenum].sector - sectors; - - // No longer totally disrupts netgames - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - EV_AddLaserThinker(§ors[s], §ors[sec], lines + i, secthinkers); + P_AddLaserThinker(lines[i].tag, lines + i, !!(lines[i].flags & ML_EFFECT1)); + P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT, secthinkers); break; case 259: // Custom FOF @@ -7215,14 +6944,13 @@ void P_SpawnSpecials(boolean fromnetsave) case 310: case 312: case 332: - sec = sides[*lines[i].sidenum].sector - sectors; - P_AddEachTimeThinker(§ors[sec], &lines[i]); + case 335: + P_AddEachTimeThinker(&lines[i]); break; // No More Enemies Linedef Exec case 313: - sec = sides[*lines[i].sidenum].sector - sectors; - P_AddNoEnemiesThinker(§ors[sec], &lines[i]); + P_AddNoEnemiesThinker(&lines[i]); break; // Pushable linedef executors (count # of pushables) @@ -7246,10 +6974,7 @@ void P_SpawnSpecials(boolean fromnetsave) else lines[i].callcount = sides[lines[i].sidenum[0]].textureoffset>>FRACBITS; if (lines[i].special == 322) // Each time - { - sec = sides[*lines[i].sidenum].sector - sectors; - P_AddEachTimeThinker(§ors[sec], &lines[i]); - } + P_AddEachTimeThinker(&lines[i]); break; // NiGHTS trigger executors @@ -7268,6 +6993,11 @@ void P_SpawnSpecials(boolean fromnetsave) case 333: break; + // Object dye executors + case 334: + case 336: + break; + case 399: // Linedef execute on map load // This is handled in P_RunLevelLoadExecutors. break; @@ -7330,6 +7060,9 @@ void P_SpawnSpecials(boolean fromnetsave) // 503 is used for a scroller // 504 is used for a scroller // 505 is used for a scroller + // 506 is used for a scroller + // 507 is used for a scroller + // 508 is used for a scroller // 510 is used for a scroller // 511 is used for a scroller // 512 is used for a scroller @@ -7359,46 +7092,46 @@ void P_SpawnSpecials(boolean fromnetsave) case 600: // floor lighting independently (e.g. lava) sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) sectors[s].floorlightsec = (INT32)sec; break; case 601: // ceiling lighting independently sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) sectors[s].ceilinglightsec = (INT32)sec; break; case 602: // Adjustable pulsating light sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_SpawnAdjustableGlowingLight(§ors[sec], §ors[s], P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); break; case 603: // Adjustable flickering light sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_SpawnAdjustableFireFlicker(§ors[sec], §ors[s], P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); break; case 604: // Adjustable Blinking Light (unsynchronized) sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, false); break; case 605: // Adjustable Blinking Light (synchronized) sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, true); break; case 606: // HACK! Copy colormaps. Just plain colormaps. - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) sectors[s].extra_colormap = sectors[s].spawn_extra_colormap = sides[lines[i].sidenum[0]].colormap_data; break; @@ -7414,7 +7147,6 @@ void P_SpawnSpecials(boolean fromnetsave) Z_Free(secthinkers); -#ifdef POLYOBJECTS // haleyjd 02/20/06: spawn polyobjects Polyobj_InitLevel(); @@ -7423,7 +7155,7 @@ void P_SpawnSpecials(boolean fromnetsave) switch (lines[i].special) { case 30: // Polyobj_Flag - EV_DoPolyObjFlag(&lines[i]); + PolyFlag(&lines[i]); break; case 31: // Polyobj_Displace @@ -7435,7 +7167,6 @@ void P_SpawnSpecials(boolean fromnetsave) break; } } -#endif P_RunLevelLoadExecutors(); } @@ -7453,7 +7184,7 @@ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinker INT32 s; size_t sec = sides[*lines[line].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromLineTag(lines+line, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[line].tag, s)) >= 0 ;) P_AddFakeFloor(§ors[s], §ors[sec], lines+line, ffloorflags, secthinkers); } @@ -7815,7 +7546,7 @@ static void P_SpawnScrollers(void) case 513: // scroll effect ceiling case 533: // scroll and carry objects on ceiling - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Scroller(sc_ceiling, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); if (special != 533) break; @@ -7824,13 +7555,13 @@ static void P_SpawnScrollers(void) case 523: // carry objects on ceiling dx = FixedMul(dx, CARRYFACTOR); dy = FixedMul(dy, CARRYFACTOR); - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Scroller(sc_carry_ceiling, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); break; case 510: // scroll effect floor case 530: // scroll and carry objects on floor - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Scroller(sc_floor, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); if (special != 530) break; @@ -7839,16 +7570,29 @@ static void P_SpawnScrollers(void) case 520: // carry objects on floor dx = FixedMul(dx, CARRYFACTOR); dy = FixedMul(dy, CARRYFACTOR); - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Scroller(sc_carry, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); break; // scroll wall according to linedef // (same direction and speed as scrolling floors) case 502: - for (s = -1; (s = P_FindLineFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindLineFromTag(l->tag, s)) >= 0 ;) if (s != (INT32)i) - Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0); + { + if (l->flags & ML_EFFECT2) // use texture offsets instead + { + dx = sides[l->sidenum[0]].textureoffset; + dy = sides[l->sidenum[0]].rowoffset; + } + if (l->flags & ML_EFFECT3) + { + if (lines[s].sidenum[1] != 0xffff) + Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[1], accel, 0); + } + else + Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0); + } break; case 505: @@ -7862,7 +7606,25 @@ static void P_SpawnScrollers(void) if (s != 0xffff) Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, lines[i].sidenum[0], accel, 0); else - CONS_Debug(DBG_GAMELOGIC, "Line special 506 (line #%s) missing 2nd side!\n", sizeu1(i)); + CONS_Debug(DBG_GAMELOGIC, "Line special 506 (line #%s) missing back side!\n", sizeu1(i)); + break; + + case 507: + s = lines[i].sidenum[0]; + + if (lines[i].sidenum[1] != 0xffff) + Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, lines[i].sidenum[1], accel, 0); + else + CONS_Debug(DBG_GAMELOGIC, "Line special 507 (line #%s) missing back side!\n", sizeu1(i)); + break; + + case 508: + s = lines[i].sidenum[1]; + + if (s != 0xffff) + Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, s, accel, 0); + else + CONS_Debug(DBG_GAMELOGIC, "Line special 508 (line #%s) missing back side!\n", sizeu1(i)); break; case 500: // scroll first side @@ -7916,7 +7678,7 @@ void T_Disappear(disappear_t *d) ffloor_t *rover; register INT32 s; - for (s = -1; (s = P_FindSectorFromLineTag(&lines[d->affectee], s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(lines[d->affectee].tag, s)) >= 0 ;) { for (rover = sectors[s].ffloors; rover; rover = rover->next) { @@ -7931,12 +7693,7 @@ void T_Disappear(disappear_t *d) if (!(lines[d->sourceline].flags & ML_NOCLIMB)) { -#ifdef ESLOPE - if (*rover->t_slope) - sectors[s].soundorg.z = P_GetZAt(*rover->t_slope, sectors[s].soundorg.x, sectors[s].soundorg.y); - else -#endif - sectors[s].soundorg.z = *rover->topheight; + sectors[s].soundorg.z = P_GetFFloorTopZAt(rover, sectors[s].soundorg.x, sectors[s].soundorg.y); S_StartSound(§ors[s].soundorg, sfx_appear); } } @@ -8675,7 +8432,7 @@ static void P_SpawnFriction(void) else movefactor = FRACUNIT; - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Friction(friction, movefactor, s, -1); } } @@ -9137,24 +8894,12 @@ void T_Pusher(pusher_t *p) if (!demoplayback || P_ControlStyle(thing->player) == CS_LMAOGALOG) { - if (thing->player == &players[consoleplayer]) - { - if (thing->angle - localangle > ANGLE_180) - localangle -= (localangle - thing->angle) / 8; - else - localangle += (thing->angle - localangle) / 8; - } - else if (thing->player == &players[secondarydisplayplayer]) - { - if (thing->angle - localangle2 > ANGLE_180) - localangle2 -= (localangle2 - thing->angle) / 8; - else - localangle2 += (thing->angle - localangle2) / 8; - } - /*if (thing->player == &players[consoleplayer]) - localangle = thing->angle; - else if (thing->player == &players[secondarydisplayplayer]) - localangle2 = thing->angle;*/ + angle_t angle = thing->player->angleturn << 16; + if (thing->angle - angle > ANGLE_180) + P_SetPlayerAngle(thing->player, angle - (angle - thing->angle) / 8); + else + P_SetPlayerAngle(thing->player, angle + (thing->angle - angle) / 8); + //P_SetPlayerAngle(thing->player, thing->angle); } } @@ -9210,15 +8955,15 @@ static void P_SpawnPushers(void) switch (l->special) { case 541: // wind - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Pusher(p_wind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 544: // current - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Pusher(p_current, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 547: // push/pull - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) { thing = P_GetPushThing(s); if (thing) // No MT_P* means no effect @@ -9226,19 +8971,19 @@ static void P_SpawnPushers(void) } break; case 545: // current up - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Pusher(p_upcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 546: // current down - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Pusher(p_downcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 542: // wind up - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Pusher(p_upwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 543: // wind down - for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) + for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) Add_Pusher(p_downwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; } diff --git a/src/p_spec.h b/src/p_spec.h index 4b64fe05d..596d8171d 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -55,7 +55,6 @@ fixed_t P_FindNextLowestFloor(sector_t *sec, fixed_t currentheight); fixed_t P_FindLowestCeilingSurrounding(sector_t *sec); fixed_t P_FindHighestCeilingSurrounding(sector_t *sec); -INT32 P_FindSectorFromLineTag(line_t *line, INT32 start); INT32 P_FindSectorFromTag(INT16 tag, INT32 start); INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); @@ -74,6 +73,7 @@ void P_RunDeNightserizeExecutors(mobj_t *actor); void P_RunNightsLapExecutors(mobj_t *actor); void P_RunNightsCapsuleTouchExecutors(mobj_t *actor, boolean entering, boolean enoughspheres); +UINT16 P_GetFFloorID(ffloor_t *fflr); ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id); // @@ -104,10 +104,9 @@ typedef struct typedef struct { thinker_t thinker; ///< Thinker structure for laser. - ffloor_t *ffloor; ///< 3Dfloor that is a laser. - sector_t *sector; ///< Sector in which the effect takes place. - sector_t *sec; + INT16 tag; line_t *sourceline; + UINT8 nobosses; } laserthink_t; /** Strobe light action structure.. @@ -307,18 +306,130 @@ typedef struct fixed_t delaytimer; fixed_t floorwasheight; // Height the floor WAS at fixed_t ceilingwasheight; // Height the ceiling WAS at - player_t *player; // Player who initiated the thinker (used for airbob) line_t *sourceline; } elevator_t; +typedef enum +{ + CF_RETURN = 1, // Return after crumbling + CF_FLOATBOB = 1<<1, // Float on water + CF_REVERSE = 1<<2, // Reverse gravity +} crumbleflag_t; + +typedef struct +{ + thinker_t thinker; + line_t *sourceline; + sector_t *sector; + sector_t *actionsector; // The sector the rover action is taking place in. + player_t *player; // Player who initiated the thinker (used for airbob) + INT32 direction; + INT32 origalpha; + INT32 timer; + fixed_t speed; + fixed_t floorwasheight; // Height the floor WAS at + fixed_t ceilingwasheight; // Height the ceiling WAS at + UINT8 flags; +} crumble_t; + typedef struct { thinker_t thinker; - fixed_t vars[16]; // Misc. variables - fixed_t var2s[16]; // Second misc variables buffer. line_t *sourceline; // Source line of the thinker - sector_t *sector; // Sector the thinker is from -} levelspecthink_t; +} noenemies_t; + +typedef struct +{ + thinker_t thinker; + sector_t *sector; + fixed_t speed; + INT32 direction; + fixed_t floorstartheight; + fixed_t ceilingstartheight; + fixed_t destheight; +} continuousfall_t; + +typedef struct +{ + thinker_t thinker; + line_t *sourceline; + sector_t *sector; + fixed_t speed; + fixed_t distance; + fixed_t floorwasheight; + fixed_t ceilingwasheight; + boolean low; +} bouncecheese_t; + +typedef struct +{ + thinker_t thinker; + sector_t *sector; + fixed_t speed; + INT32 direction; + fixed_t floorstartheight; + fixed_t ceilingstartheight; + INT16 tag; +} mariothink_t; + +typedef struct +{ + thinker_t thinker; + line_t *sourceline; + sector_t *sector; +} mariocheck_t; + +typedef struct +{ + thinker_t thinker; + line_t *sourceline; + sector_t *sector; + fixed_t crushspeed; + fixed_t retractspeed; + INT32 direction; + fixed_t floorstartheight; + fixed_t ceilingstartheight; + INT32 delay; + INT16 tag; + UINT16 sound; +} thwomp_t; + +typedef struct +{ + thinker_t thinker; + line_t *sourceline; + sector_t *sector; + INT16 tag; +} floatthink_t; + +typedef struct +{ + thinker_t thinker; + line_t *sourceline; // Source line of the thinker + boolean playersInArea[MAXPLAYERS]; + boolean playersOnArea[MAXPLAYERS]; + boolean triggerOnExit; +} eachtime_t; + +typedef enum +{ + RF_REVERSE = 1, //Lower when stood on + RF_SPINDASH = 1<<1, //Require spindash to move + RF_DYNAMIC = 1<<2, //Dynamically sinking platform +} raiseflag_t; + +typedef struct +{ + thinker_t thinker; + INT16 tag; + sector_t *sector; + fixed_t ceilingbottom; + fixed_t ceilingtop; + fixed_t basespeed; + fixed_t extraspeed; //For dynamically sinking platform + UINT8 shaketimer; //For dynamically sinking platform + UINT8 flags; +} raise_t; #define ELEVATORSPEED (FRACUNIT*4) #define FLOORSPEED (FRACUNIT) @@ -331,36 +442,34 @@ typedef enum } result_e; result_e T_MovePlane(sector_t *sector, fixed_t speed, fixed_t dest, boolean crush, - INT32 floorOrCeiling, INT32 direction); -INT32 EV_DoFloor(line_t *line, floor_e floortype); -INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed); + boolean ceiling, INT32 direction); +void EV_DoFloor(line_t *line, floor_e floortype); +void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed); void EV_CrumbleChain(sector_t *sec, ffloor_t *rover); -INT32 EV_BounceSector(sector_t *sector, fixed_t momz, line_t *sourceline); +void EV_BounceSector(sector_t *sector, fixed_t momz, line_t *sourceline); // Some other special 3dfloor types INT32 EV_StartCrumble(sector_t *sector, ffloor_t *rover, boolean floating, player_t *player, fixed_t origalpha, boolean crumblereturn); -INT32 EV_DoContinuousFall(sector_t *sec, sector_t *pbacksector, fixed_t spd, boolean backwards); +void EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, boolean backwards); -INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher); +void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher); void T_MoveFloor(floormove_t *movefloor); void T_MoveElevator(elevator_t *elevator); -void T_ContinuousFalling(levelspecthink_t *faller); -void T_BounceCheese(levelspecthink_t *bouncer); -void T_StartCrumble(elevator_t *elevator); -void T_MarioBlock(levelspecthink_t *block); -void T_SpikeSector(levelspecthink_t *spikes); -void T_FloatSector(levelspecthink_t *floater); -void T_BridgeThinker(levelspecthink_t *bridge); -void T_MarioBlockChecker(levelspecthink_t *block); -void T_ThwompSector(levelspecthink_t *thwomp); -void T_NoEnemiesSector(levelspecthink_t *nobaddies); -void T_EachTimeThinker(levelspecthink_t *eachtime); +void T_ContinuousFalling(continuousfall_t *faller); +void T_BounceCheese(bouncecheese_t *bouncer); +void T_StartCrumble(crumble_t *crumble); +void T_MarioBlock(mariothink_t *block); +void T_FloatSector(floatthink_t *floater); +void T_MarioBlockChecker(mariocheck_t *block); +void T_ThwompSector(thwomp_t *thwomp); +void T_NoEnemiesSector(noenemies_t *nobaddies); +void T_EachTimeThinker(eachtime_t *eachtime); void T_CameraScanner(elevator_t *elevator); -void T_RaiseSector(levelspecthink_t *sraise); +void T_RaiseSector(raise_t *raise); typedef struct { diff --git a/src/p_telept.c b/src/p_telept.c index 69729d208..f6feddf4b 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -63,10 +63,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, thing->reactiontime = TICRATE/2; // don't move for about half a second // absolute angle position - if (thing == players[consoleplayer].mo) - localangle = angle; - if (thing == players[secondarydisplayplayer].mo) - localangle2 = angle; + P_SetPlayerAngle(thing->player, angle); // move chasecam at new player location if (splitscreen && camera2.chase @@ -165,10 +162,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle thing->player->drawangle += (angle - thing->angle); // absolute angle position - if (thing->player == &players[consoleplayer]) - localangle = angle; - if (thing->player == &players[secondarydisplayplayer]) - localangle2 = angle; + P_SetPlayerAngle(thing->player, angle); // move chasecam at new player location if (splitscreen && camera2.chase && thing->player == &players[secondarydisplayplayer]) diff --git a/src/p_tick.c b/src/p_tick.c index 74472b71f..f84ae96c0 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -269,9 +269,7 @@ void P_RemoveThinkerDelayed(thinker_t *thinker) // void P_RemoveThinker(thinker_t *thinker) { -#ifdef HAVE_BLUA LUA_InvalidateUserdata(thinker); -#endif thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed; } @@ -643,9 +641,7 @@ void P_Ticker(boolean run) if (demoplayback) G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); - #ifdef HAVE_BLUA LUAh_PreThinkFrame(); - #endif for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) @@ -671,9 +667,7 @@ void P_Ticker(boolean run) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); -#ifdef HAVE_BLUA LUAh_ThinkFrame(); -#endif } // Run shield positioning @@ -698,7 +692,7 @@ void P_Ticker(boolean run) if (run) { - if (countdowntimer && G_PlatformGametype() && (gametype == GT_COOP || leveltime >= 4*TICRATE) && !stoppedclock && --countdowntimer <= 0) + if (countdowntimer && G_PlatformGametype() && ((gametyperules & GTR_CAMPAIGN) || leveltime >= 4*TICRATE) && !stoppedclock && --countdowntimer <= 0) { countdowntimer = 0; countdowntimeup = true; @@ -745,9 +739,7 @@ void P_Ticker(boolean run) if (modeattacking) G_GhostTicker(); -#ifdef HAVE_BLUA LUAh_PostThinkFrame(); -#endif } P_MapEnd(); @@ -763,13 +755,15 @@ void P_PreTicker(INT32 frames) postimgtype = postimgtype2 = postimg_none; + if (marathonmode & MA_INGAME) + marathonmode |= MA_INIT; + for (framecnt = 0; framecnt < frames; ++framecnt) { P_MapStart(); -#ifdef HAVE_BLUA LUAh_PreThinkFrame(); -#endif + for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) { @@ -779,7 +773,9 @@ void P_PreTicker(INT32 frames) memcpy(&temptic, &players[i].cmd, sizeof(ticcmd_t)); memset(&players[i].cmd, 0, sizeof(ticcmd_t)); // correct angle on spawn... - players[i].cmd.angleturn = temptic.angleturn; + players[i].angleturn += temptic.angleturn - players[i].oldrelangleturn; + players[i].oldrelangleturn = temptic.angleturn; + players[i].cmd.angleturn = players[i].angleturn; P_PlayerThink(&players[i]); @@ -793,9 +789,7 @@ void P_PreTicker(INT32 frames) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); -#ifdef HAVE_BLUA LUAh_ThinkFrame(); -#endif // Run shield positioning P_RunShields(); @@ -804,10 +798,11 @@ void P_PreTicker(INT32 frames) P_UpdateSpecials(); P_RespawnSpecials(); -#ifdef HAVE_BLUA LUAh_PostThinkFrame(); -#endif P_MapEnd(); } + + if (marathonmode & MA_INGAME) + marathonmode &= ~MA_INIT; } diff --git a/src/p_tick.h b/src/p_tick.h index a9501f62f..1fb88f3f2 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_user.c b/src/p_user.c index a01267b73..7a51e7bf3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,7 +22,7 @@ #include "p_local.h" #include "r_main.h" #include "s_sound.h" -#include "r_things.h" +#include "r_skins.h" #include "d_think.h" #include "r_sky.h" #include "p_setup.h" @@ -384,6 +384,9 @@ void P_GiveFinishFlags(player_t *player) if (!player->mo) return; + if (!(netgame||multiplayer)) + return; + for (i = 0; i < 3; i++) { angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; @@ -392,7 +395,7 @@ void P_GiveFinishFlags(player_t *player) mobj_t* flag = P_SpawnMobjFromMobj(player->mo, xoffs, yoffs, 0, MT_FINISHFLAG); flag->angle = angle; angle += FixedAngle(120*FRACUNIT); - + P_SetTarget(&flag->target, player->mo); } } @@ -1048,7 +1051,8 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) // Point penalty for hitting a hazard during tag. // Discourages players from intentionally hurting themselves to avoid being tagged. - if (gametype == GT_TAG && (!(player->pflags & PF_GAMETYPEOVER) && !(player->pflags & PF_TAGIT))) + if (((gametyperules & (GTR_TAG|GTR_HIDEFROZEN)) == GTR_TAG) + && (!(player->pflags & PF_GAMETYPEOVER) && !(player->pflags & PF_TAGIT))) { if (player->score >= 50) player->score -= 50; @@ -1106,7 +1110,6 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing)) return false; -#ifdef HAVE_BLUA { UINT8 shouldCollide = LUAh_PlayerCanDamage(player, thing); if (P_MobjWasRemoved(thing)) @@ -1116,7 +1119,6 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) else if (shouldCollide == 2) return false; // force no } -#endif // Invinc/super. Not for Monitors. if (!(thing->flags & MF_MONITOR) && (player->powers[pw_invulnerability] || player->powers[pw_super])) @@ -1350,7 +1352,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings) player->powers[pw_sneakers] = 0; } - if (gametype != GT_COOP) + if (!G_CoopGametype()) { HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); @@ -1387,7 +1389,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) // Continues are worthless in netgames. // If that stops being the case uncomment this. -/* if (!ultimatemode && players[i].marescore > 50000 +/* if (!ultimatemode && continuesInSession && players[i].marescore > 50000 && oldscore < 50000) { players[i].continues += 1; @@ -1407,7 +1409,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) else player->marescore = MAXSCORE; - if (!ultimatemode && !(netgame || multiplayer) && G_IsSpecialStage(gamemap) + if (!ultimatemode && continuesInSession && G_IsSpecialStage(gamemap) && player->marescore >= 50000 && oldscore < 50000) { player->continues += 1; @@ -1417,7 +1419,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) } } - if (gametype == GT_COOP) + if (G_CoopGametype()) return; } @@ -1436,7 +1438,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) } // In team match, all awarded points are incremented to the team's running score. - if (gametype == GT_TEAMMATCH) + if ((gametyperules & (GTR_TEAMS|GTR_TEAMFLAGS)) == GTR_TEAMS) { if (player->ctfteam == 1) redscore += amount; @@ -1470,7 +1472,7 @@ void P_StealPlayerScore(player_t *player, UINT32 amount) if (stolen > 0) { // In team match, all stolen points are removed from the enemy team's running score. - if (gametype == GT_TEAMMATCH) + if ((gametyperules & (GTR_TEAMS|GTR_TEAMFLAGS)) == GTR_TEAMS) { if (player->ctfteam == 1) bluescore -= amount; @@ -1489,17 +1491,10 @@ void P_PlayLivesJingle(player_t *player) if (player && !P_IsLocalPlayer(player)) return; - if (use1upSound) + if (use1upSound || cv_1upsound.value) S_StartSound(NULL, sfx_oneup); else if (mariomode) S_StartSound(NULL, sfx_marioa); - else if (cv_1upsound.value) - { - if (S_sfx[sfx_oneup].lumpnum != LUMPERROR) - S_StartSound(NULL, sfx_oneup); - else - S_StartSound(NULL, sfx_chchng);/* at least play something! */ - } else { P_PlayJingle(player, JT_1UP); @@ -1518,7 +1513,7 @@ void P_PlayJingle(player_t *player, jingletype_t jingletype) char newmusic[7]; strncpy(newmusic, musname, 7); -#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) +#ifdef HAVE_LUA_MUSICPLUS if(LUAh_MusicJingle(jingletype, newmusic, &musflags, &looping)) return; #endif @@ -1533,7 +1528,7 @@ void P_PlayJingle(player_t *player, jingletype_t jingletype) void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status) { // If gamestate != GS_LEVEL, always play the jingle (1-up intermission) - if (gamestate == GS_LEVEL && !P_IsLocalPlayer(player)) + if (gamestate == GS_LEVEL && player && !P_IsLocalPlayer(player)) return; S_RetainMusic(musname, musflags, looping, 0, status); @@ -1541,7 +1536,7 @@ void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, b S_ChangeMusicInternal(musname, looping); } -boolean P_EvaluateMusicStatus(UINT16 status) +boolean P_EvaluateMusicStatus(UINT16 status, const char *musname) { // \todo lua hook int i; @@ -1598,8 +1593,11 @@ boolean P_EvaluateMusicStatus(UINT16 status) result = (players[i].nightstime && players[i].nightstime <= 10*TICRATE); break; - case JT_NONE: // Null state case JT_OTHER: // Other state + result = LUAh_ShouldJingleContinue(&players[i], musname); + break; + + case JT_NONE: // Null state case JT_MASTER: // Main level music default: result = true; @@ -1862,10 +1860,8 @@ void P_SpawnShieldOrb(player_t *player) I_Error("P_SpawnShieldOrb: player->mo is NULL!\n"); #endif -#ifdef HAVE_BLUA if (LUAh_ShieldSpawn(player)) return; -#endif if (player->powers[pw_shield] & SH_FORCE) orbtype = MT_FORCE_ORB; @@ -1921,7 +1917,7 @@ void P_SpawnShieldOrb(player_t *player) shieldobj->colorized = true; } else - shieldobj->color = (UINT8)shieldobj->info->painchance; + shieldobj->color = (UINT16)shieldobj->info->painchance; shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK); if (shieldobj->info->seestate) @@ -2272,13 +2268,8 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, mo->x, mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, mo->x, mo->y); if (mo->z + (mo->height/2) > topheight) continue; @@ -2518,13 +2509,8 @@ boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand if (!(rover->flags & FF_QUICKSAND)) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, mo->x, mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, mo->x, mo->y); if (mo->z + flipoffset > topheight) continue; @@ -2539,6 +2525,72 @@ boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand return false; // No sand here, Captain! } +static boolean P_PlayerCanBust(player_t *player, ffloor_t *rover) +{ + if (!(rover->flags & FF_EXISTS)) + return false; + + if (!(rover->flags & FF_BUSTUP)) + return false; + + /*if (rover->master->frontsector->crumblestate != CRUMBLE_NONE) + return false;*/ + + // If it's an FF_SHATTER, you can break it just by touching it. + if (rover->flags & FF_SHATTER) + return true; + + // 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) + { + if ((player->pflags & PF_SPINNING) && !(player->pflags & PF_STARTDASH)) + return true; + + if ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE)) + return true; + } + + // Strong abilities can break even FF_STRONGBUST. + if (player->charability == CA_GLIDEANDCLIMB) + return true; + + if (player->pflags & PF_BOUNCING) + return true; + + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + return true; + + if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + return true; + + // Everyone else is out of luck. + if (rover->flags & FF_STRONGBUST) + return false; + + // Spinning (and not jumping) + if ((player->pflags & PF_SPINNING) && !(player->pflags & PF_JUMPED)) + return true; + + // Super + if (player->powers[pw_super]) + return true; + + // Dashmode + if ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) && player->dashmode >= DASHMODE_THRESHOLD) + return true; + + // NiGHTS drill + if (player->pflags & PF_DRILLING) + return true; + + // Recording for Metal Sonic + if (metalrecording) + return true; + + return false; +} + static void P_CheckBustableBlocks(player_t *player) { msecnode_t *node; @@ -2561,121 +2613,83 @@ static void P_CheckBustableBlocks(player_t *player) for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) { + ffloor_t *rover; + fixed_t topheight, bottomheight; + if (!node->m_sector) break; - if (node->m_sector->ffloors) + if (!node->m_sector->ffloors) + continue; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - ffloor_t *rover; - fixed_t topheight, bottomheight; + if (!P_PlayerCanBust(player, rover)) + continue; - for (rover = node->m_sector->ffloors; rover; rover = rover->next) + 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); + + if (((player->charability == CA_TWINSPIN) && (player->panim == PA_ABILITY)) + || ((P_MobjFlip(player->mo)*player->mo->momz < 0) && (player->pflags & PF_BOUNCING || ((player->charability2 == CA2_MELEE) && (player->panim == PA_ABILITY2))))) { - if (!(rover->flags & FF_EXISTS)) continue; - - if ((rover->flags & FF_BUSTUP)/* && !rover->master->frontsector->crumblestate*/) - { - // 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_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->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) && (player->dashmode >= DASHMODE_THRESHOLD)) - && !(player->pflags & PF_DRILLING) - && !metalrecording) - 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); - - if (((player->charability == CA_TWINSPIN) && (player->panim == PA_ABILITY)) - || ((P_MobjFlip(player->mo)*player->mo->momz < 0) && (player->pflags & PF_BOUNCING || ((player->charability2 == CA2_MELEE) && (player->panim == PA_ABILITY2))))) - { - topheight -= player->mo->momz; - bottomheight -= player->mo->momz; - } - - // Height checks - if (rover->flags & FF_SHATTERBOTTOM) - { - if (player->mo->z+player->mo->momz + player->mo->height < bottomheight) - continue; - - if (player->mo->z+player->mo->height > bottomheight) - continue; - } - else if (rover->flags & FF_SPINBUST) - { - if (player->mo->z+player->mo->momz > topheight) - continue; - - if (player->mo->z + player->mo->height < bottomheight) - continue; - } - else if (rover->flags & FF_SHATTER) - { - if (player->mo->z + player->mo->momz > topheight) - continue; - - if (player->mo->z+player->mo->momz + player->mo->height < bottomheight) - continue; - } - else - { - if (player->mo->z >= topheight) - continue; - - if (player->mo->z + player->mo->height < bottomheight) - continue; - } - - // Impede the player's fall a bit - if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight) - player->mo->momz >>= 1; - else if (rover->flags & FF_SHATTER) - { - player->mo->momx >>= 1; - player->mo->momy >>= 1; - } - - //if (metalrecording) - // G_RecordBustup(rover); - - EV_CrumbleChain(NULL, rover); // node->m_sector - - // Run a linedef executor?? - if (rover->master->flags & ML_EFFECT5) - P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), player->mo, node->m_sector); - - goto bustupdone; - } + topheight -= player->mo->momz; + bottomheight -= player->mo->momz; } + + // Height checks + if (rover->flags & FF_SHATTERBOTTOM) + { + if (player->mo->z + player->mo->momz + player->mo->height < bottomheight) + continue; + + if (player->mo->z + player->mo->height > bottomheight) + continue; + } + else if (rover->flags & FF_SPINBUST) + { + if (player->mo->z + player->mo->momz > topheight) + continue; + + if (player->mo->z + player->mo->height < bottomheight) + continue; + } + else if (rover->flags & FF_SHATTER) + { + if (player->mo->z + player->mo->momz > topheight) + continue; + + if (player->mo->z + player->mo->momz + player->mo->height < bottomheight) + continue; + } + else + { + if (player->mo->z >= topheight) + continue; + + if (player->mo->z + player->mo->height < bottomheight) + continue; + } + + // Impede the player's fall a bit + if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight) + player->mo->momz >>= 1; + else if (rover->flags & FF_SHATTER) + { + player->mo->momx >>= 1; + player->mo->momy >>= 1; + } + + //if (metalrecording) + // G_RecordBustup(rover); + + EV_CrumbleChain(NULL, rover); // node->m_sector + + // Run a linedef executor?? + if (rover->master->flags & ML_EFFECT5) + P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), player->mo, node->m_sector); + + goto bustupdone; } } bustupdone: @@ -2694,9 +2708,7 @@ static void P_CheckBouncySectors(player_t *player) fixed_t oldx; fixed_t oldy; fixed_t oldz; -#ifdef ESLOPE vector3_t momentum; -#endif oldx = player->mo->x; oldy = player->mo->y; @@ -2710,130 +2722,109 @@ static void P_CheckBouncySectors(player_t *player) for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) { + ffloor_t *rover; + if (!node->m_sector) break; - if (node->m_sector->ffloors) + if (!node->m_sector->ffloors) + continue; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - ffloor_t *rover; - boolean top = true; + fixed_t bouncestrength; fixed_t topheight, bottomheight; - for (rover = node->m_sector->ffloors; rover; rover = rover->next) + if (!(rover->flags & FF_EXISTS)) + continue; // FOFs should not be bouncy if they don't even "exist" + + if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15) + continue; // this sector type is required for FOFs to be bouncy + + 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); + + if (player->mo->z > topheight) + continue; + + if (player->mo->z + player->mo->height < bottomheight) + continue; + + bouncestrength = P_AproxDistance(rover->master->dx, rover->master->dy)/100; + + if (oldz < P_GetFOFTopZ(player->mo, node->m_sector, rover, oldx, oldy, NULL) + && oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)) { - if (!(rover->flags & FF_EXISTS)) - continue; // FOFs should not be bouncy if they don't even "exist" - - if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15) - continue; // this sector type is required for FOFs to be bouncy - - 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); - - if (player->mo->z > topheight) - continue; - - if (player->mo->z + player->mo->height < bottomheight) - continue; - - if (oldz < P_GetFOFTopZ(player->mo, node->m_sector, rover, oldx, oldy, NULL) - && oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)) - top = false; + player->mo->momx = -FixedMul(player->mo->momx,bouncestrength); + player->mo->momy = -FixedMul(player->mo->momy,bouncestrength); + if (player->pflags & PF_SPINNING) { - fixed_t linedist; - - linedist = P_AproxDistance(rover->master->v1->x-rover->master->v2->x, rover->master->v1->y-rover->master->v2->y); - - linedist = FixedDiv(linedist,100*FRACUNIT); - - if (top) - { - fixed_t newmom; - -#ifdef ESLOPE - pslope_t *slope; - if (abs(oldz - topheight) < abs(oldz + player->mo->height - bottomheight)) { // Hit top - slope = *rover->t_slope; - } else { // Hit bottom - slope = *rover->b_slope; - } - - momentum.x = player->mo->momx; - momentum.y = player->mo->momy; - momentum.z = player->mo->momz*2; - - if (slope) - P_ReverseQuantizeMomentumToSlope(&momentum, slope); - - newmom = momentum.z = -FixedMul(momentum.z,linedist)/2; -#else - newmom = -FixedMul(player->mo->momz,linedist); -#endif - - if (abs(newmom) < (linedist*2)) - { - goto bouncydone; - } - - if (!(rover->master->flags & ML_BOUNCY)) - { - if (newmom > 0) - { - if (newmom < 8*FRACUNIT) - newmom = 8*FRACUNIT; - } - else if (newmom > -8*FRACUNIT && newmom != 0) - newmom = -8*FRACUNIT; - } - - if (newmom > P_GetPlayerHeight(player)/2) - newmom = P_GetPlayerHeight(player)/2; - else if (newmom < -P_GetPlayerHeight(player)/2) - newmom = -P_GetPlayerHeight(player)/2; - -#ifdef ESLOPE - momentum.z = newmom*2; - - if (slope) - P_QuantizeMomentumToSlope(&momentum, slope); - - player->mo->momx = momentum.x; - player->mo->momy = momentum.y; - player->mo->momz = momentum.z/2; -#else - player->mo->momz = newmom; -#endif - - if (player->pflags & PF_SPINNING) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - player->pflags |= PF_THOKKED; - } - } - else - { - player->mo->momx = -FixedMul(player->mo->momx,linedist); - player->mo->momy = -FixedMul(player->mo->momy,linedist); - - if (player->pflags & PF_SPINNING) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - player->pflags |= PF_THOKKED; - } - } - - if ((player->pflags & PF_SPINNING) && player->speed < FixedMul(1<mo->scale) && player->mo->momz) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - } - - goto bouncydone; + player->pflags &= ~PF_SPINNING; + player->pflags |= P_GetJumpFlags(player); + player->pflags |= PF_THOKKED; } } + else + { + fixed_t newmom; + pslope_t *slope = (abs(oldz - topheight) < abs(oldz + player->mo->height - bottomheight)) ? *rover->t_slope : *rover->b_slope; + + momentum.x = player->mo->momx; + momentum.y = player->mo->momy; + momentum.z = player->mo->momz*2; + + if (slope) + P_ReverseQuantizeMomentumToSlope(&momentum, slope); + + newmom = momentum.z = -FixedMul(momentum.z,bouncestrength)/2; + + if (abs(newmom) < (bouncestrength*2)) + goto bouncydone; + + if (!(rover->master->flags & ML_BOUNCY)) + { + if (newmom > 0) + { + if (newmom < 8*FRACUNIT) + newmom = 8*FRACUNIT; + } + else if (newmom < 0) + { + if (newmom > -8*FRACUNIT) + newmom = -8*FRACUNIT; + } + } + + if (newmom > P_GetPlayerHeight(player)/2) + newmom = P_GetPlayerHeight(player)/2; + else if (newmom < -P_GetPlayerHeight(player)/2) + newmom = -P_GetPlayerHeight(player)/2; + + momentum.z = newmom*2; + + if (slope) + P_QuantizeMomentumToSlope(&momentum, slope); + + player->mo->momx = momentum.x; + player->mo->momy = momentum.y; + player->mo->momz = momentum.z/2; + + if (player->pflags & PF_SPINNING) + { + player->pflags &= ~PF_SPINNING; + player->pflags |= P_GetJumpFlags(player); + player->pflags |= PF_THOKKED; + } + } + + if ((player->pflags & PF_SPINNING) && player->speed < FixedMul(1<mo->scale) && player->mo->momz) + { + player->pflags &= ~PF_SPINNING; + player->pflags |= P_GetJumpFlags(player); + } + + goto bouncydone; } } bouncydone: @@ -2860,13 +2851,8 @@ static void P_CheckQuicksand(player_t *player) if (!(rover->flags & FF_QUICKSAND)) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); if (topheight >= player->mo->z && bottomheight < player->mo->z + player->mo->height) { @@ -3019,7 +3005,7 @@ static void P_CheckInvincibilityTimer(player_t *player) return; if (mariomode && !player->powers[pw_super]) - player->mo->color = (UINT8)(SKINCOLOR_RUBY + (leveltime % (MAXSKINCOLORS - SKINCOLOR_RUBY))); // Passes through all saturated colours + player->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (numskincolors - SKINCOLOR_RUBY))); // Passes through all saturated colours else if (leveltime % (TICRATE/7) == 0) { mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_IVSP); @@ -3200,26 +3186,19 @@ static void P_DoClimbing(player_t *player) boolean thrust = false; boolean boostup = false; boolean skyclimber = false; - fixed_t floorheight, ceilingheight; // ESLOPE + fixed_t floorheight, ceilingheight; if (!glidesector) floorclimb = true; else { -#ifdef ESLOPE - floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) - : glidesector->sector->floorheight; - ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) - : glidesector->sector->ceilingheight; -#else - floorheight = glidesector->sector->floorheight; - ceilingheight = glidesector->sector->ceilingheight; -#endif + floorheight = P_GetSectorFloorZAt (glidesector->sector, player->mo->x, player->mo->y); + ceilingheight = P_GetSectorCeilingZAt(glidesector->sector, player->mo->x, player->mo->y); if (glidesector->sector->ffloors) { ffloor_t *rover; - fixed_t topheight, bottomheight; // ESLOPE + fixed_t topheight, bottomheight; for (rover = glidesector->sector->ffloors; rover; rover = rover->next) { @@ -3228,13 +3207,8 @@ static void P_DoClimbing(player_t *player) floorclimb = true; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); // Only supports rovers that are moving like an 'elevator', not just the top or bottom. if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42) @@ -3275,12 +3249,7 @@ static void P_DoClimbing(player_t *player) if (roverbelow == rover) continue; -#ifdef ESLOPE - bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight; -#else - bottomheight2 = *roverbelow->bottomheight; -#endif - + bottomheight2 = P_GetFFloorBottomZAt(roverbelow, player->mo->x, player->mo->y); if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale)) foundfof = true; } @@ -3325,12 +3294,7 @@ static void P_DoClimbing(player_t *player) if (roverbelow == rover) continue; -#ifdef ESLOPE - topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight; -#else - topheight2 = *roverbelow->topheight; -#endif - + topheight2 = P_GetFFloorTopZAt(roverbelow, player->mo->x, player->mo->y); if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale)) foundfof = true; } @@ -3384,12 +3348,7 @@ static void P_DoClimbing(player_t *player) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) continue; -#ifdef ESLOPE - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; -#else - bottomheight = *rover->bottomheight; -#endif - + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale)) { foundfof = true; @@ -3429,12 +3388,7 @@ static void P_DoClimbing(player_t *player) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; -#else - topheight = *rover->topheight; -#endif - + topheight = P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); if (topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale)) { foundfof = true; @@ -3622,22 +3576,11 @@ static void P_DoClimbing(player_t *player) #define CLIMBCONEMAX FixedAngle(90*FRACUNIT) if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) { - if (player == &players[consoleplayer]) - { - 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]) - { - 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; - } + angle_t angdiff = P_GetLocalAngle(player) - player->mo->angle; + if (angdiff < ANGLE_180 && angdiff > CLIMBCONEMAX) + P_SetLocalAngle(player, player->mo->angle + CLIMBCONEMAX); + else if (angdiff > ANGLE_180 && angdiff < InvAngle(CLIMBCONEMAX)) + P_SetLocalAngle(player, player->mo->angle - CLIMBCONEMAX); } if (player->climbing == 0) @@ -3682,7 +3625,7 @@ static boolean PIT_CheckSolidsTeeter(mobj_t *thing) if (thing == teeterer) return true; - if (thing->player && cv_tailspickup.value && gametype != GT_HIDEANDSEEK) + if (thing->player && cv_tailspickup.value && !(gametyperules & GTR_HIDEFROZEN)) return true; blockdist = teeterer->radius + thing->radius; @@ -3806,14 +3749,8 @@ static void P_DoTeeter(player_t *player) sec = R_PointInSubsector(checkx, checky)->sector; - ceilingheight = sec->ceilingheight; - floorheight = sec->floorheight; -#ifdef ESLOPE - if (sec->c_slope) - ceilingheight = P_GetZAt(sec->c_slope, checkx, checky); - if (sec->f_slope) - floorheight = P_GetZAt(sec->f_slope, checkx, checky); -#endif + ceilingheight = P_GetSectorCeilingZAt(sec, checkx, checky); + floorheight = P_GetSectorFloorZAt (sec, checkx, checky); highestceilingheight = (ceilingheight > highestceilingheight) ? ceilingheight : highestceilingheight; lowestfloorheight = (floorheight < lowestfloorheight) ? floorheight : lowestfloorheight; @@ -3824,13 +3761,8 @@ static void P_DoTeeter(player_t *player) { if (!(rover->flags & FF_EXISTS)) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); if (P_CheckSolidLava(rover)) ; @@ -3902,7 +3834,6 @@ static void P_DoTeeter(player_t *player) BMBOUNDFIX(xl, xh, yl, yh); // Polyobjects -#ifdef POLYOBJECTS validcount++; for (by = yl; by <= yh; by++) @@ -3996,7 +3927,6 @@ static void P_DoTeeter(player_t *player) plink = (polymaplink_t *)(plink->link.next); } } -#endif if (teeter) // only bother with objects as a last resort if you were already teetering { mobj_t *oldtmthing = tmthing; @@ -4307,7 +4237,7 @@ static void P_DoSuperStuff(player_t *player) G_GhostAddColor(GHC_NORMAL); } - if (gametype != GT_COOP) + if (!G_CoopGametype()) { HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); @@ -4357,14 +4287,14 @@ static void P_DoSuperStuff(player_t *player) G_GhostAddColor(GHC_NORMAL); } - if (gametype != GT_COOP) + if (!G_CoopGametype()) player->powers[pw_flashing] = flashingtics-1; 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. - if (gametype != GT_COOP) + if (!G_CoopGametype()) { S_StartSound(NULL, sfx_s3k66); //let all players hear it. HU_SetCEchoFlags(0); @@ -4436,12 +4366,7 @@ void P_DoJump(player_t *player, boolean soundandstate) player->drawangle = player->mo->angle = player->mo->angle - ANGLE_180; // Turn around from the wall you were climbing. if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - { - if (player == &players[consoleplayer]) - localangle = player->mo->angle; // Adjust the local control angle. - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - } + P_SetPlayerAngle(player, player->mo->angle); player->climbing = 0; // Stop climbing, duh! P_InstaThrust(player->mo, player->mo->angle, FixedMul(6*FRACUNIT, player->mo->scale)); // Jump off the wall. @@ -4497,13 +4422,16 @@ void P_DoJump(player_t *player, boolean soundandstate) else if (player->powers[pw_carry] == CR_ROLLOUT) { player->mo->momz = 9*FRACUNIT; - if (P_MobjFlip(player->mo->tracer)*player->mo->tracer->momz > 0) - player->mo->momz += player->mo->tracer->momz; - if (!P_IsObjectOnGround(player->mo->tracer)) - P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true); + if (player->mo->tracer) + { + if (P_MobjFlip(player->mo->tracer)*player->mo->tracer->momz > 0) + player->mo->momz += player->mo->tracer->momz; + if (!P_IsObjectOnGround(player->mo->tracer)) + P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true); + player->mo->tracer->flags |= MF_PUSHABLE; + P_SetTarget(&player->mo->tracer->tracer, NULL); + } 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) @@ -4633,17 +4561,13 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) && (player->pflags & PF_JUMPSTASIS || player->mo->state-states != S_PLAY_GLIDE_LANDING)) return; -#ifdef HAVE_BLUA if (cmd->buttons & BT_USE) { if (LUAh_SpinSpecial(player)) return; } -#endif -#ifdef ESLOPE canstand = (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2); -#endif /////////////////////////////// // ability-specific behavior // @@ -4765,12 +4689,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); bullet = P_SpawnPointMissile(player->mo, lockon->x, lockon->y, zpos(lockon), player->revitem, player->mo->x, player->mo->y, zpos(player->mo)); if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - { - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - } + P_SetPlayerAngle(player, player->mo->angle); } else { @@ -4934,246 +4853,6 @@ void P_DoBubbleBounce(player_t *player) player->mo->momz = FixedMul(player->mo->momz, 5*FRACUNIT/4); } -// -// P_IsClimbingValid -// -// Unlike P_DoClimbing, don't use when up against a one-sided linedef. -// -static boolean P_IsClimbingValid(player_t *player, angle_t angle) -{ - fixed_t platx, platy; - subsector_t *glidesector; - fixed_t floorz, ceilingz; - - platx = P_ReturnThrustX(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - platy = P_ReturnThrustY(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - - glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); - -#ifdef ESLOPE - floorz = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) : glidesector->sector->floorheight; - ceilingz = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) : glidesector->sector->ceilingheight; -#else - floorz = glidesector->sector->floorheight; - ceilingz = glidesector->sector->ceilingheight; -#endif - - if (glidesector->sector != player->mo->subsector->sector) - { - boolean floorclimb = false; - fixed_t topheight, bottomheight; - - if (glidesector->sector->ffloors) - { - ffloor_t *rover; - for (rover = glidesector->sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y); -#endif - - floorclimb = true; - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if ((topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < topheight)) - { - floorclimb = true; - } - if (topheight < player->mo->z) // Waaaay below the ledge. - { - floorclimb = false; - } - if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale)) - { - floorclimb = false; - } - } - else - { - if ((bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > bottomheight)) - { - floorclimb = true; - } - if (bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge. - { - floorclimb = false; - } - if (topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale)) - { - floorclimb = false; - } - } - - if (floorclimb) - break; - } - } - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if ((floorz <= player->mo->z + player->mo->height) - && ((player->mo->z + player->mo->height - player->mo->momz) <= floorz)) - floorclimb = true; - - if ((floorz > player->mo->z) - && glidesector->sector->floorpic == skyflatnum) - return false; - - if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > ceilingz) - || (player->mo->z + player->mo->height <= floorz)) - floorclimb = true; - } - else - { - if ((ceilingz >= player->mo->z) - && ((player->mo->z - player->mo->momz) >= ceilingz)) - floorclimb = true; - - if ((ceilingz < player->mo->z+player->mo->height) - && glidesector->sector->ceilingpic == skyflatnum) - return false; - - if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < floorz) - || (player->mo->z >= ceilingz)) - floorclimb = true; - } - - if (!floorclimb) - return false; - - return true; - } - - return false; -} - -// P_TryClimb -// -// Attempts to climb a line from the player's current position -// Returns whether or not the line was climbed -// -boolean P_TryClimb(player_t *player, line_t *line) -{ - if (player && (player->pflags & PF_GLIDING || player->climbing) - && player->charability == CA_GLIDEANDCLIMB) - { - mobj_t *mo = player->mo; - line_t *checkline = line; - sector_t *checksector; - ffloor_t *rover; - fixed_t topheight, bottomheight; - boolean fofline = false; - INT32 side = P_PointOnLineSide(mo->x, mo->y, line); - - if (!side && line->backsector) - checksector = line->backsector; - else - checksector = line->frontsector; - - if (checksector->ffloors) - { - for (rover = checksector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) - continue; - - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, mo->x, mo->y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, mo->x, mo->y); -#endif - - if (topheight < mo->z) - continue; - - if (bottomheight > mo->z + mo->height) - continue; - - // Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this? - if (rover->master->flags & ML_TFERLINE) - { - size_t linenum = line-checksector->lines[0]; - checkline = rover->master->frontsector->lines[0] + linenum; - fofline = true; - } - - break; - } - } - - // see about climbing on the wall - if (!(checkline->flags & ML_NOCLIMB) && checkline->special != HORIZONSPECIAL) - { - boolean canclimb; - angle_t climbangle, climbline; - INT32 whichside = P_PointOnLineSide(mo->x, mo->y, line); - - climbangle = climbline = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); - - if (whichside) // on second side? - climbline += ANGLE_180; - - climbangle += (ANGLE_90 * (whichside ? -1 : 1)); - - canclimb = (line->backsector ? P_IsClimbingValid(player, climbangle) : true); - - if (((!player->climbing && abs((signed)(mo->angle - ANGLE_90 - climbline)) < ANGLE_45) - || (player->climbing == 1 && abs((signed)(mo->angle - climbline)) < ANGLE_135)) - && canclimb) - { - mo->angle = climbangle; - /*if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - { - if (player == &players[consoleplayer]) - localangle = mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = mo->angle; - }*/ - - if (!player->climbing) - { - S_StartSound(player->mo, sfx_s3k4a); - player->climbing = 5; - } - - player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED); - player->glidetime = 0; - player->secondjump = 0; - - if (player->climbing > 1) - mo->momz = mo->momx = mo->momy = 0; - - if (fofline) - whichside = 0; - - if (!whichside) - { - player->lastsidehit = checkline->sidenum[whichside]; - player->lastlinehit = (INT16)(checkline - lines); - } - - P_Thrust(mo, mo->angle, FixedMul(5*FRACUNIT, mo->scale)); - return true; - } - } - } - return false; -} - // // P_DoAbilityBounce // @@ -5305,6 +4984,15 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range) player->pflags |= PF_THOKKED; } +static void P_DoTwinSpin(player_t *player) +{ + player->pflags &= ~PF_NOJUMPDAMAGE; + player->pflags |= P_GetJumpFlags(player) | PF_THOKKED; + S_StartSound(player->mo, sfx_s3k42); + player->mo->frame = 0; + P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); +} + // // P_DoJumpStuff // @@ -5365,11 +5053,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } } } - if (cmd->buttons & BT_USE // Spin button effects - #ifdef HAVE_BLUA - && !LUAh_ShieldSpecial(player) - #endif - ) + if (cmd->buttons & BT_USE && !LUAh_ShieldSpecial(player)) // Spin button effects { // Force stop if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) @@ -5447,51 +5131,43 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) // and you don't have a shield, do it! P_DoSuperTransformation(player, false); } - else -#ifdef HAVE_BLUA - if (!LUAh_JumpSpinSpecial(player)) -#endif - switch (player->charability) - { - case CA_THOK: - if (player->powers[pw_super]) // Super Sonic float - { - if ((player->speed > 5*player->mo->scale) // FixedMul(5<mo->scale), but scale is FRACUNIT-based - && (P_MobjFlip(player->mo)*player->mo->momz <= 0)) + else if (!LUAh_JumpSpinSpecial(player)) + switch (player->charability) + { + case CA_THOK: + if (player->powers[pw_super]) // Super Sonic float { - if (player->panim != PA_RUN && player->panim != PA_WALK) + if ((player->speed > 5*player->mo->scale) // FixedMul(5<mo->scale), but scale is FRACUNIT-based + && (P_MobjFlip(player->mo)*player->mo->momz <= 0)) { - if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); - else - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); - } + if (player->panim != PA_RUN && player->panim != PA_WALK) + { + if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); + else + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); + } - player->mo->momz = 0; - player->pflags &= ~(PF_STARTJUMP|PF_SPINNING); + player->mo->momz = 0; + player->pflags &= ~(PF_STARTJUMP|PF_SPINNING); + } } - } - break; - case CA_TELEKINESIS: - if (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || (player->charflags & SF_MULTIABILITY)) - { - P_Telekinesis(player, - -FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player) - FixedMul(384*FRACUNIT, player->mo->scale)); - } - break; - case CA_TWINSPIN: - if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || player->charflags & SF_MULTIABILITY)) - { - player->pflags |= PF_THOKKED; - S_StartSound(player->mo, sfx_s3k42); - player->mo->frame = 0; - P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); - } - break; - default: - break; - } + break; + case CA_TELEKINESIS: + if (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || (player->charflags & SF_MULTIABILITY)) + { + P_Telekinesis(player, + -FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player) + FixedMul(384*FRACUNIT, player->mo->scale)); + } + break; + case CA_TWINSPIN: + if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || player->charflags & SF_MULTIABILITY)) + P_DoTwinSpin(player); + break; + default: + break; + } } } @@ -5527,16 +5203,13 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (cmd->buttons & BT_JUMP && !player->exiting && !P_PlayerInPain(player)) { -#ifdef HAVE_BLUA if (LUAh_JumpSpecial(player)) ; - else -#endif - if (player->pflags & PF_JUMPDOWN) // all situations below this require jump button not to be pressed already + // all situations below this require jump button not to be pressed already + else if (player->pflags & PF_JUMPDOWN) ; - else // Jump S3&K style while in quicksand. - if (P_InQuicksand(player->mo)) + else if (P_InQuicksand(player->mo)) { P_DoJump(player, true); player->secondjump = 0; @@ -5548,9 +5221,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_SetTarget(&player->mo->tracer, NULL); player->powers[pw_flashing] = TICRATE/4; } - else // can't jump while in air, can't jump while jumping - if (onground || player->climbing || player->powers[pw_carry]) + else if (onground || player->climbing || player->powers[pw_carry]) { P_DoJump(player, true); player->secondjump = 0; @@ -5566,9 +5238,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) }*/ else if (player->pflags & PF_JUMPED) { -#ifdef HAVE_BLUA if (!LUAh_AbilitySpecial(player)) -#endif switch (player->charability) { case CA_THOK: @@ -5639,9 +5309,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) /*if (!demoplayback) { if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(gc_turnleft) || PLAYER1INPUTDOWN(gc_turnright))) - localangle = player->mo->angle; + P_SetPlayerAngle(player, player->mo->angle);; else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(gc_turnleft) || PLAYER2INPUTDOWN(gc_turnright))) - localangle2 = player->mo->angle; + P_SetPlayerAngle(player, player->mo->angle); }*/ } break; @@ -5750,12 +5420,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) break; case CA_TWINSPIN: if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - player->pflags |= PF_THOKKED; - S_StartSound(player->mo, sfx_s3k42); - player->mo->frame = 0; - P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); - } + P_DoTwinSpin(player); break; default: break; @@ -5763,30 +5428,28 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } else if (player->pflags & PF_THOKKED) { -#ifdef HAVE_BLUA if (!LUAh_AbilitySpecial(player)) -#endif - switch (player->charability) - { - case CA_FLY: - case CA_SWIM: // Swim - if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) - ; // Can't do anything if you're a fish out of water! - else if (player->powers[pw_tailsfly]) // If currently flying, give an ascend boost. - { - player->fly1 = 20; + switch (player->charability) + { + case CA_FLY: + case CA_SWIM: // Swim + if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) + ; // Can't do anything if you're a fish out of water! + else if (player->powers[pw_tailsfly]) // If currently flying, give an ascend boost. + { + player->fly1 = 20; - if (player->charability == CA_SWIM) - player->fly1 /= 2; + if (player->charability == CA_SWIM) + player->fly1 /= 2; - // Slow down! - if (player->speed > FixedMul(8*FRACUNIT, player->mo->scale) && player->speed > FixedMul(player->normalspeed>>1, player->mo->scale)) - P_Thrust(player->mo, R_PointToAngle2(0,0,player->mo->momx,player->mo->momy), FixedMul(-4*FRACUNIT, player->mo->scale)); - } - break; - default: - break; - } + // Slow down! + if (player->speed > FixedMul(8*FRACUNIT, player->mo->scale) && player->speed > FixedMul(player->normalspeed>>1, player->mo->scale)) + P_Thrust(player->mo, R_PointToAngle2(0,0,player->mo->momx,player->mo->momy), FixedMul(-4*FRACUNIT, player->mo->scale)); + } + break; + default: + break; + } } else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super]) P_DoJumpShield(player); @@ -6016,11 +5679,7 @@ static void P_2dMovement(player_t *player) } else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt player->cmomx = player->cmomy = 0; - else if (player->onconveyor != 2 && player->onconveyor != 4 -#ifdef POLYOBJECTS - && player->onconveyor != 1 -#endif - ) + else if (player->onconveyor != 2 && player->onconveyor != 4 && player->onconveyor != 1) player->cmomx = player->cmomy = 0; player->rmomx = player->mo->momx - player->cmomx; @@ -6057,10 +5716,7 @@ static void P_2dMovement(player_t *player) player->mo->angle = ANGLE_180; } - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + P_SetPlayerAngle(player, player->mo->angle); if (player->pflags & PF_GLIDING) movepushangle = player->mo->angle; @@ -6161,12 +5817,10 @@ static void P_3dMovement(player_t *player) controlstyle_e controlstyle; boolean spin = ((onground = P_IsObjectOnGround(player->mo)) && (player->pflags & (PF_SPINNING|PF_THOKKED)) == PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH)); fixed_t oldMagnitude, newMagnitude; -#ifdef ESLOPE vector3_t totalthrust; totalthrust.x = totalthrust.y = 0; // I forget if this is needed totalthrust.z = FRACUNIT*P_MobjFlip(player->mo)/3; // A bit of extra push-back on slopes -#endif // ESLOPE // Get the old momentum; this will be needed at the end of the function! -SH oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); @@ -6217,11 +5871,7 @@ static void P_3dMovement(player_t *player) } else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt player->cmomx = player->cmomy = 0; - else if (player->onconveyor != 2 && player->onconveyor != 4 -#ifdef POLYOBJECTS - && player->onconveyor != 1 -#endif - ) + else if (player->onconveyor != 2 && player->onconveyor != 4 && player->onconveyor != 1) player->cmomx = player->cmomy = 0; player->rmomx = player->mo->momx - player->cmomx; @@ -6367,12 +6017,8 @@ static void P_3dMovement(player_t *player) movepushforward = FixedMul(movepushforward, player->mo->scale); -#ifdef ESLOPE totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward); totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward); -#else - P_Thrust(player->mo, movepushangle, movepushforward); -#endif } // Sideways movement if (player->climbing) @@ -6415,12 +6061,8 @@ static void P_3dMovement(player_t *player) movepushforward = FixedMul(movepushforward, player->mo->scale); -#ifdef ESLOPE totalthrust.x += P_ReturnThrustX(player->mo, controldirection, movepushforward); totalthrust.y += P_ReturnThrustY(player->mo, controldirection, movepushforward); -#else - P_Thrust(player->mo, controldirection, movepushforward); -#endif } } else if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !P_PlayerInPain(player)) @@ -6449,15 +6091,10 @@ static void P_3dMovement(player_t *player) // Finally move the player now that their speed/direction has been decided. movepushside = FixedMul(movepushside, player->mo->scale); -#ifdef ESLOPE totalthrust.x += P_ReturnThrustX(player->mo, movepushsideangle, movepushside); totalthrust.y += P_ReturnThrustY(player->mo, movepushsideangle, movepushside); -#else - P_Thrust(player->mo, movepushsideangle, movepushside); -#endif } -#ifdef ESLOPE if ((totalthrust.x || totalthrust.y) && player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) { // Factor thrust to slope, but only for the part pushing up it! @@ -6477,7 +6114,6 @@ static void P_3dMovement(player_t *player) player->mo->momx += totalthrust.x; player->mo->momy += totalthrust.y; -#endif // Time to ask three questions: // 1) Are we over topspeed? @@ -7917,10 +7553,7 @@ static void P_NiGHTSMovement(player_t *player) else player->mo->rollangle = rollangle; - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + P_SetPlayerAngle(player, player->mo->angle); // Check for crushing in our new location if ((player->mo->ceilingz - player->mo->floorz < player->mo->height) @@ -8090,14 +7723,13 @@ void P_ElementalFire(player_t *player, boolean cropcircle) newx = player->mo->x + P_ReturnThrustX(player->mo, (travelangle + ((i&1) ? -1 : 1)*ANGLE_135), FixedMul(24*FRACUNIT, player->mo->scale)); newy = player->mo->y + P_ReturnThrustY(player->mo, (travelangle + ((i&1) ? -1 : 1)*ANGLE_135), FixedMul(24*FRACUNIT, player->mo->scale)); -#ifdef ESLOPE if (player->mo->standingslope) { - ground = P_GetZAt(player->mo->standingslope, newx, newy); + ground = P_GetSlopeZAt(player->mo->standingslope, newx, newy); if (player->mo->eflags & MFE_VERTICALFLIP) ground -= FixedMul(mobjinfo[MT_SPINFIRE].height, player->mo->scale); } -#endif + flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE); P_SetTarget(&flame->target, player->mo); flame->angle = travelangle; @@ -8289,7 +7921,7 @@ static void P_MovePlayer(player_t *player) if (player->pflags & PF_TAGIT) forcestasis = true; } - else if (gametype == GT_HIDEANDSEEK) + else if (gametyperules & GTR_HIDEFROZEN) { if (!(player->pflags & PF_TAGIT)) { @@ -8325,7 +7957,7 @@ static void P_MovePlayer(player_t *player) && player->mo->state < &states[S_PLAY_NIGHTS_TRANS6]))) // Note the < instead of <= { skin_t *skin = ((skin_t *)(player->mo->skin)); - if (skin->flags & SF_SUPER) + if (( skin->flags & (SF_SUPER|SF_NONIGHTSSUPER) ) == SF_SUPER) { player->mo->color = skin->supercolor + ((player->nightstime == player->startedtime) @@ -8584,32 +8216,6 @@ static void P_MovePlayer(player_t *player) if (!player->skidtime) // TODO: make sure this works in 2D! { - /*angle_t anglediff = angle - moveangle; - fixed_t scale = mo->scale; - fixed_t accelfactor = 4*FRACUNIT - 3*FINECOSINE(((angle-moveangle) >> ANGLETOFINESHIFT) & FINEMASK); // mamgic number BAD but this feels right - fixed_t speed = FixedHypot(momx, momy); - fixed_t minspeed; - - if (anglediff > ANGLE_180) - anglediff = InvAngle(InvAngle(anglediff) >> 4); - else - anglediff = anglediff >> 4; - - if (mo->eflags & MFE_UNDERWATER) - minspeed = FixedMul((glidespeed>>1) + player->glidetime*750, scale); - else - minspeed = FixedMul(glidespeed + player->glidetime*1500, scale); - - if (speed < minspeed) - { - momx += P_ReturnThrustX(mo, angle, FixedMul(accelfactor, scale)); - momy += P_ReturnThrustY(mo, angle, FixedMul(accelfactor, scale)); - speed = FixedHypot(momx, momy); // recalculate speed - } - - mo->momx = P_ReturnThrustX(mo, moveangle + anglediff, speed) + player->cmomx; - mo->momy = P_ReturnThrustY(mo, moveangle + anglediff, speed) + player->cmomy;*/ - 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 @@ -8908,10 +8514,7 @@ static void P_MovePlayer(player_t *player) player->mo->angle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); // Update the local angle control. - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + P_SetPlayerAngle(player, player->mo->angle); } if (player->climbing == 1) @@ -8991,7 +8594,7 @@ static void P_MovePlayer(player_t *player) } #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none && cv_fovchange.value) + if (rendermode == render_opengl && cv_fovchange.value) { fixed_t speed; const fixed_t runnyspeed = 20*FRACUNIT; @@ -9107,10 +8710,7 @@ static void P_MovePlayer(player_t *player) static void P_DoZoomTube(player_t *player) { - INT32 sequence; fixed_t speed; - thinker_t *th; - mobj_t *mo2; mobj_t *waypoint = NULL; fixed_t dist; boolean reverse; @@ -9126,8 +8726,6 @@ static void P_DoZoomTube(player_t *player) speed = abs(player->speed); - sequence = player->mo->tracer->threshold; - // change slope dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z); @@ -9159,28 +8757,7 @@ static void P_DoZoomTube(player_t *player) CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n"); // Find next waypoint - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (reverse && mo2->health != player->mo->tracer->health - 1) - continue; - - if (!reverse && mo2->health != player->mo->tracer->health + 1) - continue; - - waypoint = mo2; - break; - } + waypoint = reverse ? P_GetPreviousWaypoint(player->mo->tracer, false) : P_GetNextWaypoint(player->mo->tracer, false); if (waypoint) { @@ -9213,11 +8790,7 @@ static void P_DoZoomTube(player_t *player) if (player->mo->tracer) { player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y); - - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + P_SetPlayerAngle(player, player->mo->angle); } } @@ -9231,8 +8804,6 @@ static void P_DoRopeHang(player_t *player) { INT32 sequence; fixed_t speed; - thinker_t *th; - mobj_t *mo2; mobj_t *waypoint = NULL; fixed_t dist; fixed_t playerz; @@ -9295,50 +8866,14 @@ static void P_DoRopeHang(player_t *player) CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n"); // Find next waypoint - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (mo2->health != player->mo->tracer->health + 1) - continue; - - waypoint = mo2; - break; - } + waypoint = P_GetNextWaypoint(player->mo->tracer, false); if (!(player->mo->tracer->flags & MF_SLIDEME) && !waypoint) { CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, wrapping to start...\n"); // Wrap around back to first waypoint - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (mo2->health != 0) - continue; - - waypoint = mo2; - break; - } + waypoint = P_GetFirstWaypoint(sequence); } if (waypoint) @@ -9700,7 +9235,7 @@ boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target if (enemy->health <= 0) // dead return false; - if (!((enemy->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (enemy->flags & MF_SHOOTABLE)) || (enemy->flags & MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + if (source->player && (!((enemy->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (enemy->flags & MF_SHOOTABLE)) || (enemy->flags & MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE))) // allows if it has the flags desired XOR it has the invert aimable flag return false; if (enemy->flags2 & MF2_FRET) @@ -9712,12 +9247,7 @@ boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target { source->player->drawangle = source->angle; if (!demoplayback || P_ControlStyle(source->player) == CS_LMAOGALOG) - { - if (source->player == &players[consoleplayer]) - localangle = source->angle; - else if (source->player == &players[secondarydisplayplayer]) - localangle2 = source->angle; - } + P_SetPlayerAngle(source->player, source->angle); } // change slope @@ -9912,14 +9442,14 @@ static void P_DeathThink(player_t *player) // continue logic if (!(netgame || multiplayer) && player->lives <= 0) { - if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) + if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && (!continuesInSession || player->continues > 0)) G_UseContinue(); else if (player->deadtimer >= gameovertics) G_UseContinue(); // Even if we don't have one this handles ending the game } if ((cv_cooplives.value != 1) - && (gametype == GT_COOP) + && (G_GametypeUsesCoopLives()) && (netgame || multiplayer) && (player->lives <= 0)) { @@ -10001,17 +9531,17 @@ static void P_DeathThink(player_t *player) countdown2 = 1*TICRATE; } } - //else if (gametype == GT_COOP) -- moved to G_DoReborn + //else if (G_CoopGametype()) -- moved to G_DoReborn } - if (gametype == GT_COOP && (multiplayer || netgame) && (player->lives <= 0) && (player->deadtimer >= 8*TICRATE || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE)))) + if (G_CoopGametype() && (multiplayer || netgame) && (player->lives <= 0) && (player->deadtimer >= 8*TICRATE || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE)))) { //player->spectator = true; player->outofcoop = true; player->playerstate = PST_REBORN; } - if ((gametyperules & GTR_RACE) || (gametype == GT_COOP && (multiplayer || netgame))) + if ((gametyperules & GTR_RACE) || (G_CoopGametype() && (multiplayer || netgame))) { // Keep time rolling in race mode if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER) && !stoppedclock) @@ -10028,7 +9558,7 @@ static void P_DeathThink(player_t *player) } // Return to level music - if (gametype != GT_COOP && player->lives <= 0 && player->deadtimer == gameovertics) + if (!G_CoopGametype() && player->lives <= 0 && player->deadtimer == gameovertics) P_RestoreMultiMusic(player); } @@ -10158,7 +9688,7 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) if ((thiscam == &camera && G_ControlStyle(1) == CS_SIMPLE) || (thiscam == &camera2 && G_ControlStyle(2) == CS_SIMPLE)) { - thiscam->angle = (thiscam == &camera) ? localangle : localangle2; + thiscam->angle = P_GetLocalAngle(player); thiscam->aiming = (thiscam == &camera) ? localaiming : localaiming2; } else if (!(thiscam == &camera && (cv_cam_still.value || cv_analog[0].value)) @@ -10205,7 +9735,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (player->exiting) { if (mo->target && mo->target->type == MT_SIGN && mo->target->spawnpoint - && !(gametype == GT_COOP && (netgame || multiplayer) && cv_exitmove.value) + && !((gametyperules & GTR_FRIENDLY) && (netgame || multiplayer) && cv_exitmove.value) && !(twodlevel || (mo->flags2 & MF2_TWOD))) sign = mo->target; else if ((player->powers[pw_carry] == CR_NIGHTSMODE) @@ -10359,9 +9889,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (player == &players[consoleplayer]) { if (focusangle >= localangle) - localangle += abs((signed)(focusangle - localangle))>>5; + P_ForceLocalAngle(player, localangle + (abs((signed)(focusangle - localangle))>>5)); else - localangle -= abs((signed)(focusangle - localangle))>>5; + P_ForceLocalAngle(player, localangle - (abs((signed)(focusangle - localangle))>>5)); } } else @@ -10474,9 +10004,11 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (camorbit) //Sev here, I'm guessing this is where orbital cam lives { - if (rendermode == render_opengl) +#ifdef HWRENDER + if (rendermode == render_opengl && !cv_grshearing.value) distxy = FixedMul(dist, FINECOSINE((focusaiming>>ANGLETOFINESHIFT) & FINEMASK)); else +#endif distxy = dist; distz = -FixedMul(dist, FINESINE((focusaiming>>ANGLETOFINESHIFT) & FINEMASK)) + slopez; } @@ -10604,7 +10136,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } } -#ifdef POLYOBJECTS // Check polyobjects and see if floorz/ceilingz need to be altered { INT32 xl, xh, yl, yh, bx, by; @@ -10683,7 +10214,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } } } -#endif // crushed camera if (myceilingz <= myfloorz + thiscam->height && !resetcalled && !cameranoclip) @@ -10874,7 +10404,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall boolean P_SpectatorJoinGame(player_t *player) { - if (gametype != GT_COOP && !cv_allowteamchange.value) + if (!G_CoopGametype() && !cv_allowteamchange.value) { if (P_IsLocalPlayer(player)) CONS_Printf(M_GetText("Server does not allow team change.\n")); @@ -10911,10 +10441,8 @@ boolean P_SpectatorJoinGame(player_t *player) else changeto = (P_RandomFixed() & 1) + 1; -#ifdef HAVE_BLUA if (!LUAh_TeamSwitch(player, changeto, true, false, false)) return false; -#endif if (player->mo) { @@ -10928,11 +10456,9 @@ boolean P_SpectatorJoinGame(player_t *player) //Reset away view if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) { -#ifdef HAVE_BLUA // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[displayplayer], true); -#endif + LUAh_ViewpointSwitch(player, &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -10950,10 +10476,8 @@ boolean P_SpectatorJoinGame(player_t *player) // respawn in place and sit there for the rest of the round. if (!((gametyperules & GTR_HIDEFROZEN) && leveltime > (hidetime * TICRATE))) { -#ifdef HAVE_BLUA if (!LUAh_TeamSwitch(player, 3, true, false, false)) return false; -#endif if (player->mo) { P_RemoveMobj(player->mo); @@ -10962,7 +10486,7 @@ boolean P_SpectatorJoinGame(player_t *player) player->spectator = player->outofcoop = false; player->playerstate = PST_REBORN; - if (gametype == GT_TAG) + if ((gametyperules & (GTR_TAG|GTR_HIDEFROZEN)) == GTR_TAG) { //Make joining players "it" after hidetime. if (leveltime > (hidetime * TICRATE)) @@ -10977,15 +10501,13 @@ boolean P_SpectatorJoinGame(player_t *player) //Reset away view if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) { -#ifdef HAVE_BLUA // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[displayplayer], true); -#endif + LUAh_ViewpointSwitch(player, &players[consoleplayer], true); displayplayer = consoleplayer; } - if (gametype != GT_COOP) + if (!G_CoopGametype()) CONS_Printf(M_GetText("%s entered the game.\n"), player_names[player-players]); return true; // no more player->mo, cannot continue. } @@ -11044,13 +10566,8 @@ static void P_CalcPostImg(player_t *player) if (!(rover->flags & FF_EXISTS)) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); if (pviewheight >= topheight || pviewheight <= bottomheight) continue; @@ -11072,13 +10589,8 @@ static void P_CalcPostImg(player_t *player) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKPLAYER) continue; -#ifdef ESLOPE - topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; - bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; -#else - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; -#endif + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); if (pviewheight >= topheight || pviewheight <= bottomheight) continue; @@ -11140,7 +10652,7 @@ static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *n if (!(rover->flags & (FF_EXISTS|FF_BLOCKOTHERS))) continue; - *nz = *rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight; + *nz = P_GetFFloorTopZAt(rover, x, y); if (abs(z - *nz) <= 56*FRACUNIT) { sec = §ors[rover->secnum]; @@ -11150,7 +10662,7 @@ static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *n } - *nz = sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->floorheight; + *nz = P_GetSectorFloorZAt(sec, x, y); if (abs(z - *nz) > 56*FRACUNIT) return NULL; @@ -11355,21 +10867,13 @@ static void P_MinecartThink(player_t *player) if (angdiff + minecart->angle != player->mo->angle && (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG)) { - angle_t *ang = NULL; + angdiff = P_GetLocalAngle(player) - minecart->angle; + if (angdiff < ANGLE_180 && angdiff > MINECARTCONEMAX) + P_SetLocalAngle(player, minecart->angle + MINECARTCONEMAX); + else if (angdiff > ANGLE_180 && angdiff < InvAngle(MINECARTCONEMAX)) + P_SetLocalAngle(player, minecart->angle - MINECARTCONEMAX); - if (player == &players[consoleplayer]) - ang = &localangle; - else if (player == &players[secondarydisplayplayer]) - ang = &localangle2; - if (ang) - { - angdiff = *ang - minecart->angle; - if (angdiff < ANGLE_180 && angdiff > MINECARTCONEMAX) - *ang = minecart->angle + MINECARTCONEMAX; - else if (angdiff > ANGLE_180 && angdiff < InvAngle(MINECARTCONEMAX)) - *ang = minecart->angle - MINECARTCONEMAX; - } } } @@ -11446,10 +10950,7 @@ static void P_MinecartThink(player_t *player) if (angdiff && (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG)) // maintain relative angle on turns { player->mo->angle += angdiff; - if (player == &players[consoleplayer]) - localangle += angdiff; - else if (player == &players[secondarydisplayplayer]) - localangle2 += angdiff; + P_SetPlayerAngle(player, (angle_t)(player->angleturn << 16) + angdiff); } // Sideways detection @@ -11504,8 +11005,8 @@ static void P_MinecartThink(player_t *player) if (minecart->standingslope) { fixed_t fa2 = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK; - fixed_t front = P_GetZAt(minecart->standingslope, minecart->x, minecart->y); - fixed_t back = P_GetZAt(minecart->standingslope, minecart->x - FINECOSINE(fa2), minecart->y - FINESINE(fa2)); + fixed_t front = P_GetSlopeZAt(minecart->standingslope, minecart->x, minecart->y); + fixed_t back = P_GetSlopeZAt(minecart->standingslope, minecart->x - FINECOSINE(fa2), minecart->y - FINESINE(fa2)); if (abs(front - back) < 3*FRACUNIT) currentSpeed += (back - front)/3; @@ -11872,6 +11373,10 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) fume->y = mo->y + P_ReturnThrustY(fume, angle, dist); fume->z = mo->z + ((mo->height - fume->height) >> 1); P_SetThingPosition(fume); + + // If dashmode is high enough, spawn a trail + if (player->normalspeed >= skins[player->skin].normalspeed*2) + P_SpawnGhostMobj(fume); } // @@ -11904,9 +11409,7 @@ void P_PlayerThink(player_t *player) } if (player->playerstate == PST_REBORN) { -#ifdef HAVE_BLUA LUAh_PlayerThink(player); -#endif return; } } @@ -12010,9 +11513,7 @@ void P_PlayerThink(player_t *player) if (player->playerstate == PST_DEAD) { -#ifdef HAVE_BLUA LUAh_PlayerThink(player); -#endif return; } } @@ -12033,7 +11534,7 @@ void P_PlayerThink(player_t *player) // so we can fade music if (!exitfadestarted && player->exiting > 0 && player->exiting <= 1*TICRATE && - (!multiplayer || gametype == GT_COOP ? !mapheaderinfo[gamemap-1]->musinterfadeout : true) && + (!multiplayer || G_CoopGametype() ? !mapheaderinfo[gamemap-1]->musinterfadeout : true) && // don't fade if we're fading during intermission. follows Y_StartIntermission intertype = int_coop ((gametyperules & GTR_RACE) ? countdown2 == 0 : true) && // don't fade on timeout player->lives > 0 && // don't fade on game over (competition) @@ -12106,7 +11607,7 @@ void P_PlayerThink(player_t *player) if (player->pflags & PF_FINISHED) { - if ((gametype == GT_COOP && cv_exitmove.value) && !G_EnoughPlayersFinished()) + if (((gametyperules & GTR_FRIENDLY) && cv_exitmove.value) && !G_EnoughPlayersFinished()) player->exiting = 0; else P_DoPlayerExit(player); @@ -12116,10 +11617,8 @@ void P_PlayerThink(player_t *player) P_MobjCheckWater(player->mo); #ifndef SECTORSPECIALSAFTERTHINK -#ifdef POLYOBJECTS if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) -#endif - player->onconveyor = 0; + player->onconveyor = 0; // check special sectors : damage & secrets if (!player->spectator) @@ -12135,19 +11634,17 @@ void P_PlayerThink(player_t *player) { player->mo->flags2 &= ~MF2_SHADOW; P_DeathThink(player); -#ifdef HAVE_BLUA LUAh_PlayerThink(player); -#endif return; } // Make sure spectators always have a score and ring count of 0. if (player->spectator) { - if (gametype != GT_COOP) + if (!(gametyperules & GTR_CAMPAIGN)) player->score = 0; } - else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP) + else if ((netgame || multiplayer) && player->lives <= 0 && !G_CoopGametype()) { // Outside of Co-Op, replenish a user's lives if they are depleted. // of course, this is just a cheap hack, meh... @@ -12179,9 +11676,7 @@ void P_PlayerThink(player_t *player) { if (P_SpectatorJoinGame(player)) { -#ifdef HAVE_BLUA LUAh_PlayerThink(player); -#endif return; // player->mo was removed. } } @@ -12286,9 +11781,7 @@ void P_PlayerThink(player_t *player) if (!player->mo) { -#ifdef HAVE_BLUA LUAh_PlayerThink(player); -#endif return; // P_MovePlayer removed player->mo. } @@ -12338,6 +11831,9 @@ void P_PlayerThink(player_t *player) factor = 4; } break; + case CR_DUSTDEVIL: + player->drawangle += ANG20; + break; /* -- in case we wanted to have the camera freely movable during zoom tubes case CR_ZOOMTUBE:*/ case CR_ROPEHANG: @@ -12483,12 +11979,10 @@ void P_PlayerThink(player_t *player) // it lasts for one tic. player->pflags &= ~PF_FULLSTASIS; -#ifdef POLYOBJECTS if (player->onconveyor == 1) player->onconveyor = 3; else if (player->onconveyor == 3) player->cmomy = player->cmomx = 0; -#endif P_DoSuperStuff(player); P_CheckSneakerAndLivesTimer(player); @@ -12676,6 +12170,7 @@ void P_PlayerThink(player_t *player) // Dash mode - thanks be to VelocitOni if ((player->charflags & SF_DASHMODE) && !player->gotflag && !player->powers[pw_carry] && !player->exiting && !(maptol & TOL_NIGHTS) && !metalrecording) // woo, dashmode! no nights tho. { + tic_t prevdashmode = dashmode; boolean totallyradical = player->speed >= FixedMul(player->runspeed, player->mo->scale); boolean floating = (player->secondjump == 1); @@ -12700,8 +12195,11 @@ void P_PlayerThink(player_t *player) 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; + if (prevdashmode >= DASHMODE_THRESHOLD) + { + player->normalspeed = skins[player->skin].normalspeed; // Reset to default if not capable of entering dash mode. + player->jumpfactor = skins[player->skin].jumpfactor; + } } else if (P_IsObjectOnGround(player->mo)) // Activate dash mode if we're on the ground. { @@ -12716,6 +12214,8 @@ void P_PlayerThink(player_t *player) { mobj_t *ghost = P_SpawnGhostMobj(player->mo); // Spawns afterimages ghost->fuse = 2; // Makes the images fade quickly + if (ghost->tracer && !P_MobjWasRemoved(ghost->tracer)) + ghost->tracer->fuse = ghost->fuse; } } else if (dashmode) @@ -12730,9 +12230,7 @@ void P_PlayerThink(player_t *player) } #undef dashmode -#ifdef HAVE_BLUA LUAh_PlayerThink(player); -#endif /* // Colormap verification @@ -12823,10 +12321,8 @@ void P_PlayerAfterThink(player_t *player) cmd = &player->cmd; #ifdef SECTORSPECIALSAFTERTHINK -#ifdef POLYOBJECTS if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) -#endif - player->onconveyor = 0; + player->onconveyor = 0; // check special sectors : damage & secrets if (!player->spectator) @@ -13012,17 +12508,12 @@ void P_PlayerAfterThink(player_t *player) player->mo->momz = tails->momz; } - if (gametype == GT_COOP && (!tails->player || tails->player->bot != 1)) + if (G_CoopGametype() && (!tails->player || tails->player->bot != 1)) { player->mo->angle = tails->angle; if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - { - if (player == &players[consoleplayer]) - localangle = player->mo->angle; - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - } + P_SetPlayerAngle(player, player->mo->angle); } if (P_AproxDistance(player->mo->x - tails->x, player->mo->y - tails->y) > player->mo->radius) @@ -13106,16 +12597,24 @@ void P_PlayerAfterThink(player_t *player) player->mo->angle += cmd->sidemove< ANGLE_MAX if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - { - if (player == &players[consoleplayer]) - localangle = player->mo->angle; // Adjust the local control angle. - else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; - } + P_SetPlayerAngle(player, player->mo->angle); } } break; } + case CR_DUSTDEVIL: + { + mobj_t *mo = player->mo, *dustdevil = player->mo->tracer; + + if (abs(mo->x - dustdevil->x) > dustdevil->radius || abs(mo->y - dustdevil->y) > dustdevil->radius) + { + P_SetTarget(&player->mo->tracer, NULL); + player->powers[pw_carry] = CR_NONE; + break; + } + + break; + } case CR_ROLLOUT: { mobj_t *mo = player->mo, *rock = player->mo->tracer; @@ -13257,6 +12756,12 @@ void P_PlayerAfterThink(player_t *player) player->mo->flags |= MF_NOGRAVITY; } + if (player->powers[pw_dye]) + { + player->mo->colorized = true; + player->mo->color = player->powers[pw_dye]; + } + if (player->followmobj && (player->spectator || player->mo->health <= 0 || player->followmobj->type != player->followitem)) { P_RemoveMobj(player->followmobj); @@ -13282,11 +12787,9 @@ void P_PlayerAfterThink(player_t *player) if (player->followmobj) { -#ifdef HAVE_BLUA if (LUAh_FollowMobj(player, player->followmobj) || P_MobjWasRemoved(player->followmobj)) {;} else -#endif { switch (player->followmobj->type) { @@ -13306,3 +12809,43 @@ void P_PlayerAfterThink(player_t *player) } } } + +void P_SetPlayerAngle(player_t *player, angle_t angle) +{ + INT16 delta = (INT16)(angle >> 16) - player->angleturn; + + P_ForceLocalAngle(player, P_GetLocalAngle(player) + (delta << 16)); + player->angleturn += delta; +} + +void P_SetLocalAngle(player_t *player, angle_t angle) +{ + INT16 delta = (INT16)((angle - P_GetLocalAngle(player)) >> 16); + + P_ForceLocalAngle(player, P_GetLocalAngle(player) + (angle_t)(delta << 16)); + + if (player == &players[consoleplayer]) + ticcmd_oldangleturn[0] += delta; + else if (player == &players[secondarydisplayplayer]) + ticcmd_oldangleturn[1] += delta; +} + +angle_t P_GetLocalAngle(player_t *player) +{ + if (player == &players[consoleplayer]) + return localangle; + else if (player == &players[secondarydisplayplayer]) + return localangle2; + else + return 0; +} + +void P_ForceLocalAngle(player_t *player, angle_t angle) +{ + angle = angle & ~UINT16_MAX; + + if (player == &players[consoleplayer]) + localangle = angle; + else if (player == &players[secondarydisplayplayer]) + localangle2 = angle; +} diff --git a/src/r_bsp.c b/src/r_bsp.c index 6b4667aee..a430ef040 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -354,15 +354,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) { return ( -#ifdef POLYOBJECTS !line->polyseg && -#endif back->ceilingpic == front->ceilingpic && back->floorpic == front->floorpic -#ifdef ESLOPE && back->f_slope == front->f_slope && back->c_slope == front->c_slope -#endif && back->lightlevel == front->lightlevel && !line->sidedef->midtexture // Check offsets too! @@ -484,35 +480,28 @@ static void R_AddLine(seg_t *line) if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then { - if ( -#ifdef POLYOBJECTS - !line->polyseg && -#endif - !line->sidedef->midtexture - && ((!frontsector->ffloors && !backsector->ffloors) - || (frontsector->tag == backsector->tag))) + if (!line->polyseg && + !line->sidedef->midtexture + && ((!frontsector->ffloors && !backsector->ffloors) + || (frontsector->tag == backsector->tag))) return; // line is empty, don't even bother goto clippass; // treat like wide open window instead } // Closed door. -#ifdef ESLOPE if (frontsector->f_slope || frontsector->c_slope || backsector->f_slope || backsector->c_slope) { fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, line->v1->x, line->v1->y); \ - end2 = P_GetZAt(slope, line->v2->x, line->v2->y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, line->v1->x, line->v1->y, normalheight); \ + end2 = P_GetZAt(slope, line->v2->x, line->v2->y, normalheight); - SLOPEPARAMS(frontsector->f_slope, frontf1, frontf2, frontsector->floorheight) + SLOPEPARAMS(frontsector->f_slope, frontf1, frontf2, frontsector-> floorheight) SLOPEPARAMS(frontsector->c_slope, frontc1, frontc2, frontsector->ceilingheight) - SLOPEPARAMS( backsector->f_slope, backf1, backf2, backsector->floorheight) - SLOPEPARAMS( backsector->c_slope, backc1, backc2, backsector->ceilingheight) + SLOPEPARAMS( backsector->f_slope, backf1, backf2, backsector-> floorheight) + SLOPEPARAMS( backsector->c_slope, backc1, backc2, backsector->ceilingheight) #undef SLOPEPARAMS // if both ceilings are skies, consider it always "open" // same for floors @@ -542,7 +531,6 @@ static void R_AddLine(seg_t *line) goto clippass; } else -#endif { // if both ceilings are skies, consider it always "open" // same for floors @@ -658,8 +646,6 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) return true; } -#ifdef POLYOBJECTS - size_t numpolys; // number of polyobjects in current subsector size_t num_po_ptrs; // number of polyobject pointers allocated polyobj_t **po_ptrs; // temp ptr array to sort polyobject pointers @@ -812,6 +798,9 @@ static void R_AddPolyObjects(subsector_t *sub) po = (polyobj_t *)(po->link.next); } + // for render stats + rs_numpolyobjects += numpolys; + // sort polyobjects R_SortPolyObjects(sub); @@ -823,7 +812,6 @@ static void R_AddPolyObjects(subsector_t *sub) R_AddLine(po_ptrs[i]->segs[j]); } } -#endif // // R_Subsector @@ -863,17 +851,8 @@ static void R_Subsector(size_t num) floorcolormap = ceilingcolormap = frontsector->extra_colormap; - floorcenterz = -#ifdef ESLOPE - frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) : -#endif - frontsector->floorheight; - - ceilingcenterz = -#ifdef ESLOPE - frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) : -#endif - frontsector->ceilingheight; + floorcenterz = P_GetSectorFloorZAt (frontsector, frontsector->soundorg.x, frontsector->soundorg.y); + ceilingcenterz = P_GetSectorCeilingZAt(frontsector, frontsector->soundorg.x, frontsector->soundorg.y); // Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps. if (frontsector->ffloors) @@ -899,53 +878,29 @@ static void R_Subsector(size_t num) sub->sector->extra_colormap = frontsector->extra_colormap; - if ((( -#ifdef ESLOPE - frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) : -#endif - frontsector->floorheight) < viewz || frontsector->floorpic == skyflatnum - || (frontsector->heightsec != -1 - && sectors[frontsector->heightsec].ceilingpic == skyflatnum))) + if (P_GetSectorFloorZAt(frontsector, viewx, viewy) < viewz + || frontsector->floorpic == skyflatnum + || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum)) { floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel, - frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL -#ifdef POLYOBJECTS_PLANES - , NULL -#endif -#ifdef ESLOPE - , frontsector->f_slope -#endif - ); + frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL, NULL, frontsector->f_slope); } else floorplane = NULL; - if ((( -#ifdef ESLOPE - frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) : -#endif - frontsector->ceilingheight) > viewz || frontsector->ceilingpic == skyflatnum - || (frontsector->heightsec != -1 - && sectors[frontsector->heightsec].floorpic == skyflatnum))) + if (P_GetSectorCeilingZAt(frontsector, viewx, viewy) > viewz + || frontsector->ceilingpic == skyflatnum + || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum)) { ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle, - ceilingcolormap, NULL -#ifdef POLYOBJECTS_PLANES - , NULL -#endif -#ifdef ESLOPE - , frontsector->c_slope -#endif - ); + ceilingcolormap, NULL, NULL, frontsector->c_slope); } else ceilingplane = NULL; numffloors = 0; -#ifdef ESLOPE ffloor[numffloors].slope = NULL; -#endif ffloor[numffloors].plane = NULL; ffloor[numffloors].polyobj = NULL; if (frontsector->ffloors) @@ -970,43 +925,26 @@ static void R_Subsector(size_t num) ffloor[numffloors].plane = NULL; ffloor[numffloors].polyobj = NULL; - heightcheck = -#ifdef ESLOPE - *rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : -#endif - *rover->bottomheight; + heightcheck = P_GetFFloorBottomZAt(rover, viewx, viewy); - planecenterz = -#ifdef ESLOPE - *rover->b_slope ? P_GetZAt(*rover->b_slope, frontsector->soundorg.x, frontsector->soundorg.y) : -#endif - *rover->bottomheight; + planecenterz = P_GetFFloorBottomZAt(rover, frontsector->soundorg.x, frontsector->soundorg.y); if (planecenterz <= ceilingcenterz && planecenterz >= floorcenterz - && ((viewz < heightcheck && !(rover->flags & FF_INVERTPLANES)) - || (viewz > heightcheck && (rover->flags & FF_BOTHPLANES)))) + && ((viewz < heightcheck && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) + || (viewz > heightcheck && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck); ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic, *frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, - *rover->bottomyoffs, *rover->bottomangle, *frontsector->lightlist[light].extra_colormap, rover -#ifdef POLYOBJECTS_PLANES - , NULL -#endif -#ifdef ESLOPE - , *rover->b_slope -#endif - ); + *rover->bottomyoffs, *rover->bottomangle, *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->b_slope); -#ifdef ESLOPE ffloor[numffloors].slope = *rover->b_slope; // Tell the renderer this sector has slopes in it. if (ffloor[numffloors].slope) frontsector->hasslope = true; -#endif ffloor[numffloors].height = heightcheck; ffloor[numffloors].ffloor = rover; @@ -1017,42 +955,25 @@ static void R_Subsector(size_t num) ffloor[numffloors].plane = NULL; ffloor[numffloors].polyobj = NULL; - heightcheck = -#ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : -#endif - *rover->topheight; + heightcheck = P_GetFFloorTopZAt(rover, viewx, viewy); - planecenterz = -#ifdef ESLOPE - *rover->t_slope ? P_GetZAt(*rover->t_slope, frontsector->soundorg.x, frontsector->soundorg.y) : -#endif - *rover->topheight; + planecenterz = P_GetFFloorTopZAt(rover, frontsector->soundorg.x, frontsector->soundorg.y); if (planecenterz >= floorcenterz && planecenterz <= ceilingcenterz - && ((viewz > heightcheck && !(rover->flags & FF_INVERTPLANES)) - || (viewz < heightcheck && (rover->flags & FF_BOTHPLANES)))) + && ((viewz > heightcheck && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) + || (viewz < heightcheck && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck); ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic, *frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle, - *frontsector->lightlist[light].extra_colormap, rover -#ifdef POLYOBJECTS_PLANES - , NULL -#endif -#ifdef ESLOPE - , *rover->t_slope -#endif - ); + *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->t_slope); -#ifdef ESLOPE ffloor[numffloors].slope = *rover->t_slope; // Tell the renderer this sector has slopes in it. if (ffloor[numffloors].slope) frontsector->hasslope = true; -#endif ffloor[numffloors].height = heightcheck; ffloor[numffloors].ffloor = rover; @@ -1061,7 +982,6 @@ static void R_Subsector(size_t num) } } -#ifdef POLYOBJECTS_PLANES // Polyobjects have planes, too! if (sub->polyList) { @@ -1090,18 +1010,13 @@ static void R_Subsector(size_t num) ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic, (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs, polysec->floorpic_angle-po->angle, - (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po -#ifdef ESLOPE - , NULL // will ffloors be slopable eventually? -#endif - ); + (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, + NULL); // will ffloors be slopable eventually? ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].polyobj = po; -#ifdef ESLOPE ffloor[numffloors].slope = NULL; -#endif -// ffloor[numffloors].ffloor = rover; + //ffloor[numffloors].ffloor = rover; po->visplane = ffloor[numffloors].plane; numffloors++; } @@ -1118,18 +1033,13 @@ static void R_Subsector(size_t num) light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle, - (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po -#ifdef ESLOPE - , NULL // will ffloors be slopable eventually? -#endif - ); + (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, + NULL); // will ffloors be slopable eventually? ffloor[numffloors].polyobj = po; ffloor[numffloors].height = polysec->ceilingheight; -#ifdef ESLOPE ffloor[numffloors].slope = NULL; -#endif -// ffloor[numffloors].ffloor = rover; + //ffloor[numffloors].ffloor = rover; po->visplane = ffloor[numffloors].plane; numffloors++; } @@ -1137,7 +1047,6 @@ static void R_Subsector(size_t num) po = (polyobj_t *)(po->link.next); } } -#endif #ifdef FLOORSPLATS if (sub->splats) @@ -1160,21 +1069,15 @@ static void R_Subsector(size_t num) firstseg = NULL; -#ifdef POLYOBJECTS // haleyjd 02/19/06: draw polyobjects before static lines if (sub->polyList) R_AddPolyObjects(sub); -#endif while (count--) { // CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); - if (!line->glseg -#ifdef POLYOBJECTS - && !line->polyseg // ignore segs that belong to polyobjects -#endif - ) - R_AddLine(line); + if (!line->glseg && !line->polyseg) // ignore segs that belong to polyobjects + R_AddLine(line); line++; curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */ } @@ -1192,11 +1095,9 @@ void R_Prep3DFloors(sector_t *sector) fixed_t bestheight, maxheight; INT32 count, i; sector_t *sec; -#ifdef ESLOPE pslope_t *bestslope = NULL; fixed_t heighttest; // I think it's better to check the Z height at the sector's center // than assume unsloped heights are accurate indicators of order in sloped sectors. -Red -#endif count = 1; for (rover = sector->ffloors; rover; rover = rover->next) @@ -1219,14 +1120,10 @@ void R_Prep3DFloors(sector_t *sector) else memset(sector->lightlist, 0, sizeof (lightlist_t) * count); -#ifdef ESLOPE - heighttest = sector->c_slope ? P_GetZAt(sector->c_slope, sector->soundorg.x, sector->soundorg.y) : sector->ceilingheight; + heighttest = P_GetSectorCeilingZAt(sector, sector->soundorg.x, sector->soundorg.y); sector->lightlist[0].height = heighttest + 1; sector->lightlist[0].slope = sector->c_slope; -#else - sector->lightlist[0].height = sector->ceilingheight + 1; -#endif sector->lightlist[0].lightlevel = §or->lightlevel; sector->lightlist[0].caster = NULL; sector->lightlist[0].extra_colormap = §or->extra_colormap; @@ -1244,8 +1141,7 @@ void R_Prep3DFloors(sector_t *sector) && !(rover->flags & FF_CUTLEVEL) && !(rover->flags & FF_CUTSPRITES))) continue; -#ifdef ESLOPE - heighttest = *rover->t_slope ? P_GetZAt(*rover->t_slope, sector->soundorg.x, sector->soundorg.y) : *rover->topheight; + heighttest = P_GetFFloorTopZAt(rover, sector->soundorg.x, sector->soundorg.y); if (heighttest > bestheight && heighttest < maxheight) { @@ -1255,7 +1151,7 @@ void R_Prep3DFloors(sector_t *sector) continue; } if (rover->flags & FF_DOUBLESHADOW) { - heighttest = *rover->b_slope ? P_GetZAt(*rover->b_slope, sector->soundorg.x, sector->soundorg.y) : *rover->bottomheight; + heighttest = P_GetFFloorBottomZAt(rover, sector->soundorg.x, sector->soundorg.y); if (heighttest > bestheight && heighttest < maxheight) @@ -1266,21 +1162,6 @@ void R_Prep3DFloors(sector_t *sector) continue; } } -#else - if (*rover->topheight > bestheight && *rover->topheight < maxheight) - { - best = rover; - bestheight = *rover->topheight; - continue; - } - if (rover->flags & FF_DOUBLESHADOW && *rover->bottomheight > bestheight - && *rover->bottomheight < maxheight) - { - best = rover; - bestheight = *rover->bottomheight; - continue; - } -#endif } if (!best) { @@ -1291,9 +1172,7 @@ void R_Prep3DFloors(sector_t *sector) sector->lightlist[i].height = maxheight = bestheight; sector->lightlist[i].caster = best; sector->lightlist[i].flags = best->flags; -#ifdef ESLOPE sector->lightlist[i].slope = bestslope; -#endif sec = §ors[best->secnum]; if (best->flags & FF_NOSHADE) @@ -1314,12 +1193,8 @@ void R_Prep3DFloors(sector_t *sector) if (best->flags & FF_DOUBLESHADOW) { -#ifdef ESLOPE - heighttest = *best->b_slope ? P_GetZAt(*best->b_slope, sector->soundorg.x, sector->soundorg.y) : *best->bottomheight; + heighttest = P_GetFFloorBottomZAt(best, sector->soundorg.x, sector->soundorg.y); if (bestheight == heighttest) ///TODO: do this in a more efficient way -Red -#else - if (bestheight == *best->bottomheight) -#endif { sector->lightlist[i].lightlevel = sector->lightlist[best->lastlight].lightlevel; sector->lightlist[i].extra_colormap = @@ -1363,6 +1238,9 @@ void R_RenderBSPNode(INT32 bspnum) { node_t *bsp; INT32 side; + + rs_numbspcalls++; + while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? { bsp = &nodes[bspnum]; diff --git a/src/r_bsp.h b/src/r_bsp.h index 95aea9eff..e2da8ebaf 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -40,13 +40,11 @@ void R_PortalClearClipSegs(INT32 start, INT32 end); void R_ClearDrawSegs(void); void R_RenderBSPNode(INT32 bspnum); -#ifdef POLYOBJECTS void R_SortPolyObjects(subsector_t *sub); extern size_t numpolys; // number of polyobjects in current subsector extern size_t num_po_ptrs; // number of polyobject pointers allocated extern polyobj_t **po_ptrs; // temp ptr array to sort polyobject pointers -#endif sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, INT32 *ceilinglightlevel, boolean back); diff --git a/src/r_data.c b/src/r_data.c index f5a24c2c4..b72214996 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -230,25 +230,31 @@ static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, tex UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) { RGBA_t output; + INT16 fullalpha = (alpha - (0xFF - foreground.s.alpha)); if (style == AST_TRANSLUCENT) { - if (alpha == 0) + if (fullalpha <= 0) output.rgba = background.rgba; - else if (alpha == 0xFF) - output.rgba = foreground.rgba; - else if (alpha < 0xFF) - { - UINT8 beta = (0xFF - alpha); - output.s.red = ((background.s.red * beta) + (foreground.s.red * alpha)) / 0xFF; - output.s.green = ((background.s.green * beta) + (foreground.s.green * alpha)) / 0xFF; - output.s.blue = ((background.s.blue * beta) + (foreground.s.blue * alpha)) / 0xFF; - } - // write foreground pixel alpha - // if there's no pixel in here - if (!background.rgba) - output.s.alpha = foreground.s.alpha; else - output.s.alpha = 0xFF; + { + // don't go too high + if (fullalpha >= 0xFF) + fullalpha = 0xFF; + alpha = (UINT8)fullalpha; + + // if the background pixel is empty, + // match software and don't blend anything + if (!background.s.alpha) + output.s.alpha = 0; + else + { + UINT8 beta = (0xFF - alpha); + output.s.red = ((background.s.red * beta) + (foreground.s.red * alpha)) / 0xFF; + output.s.green = ((background.s.green * beta) + (foreground.s.green * alpha)) / 0xFF; + output.s.blue = ((background.s.blue * beta) + (foreground.s.blue * alpha)) / 0xFF; + output.s.alpha = 0xFF; + } + } return output.rgba; } #define clamp(c) max(min(c, 0xFF), 0x00); @@ -716,14 +722,12 @@ Rloadflats (INT32 i, INT32 w) } else { - texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); + texstart = W_CheckNumForMarkerStartPwad("F_START", (UINT16)w, 0); texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); } if (!( texstart == INT16_MAX || texend == INT16_MAX )) { - texstart++; // Do not count the first marker - // Work through each lump between the markers in the WAD. for (j = 0; j < (texend - texstart); j++) { @@ -836,7 +840,7 @@ Rloadtextures (INT32 i, INT32 w) } else { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0); + texstart = W_CheckNumForMarkerStartPwad(TX_START, (UINT16)w, 0); texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); if (texturesLumpPos != INT16_MAX) @@ -845,8 +849,6 @@ Rloadtextures (INT32 i, INT32 w) if (!( texstart == INT16_MAX || texend == INT16_MAX )) { - texstart++; // Do not count the first marker - // Work through each lump between the markers in the WAD. for (j = 0; j < (texend - texstart); j++) { @@ -953,14 +955,12 @@ void R_LoadTextures(void) } else { - texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); + texstart = W_CheckNumForMarkerStartPwad("F_START", (UINT16)w, 0); texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); } if (!( texstart == INT16_MAX || texend == INT16_MAX )) { - texstart++; // Do not count the first marker - // PK3s have subfolders, so we can't just make a simple sum if (wadfiles[w]->type == RET_PK3) { @@ -993,15 +993,13 @@ void R_LoadTextures(void) } else { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0); + texstart = W_CheckNumForMarkerStartPwad(TX_START, (UINT16)w, 0); texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); } if (texstart == INT16_MAX || texend == INT16_MAX) continue; - texstart++; // Do not count the first marker - // PK3s have subfolders, so we can't just make a simple sum if (wadfiles[w]->type == RET_PK3) { @@ -1587,9 +1585,9 @@ lumpnum_t R_GetFlatNumForName(const char *name) switch (wadfiles[i]->type) { case RET_WAD: - if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX) + if ((start = W_CheckNumForMarkerStartPwad("F_START", (UINT16)i, 0)) == INT16_MAX) { - if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX) + if ((start = W_CheckNumForMarkerStartPwad("FF_START", (UINT16)i, 0)) == INT16_MAX) continue; else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX) continue; diff --git a/src/r_data.h b/src/r_data.h index 0569893cd..78ce35a41 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_defs.h b/src/r_defs.h index f2774edbc..a36568192 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,8 +28,6 @@ #include "m_aatree.h" #endif -#define POLYOBJECTS - // // ClipWallSegment // Clips the given range of columns @@ -107,9 +105,7 @@ typedef struct fixed_t z; ///< Z coordinate. } degenmobj_t; -#ifdef POLYOBJECTS #include "p_polyobj.h" -#endif // Store fake planes in a resizable array insted of just by // heightsec. Allows for multiple fake planes. @@ -130,11 +126,11 @@ typedef enum FF_CUTEXTRA = 0x100, ///< Cuts out hidden translucent pixels. FF_CUTLEVEL = 0x180, ///< Cuts out all hidden pixels. FF_CUTSPRITES = 0x200, ///< Final step in making 3D water. - FF_BOTHPLANES = 0x400, ///< Renders both planes all the time. + FF_BOTHPLANES = 0x400, ///< Render inside and outside planes. FF_EXTRA = 0x800, ///< Gets cut by ::FF_CUTEXTRA. FF_TRANSLUCENT = 0x1000, ///< See through! FF_FOG = 0x2000, ///< Fog "brush." - FF_INVERTPLANES = 0x4000, ///< Reverse the plane visibility rules. + FF_INVERTPLANES = 0x4000, ///< Only render inside planes. FF_ALLSIDES = 0x8000, ///< Render inside and outside sides. FF_INVERTSIDES = 0x10000, ///< Only render inside sides. FF_DOUBLESHADOW = 0x20000, ///< Make two lightlist entries to reset light? @@ -171,11 +167,9 @@ typedef struct ffloor_s fixed_t *bottomyoffs; angle_t *bottomangle; -#ifdef ESLOPE // Pointers to pointers. Yup. struct pslope_s **t_slope; struct pslope_s **b_slope; -#endif size_t secnum; ffloortype_e flags; @@ -208,9 +202,7 @@ typedef struct lightlist_s extracolormap_t **extra_colormap; // pointer-to-a-pointer, so we can react to colormap changes INT32 flags; ffloor_t *caster; -#ifdef ESLOPE struct pslope_s *slope; // FF_DOUBLESHADOW makes me have to store this pointer here. Bluh bluh. -#endif } lightlist_t; @@ -244,7 +236,6 @@ typedef struct linechain_s // Slopes -#ifdef ESLOPE typedef enum { SL_NOPHYSICS = 1, /// This plane will have no physics applied besides the positioning. SL_DYNAMIC = 1<<1, /// This plane slope will be assigned a thinker to make it dynamic. @@ -268,7 +259,6 @@ typedef struct pslope_s UINT8 flags; // Slope options } pslope_t; -#endif typedef enum { @@ -283,6 +273,16 @@ typedef enum SF_INVERTPRECIP = 1<<4, } sectorflags_t; + +typedef enum +{ + CRUMBLE_NONE, // No crumble thinker + CRUMBLE_WAIT, // Don't float on water because this is supposed to wait for a crumble + CRUMBLE_ACTIVATED, // Crumble thinker activated, but hasn't fallen yet + CRUMBLE_FALL, // Crumble thinker is falling + CRUMBLE_RESTORE, // Crumble thinker is about to restore to original position +} crumblestate_t; + // // The SECTORS record, at runtime. // Stores things/mobjs. @@ -334,11 +334,6 @@ typedef struct sector_s size_t linecount; struct line_s **lines; // [linecount] size - // Hack: store special line tagging to some sectors - // to efficiently help work around bugs by directly - // referencing the specific line that the problem happens in. - // (used in T_MovePlane mobj physics) - struct line_s *tagline; // Improved fake floor hack ffloor_t *ffloors; @@ -379,12 +374,10 @@ typedef struct sector_s precipmobj_t *preciplist; struct mprecipsecnode_s *touching_preciplist; -#ifdef ESLOPE // Eternity engine slope pslope_t *f_slope; // floor slope pslope_t *c_slope; // ceiling slope boolean hasslope; // The sector, or one of its visible FOFs, contains a slope -#endif // for fade thinker INT16 spawn_lightlevel; @@ -437,9 +430,7 @@ typedef struct line_s void *splats; // wallsplat_t list #endif INT32 firsttag, nexttag; // improves searches for tags. -#ifdef POLYOBJECTS polyobj_t *polyobj; // Belongs to a polyobject? -#endif char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 @@ -482,9 +473,7 @@ typedef struct subsector_s sector_t *sector; INT16 numlines; UINT16 firstline; -#ifdef POLYOBJECTS struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects -#endif #if 1//#ifdef FLOORSPLATS void *splats; // floorsplat_t list #endif @@ -587,10 +576,8 @@ typedef struct seg_s // Why slow things down by calculating lightlists for every thick side? size_t numlights; r_lightlist_t *rlights; -#ifdef POLYOBJECTS polyobj_t *polyseg; boolean dontrenderme; -#endif boolean glseg; } seg_t; @@ -668,11 +655,9 @@ typedef struct drawseg_s UINT8 portalpass; // if > 0 and <= portalrender, do not affect sprite clipping -#ifdef ESLOPE fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes -#endif } drawseg_t; typedef enum diff --git a/src/r_draw.c b/src/r_draw.c index 918c5f206..5351ef37f 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -105,12 +105,10 @@ boolean ds_powersoftwo; UINT8 *ds_source; // start of a 64*64 tile image UINT8 *ds_transmap; // one of the translucency tables -#ifdef ESLOPE pslope_t *ds_slope; // Current slope being used floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff? floatv3_t *ds_sup, *ds_svp, *ds_szp; float focallengthf, zeroheight; -#endif /** \brief Variable flat sizes */ @@ -137,318 +135,6 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; 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 - - // Greyscale ranges - {0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x11}, // SKINCOLOR_WHITE - {0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x05, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x11, 0x12}, // SKINCOLOR_BONE - {0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14}, // SKINCOLOR_CLOUDY - {0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, // SKINCOLOR_GREY - {0x02, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f}, // SKINCOLOR_SILVER - {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x17, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1c, 0x1d}, // SKINCOLOR_CARBON - {0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1a, 0x1b, 0x1c, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f}, // SKINCOLOR_JET - {0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f}, // SKINCOLOR_BLACK - - // Desaturated - {0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x91, 0x91, 0x91, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf}, // SKINCOLOR_AETHER - {0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0xaa, 0xaa, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xad, 0xae, 0xaf}, // SKINCOLOR_SLATE - {0x90, 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0xac, 0xac, 0xad, 0xad, 0xa8, 0xa8, 0xa9, 0xfd, 0xfe}, // SKINCOLOR_BLUEBELL - {0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0x2b, 0x2c, 0x2e}, // SKINCOLOR_PINK - {0xd0, 0x30, 0xd8, 0xd9, 0xda, 0xdb, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe3, 0xe6, 0xe8, 0xe9}, // SKINCOLOR_YOGURT - {0xdf, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef}, // SKINCOLOR_BROWN - {0xde, 0xe0, 0xe1, 0xe4, 0xe7, 0xe9, 0xeb, 0xec, 0xed, 0xed, 0xed, 0x19, 0x19, 0x1b, 0x1d, 0x1e}, // SKINCOLOR_BRONZE - {0x51, 0x51, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0xf5, 0xf5, 0xf9, 0xf9, 0xed, 0xed}, // SKINCOLOR_TAN - {0x54, 0x55, 0x56, 0x56, 0xf2, 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xed, 0xed}, // SKINCOLOR_BEIGE - {0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f}, // SKINCOLOR_MOSS - {0x90, 0x90, 0x91, 0x91, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf}, // SKINCOLOR_AZURE - {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, // SKINCOLOR_LAVENDER - - // Viv's vivid colours (toast 21/07/17) - {0xb0, 0xb0, 0xc9, 0xca, 0xcc, 0x26, 0x27, 0x28, 0x29, 0x2a, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfd}, // SKINCOLOR_RUBY - {0xd0, 0xd0, 0xd1, 0xd2, 0x20, 0x21, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e}, // SKINCOLOR_SALMON - {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, // SKINCOLOR_RED - {0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x1f}, // SKINCOLOR_CRIMSON - {0x31, 0x32, 0x33, 0x36, 0x22, 0x22, 0x25, 0x25, 0x25, 0xcd, 0xcf, 0xcf, 0xc5, 0xc5, 0xc7, 0xc7}, // SKINCOLOR_FLAME - {0x48, 0x49, 0x40, 0x33, 0x34, 0x36, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2b, 0x2c, 0x47, 0x2e, 0x2f}, // SKINCOLOR_KETCHUP - {0xd0, 0x30, 0x31, 0x31, 0x32, 0x32, 0xdc, 0xdc, 0xdc, 0xd3, 0xd4, 0xd4, 0xcc, 0xcd, 0xce, 0xcf}, // SKINCOLOR_PEACHY - {0xd8, 0xd9, 0xdb, 0xdc, 0xde, 0xdf, 0xd5, 0xd5, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0x1d, 0x1f}, // SKINCOLOR_QUAIL - {0x51, 0x52, 0x40, 0x40, 0x34, 0x36, 0xd5, 0xd5, 0xd6, 0xd7, 0xcf, 0xcf, 0xc6, 0xc6, 0xc7, 0xfe}, // SKINCOLOR_SUNSET - {0x58, 0x54, 0x40, 0x34, 0x35, 0x38, 0x3a, 0x3c, 0x3d, 0x2a, 0x2b, 0x2c, 0x2c, 0xba, 0xba, 0xbb}, // SKINCOLOR_COPPER - {0x00, 0xd8, 0xd9, 0xda, 0xdb, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e}, // SKINCOLOR_APRICOT - {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x2c}, // SKINCOLOR_ORANGE - {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3f, 0x2c, 0x2d, 0x47, 0x2e, 0x2f, 0x2f}, // SKINCOLOR_RUST - {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, // SKINCOLOR_GOLD - {0x53, 0x40, 0x41, 0x42, 0x43, 0xe6, 0xe9, 0xe9, 0xea, 0xec, 0xec, 0xc6, 0xc6, 0xc7, 0xc7, 0xfe}, // SKINCOLOR_SANDY - {0x52, 0x53, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0xed}, // SKINCOLOR_YELLOW - {0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4e, 0xe7, 0xe7, 0xe9, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7, 0xfd}, // SKINCOLOR_OLIVE - {0x50, 0x51, 0x52, 0x53, 0x48, 0xbc, 0xbd, 0xbe, 0xbe, 0xbf, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, // SKINCOLOR_LIME - {0x58, 0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0x5e, 0x5e, 0x5f, 0x5f, 0x77, 0x77}, // SKINCOLOR_PERIDOT - {0x49, 0x49, 0xbc, 0xbd, 0xbe, 0xbe, 0xbe, 0x67, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6d}, // SKINCOLOR_APPLE - {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, // SKINCOLOR_GREEN - {0x65, 0x66, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f}, // SKINCOLOR_FOREST - {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, // SKINCOLOR_EMERALD - {0x00, 0x00, 0x58, 0x58, 0x59, 0x62, 0x62, 0x62, 0x64, 0x67, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a}, // SKINCOLOR_MINT - {0x01, 0x58, 0x59, 0x5a, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0xfd, 0xfd}, // SKINCOLOR_SEAFOAM - {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, // SKINCOLOR_AQUA - {0x78, 0x78, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0x8a}, // SKINCOLOR_TEAL - {0x00, 0x78, 0x78, 0x79, 0x8d, 0x87, 0x88, 0x89, 0x89, 0xae, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfd}, // SKINCOLOR_WAVE - {0x80, 0x81, 0xff, 0xff, 0x83, 0x83, 0x8d, 0x8d, 0x8d, 0x8e, 0x7e, 0x7f, 0x76, 0x76, 0x77, 0x6e}, // SKINCOLOR_CYAN - {0x80, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x85, 0x85, 0x86, 0x87, 0x88, 0x89, 0x89, 0x8a, 0x8b}, // SKINCOLOR_SKY - {0x85, 0x86, 0x87, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0xfd, 0xfd, 0xfd, 0x1f, 0x1f, 0x1f}, // SKINCOLOR_CERULEAN - {0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0x83, 0x83, 0x86, 0x87, 0x95, 0x95, 0xad, 0xad, 0xae, 0xaf}, // SKINCOLOR_ICY - {0x80, 0x83, 0x86, 0x87, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, // SKINCOLOR_SAPPHIRE - {0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x9a, 0x9c, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e}, // SKINCOLOR_CORNFLOWER - {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, // SKINCOLOR_BLUE - {0x93, 0x94, 0x95, 0x96, 0x98, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfd, 0xfe, 0xfe}, // SKINCOLOR_COBALT - {0x80, 0x81, 0x83, 0x86, 0x94, 0x94, 0xa3, 0xa3, 0xa4, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa9, 0xa9}, // SKINCOLOR_VAPOR - {0x92, 0x93, 0x94, 0x94, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xa9, 0xa9, 0xfd, 0xfd}, // SKINCOLOR_DUSK - {0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, // SKINCOLOR_PASTEL - {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9}, // SKINCOLOR_PURPLE - {0x00, 0xd0, 0xd0, 0xc8, 0xc8, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, // SKINCOLOR_BUBBLEGUM - {0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb}, // SKINCOLOR_MAGENTA - {0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb, 0xc7, 0xc7, 0x1d, 0x1d, 0x1e}, // SKINCOLOR_NEON - {0xd0, 0xd1, 0xd2, 0xca, 0xcc, 0xb8, 0xb9, 0xb9, 0xba, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfe, 0xfe}, // SKINCOLOR_VIOLET - {0x00, 0xd0, 0xd1, 0xd2, 0xd3, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xfe, 0x1f}, // SKINCOLOR_LILAC - {0xc8, 0xd3, 0xd5, 0xd6, 0xd7, 0xce, 0xcf, 0xb9, 0xb9, 0xba, 0xba, 0xa9, 0xa9, 0xa9, 0xfd, 0xfe}, // SKINCOLOR_PLUM - {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, // SKINCOLOR_RASPBERRY - {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, // SKINCOLOR_ROSY - - // {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // SKINCOLOR_? - - // super - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03}, // SKINCOLOR_SUPERSILVER1 - {0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07}, // SKINCOLOR_SUPERSILVER2 - {0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b}, // SKINCOLOR_SUPERSILVER3 - {0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11}, // SKINCOLOR_SUPERSILVER4 - {0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13}, // SKINCOLOR_SUPERSILVER5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2}, // SKINCOLOR_SUPERRED1 - {0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21}, // SKINCOLOR_SUPERRED2 - {0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23}, // SKINCOLOR_SUPERRED3 - {0x00, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24}, // SKINCOLOR_SUPERRED4 - {0xd0, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25}, // SKINCOLOR_SUPERRED5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34}, // SKINCOLOR_SUPERORANGE1 - {0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34}, // SKINCOLOR_SUPERORANGE2 - {0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35}, // SKINCOLOR_SUPERORANGE3 - {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, // SKINCOLOR_SUPERORANGE4 - {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, // SKINCOLOR_SUPERORANGE5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48}, // SKINCOLOR_SUPERGOLD1 - {0x00, 0x50, 0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41}, // SKINCOLOR_SUPERGOLD2 - {0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43}, // SKINCOLOR_SUPERGOLD3 - {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, // SKINCOLOR_SUPERGOLD4 - {0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}, // SKINCOLOR_SUPERGOLD5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, // SKINCOLOR_SUPERPERIDOT1 - {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, // SKINCOLOR_SUPERPERIDOT2 - {0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf}, // SKINCOLOR_SUPERPERIDOT3 - {0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f}, // SKINCOLOR_SUPERPERIDOT4 - {0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f, 0x77}, // SKINCOLOR_SUPERPERIDOT5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84}, // SKINCOLOR_SUPERSKY1 - {0x00, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86}, // SKINCOLOR_SUPERSKY2 - {0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87}, // SKINCOLOR_SUPERSKY3 - {0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a}, // SKINCOLOR_SUPERSKY4 - {0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a, 0x8b}, // SKINCOLOR_SUPERSKY5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa2}, // SKINCOLOR_SUPERPURPLE1 - {0x00, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5}, // SKINCOLOR_SUPERPURPLE2 - {0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6}, // SKINCOLOR_SUPERPURPLE3 - {0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9}, // SKINCOLOR_SUPERPURPLE4 - {0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9, 0xfd}, // SKINCOLOR_SUPERPURPLE5 - - {0x00, 0xd0, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x32, 0x33, 0x37, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x2e}, // SKINCOLOR_SUPERRUST1 - {0x30, 0x31, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x47, 0x2e}, // SKINCOLOR_SUPERRUST2 - {0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x3a, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x2e, 0x2e}, // SKINCOLOR_SUPERRUST3 - {0x48, 0x40, 0x41, 0x42, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x2e, 0x2e, 0x2e}, // SKINCOLOR_SUPERRUST4 - {0x41, 0x42, 0x43, 0x43, 0x44, 0x44, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, 0xee, 0xef, 0xef}, // SKINCOLOR_SUPERRUST5 - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52}, // SKINCOLOR_SUPERTAN1 - {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, // SKINCOLOR_SUPERTAN2 - {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, // SKINCOLOR_SUPERTAN3 - {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, // SKINCOLOR_SUPERTAN4 - {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef} // SKINCOLOR_SUPERTAN5 -}; - -// See also the enum skincolors_t -// TODO Callum: Can this be translated? -const char *Color_Names[MAXSKINCOLORS + NUMSUPERCOLORS] = -{ - "None", // SKINCOLOR_NONE, - - // Greyscale ranges - "White", // SKINCOLOR_WHITE, - "Bone", // SKINCOLOR_BONE, - "Cloudy", // SKINCOLOR_CLOUDY, - "Grey", // SKINCOLOR_GREY, - "Silver", // SKINCOLOR_SILVER, - "Carbon", // SKINCOLOR_CARBON, - "Jet", // SKINCOLOR_JET, - "Black", // SKINCOLOR_BLACK, - - // Desaturated - "Aether", // SKINCOLOR_AETHER, - "Slate", // SKINCOLOR_SLATE, - "Bluebell", // SKINCOLOR_BLUEBELL, - "Pink", // SKINCOLOR_PINK, - "Yogurt", // SKINCOLOR_YOGURT, - "Brown", // SKINCOLOR_BROWN, - "Bronze", // SKINCOLOR_BRONZE, - "Tan", // SKINCOLOR_TAN, - "Beige", // SKINCOLOR_BEIGE, - "Moss", // SKINCOLOR_MOSS, - "Azure", // SKINCOLOR_AZURE, - "Lavender", // SKINCOLOR_LAVENDER, - - // Viv's vivid colours (toast 21/07/17) - "Ruby", // SKINCOLOR_RUBY, - "Salmon", // SKINCOLOR_SALMON, - "Red", // SKINCOLOR_RED, - "Crimson", // SKINCOLOR_CRIMSON, - "Flame", // SKINCOLOR_FLAME, - "Ketchup", // SKINCOLOR_KETCHUP, - "Peachy", // SKINCOLOR_PEACHY, - "Quail", // SKINCOLOR_QUAIL, - "Sunset", // SKINCOLOR_SUNSET, - "Copper", // SKINCOLOR_COPPER, - "Apricot", // SKINCOLOR_APRICOT, - "Orange", // SKINCOLOR_ORANGE, - "Rust", // SKINCOLOR_RUST, - "Gold", // SKINCOLOR_GOLD, - "Sandy", // SKINCOLOR_SANDY, - "Yellow", // SKINCOLOR_YELLOW, - "Olive", // SKINCOLOR_OLIVE, - "Lime", // SKINCOLOR_LIME, - "Peridot", // SKINCOLOR_PERIDOT, - "Apple", // SKINCOLOR_APPLE, - "Green", // SKINCOLOR_GREEN, - "Forest", // SKINCOLOR_FOREST, - "Emerald", // SKINCOLOR_EMERALD, - "Mint", // SKINCOLOR_MINT, - "Seafoam", // SKINCOLOR_SEAFOAM, - "Aqua", // SKINCOLOR_AQUA, - "Teal", // SKINCOLOR_TEAL, - "Wave", // SKINCOLOR_WAVE, - "Cyan", // SKINCOLOR_CYAN, - "Sky", // SKINCOLOR_SKY, - "Cerulean", // SKINCOLOR_CERULEAN, - "Icy", // SKINCOLOR_ICY, - "Sapphire", // SKINCOLOR_SAPPHIRE, - "Cornflower", // SKINCOLOR_CORNFLOWER, - "Blue", // SKINCOLOR_BLUE, - "Cobalt", // SKINCOLOR_COBALT, - "Vapor", // SKINCOLOR_VAPOR, - "Dusk", // SKINCOLOR_DUSK, - "Pastel", // SKINCOLOR_PASTEL, - "Purple", // SKINCOLOR_PURPLE, - "Bubblegum", // SKINCOLOR_BUBBLEGUM, - "Magenta", // SKINCOLOR_MAGENTA, - "Neon", // SKINCOLOR_NEON, - "Violet", // SKINCOLOR_VIOLET, - "Lilac", // SKINCOLOR_LILAC, - "Plum", // SKINCOLOR_PLUM, - "Raspberry", // SKINCOLOR_RASPBERRY, - "Rosy", // SKINCOLOR_ROSY, - - // Super behaves by different rules (one name per 5 colours), and will be accessed exclusively via R_GetSuperColorByName instead of R_GetColorByName. - "Silver", // SKINCOLOR_SUPERSILVER1, - "Red", // SKINCOLOR_SUPERRED1, - "Orange", // SKINCOLOR_SUPERORANGE1, - "Gold", // SKINCOLOR_SUPERGOLD1, - "Peridot", // SKINCOLOR_SUPERPERIDOT1, - "Sky", // SKINCOLOR_SUPERSKY1, - "Purple", // SKINCOLOR_SUPERPURPLE1, - "Rust", // SKINCOLOR_SUPERRUST1, - "Tan" // SKINCOLOR_SUPERTAN1, -}; - -/* -A word of warning: If the following array is non-symmetrical, -A_SignPlayer's prefoppositecolor behaviour will break. -*/ -// [0] = opposite skin color, -// [1] = shade index used by signpost, 0-15 (actual sprite frame is 15 minus this value) -const UINT8 Color_Opposite[MAXSKINCOLORS - 1][2] = -{ - // {SKINCOLOR_NONE, 8}, // SKINCOLOR_NONE - - // Greyscale ranges - {SKINCOLOR_BLACK, 5}, // SKINCOLOR_WHITE, - {SKINCOLOR_JET, 7}, // SKINCOLOR_BONE, - {SKINCOLOR_CARBON, 7}, // SKINCOLOR_CLOUDY, - {SKINCOLOR_AETHER, 12}, // SKINCOLOR_GREY, - {SKINCOLOR_SLATE, 12}, // SKINCOLOR_SILVER, - {SKINCOLOR_CLOUDY, 7}, // SKINCOLOR_CARBON, - {SKINCOLOR_BONE, 7}, // SKINCOLOR_JET, - {SKINCOLOR_WHITE, 7}, // SKINCOLOR_BLACK, - - // Desaturated - {SKINCOLOR_GREY, 15}, // SKINCOLOR_AETHER, - {SKINCOLOR_SILVER, 12}, // SKINCOLOR_SLATE, - {SKINCOLOR_COPPER, 4}, // SKINCOLOR_BLUEBELL, - {SKINCOLOR_AZURE, 9}, // SKINCOLOR_PINK, - {SKINCOLOR_RUST, 7}, // SKINCOLOR_YOGURT, - {SKINCOLOR_TAN, 2}, // SKINCOLOR_BROWN, - {SKINCOLOR_KETCHUP, 0}, // SKINCOLOR_BRONZE, - {SKINCOLOR_BROWN, 12}, // SKINCOLOR_TAN, - {SKINCOLOR_MOSS, 5}, // SKINCOLOR_BEIGE, - {SKINCOLOR_BEIGE, 13}, // SKINCOLOR_MOSS, - {SKINCOLOR_PINK, 5}, // SKINCOLOR_AZURE, - {SKINCOLOR_GOLD, 4}, // SKINCOLOR_LAVENDER, - - // Viv's vivid colours (toast 21/07/17) - {SKINCOLOR_EMERALD, 10}, // SKINCOLOR_RUBY, - {SKINCOLOR_FOREST, 6}, // SKINCOLOR_SALMON, - {SKINCOLOR_GREEN, 10}, // SKINCOLOR_RED, - {SKINCOLOR_ICY, 10}, // SKINCOLOR_CRIMSON, - {SKINCOLOR_PURPLE, 8}, // SKINCOLOR_FLAME, - {SKINCOLOR_BRONZE, 8}, // SKINCOLOR_KETCHUP, - {SKINCOLOR_TEAL, 7}, // SKINCOLOR_PEACHY, - {SKINCOLOR_WAVE, 5}, // SKINCOLOR_QUAIL, - {SKINCOLOR_SAPPHIRE, 5}, // SKINCOLOR_SUNSET, - {SKINCOLOR_BLUEBELL, 5}, // SKINCOLOR_COPPER - {SKINCOLOR_CYAN, 4}, // SKINCOLOR_APRICOT, - {SKINCOLOR_BLUE, 4}, // SKINCOLOR_ORANGE, - {SKINCOLOR_YOGURT, 8}, // SKINCOLOR_RUST, - {SKINCOLOR_LAVENDER, 10}, // SKINCOLOR_GOLD, - {SKINCOLOR_SKY, 8}, // SKINCOLOR_SANDY, - {SKINCOLOR_CORNFLOWER, 8}, // SKINCOLOR_YELLOW, - {SKINCOLOR_DUSK, 3}, // SKINCOLOR_OLIVE, - {SKINCOLOR_MAGENTA, 9}, // SKINCOLOR_LIME, - {SKINCOLOR_COBALT, 2}, // SKINCOLOR_PERIDOT, - {SKINCOLOR_RASPBERRY, 13}, // SKINCOLOR_APPLE, - {SKINCOLOR_RED, 6}, // SKINCOLOR_GREEN, - {SKINCOLOR_SALMON, 9}, // SKINCOLOR_FOREST, - {SKINCOLOR_RUBY, 4}, // SKINCOLOR_EMERALD, - {SKINCOLOR_VIOLET, 5}, // SKINCOLOR_MINT, - {SKINCOLOR_PLUM, 6}, // SKINCOLOR_SEAFOAM, - {SKINCOLOR_ROSY, 7}, // SKINCOLOR_AQUA, - {SKINCOLOR_PEACHY, 7}, // SKINCOLOR_TEAL, - {SKINCOLOR_QUAIL, 5}, // SKINCOLOR_WAVE, - {SKINCOLOR_APRICOT, 6}, // SKINCOLOR_CYAN, - {SKINCOLOR_SANDY, 1}, // SKINCOLOR_SKY, - {SKINCOLOR_NEON, 4}, // SKINCOLOR_CERULEAN, - {SKINCOLOR_CRIMSON, 0}, // SKINCOLOR_ICY, - {SKINCOLOR_SUNSET, 5}, // SKINCOLOR_SAPPHIRE, - {SKINCOLOR_YELLOW, 4}, // SKINCOLOR_CORNFLOWER, - {SKINCOLOR_ORANGE, 5}, // SKINCOLOR_BLUE, - {SKINCOLOR_PERIDOT, 5}, // SKINCOLOR_COBALT, - {SKINCOLOR_LILAC, 4}, // SKINCOLOR_VAPOR, - {SKINCOLOR_OLIVE, 0}, // SKINCOLOR_DUSK, - {SKINCOLOR_BUBBLEGUM, 9}, // SKINCOLOR_PASTEL, - {SKINCOLOR_FLAME, 7}, // SKINCOLOR_PURPLE, - {SKINCOLOR_PASTEL, 8}, // SKINCOLOR_BUBBLEGUM, - {SKINCOLOR_LIME, 6}, // SKINCOLOR_MAGENTA, - {SKINCOLOR_CERULEAN, 2}, // SKINCOLOR_NEON, - {SKINCOLOR_MINT, 6}, // SKINCOLOR_VIOLET, - {SKINCOLOR_VAPOR, 4}, // SKINCOLOR_LILAC, - {SKINCOLOR_MINT, 7}, // SKINCOLOR_PLUM, - {SKINCOLOR_APPLE, 13}, // SKINCOLOR_RASPBERRY - {SKINCOLOR_AQUA, 1} // SKINCOLOR_ROSY, -}; - CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; /** \brief The R_InitTranslationTables @@ -498,7 +184,7 @@ void R_InitTranslationTables(void) \param dest_colormap colormap to populate \param skincolor translation color */ -static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) +static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor) { INT32 i; RGBA_t color; @@ -511,7 +197,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) // first generate the brightness of all the colours of that skincolour for (i = 0; i < 16; i++) { - color = V_GetColor(Color_Index[skincolor-1][i]); + color = V_GetColor(skincolors[skincolor].ramp[i]); SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue); } @@ -532,7 +218,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) if (temp < brightdif) { brightdif = (UINT16)temp; - dest_colormap[i] = Color_Index[skincolor-1][j]; + dest_colormap[i] = skincolors[skincolor].ramp[j]; } } } @@ -540,7 +226,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) #undef SETBRIGHTNESS -static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) +static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color) { INT32 i, starttranscolor, skinramplength; @@ -553,7 +239,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8)); return; case TC_RAINBOW: - if (color >= MAXTRANSLATIONS) + if (color >= numskincolors) I_Error("Invalid skin color #%hu.", (UINT16)color); if (color != SKINCOLOR_NONE) { @@ -562,11 +248,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U } break; case TC_BLINK: - if (color >= MAXTRANSLATIONS) + if (color >= numskincolors) I_Error("Invalid skin color #%hu.", (UINT16)color); if (color != SKINCOLOR_NONE) { - memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8)); + memset(dest_colormap, skincolors[color].ramp[3], NUM_PALETTE_ENTRIES * sizeof(UINT8)); return; } break; @@ -587,11 +273,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U { for (i = 0; i < 6; i++) { - dest_colormap[Color_Index[SKINCOLOR_BLUE-1][12-i]] = Color_Index[SKINCOLOR_BLUE-1][i]; + dest_colormap[skincolors[SKINCOLOR_BLUE].ramp[12-i]] = skincolors[SKINCOLOR_BLUE].ramp[i]; } dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0; for (i = 0; i < 16; i++) - dest_colormap[96+i] = dest_colormap[Color_Index[SKINCOLOR_COBALT-1][i]]; + dest_colormap[96+i] = dest_colormap[skincolors[SKINCOLOR_COBALT].ramp[i]]; } else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices { @@ -636,7 +322,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U return; } - if (color >= MAXTRANSLATIONS) + if (color >= numskincolors) I_Error("Invalid skin color #%hu.", (UINT16)color); starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; @@ -660,7 +346,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U // Build the translated ramp for (i = 0; i < skinramplength; i++) - dest_colormap[starttranscolor + i] = (UINT8)Color_Index[color-1][i]; + dest_colormap[starttranscolor + i] = (UINT8)skincolors[color].ramp[i]; } @@ -672,7 +358,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U \return Colormap. If not cached, caller should Z_Free. */ -UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) +UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags) { UINT8* ret; INT32 skintableindex; @@ -695,7 +381,7 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) // Allocate table for skin if necessary if (!translationtablecache[skintableindex]) - translationtablecache[skintableindex] = Z_Calloc(MAXTRANSLATIONS * sizeof(UINT8**), PU_STATIC, NULL); + translationtablecache[skintableindex] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL); // Get colormap ret = translationtablecache[skintableindex][color]; @@ -730,29 +416,32 @@ void R_FlushTranslationColormapCache(void) for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++) if (translationtablecache[i]) - memset(translationtablecache[i], 0, MAXTRANSLATIONS * sizeof(UINT8**)); + memset(translationtablecache[i], 0, MAXSKINCOLORS * sizeof(UINT8**)); } -UINT8 R_GetColorByName(const char *name) +UINT16 R_GetColorByName(const char *name) { - UINT8 color = (UINT8)atoi(name); - if (color > 0 && color < MAXSKINCOLORS) + UINT16 color = (UINT16)atoi(name); + if (color > 0 && color < numskincolors) return color; - for (color = 1; color < MAXSKINCOLORS; color++) - if (!stricmp(Color_Names[color], name)) + for (color = 1; color < numskincolors; color++) + if (!stricmp(skincolors[color].name, name)) return color; return SKINCOLOR_GREEN; } -UINT8 R_GetSuperColorByName(const char *name) +UINT16 R_GetSuperColorByName(const char *name) { - UINT8 color; /* = (UINT8)atoi(name); -- This isn't relevant to S_SKIN, which is the only way it's accessible right now. Let's simplify things. - if (color > MAXSKINCOLORS && color < MAXTRANSLATIONS && !((color - MAXSKINCOLORS) % 5)) - return color;*/ - for (color = 0; color < NUMSUPERCOLORS; color++) - if (!stricmp(Color_Names[color + MAXSKINCOLORS], name)) - return ((color*5) + MAXSKINCOLORS); - return SKINCOLOR_SUPERGOLD1; + UINT16 i, color = SKINCOLOR_SUPERGOLD1; + char *realname = Z_Malloc(MAXCOLORNAME+1, PU_STATIC, NULL); + snprintf(realname, MAXCOLORNAME+1, "Super %s 1", name); + for (i = 1; i < numskincolors; i++) + if (!stricmp(skincolors[i].name, realname)) { + color = i; + break; + } + Z_Free(realname); + return color; } // ========================================================================== diff --git a/src/r_draw.h b/src/r_draw.h index da38c40e0..329c4974a 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -62,7 +62,6 @@ extern boolean ds_powersoftwo; extern UINT8 *ds_source; extern UINT8 *ds_transmap; -#ifdef ESLOPE typedef struct { float x, y, z; } floatv3_t; @@ -71,7 +70,6 @@ extern pslope_t *ds_slope; // Current slope being used extern floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff? extern floatv3_t *ds_sup, *ds_svp, *ds_szp; extern float focallengthf, zeroheight; -#endif // Variable flat sizes extern UINT32 nflatxshift; @@ -114,10 +112,10 @@ extern lumpnum_t viewborderlump[8]; // Initialize color translation tables, for player rendering etc. void R_InitTranslationTables(void); -UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags); +UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags); void R_FlushTranslationColormapCache(void); -UINT8 R_GetColorByName(const char *name); -UINT8 R_GetSuperColorByName(const char *name); +UINT16 R_GetColorByName(const char *name); +UINT16 R_GetSuperColorByName(const char *name); // Custom player skin translation void R_InitViewBuffer(INT32 width, INT32 height); @@ -152,7 +150,6 @@ void R_DrawSpan_8(void); void R_DrawSplat_8(void); void R_DrawTranslucentSpan_8(void); void R_DrawTranslucentSplat_8(void); -#ifdef ESLOPE void R_DrawTiltedSpan_8(void); void R_DrawTiltedTranslucentSpan_8(void); #ifndef NOWATER @@ -161,7 +158,6 @@ void R_DrawTiltedTranslucentWaterSpan_8(void); void R_DrawTiltedSplat_8(void); void R_CalcTiltedLighting(fixed_t start, fixed_t end); extern INT32 tiltlighting[MAXVIDWIDTH]; -#endif #ifndef NOWATER void R_DrawTranslucentWaterSpan_8(void); extern INT32 ds_bgofs; @@ -174,14 +170,12 @@ void R_DrawSpan_NPO2_8(void); void R_DrawTranslucentSpan_NPO2_8(void); void R_DrawSplat_NPO2_8(void); void R_DrawTranslucentSplat_NPO2_8(void); -#ifdef ESLOPE void R_DrawTiltedSpan_NPO2_8(void); void R_DrawTiltedTranslucentSpan_NPO2_8(void); #ifndef NOWATER void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void); #endif void R_DrawTiltedSplat_NPO2_8(void); -#endif #ifndef NOWATER void R_DrawTranslucentWaterSpan_NPO2_8(void); #endif diff --git a/src/r_draw16.c b/src/r_draw16.c index 48017f45e..8b1d29e8d 100644 --- a/src/r_draw16.c +++ b/src/r_draw16.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_draw8.c b/src/r_draw8.c index 2f6bdcfa4..940ea724b 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -620,7 +620,6 @@ void R_DrawSpan_8 (void) } } -#ifdef ESLOPE // R_CalcTiltedLighting // Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly. INT32 tiltlighting[MAXVIDWIDTH]; @@ -1199,7 +1198,6 @@ void R_DrawTiltedSplat_8(void) } #endif } -#endif // ESLOPE /** \brief The R_DrawSplat_8 function Just like R_DrawSpan_8, but skips transparent pixels. diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index aa38ee2d9..020155694 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -61,8 +61,6 @@ void R_DrawSpan_NPO2_8 (void) } } -#ifdef ESLOPE - #define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) /** \brief The R_DrawTiltedSpan_NPO2_8 function @@ -661,7 +659,6 @@ void R_DrawTiltedSplat_NPO2_8(void) } #endif } -#endif // ESLOPE /** \brief The R_DrawSplat_NPO2_8 function Just like R_DrawSpan_NPO2_8, but skips transparent pixels. @@ -846,7 +843,6 @@ void R_DrawTranslucentWaterSpan_NPO2_8(void) } } -#ifdef ESLOPE /** \brief The R_DrawTiltedTranslucentWaterSpan_NPO2_8 function Like DrawTiltedTranslucentSpan_NPO2, but for water */ @@ -1043,5 +1039,4 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) } #endif } -#endif // ESLOPE #endif // NOWATER diff --git a/src/r_local.h b/src/r_local.h index 379d55205..48044118d 100644 --- a/src/r_local.h +++ b/src/r_local.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_main.c b/src/r_main.c index 643d8ea49..cf7360804 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -33,6 +33,8 @@ #include "z_zone.h" #include "m_random.h" // quake camera shake #include "r_portal.h" +#include "r_main.h" +#include "i_system.h" // I_GetTimeMicros #ifdef HWRENDER #include "hardware/hw_main.h" @@ -97,6 +99,22 @@ lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // Hack to support extra boom colormaps. extracolormap_t *extra_colormaps = NULL; +// Render stats +int rs_prevframetime = 0; +int rs_rendercalltime = 0; +int rs_swaptime = 0; + +int rs_bsptime = 0; + +int rs_sw_portaltime = 0; +int rs_sw_planetime = 0; +int rs_sw_maskedtime = 0; + +int rs_numbspcalls = 0; +int rs_numsprites = 0; +int rs_numdrawnodes = 0; +int rs_numpolyobjects = 0; + static CV_PossibleValue_t drawdist_cons_t[] = { {256, "256"}, {512, "512"}, {768, "768"}, {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, @@ -147,6 +165,8 @@ consvar_t cv_homremoval = {"homremoval", "No", CV_SAVE, homremoval_cons_t, NULL, consvar_t cv_maxportals = {"maxportals", "2", CV_SAVE, maxportals_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_renderstats = {"renderstats", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + void SplitScreen_OnChange(void) { if (!cv_debug && netgame) @@ -459,9 +479,7 @@ static void R_InitTextureMapping(void) focallength = FixedDiv(projection, FINETANGENT(FINEANGLES/4+FIELDOFVIEW/2)); -#ifdef ESLOPE focallengthf = FIXED_TO_FLOAT(focallength); -#endif for (i = 0; i < FINEANGLES/2; i++) { @@ -902,11 +920,6 @@ void R_ExecuteSetViewSize(void) R_InitTextureMapping(); -#ifdef HWRENDER - if (rendermode != render_soft) - HWR_InitTextureMapping(); -#endif - // thing clipping for (i = 0; i < viewwidth; i++) screenheightarray[i] = (INT16)viewheight; @@ -1040,29 +1053,34 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y) // R_SetupFrame // -// WARNING: a should be unsigned but to add with 2048, it isn't! -#define AIMINGTODY(a) ((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)/fovtan) - // recalc necessary stuff for mouseaiming // slopes are already calculated for the full possible view (which is 4*viewheight). // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) static void R_SetupFreelook(void) { INT32 dy = 0; + + // clip it in the case we are looking a hardware 90 degrees full aiming + // (lmps, network and use F12...) + if (rendermode == render_soft +#ifdef HWRENDER + || cv_grshearing.value +#endif + ) + { + G_SoftwareClipAimingPitch((INT32 *)&aimingangle); + } + if (rendermode == render_soft) { - // clip it in the case we are looking a hardware 90 degrees full aiming - // (lmps, network and use F12...) - G_SoftwareClipAimingPitch((INT32 *)&aimingangle); - dy = AIMINGTODY(aimingangle) * viewwidth/BASEVIDWIDTH; + dy = (AIMINGTODY(aimingangle)>>FRACBITS) * viewwidth/BASEVIDWIDTH; yslope = &yslopetab[viewheight*8 - (viewheight/2 + dy)]; } + centery = (viewheight/2) + dy; centeryfrac = centery<climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode) + chasecam = true; // force chasecam on + else if (player->spectator) // no spectator chasecam + chasecam = false; // force chasecam off + + return chasecam; +} + +boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox) +{ + boolean chasecam = R_ViewpointHasChasecam(player); + + // cut-away view stuff + if (player->awayviewtics || skybox) + return chasecam; + // use outside cam view + else if (!player->spectator && chasecam) + return true; + + // use the player's eyes view + return false; +} + static void R_PortalFrame(portal_t *portal) { viewx = portal->viewx; @@ -1390,7 +1440,7 @@ void R_RenderPlayerView(player_t *player) else { portalclipstart = 0; - portalclipend = viewwidth-1; + portalclipend = viewwidth; R_ClearClipSegs(); } R_ClearDrawSegs(); @@ -1412,7 +1462,11 @@ void R_RenderPlayerView(player_t *player) mytotal = 0; ProfZeroTimer(); #endif + rs_numbspcalls = rs_numpolyobjects = rs_numdrawnodes = 0; + rs_bsptime = I_GetTimeMicros(); R_RenderBSPNode((INT32)numnodes - 1); + rs_bsptime = I_GetTimeMicros() - rs_bsptime; + rs_numsprites = visspritecount; #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add @@ -1430,6 +1484,7 @@ void R_RenderPlayerView(player_t *player) Portal_AddSkyboxPortals(); // Portal rendering. Hijacks the BSP traversal. + rs_sw_portaltime = I_GetTimeMicros(); if (portal_base) { portal_t *portal; @@ -1469,15 +1524,20 @@ void R_RenderPlayerView(player_t *player) Portal_Remove(portal); } } + rs_sw_portaltime = I_GetTimeMicros() - rs_sw_portaltime; + rs_sw_planetime = I_GetTimeMicros(); R_DrawPlanes(); #ifdef FLOORSPLATS R_DrawVisibleFloorSplats(); #endif + rs_sw_planetime = I_GetTimeMicros() - rs_sw_planetime; // draw mid texture and sprite // And now 3D floors/sides! + rs_sw_maskedtime = I_GetTimeMicros(); R_DrawMasked(masks, nummasks); + rs_sw_maskedtime = I_GetTimeMicros() - rs_sw_maskedtime; free(masks); } diff --git a/src/r_main.h b/src/r_main.h index 8cf3d7cbc..99a25d86e 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -26,7 +26,10 @@ extern INT32 centerx, centery; extern fixed_t centerxfrac, centeryfrac; extern fixed_t projection, projectiony; -extern fixed_t fovtan; // field of view +extern fixed_t fovtan; + +// WARNING: a should be unsigned but to add with 2048, it isn't! +#define AIMINGTODY(a) FixedDiv((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160), fovtan) extern size_t validcount, linecount, loopcount, framecount; @@ -71,6 +74,25 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y); boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); +// Render stats + +extern consvar_t cv_renderstats; + +extern int rs_prevframetime;// time when previous frame was rendered +extern int rs_rendercalltime; +extern int rs_swaptime; + +extern int rs_bsptime; + +extern int rs_sw_portaltime; +extern int rs_sw_planetime; +extern int rs_sw_maskedtime; + +extern int rs_numbspcalls; +extern int rs_numsprites; +extern int rs_numdrawnodes; +extern int rs_numpolyobjects; + // // REFRESH - the actual rendering functions. // @@ -104,10 +126,13 @@ void R_SetViewSize(void); // do it (sometimes explicitly called) void R_ExecuteSetViewSize(void); +void R_SetupFrame(player_t *player); void R_SkyboxFrame(player_t *player); -void R_SetupFrame(player_t *player); -// Called by G_Drawer. +boolean R_ViewpointHasChasecam(player_t *player); +boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox); + +// Called by D_Display. void R_RenderPlayerView(player_t *player); // add commands related to engine, at game startup diff --git a/src/r_patch.c b/src/r_patch.c index 9e31d4d19..ad4b3329a 100644 --- a/src/r_patch.c +++ b/src/r_patch.c @@ -1231,9 +1231,9 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp if (!R_CheckIfPatch(lump)) return; - width = patch->width; - height = patch->height; - leftoffset = patch->leftoffset; + width = SHORT(patch->width); + height = SHORT(patch->height); + leftoffset = SHORT(patch->leftoffset); // rotation pivot px = SPRITE_XCENTER; @@ -1348,7 +1348,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp newpatch = R_MaskedFlatToPatch(rawdst, newwidth, newheight, 0, 0, &size); { newpatch->leftoffset = (newpatch->width / 2) + (leftoffset - px); - newpatch->topoffset = (newpatch->height / 2) + (patch->topoffset - py); + newpatch->topoffset = (newpatch->height / 2) + (SHORT(patch->topoffset) - py); } //BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer @@ -1358,6 +1358,12 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp // P_PrecacheLevel if (devparm) spritememory += size; + // convert everything to little-endian, for big-endian support + newpatch->width = SHORT(newpatch->width); + newpatch->height = SHORT(newpatch->height); + newpatch->leftoffset = SHORT(newpatch->leftoffset); + newpatch->topoffset = SHORT(newpatch->topoffset); + #ifdef HWRENDER if (rendermode == render_opengl) { diff --git a/src/r_patch.h b/src/r_patch.h index e743a7d09..a2db6320c 100644 --- a/src/r_patch.h +++ b/src/r_patch.h @@ -1,8 +1,8 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 2018-2019 by Jaime "Lactozilla" Passos. -// Copyright (C) 2019 by Sonic Team Junior. +// Copyright (C) 2018-2020 by Jaime "Lactozilla" Passos. +// Copyright (C) 2019-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_plane.c b/src/r_plane.c index e62e571e4..92795d0fb 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -202,7 +202,6 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) // Needed for ds_bgofs R_PlaneRipple(currentplane, y, planeheight); -#ifdef ESLOPE if (currentplane->slope) { ds_sup = &ds_su[y]; @@ -210,7 +209,6 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) ds_szp = &ds_sz[y]; } else -#endif { ds_xfrac += ripple_xfrac; ds_yfrac += ripple_yfrac; @@ -227,12 +225,10 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) if (pindex >= MAXLIGHTZ) pindex = MAXLIGHTZ - 1; -#ifdef ESLOPE if (currentplane->slope) ds_colormap = colormaps; else -#endif - ds_colormap = planezlight[pindex]; + ds_colormap = planezlight[pindex]; if (currentplane->extra_colormap) ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); @@ -341,21 +337,12 @@ static visplane_t *new_visplane(unsigned hash) // visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, - ffloor_t *pfloor -#ifdef POLYOBJECTS_PLANES - , polyobj_t *polyobj -#endif -#ifdef ESLOPE - , pslope_t *slope -#endif - ) + ffloor_t *pfloor, polyobj_t *polyobj, pslope_t *slope) { visplane_t *check; unsigned hash; -#ifdef ESLOPE - if (slope); else // Don't mess with this right now if a slope is involved -#endif + if (!slope) // Don't mess with this right now if a slope is involved { xoff += viewx; yoff -= viewy; @@ -370,7 +357,6 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, } } -#ifdef POLYOBJECTS_PLANES if (polyobj) { if (polyobj->angle != 0) @@ -385,7 +371,6 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, yoff += polyobj->centerPt.y; } } -#endif // This appears to fix the Nimbus Ruins sky bug. if (picnum == skyflatnum && pfloor) @@ -399,12 +384,10 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, for (check = visplanes[hash]; check; check = check->next) { -#ifdef POLYOBJECTS_PLANES if (check->polyobj && pfloor) continue; if (polyobj != check->polyobj) continue; -#endif if (height == check->height && picnum == check->picnum && lightlevel == check->lightlevel && xoff == check->xoffs && yoff == check->yoffs @@ -413,10 +396,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, && check->viewx == viewx && check->viewy == viewy && check->viewz == viewz && check->viewangle == viewangle && check->plangle == plangle -#ifdef ESLOPE - && check->slope == slope -#endif - ) + && check->slope == slope) { return check; } @@ -438,12 +418,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, check->viewz = viewz; check->viewangle = viewangle; check->plangle = plangle; -#ifdef POLYOBJECTS_PLANES check->polyobj = polyobj; -#endif -#ifdef ESLOPE check->slope = slope; -#endif memset(check->top, 0xff, sizeof (check->top)); memset(check->bottom, 0x00, sizeof (check->bottom)); @@ -510,12 +486,8 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) new_pl->viewz = pl->viewz; new_pl->viewangle = pl->viewangle; new_pl->plangle = pl->plangle; -#ifdef POLYOBJECTS_PLANES new_pl->polyobj = pl->polyobj; -#endif -#ifdef ESLOPE new_pl->slope = pl->slope; -#endif pl = new_pl; pl->minx = start; pl->maxx = stop; @@ -539,11 +511,9 @@ void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop) // INT32 unionl, unionh; // INT32 x; -#ifdef POLYOBJECTS_PLANES // Don't expand polyobject planes here - we do that on our own. if (pl->polyobj) return; -#endif if (pl->minx > start) pl->minx = start; if (pl->maxx < stop) pl->maxx = stop; @@ -619,11 +589,7 @@ void R_DrawPlanes(void) { for (pl = visplanes[i]; pl; pl = pl->next) { - if (pl->ffloor != NULL -#ifdef POLYOBJECTS_PLANES - || pl->polyobj != NULL -#endif - ) + if (pl->ffloor != NULL || pl->polyobj != NULL) continue; R_DrawSinglePlane(pl); @@ -860,7 +826,6 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo return flat; } -#ifdef ESLOPE static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) { // Potentially override other stuff for now cus we're mean. :< But draw a slope plane! @@ -868,15 +833,15 @@ static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) floatv3_t p, m, n; float ang; float vx, vy, vz; - // compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly - // use this as a temp var to store P_GetZAt's return value each time + // compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly + // use this as a temp var to store P_GetSlopeZAt's return value each time fixed_t temp; vx = FIXED_TO_FLOAT(pl->viewx+xoffs); vy = FIXED_TO_FLOAT(pl->viewy-yoffs); vz = FIXED_TO_FLOAT(pl->viewz); - temp = P_GetZAt(pl->slope, pl->viewx, pl->viewy); + temp = P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy); zeroheight = FIXED_TO_FLOAT(temp); // p is the texture origin in view space @@ -885,7 +850,7 @@ static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) ang = ANG2RAD(ANGLE_270 - pl->viewangle); p.x = vx * cos(ang) - vy * sin(ang); p.z = vx * sin(ang) + vy * cos(ang); - temp = P_GetZAt(pl->slope, -xoffs, yoffs); + temp = P_GetSlopeZAt(pl->slope, -xoffs, yoffs); p.y = FIXED_TO_FLOAT(temp) - vz; // m is the v direction vector in view space @@ -898,9 +863,9 @@ static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) n.z = -cos(ang); ang = ANG2RAD(pl->plangle); - temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(sin(ang)), pl->viewy + FLOAT_TO_FIXED(cos(ang))); + temp = P_GetSlopeZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(sin(ang)), pl->viewy + FLOAT_TO_FIXED(cos(ang))); m.y = FIXED_TO_FLOAT(temp) - zeroheight; - temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang))); + temp = P_GetSlopeZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang))); n.y = FIXED_TO_FLOAT(temp) - zeroheight; if (ds_powersoftwo) @@ -951,7 +916,6 @@ d.z = (v1.x * v2.y) - (v1.y * v2.x) } #undef SFMULT } -#endif // ESLOPE void R_DrawSinglePlane(visplane_t *pl) { @@ -979,118 +943,118 @@ void R_DrawSinglePlane(visplane_t *pl) #endif spanfunc = spanfuncs[BASEDRAWFUNC]; -#ifdef POLYOBJECTS_PLANES - if (pl->polyobj && pl->polyobj->translucency != 0) + if (pl->polyobj) { - spanfunctype = SPANDRAWFUNC_TRANS; - // Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red) if (pl->polyobj->translucency >= 10) return; // Don't even draw it else if (pl->polyobj->translucency > 0) + { + spanfunctype = (pl->polyobj->flags & POF_SPLAT) ? SPANDRAWFUNC_TRANSSPLAT : SPANDRAWFUNC_TRANS; ds_transmap = transtables + ((pl->polyobj->translucency-1)<polyobj->flags & POF_SPLAT) // Opaque, but allow transparent flat pixels spanfunctype = SPANDRAWFUNC_SPLAT; - if ((spanfunctype == SPANDRAWFUNC_SPLAT) || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) + if (pl->polyobj->translucency == 0 || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) light = (pl->lightlevel >> LIGHTSEGSHIFT); else light = LIGHTLEVELS-1; - - } else -#endif - if (pl->ffloor) + } + else { - // Don't draw planes that shouldn't be drawn. - for (rover = pl->ffloor->target->ffloors; rover; rover = rover->next) + if (pl->ffloor) { - if ((pl->ffloor->flags & FF_CUTEXTRA) && (rover->flags & FF_EXTRA)) + // Don't draw planes that shouldn't be drawn. + for (rover = pl->ffloor->target->ffloors; rover; rover = rover->next) { - if (pl->ffloor->flags & FF_EXTRA) + if ((pl->ffloor->flags & FF_CUTEXTRA) && (rover->flags & FF_EXTRA)) { - // The plane is from an extra 3D floor... Check the flags so - // there are no undesired cuts. - if (((pl->ffloor->flags & (FF_FOG|FF_SWIMMABLE)) == (rover->flags & (FF_FOG|FF_SWIMMABLE))) - && pl->height < *rover->topheight - && pl->height > *rover->bottomheight) - return; + if (pl->ffloor->flags & FF_EXTRA) + { + // The plane is from an extra 3D floor... Check the flags so + // there are no undesired cuts. + if (((pl->ffloor->flags & (FF_FOG|FF_SWIMMABLE)) == (rover->flags & (FF_FOG|FF_SWIMMABLE))) + && pl->height < *rover->topheight + && pl->height > *rover->bottomheight) + return; + } } } - } - if (pl->ffloor->flags & FF_TRANSLUCENT) - { - spanfunctype = SPANDRAWFUNC_TRANS; - - // Hacked up support for alpha value in software mode Tails 09-24-2002 - if (pl->ffloor->alpha < 12) - return; // Don't even draw it - else if (pl->ffloor->alpha < 38) - ds_transmap = transtables + ((tr_trans90-1)<ffloor->alpha < 64) - ds_transmap = transtables + ((tr_trans80-1)<ffloor->alpha < 89) - ds_transmap = transtables + ((tr_trans70-1)<ffloor->alpha < 115) - ds_transmap = transtables + ((tr_trans60-1)<ffloor->alpha < 140) - ds_transmap = transtables + ((tr_trans50-1)<ffloor->alpha < 166) - ds_transmap = transtables + ((tr_trans40-1)<ffloor->alpha < 192) - ds_transmap = transtables + ((tr_trans30-1)<ffloor->alpha < 217) - ds_transmap = transtables + ((tr_trans20-1)<ffloor->alpha < 243) - ds_transmap = transtables + ((tr_trans10-1)<extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) - light = (pl->lightlevel >> LIGHTSEGSHIFT); - else - light = LIGHTLEVELS-1; - } - else if (pl->ffloor->flags & FF_FOG) - { - spanfunctype = SPANDRAWFUNC_FOG; - light = (pl->lightlevel >> LIGHTSEGSHIFT); - } - else light = (pl->lightlevel >> LIGHTSEGSHIFT); - -#ifndef NOWATER - if (pl->ffloor->flags & FF_RIPPLE) - { - INT32 top, bottom; - - itswater = true; - if (spanfunctype == SPANDRAWFUNC_TRANS) + if (pl->ffloor->flags & FF_TRANSLUCENT) { - spanfunctype = SPANDRAWFUNC_WATER; + spanfunctype = (pl->ffloor->master->flags & ML_EFFECT6) ? SPANDRAWFUNC_TRANSSPLAT : SPANDRAWFUNC_TRANS; - // Copy the current scene, ugh - top = pl->high-8; - bottom = pl->low+8; + // Hacked up support for alpha value in software mode Tails 09-24-2002 + if (pl->ffloor->alpha < 12) + return; // Don't even draw it + else if (pl->ffloor->alpha < 38) + ds_transmap = transtables + ((tr_trans90-1)<ffloor->alpha < 64) + ds_transmap = transtables + ((tr_trans80-1)<ffloor->alpha < 89) + ds_transmap = transtables + ((tr_trans70-1)<ffloor->alpha < 115) + ds_transmap = transtables + ((tr_trans60-1)<ffloor->alpha < 140) + ds_transmap = transtables + ((tr_trans50-1)<ffloor->alpha < 166) + ds_transmap = transtables + ((tr_trans40-1)<ffloor->alpha < 192) + ds_transmap = transtables + ((tr_trans30-1)<ffloor->alpha < 217) + ds_transmap = transtables + ((tr_trans20-1)<ffloor->alpha < 243) + ds_transmap = transtables + ((tr_trans10-1)< vid.height) - bottom = vid.height; - - // Only copy the part of the screen we need - VID_BlitLinearScreen((splitscreen && viewplayer == &players[secondarydisplayplayer]) ? screens[0] + (top+(vid.height>>1))*vid.width : screens[0]+((top)*vid.width), screens[1]+((top)*vid.width), - vid.width, bottom-top, - vid.width, vid.width); + if ((spanfunctype == SPANDRAWFUNC_SPLAT) || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) + light = (pl->lightlevel >> LIGHTSEGSHIFT); + else + light = LIGHTLEVELS-1; } - } -#endif - } - else light = (pl->lightlevel >> LIGHTSEGSHIFT); + else if (pl->ffloor->flags & FF_FOG) + { + spanfunctype = SPANDRAWFUNC_FOG; + light = (pl->lightlevel >> LIGHTSEGSHIFT); + } + else light = (pl->lightlevel >> LIGHTSEGSHIFT); -#ifdef ESLOPE - if (!pl->slope) // Don't mess with angle on slopes! We'll handle this ourselves later -#endif - if (viewangle != pl->viewangle+pl->plangle) + #ifndef NOWATER + if (pl->ffloor->flags & FF_RIPPLE) + { + INT32 top, bottom; + + itswater = true; + if (spanfunctype == SPANDRAWFUNC_TRANS) + { + spanfunctype = SPANDRAWFUNC_WATER; + + // Copy the current scene, ugh + top = pl->high-8; + bottom = pl->low+8; + + if (top < 0) + top = 0; + if (bottom > vid.height) + bottom = vid.height; + + // Only copy the part of the screen we need + VID_BlitLinearScreen((splitscreen && viewplayer == &players[secondarydisplayplayer]) ? screens[0] + (top+(vid.height>>1))*vid.width : screens[0]+((top)*vid.width), screens[1]+((top)*vid.width), + vid.width, bottom-top, + vid.width, vid.width); + } + } + #endif + } + else + light = (pl->lightlevel >> LIGHTSEGSHIFT); + } + + if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later + && viewangle != pl->viewangle+pl->plangle) { memset(cachedheight, 0, sizeof (cachedheight)); angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; @@ -1148,7 +1112,6 @@ void R_DrawSinglePlane(visplane_t *pl) if (light < 0) light = 0; -#ifdef ESLOPE if (pl->slope) { float fudgecanyon = 0; @@ -1214,7 +1177,7 @@ void R_DrawSinglePlane(visplane_t *pl) if (itswater) { INT32 i; - fixed_t plheight = abs(P_GetZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); + fixed_t plheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); fixed_t rxoffs = xoffs; fixed_t ryoffs = yoffs; @@ -1248,10 +1211,9 @@ void R_DrawSinglePlane(visplane_t *pl) spanfunctype = SPANDRAWFUNC_TILTED; planezlight = scalelight[light]; - } else -#endif // ESLOPE - - planezlight = zlight[light]; + } + else + planezlight = zlight[light]; // Use the correct span drawer depending on the powers-of-twoness if (!ds_powersoftwo) diff --git a/src/r_plane.h b/src/r_plane.h index d9ba5c56b..67fa19f38 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -47,12 +47,8 @@ typedef struct visplane_s fixed_t xoffs, yoffs; // Scrolling flats. struct ffloor_s *ffloor; -#ifdef POLYOBJECTS_PLANES polyobj_t *polyobj; -#endif -#ifdef ESLOPE pslope_t *slope; -#endif } visplane_t; extern visplane_t *visplanes[MAXVISPLANES]; @@ -82,14 +78,7 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2); void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2); void R_DrawPlanes(void); visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, - extracolormap_t *planecolormap, ffloor_t *ffloor -#ifdef POLYOBJECTS_PLANES - , polyobj_t *polyobj -#endif -#ifdef ESLOPE - , pslope_t *slope -#endif - ); + extracolormap_t *planecolormap, ffloor_t *ffloor, polyobj_t *polyobj, pslope_t *slope); visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); @@ -110,18 +99,14 @@ typedef struct planemgr_s INT16 f_clip[MAXVIDWIDTH]; INT16 c_clip[MAXVIDWIDTH]; -#ifdef ESLOPE // For slope rendering; the height at the other end fixed_t f_pos_slope; fixed_t b_pos_slope; struct pslope_s *slope; -#endif struct ffloor_s *ffloor; -#ifdef POLYOBJECTS_PLANES polyobj_t *polyobj; -#endif } visffloor_t; extern visffloor_t ffloor[MAXFFLOORS]; diff --git a/src/r_portal.c b/src/r_portal.c index 576b606ec..1aca145ec 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_portal.h b/src/r_portal.h index c46ddfdab..406b98d10 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_segs.c b/src/r_segs.c index 057518fb5..741a25254 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -52,20 +52,16 @@ static fixed_t rw_offset2; // for splats static fixed_t rw_scale, rw_scalestep; static fixed_t rw_midtexturemid, rw_toptexturemid, rw_bottomtexturemid; static INT32 worldtop, worldbottom, worldhigh, worldlow; -#ifdef ESLOPE static INT32 worldtopslope, worldbottomslope, worldhighslope, worldlowslope; // worldtop/bottom at end of slope static fixed_t rw_toptextureslide, rw_midtextureslide, rw_bottomtextureslide; // Defines how to adjust Y offsets along the wall for slopes static fixed_t rw_midtextureback, rw_midtexturebackslide; // Values for masked midtexture height calculation -#endif static fixed_t pixhigh, pixlow, pixhighstep, pixlowstep; static fixed_t topfrac, topstep; static fixed_t bottomfrac, bottomstep; static lighttable_t **walllights; static INT16 *maskedtexturecol; -#ifdef ESLOPE static fixed_t *maskedtextureheight = NULL; -#endif // ========================================================================== // R_Splats Wall Splats Drawer @@ -240,14 +236,13 @@ static void R_DrawWallSplats(void) // way we don't have to store extra post_t info with each column for // multi-patch textures. They are not normally needed as multi-patch // textures don't have holes in it. At least not for now. -static INT32 column2s_length; // column->length : for multi-patch on 2sided wall = texture->height static void R_Render2sidedMultiPatchColumn(column_t *column) { INT32 topscreen, bottomscreen; topscreen = sprtopscreen; // + spryscale*column->topdelta; topdelta is 0 for the wall - bottomscreen = topscreen + spryscale * column2s_length; + bottomscreen = topscreen + spryscale * lengthcol; dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS; @@ -279,13 +274,6 @@ static void R_Render2sidedMultiPatchColumn(column_t *column) } } -// quick wrapper for R_DrawFlippedMaskedColumn so it can be set as a colfunc_2s value -// uses column2s_length for texture->height as above -static void R_DrawFlippedMaskedSegColumn(column_t *column) -{ - R_DrawFlippedMaskedColumn(column, column2s_length); -} - void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { size_t pindex; @@ -299,9 +287,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) sector_t *front, *back; INT32 times, repeats; INT64 overflow_test; -#ifdef ESLOPE INT32 range; -#endif // Calculate light table. // Use different light tables @@ -349,9 +335,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } -#ifdef ESLOPE range = max(ds->x2-ds->x1, 1); -#endif rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; @@ -364,8 +348,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { if (textures[texnum]->flip & 2) // vertically flipped? { - colfunc_2s = R_DrawFlippedMaskedSegColumn; - column2s_length = textures[texnum]->height; + colfunc_2s = R_DrawFlippedMaskedColumn; + lengthcol = textures[texnum]->height; } else colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture @@ -373,7 +357,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) else { colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info) - column2s_length = textures[texnum]->height; + lengthcol = textures[texnum]->height; } // Setup lighting based on the presence/lack-of 3D floors. @@ -389,30 +373,20 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) for (i = 0; i < dc_numlights; i++) { -#ifdef ESLOPE fixed_t leftheight, rightheight; -#endif light = &frontsector->lightlist[i]; rlight = &dc_lightlist[i]; -#ifdef ESLOPE - if (light->slope) { - leftheight = P_GetZAt(light->slope, ds->leftpos.x, ds->leftpos.y); - rightheight = P_GetZAt(light->slope, ds->rightpos.x, ds->rightpos.y); - } else - leftheight = rightheight = light->height; + leftheight = P_GetLightZAt(light, ds-> leftpos.x, ds-> leftpos.y); + rightheight = P_GetLightZAt(light, ds->rightpos.x, ds->rightpos.y); - leftheight -= viewz; + leftheight -= viewz; rightheight -= viewz; - rlight->height = (centeryfrac) - FixedMul(leftheight, ds->scale1); + rlight->height = (centeryfrac) - FixedMul(leftheight , ds->scale1); rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2); rlight->heightstep = (rlight->heightstep-rlight->height)/(range); //if (x1 > ds->x1) //rlight->height -= (x1 - ds->x1)*rlight->heightstep; -#else - rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale); - rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz)); -#endif rlight->startheight = rlight->height; // keep starting value here to reset for each repeat rlight->lightlevel = *light->lightlevel; rlight->extra_colormap = *light->extra_colormap; @@ -513,40 +487,17 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } } -#ifndef ESLOPE - if (curline->linedef->flags & ML_DONTPEGBOTTOM) - { - dc_texturemid = front->floorheight > back->floorheight - ? front->floorheight : back->floorheight; - dc_texturemid = dc_texturemid + textureheight[texnum] - viewz; - } - else - { - dc_texturemid = front->ceilingheight < back->ceilingheight - ? front->ceilingheight : back->ceilingheight; - dc_texturemid = dc_texturemid - viewz; - } - dc_texturemid += curline->sidedef->rowoffset; - - if (curline->linedef->flags & ML_DONTPEGBOTTOM) - dc_texturemid += (textureheight[texnum])*times; - else - dc_texturemid -= (textureheight[texnum])*times; -#endif - dc_texheight = textureheight[texnum]>>FRACBITS; // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { -#ifdef ESLOPE dc_texturemid = ds->maskedtextureheight[dc_x]; if (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3)) dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; else dc_texturemid -= (textureheight[texnum])*times; -#endif // calculate lighting if (maskedtexturecol[dc_x] != INT16_MAX) { @@ -656,7 +607,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // draw the texture col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); -//#ifdef POLYOBJECTS_PLANES #if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red if (curline->dontrenderme && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES)) { @@ -733,7 +683,7 @@ static void R_DrawRepeatMaskedColumn(column_t *col) static void R_DrawRepeatFlippedMaskedColumn(column_t *col) { do { - R_DrawFlippedMaskedColumn(col, column2s_length); + R_DrawFlippedMaskedColumn(col); sprtopscreen += dc_texheight*spryscale; } while (sprtopscreen < sprbotscreen); } @@ -755,14 +705,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) fixed_t offsetvalue = 0; lightlist_t *light; r_lightlist_t *rlight; -#ifdef ESLOPE INT32 range; -#endif -#ifndef ESLOPE - fixed_t lheight; -#endif line_t *newline = NULL; -#ifdef ESLOPE // Render FOF sides kinda like normal sides, with the frac and step and everything // NOTE: INT64 instead of fixed_t because overflow concerns INT64 top_frac, top_step, bottom_frac, bottom_step; @@ -772,7 +716,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) INT32 oldx = -1; fixed_t left_top, left_bottom; // needed here for slope skewing pslope_t *skewslope = NULL; -#endif void (*colfunc_2s) (column_t *); @@ -829,9 +772,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) else if (pfloor->flags & FF_FOG) colfunc = colfuncs[COLDRAWFUNC_FOG]; -#ifdef ESLOPE range = max(ds->x2-ds->x1, 1); -#endif //SoM: Moved these up here so they are available for my lightlist calculations rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; @@ -848,21 +789,15 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) for (i = p = 0; i < dc_numlights; i++) { -#ifdef ESLOPE fixed_t leftheight, rightheight; fixed_t pfloorleft, pfloorright; INT64 overflow_test; -#endif light = &frontsector->lightlist[i]; rlight = &dc_lightlist[p]; -#ifdef ESLOPE #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, ds->leftpos.x, ds->leftpos.y); \ - end2 = P_GetZAt(slope, ds->rightpos.x, ds->rightpos.y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, ds-> leftpos.x, ds-> leftpos.y, normalheight); \ + end2 = P_GetZAt(slope, ds->rightpos.x, ds->rightpos.y, normalheight); SLOPEPARAMS(light->slope, leftheight, rightheight, light->height) SLOPEPARAMS(*pfloor->b_slope, pfloorleft, pfloorright, *pfloor->bottomheight) @@ -875,8 +810,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights) { lightlist_t *nextlight = &frontsector->lightlist[i+1]; - if ((nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height) > pfloorleft - && (nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height) > pfloorright) + if (P_GetZAt(nextlight->slope, ds-> leftpos.x, ds-> leftpos.y, nextlight->height) > pfloorleft + && P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y, nextlight->height) > pfloorright) continue; } @@ -896,21 +831,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) else if (overflow_test > (INT64)CLAMPMIN) rlight->heightstep = (fixed_t)overflow_test; else rlight->heightstep = CLAMPMIN; rlight->heightstep = (rlight->heightstep-rlight->height)/(range); -#else - if (light->height < *pfloor->bottomheight) - continue; - - if (light->height > *pfloor->topheight && i+1 < dc_numlights && frontsector->lightlist[i+1].height > *pfloor->topheight) - continue; - - lheight = light->height;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : light->height; - rlight->heightstep = -FixedMul (rw_scalestep, (lheight - viewz)); - rlight->height = (centeryfrac) - FixedMul((lheight - viewz), spryscale); -#endif rlight->flags = light->flags; if (light->flags & FF_CUTLEVEL) { -#ifdef ESLOPE SLOPEPARAMS(*light->caster->b_slope, leftheight, rightheight, *light->caster->bottomheight) #undef SLOPEPARAMS leftheight -= viewz; @@ -927,11 +850,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) else if (overflow_test > (INT64)CLAMPMIN) rlight->botheightstep = (fixed_t)overflow_test; else rlight->botheightstep = CLAMPMIN; rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range); -#else - lheight = *light->caster->bottomheight;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : *light->caster->bottomheight; - rlight->botheightstep = -FixedMul (rw_scalestep, (lheight - viewz)); - rlight->botheight = (centeryfrac) - FixedMul((lheight - viewz), spryscale); -#endif } rlight->lightlevel = *light->lightlevel; @@ -988,17 +906,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) mceilingclip = ds->sprtopclip; dc_texheight = textureheight[texnum]>>FRACBITS; -#ifdef ESLOPE // calculate both left ends - if (*pfloor->t_slope) - left_top = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) - viewz; - else - left_top = *pfloor->topheight - viewz; + left_top = P_GetFFloorTopZAt (pfloor, ds->leftpos.x, ds->leftpos.y) - viewz; + left_bottom = P_GetFFloorBottomZAt(pfloor, ds->leftpos.x, ds->leftpos.y) - viewz; - if (*pfloor->b_slope) - left_bottom = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) - viewz; - else - left_bottom = *pfloor->bottomheight - viewz; skewslope = *pfloor->t_slope; // skew using top slope by default if (newline) { @@ -1011,21 +922,18 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (slopeskew) dc_texturemid = left_top; else -#endif - dc_texturemid = *pfloor->topheight - viewz; + dc_texturemid = *pfloor->topheight - viewz; if (newline) { offsetvalue = sides[newline->sidenum[0]].rowoffset; if (newline->flags & ML_DONTPEGBOTTOM) { -#ifdef ESLOPE skewslope = *pfloor->b_slope; // skew using bottom slope if (slopeskew) dc_texturemid = left_bottom; else -#endif - offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; + offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; } } else @@ -1033,17 +941,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset; if (curline->linedef->flags & ML_DONTPEGBOTTOM) { -#ifdef ESLOPE skewslope = *pfloor->b_slope; // skew using bottom slope if (slopeskew) dc_texturemid = left_bottom; else -#endif - offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; + offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; } } -#ifdef ESLOPE if (slopeskew) { angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); @@ -1051,7 +956,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (skewslope) ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT)); } -#endif dc_texturemid += offsetvalue; @@ -1065,7 +969,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (textures[texnum]->flip & 2) // vertically flipped? { colfunc_2s = R_DrawRepeatFlippedMaskedColumn; - column2s_length = textures[texnum]->height; + lengthcol = textures[texnum]->height; } else colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture @@ -1073,24 +977,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) else { colfunc_2s = R_Render2sidedMultiPatchColumn; //render multipatch with no holes (no post_t info) - column2s_length = textures[texnum]->height; + lengthcol = textures[texnum]->height; } -#ifdef ESLOPE // Set heights according to plane, or slope, whichever { fixed_t right_top, right_bottom; // calculate right ends now - if (*pfloor->t_slope) - right_top = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) - viewz; - else - right_top = *pfloor->topheight - viewz; - - if (*pfloor->b_slope) - right_bottom = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) - viewz; - else - right_bottom = *pfloor->bottomheight - viewz; + right_top = P_GetFFloorTopZAt (pfloor, ds->rightpos.x, ds->rightpos.y) - viewz; + right_bottom = P_GetFFloorBottomZAt(pfloor, ds->rightpos.x, ds->rightpos.y) - viewz; // using INT64 to avoid 32bit overflow top_frac = (INT64)centeryfrac - (((INT64)left_top * ds->scale1) >> FRACBITS); @@ -1104,24 +1000,20 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) top_frac += top_step * (x1 - ds->x1); bottom_frac += bottom_step * (x1 - ds->x1); } -#endif // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { if (maskedtexturecol[dc_x] != INT16_MAX) { -#ifdef ESLOPE if (ffloortextureslide) { // skew FOF walls if (oldx != -1) dc_texturemid += FixedMul(ffloortextureslide, (maskedtexturecol[oldx]-maskedtexturecol[dc_x])< (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX; else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac; else sprtopscreen = windowtop = CLAMPMIN; @@ -1131,10 +1023,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) top_frac += top_step; bottom_frac += bottom_step; -#else - sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale)); - sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen; -#endif // SoM: If column is out of range, why bother with it?? if (windowbottom < topbounds || windowtop > bottombounds) @@ -1344,9 +1232,7 @@ static void R_RenderSegLoop (void) INT32 mid; fixed_t texturecolumn = 0; -#ifdef ESLOPE fixed_t oldtexturecolumn = -1; -#endif INT32 top; INT32 bottom; INT32 i; @@ -1403,10 +1289,8 @@ static void R_RenderSegLoop (void) for (i = 0; i < numffloors; i++) { -#ifdef POLYOBJECTS_PLANES if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg)) continue; -#endif if (ffloor[i].height < viewz) { @@ -1419,18 +1303,19 @@ static void R_RenderSegLoop (void) if (bottom_w > bottom) bottom_w = bottom; -#ifdef POLYOBJECTS_PLANES // Polyobject-specific hack to fix plane leaking -Red - if (ffloor[i].polyobj && top_w >= bottom_w) { + if (ffloor[i].polyobj && top_w >= bottom_w) + { ffloor[i].plane->top[rw_x] = 0xFFFF; ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 - } else -#endif - - if (top_w <= bottom_w) + } + else { - ffloor[i].plane->top[rw_x] = (INT16)top_w; - ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w; + if (top_w <= bottom_w) + { + ffloor[i].plane->top[rw_x] = (INT16)top_w; + ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w; + } } } else if (ffloor[i].height > viewz) @@ -1444,18 +1329,19 @@ static void R_RenderSegLoop (void) if (bottom_w > bottom) bottom_w = bottom; -#ifdef POLYOBJECTS_PLANES // Polyobject-specific hack to fix plane leaking -Red - if (ffloor[i].polyobj && top_w >= bottom_w) { + if (ffloor[i].polyobj && top_w >= bottom_w) + { ffloor[i].plane->top[rw_x] = 0xFFFF; ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 - } else -#endif - - if (top_w <= bottom_w) + } + else { - ffloor[i].plane->top[rw_x] = (INT16)top_w; - ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w; + if (top_w <= bottom_w) + { + ffloor[i].plane->top[rw_x] = (INT16)top_w; + ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w; + } } } } @@ -1466,7 +1352,6 @@ static void R_RenderSegLoop (void) angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; texturecolumn = rw_offset-FixedMul(FINETANGENT(angle),rw_distance); -#ifdef ESLOPE if (oldtexturecolumn != -1) { rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn-texturecolumn); rw_midtexturemid += FixedMul(rw_midtextureslide, oldtexturecolumn-texturecolumn); @@ -1474,7 +1359,6 @@ static void R_RenderSegLoop (void) rw_midtextureback += FixedMul(rw_midtexturebackslide, oldtexturecolumn-texturecolumn); } oldtexturecolumn = texturecolumn; -#endif texturecolumn >>= FRACBITS; @@ -1650,13 +1534,11 @@ static void R_RenderSegLoop (void) // for backdrawing of masked mid texture maskedtexturecol[rw_x] = (INT16)texturecolumn; -#ifdef ESLOPE if (maskedtextureheight != NULL) { maskedtextureheight[rw_x] = (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3) ? max(rw_midtexturemid, rw_midtextureback) : min(rw_midtexturemid, rw_midtextureback)); } -#endif } if (dc_numlights) @@ -1712,26 +1594,19 @@ void R_StoreWallRange(INT32 start, INT32 stop) fixed_t sineval; angle_t distangle, offsetangle; boolean longboi; -#ifndef ESLOPE - fixed_t vtop; -#endif INT32 lightnum; INT32 i, p; lightlist_t *light; r_lightlist_t *rlight; INT32 range; -#ifdef ESLOPE vertex_t segleft, segright; fixed_t ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide; -#endif static size_t maxdrawsegs = 0; -#ifdef ESLOPE maskedtextureheight = NULL; //initialize segleft and segright memset(&segleft, 0x00, sizeof(segleft)); memset(&segright, 0x00, sizeof(segright)); -#endif colfunc = colfuncs[BASEDRAWFUNC]; @@ -1841,7 +1716,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) // calculate texture boundaries // and decide if floor / ceiling marks are needed -#ifdef ESLOPE // Figure out map coordinates of where start and end are mapping to on seg, so we can clip right for slope bullshit if (frontsector->hasslope || (backsector && backsector->hasslope)) // Commenting this out for FOFslop. -Red { @@ -1894,11 +1768,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - if (slope) { \ - end1 = P_GetZAt(slope, segleft.x, segleft.y); \ - end2 = P_GetZAt(slope, segright.x, segright.y); \ - } else \ - end1 = end2 = normalheight; + end1 = P_GetZAt(slope, segleft.x, segleft.y, normalheight); \ + end2 = P_GetZAt(slope, segright.x, segright.y, normalheight); SLOPEPARAMS(frontsector->c_slope, worldtop, worldtopslope, frontsector->ceilingheight) SLOPEPARAMS(frontsector->f_slope, worldbottom, worldbottomslope, frontsector->floorheight) @@ -1908,10 +1779,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldtopslope -= viewz; worldbottom -= viewz; worldbottomslope -= viewz; -#else - worldtop = frontsector->ceilingheight - viewz; - worldbottom = frontsector->floorheight - viewz; -#endif midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; @@ -1928,23 +1795,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) { for (i = 0; i < numffloors; i++) { -#ifdef POLYOBJECTS_PLANES if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg)) continue; -#endif -#ifdef ESLOPE - if (ffloor[i].slope) { - ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft.x, segleft.y) - viewz; - ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y) - viewz; - } else - ffloor[i].f_pos_slope = -#endif - ffloor[i].f_pos = ffloor[i].height - viewz; + ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft .x, segleft .y, ffloor[i].height) - viewz; + ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y, ffloor[i].height) - viewz; } } -#ifdef ESLOPE // Set up texture Y offset slides for sloped walls rw_toptextureslide = rw_midtextureslide = rw_bottomtextureslide = 0; ceilingfrontslide = floorfrontslide = ceilingbackslide = floorbackslide = 0; @@ -1964,7 +1822,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (backsector && backsector->c_slope) ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); } -#endif if (!backsector) { @@ -1974,33 +1831,22 @@ void R_StoreWallRange(INT32 start, INT32 stop) texheight = textureheight[midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; -#ifdef ESLOPE if (linedef->flags & ML_EFFECT2) { if (linedef->flags & ML_DONTPEGBOTTOM) rw_midtexturemid = frontsector->floorheight + texheight - viewz; else rw_midtexturemid = frontsector->ceilingheight - viewz; } - else -#endif - if (linedef->flags & ML_DONTPEGBOTTOM) + else if (linedef->flags & ML_DONTPEGBOTTOM) { -#ifdef ESLOPE rw_midtexturemid = worldbottom + texheight; rw_midtextureslide = floorfrontslide; -#else - vtop = frontsector->floorheight + texheight; - // bottom of texture at bottom - rw_midtexturemid = vtop - viewz; -#endif } else { // top of texture at top rw_midtexturemid = worldtop; -#ifdef ESLOPE rw_midtextureslide = ceilingfrontslide; -#endif } rw_midtexturemid += sidedef->rowoffset; @@ -2016,17 +1862,12 @@ void R_StoreWallRange(INT32 start, INT32 stop) boolean bothceilingssky = false; // turned on if both back and front ceilings are sky boolean bothfloorssky = false; // likewise, but for floors -#ifdef ESLOPE SLOPEPARAMS(backsector->c_slope, worldhigh, worldhighslope, backsector->ceilingheight) SLOPEPARAMS(backsector->f_slope, worldlow, worldlowslope, backsector->floorheight) worldhigh -= viewz; worldhighslope -= viewz; worldlow -= viewz; worldlowslope -= viewz; -#else - worldhigh = backsector->ceilingheight - viewz; - worldlow = backsector->floorheight - viewz; -#endif // hack to allow height changes in outdoor areas // This is what gets rid of the upper textures if there should be sky @@ -2048,27 +1889,15 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (!bothfloorssky) { - if ( -#ifdef ESLOPE - worldbottomslope > worldlowslope || -#endif - worldbottom > worldlow) + if (worldbottomslope > worldlowslope || worldbottom > worldlow) { ds_p->silhouette = SIL_BOTTOM; -#ifdef ESLOPE - if ((backsector->f_slope ? P_GetZAt(backsector->f_slope, viewx, viewy) : backsector->floorheight) > viewz) + if (P_GetSectorFloorZAt(backsector, viewx, viewy) > viewz) ds_p->bsilheight = INT32_MAX; else ds_p->bsilheight = (frontsector->f_slope ? INT32_MAX : frontsector->floorheight); -#else - ds_p->bsilheight = frontsector->floorheight; -#endif } -#ifdef ESLOPE - else if ((backsector->f_slope ? P_GetZAt(backsector->f_slope, viewx, viewy) : backsector->floorheight) > viewz) -#else - else if (backsector->floorheight > viewz) -#endif + else if (P_GetSectorFloorZAt(backsector, viewx, viewy) > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT32_MAX; @@ -2078,27 +1907,15 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (!bothceilingssky) { - if ( -#ifdef ESLOPE - worldtopslope < worldhighslope || -#endif - worldtop < worldhigh) + if (worldtopslope < worldhighslope || worldtop < worldhigh) { ds_p->silhouette |= SIL_TOP; -#ifdef ESLOPE - if ((backsector->c_slope ? P_GetZAt(backsector->c_slope, viewx, viewy) : backsector->ceilingheight) < viewz) + if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) ds_p->tsilheight = INT32_MIN; else ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight); -#else - ds_p->tsilheight = frontsector->ceilingheight; -#endif } -#ifdef ESLOPE - else if ((backsector->c_slope ? P_GetZAt(backsector->c_slope, viewx, viewy) : backsector->ceilingheight) < viewz) -#else - else if (backsector->ceilingheight < viewz) -#endif + else if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT32_MIN; @@ -2108,22 +1925,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (!bothceilingssky && !bothfloorssky) { -#ifdef ESLOPE if (worldhigh <= worldbottom && worldhighslope <= worldbottomslope) -#else - if (worldhigh <= worldbottom) -#endif { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->silhouette |= SIL_BOTTOM; } -#ifdef ESLOPE if (worldlow >= worldtop && worldlowslope >= worldtopslope) -#else - if (worldlow >= worldtop) -#endif { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT32_MIN; @@ -2136,21 +1945,13 @@ void R_StoreWallRange(INT32 start, INT32 stop) // Without the following code, sprites get displayed behind closed doors. if (!bothceilingssky && !bothfloorssky) { -#ifdef ESLOPE if (doorclosed || (worldhigh <= worldbottom && worldhighslope <= worldbottomslope)) -#else - if (doorclosed || backsector->ceilingheight <= frontsector->floorheight) -#endif { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->silhouette |= SIL_BOTTOM; } -#ifdef ESLOPE if (doorclosed || (worldlow >= worldtop && worldlowslope >= worldtopslope)) -#else - if (doorclosed || backsector->floorheight >= frontsector->ceilingheight) -#endif { // killough 1/17/98, 2/8/98 ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT32_MIN; @@ -2165,10 +1966,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) markfloor = false; } else if (worldlow != worldbottom -#ifdef ESLOPE || worldlowslope != worldbottomslope || backsector->f_slope != frontsector->f_slope -#endif || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. @@ -2198,10 +1997,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) markceiling = false; } else if (worldhigh != worldtop -#ifdef ESLOPE || worldhighslope != worldtopslope || backsector->c_slope != frontsector->c_slope -#endif || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. @@ -2225,13 +2022,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (!bothceilingssky && !bothfloorssky) { -#ifdef ESLOPE if ((worldhigh <= worldbottom && worldhighslope <= worldbottomslope) || (worldlow >= worldtop && worldlowslope >= worldtopslope)) -#else - if (backsector->ceilingheight <= frontsector->floorheight - || backsector->floorheight >= frontsector->ceilingheight) -#endif { // closed door markceiling = markfloor = true; @@ -2240,11 +2032,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // check TOP TEXTURE if (!bothceilingssky // never draw the top texture if on - && (worldhigh < worldtop -#ifdef ESLOPE - || worldhighslope < worldtopslope -#endif - )) + && (worldhigh < worldtop || worldhighslope < worldtopslope)) { fixed_t texheight; // top texture @@ -2264,67 +2052,47 @@ void R_StoreWallRange(INT32 start, INT32 stop) toptexture = R_GetTextureNum(sidedef->toptexture); texheight = textureheight[toptexture]; } -#ifdef ESLOPE if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked if (linedef->flags & ML_DONTPEGTOP) rw_toptexturemid = frontsector->ceilingheight - viewz; else rw_toptexturemid = backsector->ceilingheight - viewz; - } else -#endif - if (linedef->flags & ML_DONTPEGTOP) + } + else if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; -#ifdef ESLOPE rw_toptextureslide = ceilingfrontslide; -#endif } else { -#ifdef ESLOPE rw_toptexturemid = worldhigh + texheight; rw_toptextureslide = ceilingbackslide; -#else - vtop = backsector->ceilingheight + texheight; - // bottom of texture - rw_toptexturemid = vtop - viewz; -#endif } } // check BOTTOM TEXTURE if (!bothfloorssky // never draw the bottom texture if on - && (worldlow > worldbottom -#ifdef ESLOPE - || worldlowslope > worldbottomslope -#endif - )) //seulement si VISIBLE!!! + && (worldlow > worldbottom || worldlowslope > worldbottomslope)) // Only if VISIBLE!!! { // bottom texture bottomtexture = R_GetTextureNum(sidedef->bottomtexture); -#ifdef ESLOPE if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked if (linedef->flags & ML_DONTPEGBOTTOM) rw_bottomtexturemid = frontsector->floorheight - viewz; else rw_bottomtexturemid = backsector->floorheight - viewz; - } else -#endif - if (linedef->flags & ML_DONTPEGBOTTOM) + } + else if (linedef->flags & ML_DONTPEGBOTTOM) { // bottom of texture at bottom // top of texture at top rw_bottomtexturemid = worldbottom; -#ifdef ESLOPE rw_bottomtextureslide = floorfrontslide; -#endif } else { // top of texture at top rw_bottomtexturemid = worldlow; -#ifdef ESLOPE rw_bottomtextureslide = floorbackslide; -#endif } } @@ -2337,12 +2105,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor_t *rover; ffloor_t *r2; fixed_t lowcut, highcut; -#ifdef ESLOPE fixed_t lowcutslope, highcutslope; // Used for height comparisons and etc across FOFs and slopes fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2; -#endif //markceiling = markfloor = true; maskedtexture = true; @@ -2352,10 +2118,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) lowcut = max(worldbottom, worldlow) + viewz; highcut = min(worldtop, worldhigh) + viewz; -#ifdef ESLOPE lowcutslope = max(worldbottomslope, worldlowslope) + viewz; highcutslope = min(worldtopslope, worldhighslope) + viewz; -#endif if (frontsector->ffloors && backsector->ffloors) { @@ -2364,22 +2128,17 @@ void R_StoreWallRange(INT32 start, INT32 stop) { if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS)) continue; - if (rover->flags & FF_INVERTSIDES) + if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES) continue; if (rover->norender == leveltime) continue; -#ifdef ESLOPE SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) continue; -#else - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) - continue; -#endif for (r2 = frontsector->ffloors; r2; r2 = r2->next) { @@ -2403,7 +2162,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; } -#ifdef ESLOPE SLOPEPARAMS(*r2->t_slope, high2, highslope2, *r2->topheight) SLOPEPARAMS(*r2->b_slope, low2, lowslope2, *r2->bottomheight) @@ -2411,12 +2169,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; if ((high1 > high2 || highslope1 > highslope2) || (low1 < low2 || lowslope1 < lowslope2)) continue; -#else - if (*r2->topheight < lowcut || *r2->bottomheight > highcut) - continue; - if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight) - continue; -#endif break; } @@ -2431,22 +2183,17 @@ void R_StoreWallRange(INT32 start, INT32 stop) { if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS)) continue; - if (!(rover->flags & FF_ALLSIDES)) + if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) continue; if (rover->norender == leveltime) continue; -#ifdef ESLOPE SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) continue; -#else - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) - continue; -#endif for (r2 = backsector->ffloors; r2; r2 = r2->next) { @@ -2470,7 +2217,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; } -#ifdef ESLOPE SLOPEPARAMS(*r2->t_slope, high2, highslope2, *r2->topheight) SLOPEPARAMS(*r2->b_slope, low2, lowslope2, *r2->bottomheight) #undef SLOPEPARAMS @@ -2478,12 +2224,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) continue; if ((high1 > high2 || highslope1 > highslope2) || (low1 < low2 || lowslope1 < lowslope2)) continue; -#else - if (*r2->topheight < lowcut || *r2->bottomheight > highcut) - continue; - if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight) - continue; -#endif break; } @@ -2498,22 +2238,19 @@ void R_StoreWallRange(INT32 start, INT32 stop) { for (rover = backsector->ffloors, i = 0; rover && i < MAXFFLOORS; rover = rover->next) { - if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || rover->flags & FF_INVERTSIDES) + if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS)) + continue; + if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES) continue; if (rover->norender == leveltime) continue; -#ifdef ESLOPE // Oy vey. - if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz - && (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz) - ||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz - && (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz)) + if ( ((P_GetFFloorTopZAt (rover, segleft .x, segleft .y)) <= worldbottom + viewz + && (P_GetFFloorTopZAt (rover, segright.x, segright.y)) <= worldbottomslope + viewz) + ||((P_GetFFloorBottomZAt(rover, segleft .x, segleft .y)) >= worldtop + viewz + && (P_GetFFloorBottomZAt(rover, segright.x, segright.y)) >= worldtopslope + viewz)) continue; -#else - if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight) - continue; -#endif ds_p->thicksides[i] = rover; i++; @@ -2523,29 +2260,24 @@ void R_StoreWallRange(INT32 start, INT32 stop) { for (rover = frontsector->ffloors, i = 0; rover && i < MAXFFLOORS; rover = rover->next) { - if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_ALLSIDES)) + if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS)) + continue; + if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) continue; if (rover->norender == leveltime) continue; -#ifdef ESLOPE // Oy vey. - if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz - && (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz) - ||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz - && (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz)) + if ( (P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= worldbottom + viewz + && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= worldbottomslope + viewz) + ||(P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) >= worldtop + viewz + && P_GetFFloorBottomZAt(rover, segright.x, segright.y) >= worldtopslope + viewz)) continue; - if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldlow+viewz - && (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldlowslope+viewz) - ||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldhigh+viewz - && (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldhighslope+viewz)) + if ( (P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= worldlow + viewz + && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= worldlowslope + viewz) + ||(P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) >= worldhigh + viewz + && P_GetFFloorBottomZAt(rover, segright.x, segright.y) >= worldhighslope + viewz)) continue; -#else - if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight) - continue; - if (*rover->topheight <= backsector->floorheight || *rover->bottomheight >= backsector->ceilingheight) - continue; -#endif ds_p->thicksides[i] = rover; i++; @@ -2565,40 +2297,45 @@ void R_StoreWallRange(INT32 start, INT32 stop) else ds_p->maskedtexturecol = ds_p->thicksidecol; -#ifdef ESLOPE maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0]) -#ifdef POLYOBJECTS - if (curline->polyseg) { // use REAL front and back floors please, so midtexture rendering isn't mucked up + if (curline->polyseg) + { // use REAL front and back floors please, so midtexture rendering isn't mucked up rw_midtextureslide = rw_midtexturebackslide = 0; if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; else rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz; - } else -#endif - // Set midtexture starting height - if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing - rw_midtextureslide = rw_midtexturebackslide = 0; - if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) - rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; - else - rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; + } + else + { + // Set midtexture starting height + if (linedef->flags & ML_EFFECT2) + { // Ignore slopes when texturing + rw_midtextureslide = rw_midtexturebackslide = 0; + if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; + else + rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; - } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { - rw_midtexturemid = worldbottom; - rw_midtextureslide = floorfrontslide; - rw_midtextureback = worldlow; - rw_midtexturebackslide = floorbackslide; - } else { - rw_midtexturemid = worldtop; - rw_midtextureslide = ceilingfrontslide; - rw_midtextureback = worldhigh; - rw_midtexturebackslide = ceilingbackslide; + } + else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + { + rw_midtexturemid = worldbottom; + rw_midtextureslide = floorfrontslide; + rw_midtextureback = worldlow; + rw_midtexturebackslide = floorbackslide; + } + else + { + rw_midtexturemid = worldtop; + rw_midtextureslide = ceilingfrontslide; + rw_midtextureback = worldhigh; + rw_midtexturebackslide = ceilingbackslide; + } } rw_midtexturemid += sidedef->rowoffset; rw_midtextureback += sidedef->rowoffset; -#endif maskedtexture = true; } @@ -2662,23 +2399,13 @@ void R_StoreWallRange(INT32 start, INT32 stop) // and doesn't need to be marked. if (frontsector->heightsec == -1) { - if (frontsector->floorpic != skyflatnum - && ( -#ifdef ESLOPE - frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) : -#endif - frontsector->floorheight) >= viewz) + if (frontsector->floorpic != skyflatnum && P_GetSectorFloorZAt(frontsector, viewx, viewy) >= viewz) { // above view plane markfloor = false; } - if (frontsector->ceilingpic != skyflatnum - && ( -#ifdef ESLOPE - frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) : -#endif - frontsector->ceilingheight) <= viewz) + if (frontsector->ceilingpic != skyflatnum && P_GetSectorCeilingZAt(frontsector, viewx, viewy) <= viewz) { // below view plane markceiling = false; @@ -2688,10 +2415,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) // calculate incremental stepping values for texture edges worldtop >>= 4; worldbottom >>= 4; -#ifdef ESLOPE worldtopslope >>= 4; worldbottomslope >>= 4; -#endif if (linedef->special == HORIZONSPECIAL) { // HORIZON LINES topstep = bottomstep = 0; @@ -2704,7 +2429,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) bottomstep = -FixedMul (rw_scalestep,worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); -#ifdef ESLOPE if (frontsector->c_slope) { fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); topstep = (topfracend-topfrac)/(range); @@ -2713,7 +2437,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); bottomstep = (bottomfracend-bottomfrac)/(range); } -#endif } dc_numlights = 0; @@ -2729,83 +2452,57 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (i = p = 0; i < dc_numlights; i++) { -#ifdef ESLOPE fixed_t leftheight, rightheight; -#endif light = &frontsector->lightlist[i]; rlight = &dc_lightlist[p]; -#ifdef ESLOPE - if (light->slope) { - leftheight = P_GetZAt(light->slope, segleft.x, segleft.y); - rightheight = P_GetZAt(light->slope, segright.x, segright.y); + leftheight = P_GetLightZAt(light, segleft.x, segleft.y); + rightheight = P_GetLightZAt(light, segright.x, segright.y); + if (light->slope) // Flag sector as having slopes frontsector->hasslope = true; - } else - leftheight = rightheight = light->height; leftheight -= viewz; rightheight -= viewz; leftheight >>= 4; rightheight >>= 4; -#endif if (i != 0) { -#ifdef ESLOPE if (leftheight < worldbottom && rightheight < worldbottomslope) continue; if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) continue; -#else - if (light->height < frontsector->floorheight) - continue; - - if (light->height > frontsector->ceilingheight && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) - continue; -#endif } -#ifdef ESLOPE rlight->height = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); rlight->heightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); rlight->heightstep = (rlight->heightstep-rlight->height)/(range); -#else - rlight->height = (centeryfrac>>4) - FixedMul((light->height - viewz) >> 4, rw_scale); - rlight->heightstep = -FixedMul (rw_scalestep, (light->height - viewz) >> 4); -#endif rlight->flags = light->flags; if (light->caster && light->caster->flags & FF_CUTSOLIDS) { -#ifdef ESLOPE - if (*light->caster->b_slope) { - leftheight = P_GetZAt(*light->caster->b_slope, segleft.x, segleft.y); - rightheight = P_GetZAt(*light->caster->b_slope, segright.x, segright.y); + leftheight = P_GetFFloorBottomZAt(light->caster, segleft.x, segleft.y); + rightheight = P_GetFFloorBottomZAt(light->caster, segright.x, segright.y); + if (*light->caster->b_slope) // Flag sector as having slopes frontsector->hasslope = true; - } else - leftheight = rightheight = *light->caster->bottomheight; - leftheight -= viewz; + leftheight -= viewz; rightheight -= viewz; - leftheight >>= 4; + leftheight >>= 4; rightheight >>= 4; rlight->botheight = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); rlight->botheightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range); -#else - rlight->botheight = (centeryfrac >> 4) - FixedMul((*light->caster->bottomheight - viewz) >> 4, rw_scale); - rlight->botheightstep = -FixedMul (rw_scalestep, (*light->caster->bottomheight - viewz) >> 4); -#endif } rlight->lightlevel = *light->lightlevel; @@ -2821,9 +2518,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (i = 0; i < numffloors; i++) { ffloor[i].f_pos >>= 4; -#ifdef ESLOPE ffloor[i].f_pos_slope >>= 4; -#endif if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too. { ffloor[i].f_step = 0; @@ -2832,13 +2527,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) } else { -#ifdef ESLOPE ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range); -#else - ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); - ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); -#endif } } } @@ -2847,42 +2537,34 @@ void R_StoreWallRange(INT32 start, INT32 stop) { worldhigh >>= 4; worldlow >>= 4; -#ifdef ESLOPE worldhighslope >>= 4; worldlowslope >>= 4; -#endif if (toptexture) { pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = -FixedMul (rw_scalestep,worldhigh); -#ifdef ESLOPE if (backsector->c_slope) { fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2); pixhighstep = (topfracend-pixhigh)/(range); } -#endif } if (bottomtexture) { pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); pixlowstep = -FixedMul (rw_scalestep,worldlow); -#ifdef ESLOPE if (backsector->f_slope) { fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2); pixlowstep = (bottomfracend-pixlow)/(range); } -#endif } { ffloor_t * rover; -#ifdef ESLOPE fixed_t roverleft, roverright; fixed_t planevistest; -#endif i = 0; if (backsector->ffloors) @@ -2894,19 +2576,18 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (rover->norender == leveltime) continue; -#ifdef ESLOPE // Let the renderer know this sector is sloped. if (*rover->b_slope || *rover->t_slope) backsector->hasslope = true; - roverleft = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz; - roverright = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz; - planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight); + roverleft = P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) - viewz; + roverright = P_GetFFloorBottomZAt(rover, segright.x, segright.y) - viewz; + planevistest = P_GetFFloorBottomZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) + ((viewz < planevistest && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) || + (viewz > planevistest && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { //ffloor[i].slope = *rover->b_slope; ffloor[i].b_pos = roverleft; @@ -2922,14 +2603,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (i >= MAXFFLOORS) break; - roverleft = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz; - roverright = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz; - planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight); + roverleft = P_GetFFloorTopZAt(rover, segleft .x, segleft .y) - viewz; + roverright = P_GetFFloorTopZAt(rover, segright.x, segright.y) - viewz; + planevistest = P_GetFFloorTopZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) + ((viewz > planevistest && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) || + (viewz < planevistest && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { //ffloor[i].slope = *rover->t_slope; ffloor[i].b_pos = roverleft; @@ -2941,34 +2622,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); i++; } -#else - if (*rover->bottomheight <= backsector->ceilingheight && - *rover->bottomheight >= backsector->floorheight && - ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) || - (viewz > *rover->bottomheight && (rover->flags & FF_BOTHPLANES)))) - { - ffloor[i].b_pos = *rover->bottomheight; - ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; - ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - i++; - } - - if (i >= MAXFFLOORS) - break; - - if (*rover->topheight >= backsector->floorheight && - *rover->topheight <= backsector->ceilingheight && - ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) || - (viewz < *rover->topheight && (rover->flags & FF_BOTHPLANES)))) - { - ffloor[i].b_pos = *rover->topheight; - ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; - ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - i++; - } -#endif } } else if (frontsector && frontsector->ffloors) @@ -2980,20 +2633,18 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (rover->norender == leveltime) continue; - -#ifdef ESLOPE // Let the renderer know this sector is sloped. if (*rover->b_slope || *rover->t_slope) frontsector->hasslope = true; - roverleft = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz; - roverright = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz; - planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight); + roverleft = P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) - viewz; + roverright = P_GetFFloorBottomZAt(rover, segright.x, segright.y) - viewz; + planevistest = P_GetFFloorBottomZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) + ((viewz < planevistest && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) || + (viewz > planevistest && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { //ffloor[i].slope = *rover->b_slope; ffloor[i].b_pos = roverleft; @@ -3009,14 +2660,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (i >= MAXFFLOORS) break; - roverleft = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz; - roverright = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz; - planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight); + roverleft = P_GetFFloorTopZAt(rover, segleft .x, segleft .y) - viewz; + roverright = P_GetFFloorTopZAt(rover, segright.x, segright.y) - viewz; + planevistest = P_GetFFloorTopZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) + ((viewz > planevistest && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) || + (viewz < planevistest && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES)))) { //ffloor[i].slope = *rover->t_slope; ffloor[i].b_pos = roverleft; @@ -3028,35 +2679,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); i++; } -#else - if (*rover->bottomheight <= frontsector->ceilingheight && - *rover->bottomheight >= frontsector->floorheight && - ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) || - (viewz > *rover->bottomheight && (rover->flags & FF_BOTHPLANES)))) - { - ffloor[i].b_pos = *rover->bottomheight; - ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; - ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - i++; - } - if (i >= MAXFFLOORS) - break; - if (*rover->topheight >= frontsector->floorheight && - *rover->topheight <= frontsector->ceilingheight && - ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) || - (viewz < *rover->topheight && (rover->flags & FF_BOTHPLANES)))) - { - ffloor[i].b_pos = *rover->topheight; - ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; - ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - i++; - } -#endif } } -#ifdef POLYOBJECTS_PLANES if (curline->polyseg && frontsector && (curline->polyseg->flags & POF_RENDERPLANES)) { while (i < numffloors && ffloor[i].polyobj != curline->polyseg) i++; @@ -3070,9 +2694,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ffloor[i].plane->maxx < ds_p->x2) ffloor[i].plane->maxx = ds_p->x2; -#ifdef ESLOPE ffloor[i].slope = NULL; -#endif ffloor[i].b_pos = backsector->floorheight; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); @@ -3089,9 +2711,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ffloor[i].plane->maxx < ds_p->x2) ffloor[i].plane->maxx = ds_p->x2; -#ifdef ESLOPE ffloor[i].slope = NULL; -#endif ffloor[i].b_pos = backsector->ceilingheight; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); @@ -3099,7 +2719,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) i++; } } -#endif numbackffloors = i; } @@ -3153,7 +2772,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (i = 0; i < numffloors; i++) R_ExpandPlane(ffloor[i].plane, rw_x, rw_stopx - 1); } -#ifdef POLYOBJECTS_PLANES // FIXME hack to fix planes disappearing when a seg goes behind the camera. This NEEDS to be changed to be done properly. -Red if (curline->polyseg) { @@ -3168,7 +2786,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].plane->maxx = rw_stopx - 1; } } -#endif } #ifdef WALLSPLATS diff --git a/src/r_segs.h b/src/r_segs.h index 1c852ddc7..a61f1f921 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_skins.c b/src/r_skins.c new file mode 100644 index 000000000..57ce382c4 --- /dev/null +++ b/src/r_skins.c @@ -0,0 +1,826 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_skins.c +/// \brief Loading skins + +#include "doomdef.h" +#include "console.h" +#include "g_game.h" +#include "r_local.h" +#include "st_stuff.h" +#include "w_wad.h" +#include "z_zone.h" +#include "m_misc.h" +#include "info.h" // spr2names +#include "i_video.h" // rendermode +#include "i_system.h" +#include "r_things.h" +#include "r_skins.h" +#include "p_local.h" +#include "dehacked.h" // get_number (for thok) +#include "m_cond.h" +#ifdef HWRENDER +#include "hardware/hw_md2.h" +#endif + +#ifdef PC_DOS +#include // for snprintf +int snprintf(char *str, size_t n, const char *fmt, ...); +//int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); +#endif + +INT32 numskins = 0; +skin_t skins[MAXSKINS]; + +// FIXTHIS: don't work because it must be inistilised before the config load +//#define SKINVALUES +#ifdef SKINVALUES +CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; +#endif + +// +// P_GetSkinSprite2 +// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing. +// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version. +// + +UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) +{ + UINT8 super = 0, i = 0; + + if (!skin) + return 0; + + if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2) + return 0; + + while (!skin->sprites[spr2].numframes + && spr2 != SPR2_STND + && ++i < 32) // recursion limiter + { + if (spr2 & FF_SPR2SUPER) + { + super = FF_SPR2SUPER; + spr2 &= ~FF_SPR2SUPER; + continue; + } + + switch(spr2) + { + // Normal special cases. + case SPR2_JUMP: + spr2 = ((player + ? player->charflags + : skin->flags) + & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; + break; + case SPR2_TIRE: + spr2 = ((player + ? player->charability + : skin->ability) + == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; + break; + // Use the handy list, that's what it's there for! + default: + spr2 = spr2defaults[spr2]; + break; + } + + spr2 |= super; + } + + if (i >= 32) // probably an infinite loop... + return 0; + + return spr2; +} + +static void Sk_SetDefaultValue(skin_t *skin) +{ + INT32 i; + // + // set default skin values + // + memset(skin, 0, sizeof (skin_t)); + snprintf(skin->name, + sizeof skin->name, "skin %u", (UINT32)(skin-skins)); + skin->name[sizeof skin->name - 1] = '\0'; + skin->wadnum = INT16_MAX; + + skin->flags = 0; + + strcpy(skin->realname, "Someone"); + strcpy(skin->hudname, "???"); + + skin->starttranscolor = 96; + skin->prefcolor = SKINCOLOR_GREEN; + skin->supercolor = SKINCOLOR_SUPERGOLD1; + skin->prefoppositecolor = 0; // use tables + + skin->normalspeed = 36<runspeed = 28<thrustfactor = 5; + skin->accelstart = 96; + skin->acceleration = 40; + + skin->ability = CA_NONE; + skin->ability2 = CA2_SPINDASH; + skin->jumpfactor = FRACUNIT; + skin->actionspd = 30<mindash = 15<maxdash = 70<radius = mobjinfo[MT_PLAYER].radius; + skin->height = mobjinfo[MT_PLAYER].height; + skin->spinheight = FixedMul(skin->height, 2*FRACUNIT/3); + + skin->shieldscale = FRACUNIT; + skin->camerascale = FRACUNIT; + + skin->thokitem = -1; + skin->spinitem = -1; + skin->revitem = -1; + skin->followitem = 0; + + skin->highresscale = FRACUNIT; + skin->contspeed = 17; + skin->contangle = 0; + + skin->availability = 0; + + for (i = 0; i < sfx_skinsoundslot0; i++) + if (S_sfx[i].skinsound != -1) + skin->soundsid[S_sfx[i].skinsound] = i; +} + +// +// Initialize the basic skins +// +void R_InitSkins(void) +{ +#ifdef SKINVALUES + INT32 i; + + for (i = 0; i <= MAXSKINS; i++) + { + skin_cons_t[i].value = 0; + skin_cons_t[i].strvalue = NULL; + } +#endif + + // no default skin! + numskins = 0; +} + +UINT32 R_GetSkinAvailabilities(void) +{ + INT32 s; + UINT32 response = 0; + + for (s = 0; s < MAXSKINS; s++) + { + if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked) + response |= (1 << s); + } + return response; +} + +// returns true if available in circumstances, otherwise nope +// warning don't use with an invalid skinnum other than -1 which always returns true +boolean R_SkinUsable(INT32 playernum, INT32 skinnum) +{ + return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0... + || (!skins[skinnum].availability) + || (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked)) + || (modeattacking) // If you have someone else's run you might as well take a look + || (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1. + || (netgame && (cv_forceskin.value == skinnum)) // Force 2. + || (metalrecording && skinnum == 5) // Force 3. + ); +} + +// returns true if the skin name is found (loaded from pwad) +// warning return -1 if not found +INT32 R_SkinAvailable(const char *name) +{ + INT32 i; + + for (i = 0; i < numskins; i++) + { + // search in the skin list + if (stricmp(skins[i].name,name)==0) + return i; + } + return -1; +} + +// network code calls this when a 'skin change' is received +void SetPlayerSkin(INT32 playernum, const char *skinname) +{ + INT32 i = R_SkinAvailable(skinname); + player_t *player = &players[playernum]; + + if ((i != -1) && R_SkinUsable(playernum, i)) + { + SetPlayerSkinByNum(playernum, i); + return; + } + + if (P_IsLocalPlayer(player)) + CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname); + else if(server || IsPlayerAdmin(consoleplayer)) + CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); + + SetPlayerSkinByNum(playernum, 0); +} + +// Same as SetPlayerSkin, but uses the skin #. +// network code calls this when a 'skin change' is received +void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) +{ + player_t *player = &players[playernum]; + skin_t *skin = &skins[skinnum]; + UINT16 newcolor = 0; + + if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists! + { + player->skin = skinnum; + + player->camerascale = skin->camerascale; + player->shieldscale = skin->shieldscale; + + player->charability = (UINT8)skin->ability; + player->charability2 = (UINT8)skin->ability2; + + player->charflags = (UINT32)skin->flags; + + player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; + player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; + player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; + player->followitem = skin->followitem; + + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff. + player->powers[pw_shield] &= SH_STACK; + + player->actionspd = skin->actionspd; + player->mindash = skin->mindash; + player->maxdash = skin->maxdash; + + player->normalspeed = skin->normalspeed; + player->runspeed = skin->runspeed; + player->thrustfactor = skin->thrustfactor; + player->accelstart = skin->accelstart; + player->acceleration = skin->acceleration; + + player->jumpfactor = skin->jumpfactor; + + player->height = skin->height; + player->spinheight = skin->spinheight; + + if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) + { + if (playernum == consoleplayer) + CV_StealthSetValue(&cv_playercolor, skin->prefcolor); + else if (playernum == secondarydisplayplayer) + CV_StealthSetValue(&cv_playercolor2, skin->prefcolor); + player->skincolor = newcolor = skin->prefcolor; + } + + if (player->followmobj) + { + P_RemoveMobj(player->followmobj); + P_SetTarget(&player->followmobj, NULL); + } + + if (player->mo) + { + fixed_t radius = FixedMul(skin->radius, player->mo->scale); + if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin. + { + skin = &skins[DEFAULTNIGHTSSKIN]; + player->followitem = skin->followitem; + if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) + newcolor = skin->prefcolor; // will be updated in thinker to flashing + } + player->mo->skin = skin; + if (newcolor) + player->mo->color = newcolor; + P_SetScale(player->mo, player->mo->scale); + player->mo->radius = radius; + + P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames + } + return; + } + + if (P_IsLocalPlayer(player)) + 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 %d not found\n", playernum, player_names[playernum], skinnum); + SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin +} + +// +// Add skins from a pwad, each skin preceded by 'S_SKIN' marker +// + +// Does the same is in w_wad, but check only for +// the first 6 characters (this is so we can have S_SKIN1, S_SKIN2.. +// for wad editors that don't like multiple resources of the same name) +// +static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) +{ + UINT16 i; + const char *S_SKIN = "S_SKIN"; + lumpinfo_t *lump_p; + + // scan forward, start at + if (startlump < wadfiles[wadid]->numlumps) + { + lump_p = wadfiles[wadid]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name,S_SKIN,6)==0) + return i; + } + return INT16_MAX; // not found +} + +#define HUDNAMEWRITE(value) STRBUFCPY(skin->hudname, value) + +// turn _ into spaces and . into katana dot +#define SYMBOLCONVERT(name) for (value = name; *value; value++)\ + {\ + if (*value == '_') *value = ' ';\ + else if (*value == '.') *value = '\x1E';\ + } + +// +// Patch skins from a pwad, each skin preceded by 'P_SKIN' marker +// + +// Does the same is in w_wad, but check only for +// the first 6 characters (this is so we can have P_SKIN1, P_SKIN2.. +// for wad editors that don't like multiple resources of the same name) +// +static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) +{ + UINT16 i; + const char *P_SKIN = "P_SKIN"; + lumpinfo_t *lump_p; + + // scan forward, start at + if (startlump < wadfiles[wadid]->numlumps) + { + lump_p = wadfiles[wadid]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name,P_SKIN,6)==0) + return i; + } + return INT16_MAX; // not found +} + +static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin) +{ + UINT16 newlastlump; + UINT8 sprite2; + + *lump += 1; // start after S_SKIN + *lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END + + // old wadding practices die hard -- stop at S_SKIN (or P_SKIN) or S_START if they come before S_END. + newlastlump = W_CheckForSkinMarkerInPwad(wadnum,*lump); + if (newlastlump < *lastlump) *lastlump = newlastlump; + newlastlump = W_CheckForPatchSkinMarkerInPwad(wadnum,*lump); + if (newlastlump < *lastlump) *lastlump = newlastlump; + newlastlump = W_CheckNumForNamePwad("S_START",wadnum,*lump); + if (newlastlump < *lastlump) *lastlump = newlastlump; + + // ...and let's handle super, too + newlastlump = W_CheckNumForNamePwad("S_SUPER",wadnum,*lump); + if (newlastlump < *lastlump) + { + newlastlump++; + // load all sprite sets we are aware of... for super! + for (sprite2 = 0; sprite2 < free_spr2; sprite2++) + R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump); + + newlastlump--; + *lastlump = newlastlump; // okay, make the normal sprite set loading end there + } + + // load all sprite sets we are aware of... for normal stuff. + for (sprite2 = 0; sprite2 < free_spr2; sprite2++) + R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump); + + if (skin->sprites[0].numframes == 0) + I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]); +} + +// returns whether found appropriate property +static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) +{ + // custom translation table + if (!stricmp(stoken, "startcolor")) + skin->starttranscolor = atoi(value); + +#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); + // character type identification + FULLPROCESS(flags) + FULLPROCESS(ability) + FULLPROCESS(ability2) + + FULLPROCESS(thokitem) + FULLPROCESS(spinitem) + FULLPROCESS(revitem) + FULLPROCESS(followitem) +#undef FULLPROCESS + +#define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<field = atoi(value); + GETINT(thrustfactor) + GETINT(accelstart) + GETINT(acceleration) + GETINT(contspeed) + GETINT(contangle) +#undef GETINT + +#define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value); + GETSKINCOLOR(prefcolor) + GETSKINCOLOR(prefoppositecolor) +#undef GETSKINCOLOR + else if (!stricmp(stoken, "supercolor")) + skin->supercolor = R_GetSuperColorByName(value); + +#define GETFLOAT(field) else if (!stricmp(stoken, #field)) skin->field = FLOAT_TO_FIXED(atof(value)); + GETFLOAT(jumpfactor) + GETFLOAT(highresscale) + GETFLOAT(shieldscale) + GETFLOAT(camerascale) +#undef GETFLOAT + +#define GETFLAG(field) else if (!stricmp(stoken, #field)) { \ + strupr(value); \ + if (atoi(value) || value[0] == 'T' || value[0] == 'Y') \ + skin->flags |= (SF_##field); \ + else \ + skin->flags &= ~(SF_##field); \ +} + // parameters for individual character flags + // these are uppercase so they can be concatenated with SF_ + // 1, true, yes are all valid values + GETFLAG(SUPER) + GETFLAG(NOSUPERSPIN) + GETFLAG(NOSPINDASHDUST) + GETFLAG(HIRES) + GETFLAG(NOSKID) + GETFLAG(NOSPEEDADJUST) + GETFLAG(RUNONWATER) + GETFLAG(NOJUMPSPIN) + GETFLAG(NOJUMPDAMAGE) + GETFLAG(STOMPDAMAGE) + GETFLAG(MARIODAMAGE) + GETFLAG(MACHINE) + GETFLAG(DASHMODE) + GETFLAG(FASTEDGE) + GETFLAG(MULTIABILITY) + GETFLAG(NONIGHTSROTATION) + GETFLAG(NONIGHTSSUPER) +#undef GETFLAG + + else // let's check if it's a sound, otherwise error out + { + boolean found = false; + sfxenum_t i; + size_t stokenadjust; + + // Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.) + if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS* + stokenadjust = 2; + else // sfx_* + stokenadjust = 4; + + // Remove the prefix. (We can affect this directly since we're not going to use it again.) + if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS* + value += 2; + else // sfx_* + value += 4; + + // copy name of sounds that are remapped + // for this skin + for (i = 0; i < sfx_skinsoundslot0; i++) + { + if (!S_sfx[i].name) + continue; + if (S_sfx[i].skinsound != -1 + && !stricmp(S_sfx[i].name, + stoken + stokenadjust)) + { + skin->soundsid[S_sfx[i].skinsound] = + S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true); + found = true; + } + } + return found; + } + return true; +} + +// +// Find skin sprites, sounds & optional status bar face, & add them +// +void R_AddSkins(UINT16 wadnum) +{ + UINT16 lump, lastlump = 0; + char *buf; + char *buf2; + char *stoken; + char *value; + size_t size; + skin_t *skin; + boolean hudname, realname; + + // + // search for all skin markers in pwad + // + + while ((lump = W_CheckForSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) + { + // advance by default + lastlump = lump + 1; + + if (numskins >= MAXSKINS) + { + CONS_Debug(DBG_RENDER, "ignored skin (%d skins maximum)\n", MAXSKINS); + continue; // so we know how many skins couldn't be added + } + buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + // for strtok + buf2 = malloc(size+1); + if (!buf2) + I_Error("R_AddSkins: No more free memory\n"); + M_Memcpy(buf2,buf,size); + buf2[size] = '\0'; + + // set defaults + skin = &skins[numskins]; + Sk_SetDefaultValue(skin); + skin->wadnum = wadnum; + hudname = realname = false; + // parse + stoken = strtok (buf2, "\r\n= "); + while (stoken) + { + if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#'))// skip comments + { + stoken = strtok(NULL, "\r\n"); // skip end of line + goto next_token; // find the real next token + } + + value = strtok(NULL, "\r\n= "); + + if (!value) + I_Error("R_AddSkins: syntax error in S_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); + + // Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines. + // Others can't go in there because we don't want them to be patchable. + if (!stricmp(stoken, "name")) + { + INT32 skinnum = R_SkinAvailable(value); + strlwr(value); + if (skinnum == -1) + STRBUFCPY(skin->name, value); + // the skin name must uniquely identify a single skin + // if the name is already used I make the name 'namex' + // using the default skin name's number set above + else + { + const size_t stringspace = + strlen(value) + sizeof (numskins) + 1; + char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL); + snprintf(value2, stringspace, + "%s%d", value, numskins); + value2[stringspace - 1] = '\0'; + if (R_SkinAvailable(value2) == -1) + // I'm lazy so if NEW name is already used I leave the 'skin x' + // default skin name set in Sk_SetDefaultValue + STRBUFCPY(skin->name, value2); + Z_Free(value2); + } + + // copy to hudname and fullname as a default. + if (!realname) + { + STRBUFCPY(skin->realname, skin->name); + for (value = skin->realname; *value; value++) + { + if (*value == '_') *value = ' '; // turn _ into spaces. + else if (*value == '.') *value = '\x1E'; // turn . into katana dot. + } + } + if (!hudname) + { + HUDNAMEWRITE(skin->name); + strupr(skin->hudname); + SYMBOLCONVERT(skin->hudname) + } + } + else if (!stricmp(stoken, "realname")) + { // Display name (eg. "Knuckles") + realname = true; + STRBUFCPY(skin->realname, value); + SYMBOLCONVERT(skin->realname) + if (!hudname) + HUDNAMEWRITE(skin->realname); + } + else if (!stricmp(stoken, "hudname")) + { // Life icon name (eg. "K.T.E") + hudname = true; + HUDNAMEWRITE(value); + SYMBOLCONVERT(skin->hudname) + if (!realname) + STRBUFCPY(skin->realname, skin->hudname); + } + else if (!stricmp(stoken, "availability")) + { + skin->availability = atoi(value); + if (skin->availability >= MAXUNLOCKABLES) + skin->availability = 0; + } + else if (!R_ProcessPatchableFields(skin, stoken, value)) + CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); + +next_token: + stoken = strtok(NULL, "\r\n= "); + } + free(buf2); + + // Add sprites + R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); + //ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere + + R_FlushTranslationColormapCache(); + + if (!skin->availability) // Safe to print... + CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); +#ifdef SKINVALUES + skin_cons_t[numskins].value = numskins; + skin_cons_t[numskins].strvalue = skin->name; +#endif + +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_AddPlayerModel(numskins); +#endif + + numskins++; + } + return; +} + +// +// Patch skin sprites +// +void R_PatchSkins(UINT16 wadnum) +{ + UINT16 lump, lastlump = 0; + char *buf; + char *buf2; + char *stoken; + char *value; + size_t size; + skin_t *skin; + boolean noskincomplain, realname, hudname; + + // + // search for all skin patch markers in pwad + // + + while ((lump = W_CheckForPatchSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) + { + INT32 skinnum = 0; + + // advance by default + lastlump = lump + 1; + + buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + // for strtok + buf2 = malloc(size+1); + if (!buf2) + I_Error("R_PatchSkins: No more free memory\n"); + M_Memcpy(buf2,buf,size); + buf2[size] = '\0'; + + skin = NULL; + noskincomplain = realname = hudname = false; + + /* + Parse. Has more phases than the parser in R_AddSkins because it needs to have the patching name first (no default skin name is acceptible for patching, unlike skin creation) + */ + + stoken = strtok(buf2, "\r\n= "); + while (stoken) + { + if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#'))// skip comments + { + stoken = strtok(NULL, "\r\n"); // skip end of line + goto next_token; // find the real next token + } + + value = strtok(NULL, "\r\n= "); + + if (!value) + I_Error("R_PatchSkins: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); + + if (!skin) // Get the name! + { + if (!stricmp(stoken, "name")) + { + strlwr(value); + skinnum = R_SkinAvailable(value); + if (skinnum != -1) + skin = &skins[skinnum]; + else + { + CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); + noskincomplain = true; + } + } + } + else // Get the properties! + { + // Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines. + if (!stricmp(stoken, "realname")) + { // Display name (eg. "Knuckles") + realname = true; + STRBUFCPY(skin->realname, value); + SYMBOLCONVERT(skin->realname) + if (!hudname) + HUDNAMEWRITE(skin->realname); + } + else if (!stricmp(stoken, "hudname")) + { // Life icon name (eg. "K.T.E") + hudname = true; + HUDNAMEWRITE(value); + SYMBOLCONVERT(skin->hudname) + if (!realname) + STRBUFCPY(skin->realname, skin->hudname); + } + else if (!R_ProcessPatchableFields(skin, stoken, value)) + CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); + } + + if (!skin) + break; + +next_token: + stoken = strtok(NULL, "\r\n= "); + } + free(buf2); + + if (!skin) // Didn't include a name parameter? What a waste. + { + if (!noskincomplain) + CONS_Debug(DBG_SETUP, "R_PatchSkins: no skin name given in P_SKIN lump #%d (WAD %s)\n", lump, wadfiles[wadnum]->filename); + continue; + } + + // Patch sprites + R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); + //ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere + + R_FlushTranslationColormapCache(); + + if (!skin->availability) // Safe to print... + CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name); + } + return; +} + +#undef HUDNAMEWRITE +#undef SYMBOLCONVERT diff --git a/src/r_skins.h b/src/r_skins.h new file mode 100644 index 000000000..45c90bdb4 --- /dev/null +++ b/src/r_skins.h @@ -0,0 +1,103 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_skins.h +/// \brief Skins stuff + +#ifndef __R_SKINS__ +#define __R_SKINS__ + +#include "info.h" +#include "sounds.h" +#include "d_player.h" // skinflags +#include "r_patch.h" // spriteinfo_t +#include "r_defs.h" // spritedef_t + +/// Defaults +#define SKINNAMESIZE 16 +// should be all lowercase!! S_SKIN processing does a strlwr +#define DEFAULTSKIN "sonic" +#define DEFAULTSKIN2 "tails" // secondary player +#define DEFAULTNIGHTSSKIN 0 + +/// The skin_t struct +typedef struct +{ + char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin + UINT16 wadnum; + skinflags_t flags; + + char realname[SKINNAMESIZE+1]; // Display name for level completion. + char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) + + UINT8 ability; // ability definition + UINT8 ability2; // secondary ability definition + INT32 thokitem; + INT32 spinitem; + INT32 revitem; + INT32 followitem; + fixed_t actionspd; + fixed_t mindash; + fixed_t maxdash; + + fixed_t normalspeed; // Normal ground + fixed_t runspeed; // Speed that you break into your run animation + + UINT8 thrustfactor; // Thrust = thrustfactor * acceleration + UINT8 accelstart; // Acceleration if speed = 0 + UINT8 acceleration; // Acceleration + + fixed_t jumpfactor; // multiple of standard jump height + + fixed_t radius; // Bounding box changes. + fixed_t height; + fixed_t spinheight; + + fixed_t shieldscale; // no change to bounding box, but helps set the shield's sprite size + fixed_t camerascale; + + // Definable color translation table + UINT8 starttranscolor; + UINT16 prefcolor; + UINT16 supercolor; + UINT16 prefoppositecolor; // if 0 use tables instead + + fixed_t highresscale; // scale of highres, default is 0.5 + UINT8 contspeed; // continue screen animation speed + UINT8 contangle; // initial angle on continue screen + + // specific sounds per skin + sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table + + // contains super versions too + spritedef_t sprites[NUMPLAYERSPRITES*2]; + spriteinfo_t sprinfo[NUMPLAYERSPRITES*2]; + + UINT8 availability; // lock? +} skin_t; + +/// Externs +extern INT32 numskins; +extern skin_t skins[MAXSKINS]; + +/// Function prototypes +void R_InitSkins(void); + +void SetPlayerSkin(INT32 playernum,const char *skinname); +void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 +boolean R_SkinUsable(INT32 playernum, INT32 skinnum); +UINT32 R_GetSkinAvailabilities(void); +INT32 R_SkinAvailable(const char *name); +void R_PatchSkins(UINT16 wadnum); +void R_AddSkins(UINT16 wadnum); + +UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player); + +#endif //__R_SKINS__ diff --git a/src/r_sky.c b/src/r_sky.c index da36eb937..7cdcfa44d 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_sky.h b/src/r_sky.h index 8eca2077a..55d866b86 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_splats.c b/src/r_splats.c index f690dfa94..dfec185a1 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_splats.h b/src/r_splats.h index 7565b4bcc..4ad893abb 100644 --- a/src/r_splats.h +++ b/src/r_splats.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_state.h b/src/r_state.h index 1451fca7a..7c860a6f2 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_things.c b/src/r_things.c index 94408f02c..de5eb208f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -30,11 +30,8 @@ #include "p_tick.h" #include "p_local.h" #include "p_slopes.h" -#include "dehacked.h" // get_number (for thok) #include "d_netfil.h" // blargh. for nameonly(). #include "m_cheat.h" // objectplace -#include "m_cond.h" -#include "fastcmp.h" #ifdef HWRENDER #include "hardware/hw_md2.h" #include "hardware/hw_glob.h" @@ -42,14 +39,6 @@ #include "hardware/hw_drv.h" #endif -#ifdef PC_DOS -#include // for snprintf -int snprintf(char *str, size_t n, const char *fmt, ...); -//int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); -#endif - -static void R_InitSkins(void); - #define MINZ (FRACUNIT*4) #define BASEYCENTER (BASEVIDHEIGHT/2) @@ -233,7 +222,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch // // Returns true if the sprite was succesfully added // -static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump) +boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump) { UINT16 l; UINT8 frame; @@ -245,6 +234,8 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, memset(sprtemp,0xFF, sizeof (sprtemp)); maxframe = (size_t)-1; + spritename = sprname; + // are we 'patching' a sprite already loaded ? // if so, it might patch only certain frames, not all if (spritedef->numframes) // (then spriteframes is not null) @@ -437,9 +428,9 @@ void R_AddSpriteDefs(UINT16 wadnum) switch (wadfiles[wadnum]->type) { case RET_WAD: - start = W_CheckNumForNamePwad("S_START", wadnum, 0); + start = W_CheckNumForMarkerStartPwad("S_START", wadnum, 0); if (start == INT16_MAX) - start = W_CheckNumForNamePwad("SS_START", wadnum, 0); //deutex compatib. + start = W_CheckNumForMarkerStartPwad("SS_START", wadnum, 0); //deutex compatib. end = W_CheckNumForNamePwad("S_END",wadnum,start); if (end == INT16_MAX) @@ -461,8 +452,6 @@ void R_AddSpriteDefs(UINT16 wadnum) start = 0; //let say S_START is lump 0 } - else - start++; // just after S_START if (end == INT16_MAX || start >= end) { @@ -476,11 +465,10 @@ void R_AddSpriteDefs(UINT16 wadnum) // for (i = 0; i < numsprites; i++) { - spritename = sprnames[i]; - if (spritename[4] && wadnum >= (UINT16)spritename[4]) + if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4]) continue; - if (R_AddSingleSpriteDef(spritename, &sprites[i], wadnum, start, end)) + if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end)) { #ifdef HWRENDER if (rendermode == render_opengl) @@ -489,7 +477,7 @@ void R_AddSpriteDefs(UINT16 wadnum) // if a new sprite was added (not just replaced) addsprites++; #ifndef ZDEBUG - CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", spritename, wadnum); + CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum); #endif } } @@ -651,10 +639,10 @@ void R_DrawMaskedColumn(column_t *column) dc_yl = mceilingclip[dc_x]+1; if (dc_yl < 0) dc_yl = 0; - if (dc_yh >= vid.height) + if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop dc_yh = vid.height - 1; - if (dc_yl <= dc_yh && dc_yl < vid.height && dc_yh > 0) + if (dc_yl <= dc_yh && dc_yh > 0) { dc_source = (UINT8 *)column + 3; dc_texturemid = basetexturemid - (topdelta<length + 4); } @@ -681,7 +664,9 @@ void R_DrawMaskedColumn(column_t *column) dc_texturemid = basetexturemid; } -void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) +INT32 lengthcol; // column->length : for flipped column function pointers and multi-patch on 2sided wall = texture->height + +void R_DrawFlippedMaskedColumn(column_t *column) { INT32 topscreen; INT32 bottomscreen; @@ -697,7 +682,7 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) if (topdelta <= prevdelta) topdelta += prevdelta; prevdelta = topdelta; - topdelta = texheight-column->length-topdelta; + topdelta = lengthcol-column->length-topdelta; topscreen = sprtopscreen + spryscale*topdelta; bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*column->length : sprbotscreen + spryscale*column->length; @@ -719,10 +704,10 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) dc_yl = mceilingclip[dc_x]+1; if (dc_yl < 0) dc_yl = 0; - if (dc_yh >= vid.height) + if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop dc_yh = vid.height - 1; - if (dc_yl <= dc_yh && dc_yl < vid.height && dc_yh > 0) + if (dc_yl <= dc_yh && dc_yh > 0) { dc_source = ZZ_Alloc(column->length); for (s = (UINT8 *)column+2+column->length, d = dc_source; d < dc_source+column->length; --s) @@ -732,15 +717,10 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) // Still drawn by R_DrawColumn. if (ylookup[dc_yl]) colfunc(); - else if (colfunc == colfuncs[COLDRAWFUNC_BASE]) - { - static INT32 first = 1; - if (first) - { - CONS_Debug(DBG_RENDER, "WARNING: avoiding a crash in %s %d\n", __FILE__, __LINE__); - first = 0; - } - } +#ifdef PARANOIA + else + I_Error("R_DrawMaskedColumn: Invalid ylookup for dc_yl %d", dc_yl); +#endif Z_Free(dc_source); } column = (column_t *)((UINT8 *)column + column->length + 4); @@ -756,7 +736,9 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) static void R_DrawVisSprite(vissprite_t *vis) { column_t *column; + void (*localcolfunc)(column_t *); INT32 texturecolumn; + INT32 pwidth; fixed_t frac; patch_t *patch = vis->patch; fixed_t this_scale = vis->mobj->scale; @@ -905,50 +887,52 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->x2 >= vid.width) vis->x2 = vid.width-1; + localcolfunc = (vis->cut & SC_VFLIP) ? R_DrawFlippedMaskedColumn : R_DrawMaskedColumn; + lengthcol = SHORT(patch->height); + // Split drawing loops for paper and non-paper to reduce conditional checks per sprite if (vis->scalestep) { - // Papersprite drawing loop + pwidth = SHORT(patch->width); + // Papersprite drawing loop for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += vis->scalestep) { angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF; texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / this_scale; - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) + if (texturecolumn < 0 || texturecolumn >= pwidth) continue; if (vis->xiscale < 0) // Flipped sprite - texturecolumn = SHORT(patch->width) - 1 - texturecolumn; + texturecolumn = pwidth - 1 - texturecolumn; sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); dc_iscale = (0xffffffffu / (unsigned)spryscale); column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); - if (vis->cut & SC_VFLIP) - R_DrawFlippedMaskedColumn(column, patch->height); - else - R_DrawMaskedColumn(column); + localcolfunc (column); } } else { +#ifdef RANGECHECK + pwidth = SHORT(patch->width); +#endif + // Non-paper drawing loop for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, sprtopscreen += vis->shear.tan) { #ifdef RANGECHECK texturecolumn = frac>>FRACBITS; - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) + if (texturecolumn < 0 || texturecolumn >= pwidth) I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x); column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); #else column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); #endif - if (vis->cut & SC_VFLIP) - R_DrawFlippedMaskedColumn(column, patch->height); - else - R_DrawMaskedColumn(column); + localcolfunc (column); } } @@ -1035,15 +1019,12 @@ static void R_SplitSprite(vissprite_t *sprite) for (i = 1; i < sector->numlights; i++) { - fixed_t testheight = sector->lightlist[i].height; + fixed_t testheight; if (!(sector->lightlist[i].caster->flags & FF_CUTSPRITES)) continue; -#ifdef ESLOPE - if (sector->lightlist[i].slope) - testheight = P_GetZAt(sector->lightlist[i].slope, sprite->gx, sprite->gy); -#endif + testheight = P_GetLightZAt(§or->lightlist[i], sprite->gx, sprite->gy); if (testheight >= sprite->gzt) continue; @@ -1115,25 +1096,29 @@ static void R_SplitSprite(vissprite_t *sprite) // fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) { - fixed_t z, floorz = INT32_MIN; - pslope_t *slope, *floorslope = NULL; + boolean isflipped = thing->eflags & MFE_VERTICALFLIP; + fixed_t z, groundz = isflipped ? INT32_MAX : INT32_MIN; + pslope_t *slope, *groundslope = NULL; msecnode_t *node; sector_t *sector; ffloor_t *rover; +#define CHECKZ (isflipped ? z > thing->z+thing->height/2 && z < groundz : z < thing->z+thing->height/2 && z > groundz) for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next) { sector = node->m_sector; - slope = (sector->heightsec != -1) ? NULL : sector->f_slope; - z = slope ? P_GetZAt(slope, thing->x, thing->y) : ( - (sector->heightsec != -1) ? sectors[sector->heightsec].floorheight : sector->floorheight - ); + slope = sector->heightsec != -1 ? NULL : (isflipped ? sector->c_slope : sector->f_slope); - if (z < thing->z+thing->height/2 && z > floorz) + if (sector->heightsec != -1) + z = isflipped ? sectors[sector->heightsec].ceilingheight : sectors[sector->heightsec].floorheight; + else + z = isflipped ? P_GetSectorCeilingZAt(sector, thing->x, thing->y) : P_GetSectorFloorZAt(sector, thing->x, thing->y); + + if CHECKZ { - floorz = z; - floorslope = slope; + groundz = z; + groundslope = slope; } if (sector->ffloors) @@ -1142,24 +1127,25 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE))) continue; - z = *rover->t_slope ? P_GetZAt(*rover->t_slope, thing->x, thing->y) : *rover->topheight; - if (z < thing->z+thing->height/2 && z > floorz) + z = isflipped ? P_GetFFloorBottomZAt(rover, thing->x, thing->y) : P_GetFFloorTopZAt(rover, thing->x, thing->y); + if CHECKZ { - floorz = z; - floorslope = *rover->t_slope; + groundz = z; + groundslope = isflipped ? *rover->b_slope : *rover->t_slope; } } } - if (thing->floorz > floorz + (!floorslope ? 0 : FixedMul(abs(floorslope->zdelta), thing->radius*3/2))) + if (isflipped ? (thing->ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))) + : (thing->floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))) { - floorz = thing->floorz; - floorslope = NULL; + groundz = isflipped ? thing->ceilingz : thing->floorz; + groundslope = NULL; } #if 0 // Unfortunately, this drops CEZ2 down to sub-17 FPS on my i7. -//#ifdef POLYOBJECTS - // Check polyobjects and see if floorz needs to be altered, for rings only because they don't update floorz + // NOTE: this section was not updated to reflect reverse gravity support + // Check polyobjects and see if groundz needs to be altered, for rings only because they don't update floorz if (thing->type == MT_RING) { INT32 xl, xh, yl, yh, bx, by; @@ -1204,10 +1190,10 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) // We're inside it! Yess... z = po->lines[0]->backsector->ceilingheight; - if (z < thing->z+thing->height/2 && z > floorz) + if (z < thing->z+thing->height/2 && z > groundz) { - floorz = z; - floorslope = NULL; + groundz = z; + groundslope = NULL; } } plink = (polymaplink_t *)(plink->link.next); @@ -1217,9 +1203,10 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) #endif if (shadowslope != NULL) - *shadowslope = floorslope; + *shadowslope = groundslope; - return floorz; + return groundz; +#undef CHECKZ } static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz) @@ -1230,14 +1217,15 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, INT32 light = 0; fixed_t scalemul; UINT8 trans; fixed_t floordiff; - fixed_t floorz; - pslope_t *floorslope; + fixed_t groundz; + pslope_t *groundslope; + boolean isflipped = thing->eflags & MFE_VERTICALFLIP; - floorz = R_GetShadowZ(thing, &floorslope); + groundz = R_GetShadowZ(thing, &groundslope); - if (abs(floorz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes + if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes - floordiff = abs(thing->z - floorz); + floordiff = abs((isflipped ? thing->height : 0) + thing->z - groundz); trans = floordiff / (100*FRACUNIT) + 3; if (trans >= 9) return; @@ -1248,48 +1236,48 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, xscale = FixedDiv(projection, tz); yscale = FixedDiv(projectiony, tz); shadowxscale = FixedMul(thing->radius*2, scalemul); - shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(floorz - viewz), tz)); - shadowyscale = min(shadowyscale, shadowxscale) / patch->height; - shadowxscale /= patch->width; + shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz)); + shadowyscale = min(shadowyscale, shadowxscale) / SHORT(patch->height); + shadowxscale /= SHORT(patch->width); shadowskew = 0; - if (floorslope) + if (groundslope) { // haha let's try some dumb stuff fixed_t xslope, zslope; - angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - floorslope->xydirection) >> ANGLETOFINESHIFT; + angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT; - xslope = FixedMul(FINESINE(sloperelang), floorslope->zdelta); - zslope = FixedMul(FINECOSINE(sloperelang), floorslope->zdelta); + xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); + zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope); - if (viewz < floorz) - shadowyscale += FixedMul(FixedMul(thing->radius*2 / patch->height, scalemul), zslope); + if (viewz < groundz) + shadowyscale += FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope); else - shadowyscale -= FixedMul(FixedMul(thing->radius*2 / patch->height, scalemul), zslope); + shadowyscale -= FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope); shadowyscale = abs(shadowyscale); shadowskew = xslope; } - tx -= patch->width * shadowxscale/2; + tx -= SHORT(patch->width) * shadowxscale/2; x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; if (x1 >= viewwidth) return; - tx += patch->width * shadowxscale; + tx += SHORT(patch->width) * shadowxscale; x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--; if (x2 < 0 || x2 <= x1) return; - if (shadowyscale < FRACUNIT/patch->height) return; // fix some crashes? + if (shadowyscale < FRACUNIT/SHORT(patch->height)) return; // fix some crashes? shadow = R_NewVisSprite(); shadow->patch = patch; shadow->heightsec = vis->heightsec; shadow->thingheight = FRACUNIT; - shadow->pz = floorz; + shadow->pz = groundz + (isflipped ? -shadow->thingheight : 0); shadow->pzt = shadow->pz + shadow->thingheight; shadow->mobjflags = 0; @@ -1297,8 +1285,8 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->dispoffset = vis->dispoffset - 5; shadow->gx = thing->x; shadow->gy = thing->y; - shadow->gzt = shadow->pz + shadow->patch->height * shadowyscale / 2; - shadow->gz = shadow->gzt - shadow->patch->height * shadowyscale; + shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + SHORT(patch->height) * shadowyscale / 2; + shadow->gz = shadow->gzt - SHORT(patch->height) * shadowyscale; shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale); @@ -1319,7 +1307,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->startfrac = 0; //shadow->xiscale = 0x7ffffff0 / (shadow->xscale/2); - shadow->xiscale = (patch->width<xiscale = (SHORT(patch->width)<x1 > x1) shadow->startfrac += shadow->xiscale*(shadow->x1-x1); @@ -1331,20 +1319,17 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, if (thing->subsector->sector->numlights) { INT32 lightnum; -#ifdef ESLOPE // R_GetPlaneLight won't work on sloped lights! light = thing->subsector->sector->numlights - 1; + // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thing->x, thing->y) - : thing->subsector->sector->lightlist[lightnum].height; + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); if (h <= shadow->gzt) { light = lightnum - 1; break; } } -#else - light = R_GetPlaneLight(thing->subsector->sector, shadow->gzt, false); -#endif + //light = R_GetPlaneLight(thing->subsector->sector, shadow->gzt, false); } if (thing->subsector->sector->numlights) @@ -1367,7 +1352,6 @@ static void R_ProjectSprite(mobj_t *thing) { mobj_t *oldthing = thing; fixed_t tr_x, tr_y; - fixed_t gxt, gyt; fixed_t tx, tz; fixed_t xscale, yscale, sortscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! @@ -1380,7 +1364,7 @@ static void R_ProjectSprite(mobj_t *thing) #endif size_t lump; - size_t rot; + size_t frame, rot; UINT16 flip; boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); @@ -1420,21 +1404,16 @@ static void R_ProjectSprite(mobj_t *thing) tr_x = thing->x - viewx; tr_y = thing->y - viewy; - gxt = FixedMul(tr_x, viewcos); - gyt = -FixedMul(tr_y, viewsin); - - tz = gxt-gyt; + tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance // thing is behind view plane? if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later return; - gxt = -FixedMul(tr_x, viewsin); - gyt = FixedMul(tr_y, viewcos); - basetx = tx = -(gyt + gxt); + basetx = tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // sideways distance // too far off the side? - if (!papersprite && abs(tx) > tz<<2) // papersprite clipping is handled later + if (!papersprite && abs(tx) > FixedMul(tz, fovtan)<<2) // papersprite clipping is handled later return; // aspect ratio stuff @@ -1447,7 +1426,7 @@ static void R_ProjectSprite(mobj_t *thing) I_Error("R_ProjectSprite: invalid sprite number %d ", thing->sprite); #endif - rot = thing->frame&FF_FRAMEMASK; + frame = thing->frame&FF_FRAMEMASK; //Fab : 02-08-98: 'skin' override spritedef currently used for skin if (thing->skin && thing->sprite == SPR_PLAY) @@ -1456,15 +1435,15 @@ static void R_ProjectSprite(mobj_t *thing) #ifdef ROTSPRITE sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2]; #endif - if (rot >= sprdef->numframes) { - CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(rot)); + if (frame >= sprdef->numframes) { + CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(frame)); thing->sprite = states[S_UNKNOWN].sprite; thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; #ifdef ROTSPRITE sprinfo = NULL; #endif - rot = thing->frame&FF_FRAMEMASK; + frame = thing->frame&FF_FRAMEMASK; } } else @@ -1474,10 +1453,10 @@ static void R_ProjectSprite(mobj_t *thing) sprinfo = NULL; #endif - if (rot >= sprdef->numframes) + if (frame >= sprdef->numframes) { CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"), - sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]); + sizeu1(frame), sizeu2(sprdef->numframes), sprnames[thing->sprite]); if (thing->sprite == thing->state->sprite && thing->frame == thing->state->frame) { thing->state->sprite = states[S_UNKNOWN].sprite; @@ -1486,11 +1465,11 @@ static void R_ProjectSprite(mobj_t *thing) thing->sprite = states[S_UNKNOWN].sprite; thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; - rot = thing->frame&FF_FRAMEMASK; + frame = thing->frame&FF_FRAMEMASK; } } - sprframe = &sprdef->spriteframes[rot]; + sprframe = &sprdef->spriteframes[frame]; #ifdef PARANOIA if (!sprframe) @@ -1544,14 +1523,14 @@ static void R_ProjectSprite(mobj_t *thing) { rollangle = R_GetRollAngle(thing->rollangle); if (!(sprframe->rotsprite.cached & (1<sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip); + R_CacheRotSprite(thing->sprite, frame, sprinfo, sprframe, rot, flip); rotsprite = sprframe->rotsprite.patch[rot][rollangle]; if (rotsprite != NULL) { - spr_width = rotsprite->width << FRACBITS; - spr_height = rotsprite->height << FRACBITS; - spr_offset = rotsprite->leftoffset << FRACBITS; - spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_width = SHORT(rotsprite->width) << FRACBITS; + spr_height = SHORT(rotsprite->height) << FRACBITS; + spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS; + spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS; // flip -> rotate, not rotate -> flip flip = 0; } @@ -1582,17 +1561,9 @@ static void R_ProjectSprite(mobj_t *thing) tr_x += FixedMul(offset, cosmul); tr_y += FixedMul(offset, sinmul); - gxt = FixedMul(tr_x, viewcos); - gyt = -FixedMul(tr_y, viewsin); - tz = gxt-gyt; - yscale = FixedDiv(projectiony, tz); - //if (yscale < 64) return; // Fix some funky visuals + tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); - gxt = -FixedMul(tr_x, viewsin); - gyt = FixedMul(tr_y, viewcos); - tx = -(gyt + gxt); - xscale = FixedDiv(projection, tz); - x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; + tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // Get paperoffset (offset) and paperoffset (distance) paperoffset = -FixedMul(tr_x, cosmul) - FixedMul(tr_y, sinmul); @@ -1606,17 +1577,9 @@ static void R_ProjectSprite(mobj_t *thing) tr_x += FixedMul(offset2, cosmul); tr_y += FixedMul(offset2, sinmul); - gxt = FixedMul(tr_x, viewcos); - gyt = -FixedMul(tr_y, viewsin); - tz2 = gxt-gyt; - yscale2 = FixedDiv(projectiony, tz2); - //if (yscale2 < 64) return; // ditto + tz2 = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); - gxt = -FixedMul(tr_x, viewsin); - gyt = FixedMul(tr_y, viewcos); - tx2 = -(gyt + gxt); - xscale2 = FixedDiv(projection, tz2); - x2 = ((centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS); + tx2 = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; @@ -1627,24 +1590,31 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t div = FixedDiv(tz2-tz, FixedMul(MINZ, this_scale)-tz); tx += FixedDiv(tx2-tx, div); tz = FixedMul(MINZ, this_scale); - yscale = FixedDiv(projectiony, tz); - xscale = FixedDiv(projection, tz); - x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; } else if (tz2 < FixedMul(MINZ, this_scale)) { fixed_t div = FixedDiv(tz-tz2, FixedMul(MINZ, this_scale)-tz2); tx2 += FixedDiv(tx-tx2, div); tz2 = FixedMul(MINZ, this_scale); - yscale2 = FixedDiv(projectiony, tz2); - xscale2 = FixedDiv(projection, tz2); - x2 = (centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS; } + if (tx2 < -(FixedMul(tz2, fovtan)<<2) || tx > FixedMul(tz, fovtan)<<2) // too far off the side? + return; + + yscale = FixedDiv(projectiony, tz); + xscale = FixedDiv(projection, tz); + + x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; + // off the right side? if (x1 > viewwidth) return; + yscale2 = FixedDiv(projectiony, tz2); + xscale2 = FixedDiv(projection, tz2); + + x2 = (centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS; + // off the left side if (x2 < 0) return; @@ -1691,9 +1661,7 @@ static void R_ProjectSprite(mobj_t *thing) tr_x = thing->x - viewx; tr_y = thing->y - viewy; - gxt = FixedMul(tr_x, viewcos); - gyt = -FixedMul(tr_y, viewsin); - tz = gxt-gyt; + tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); linkscale = FixedDiv(projectiony, tz); if (tz < FixedMul(MINZ, this_scale)) @@ -1709,7 +1677,7 @@ static void R_ProjectSprite(mobj_t *thing) // PORTAL SPRITE CLIPPING if (portalrender && portalclipline) { - if (x2 < portalclipstart || x1 > portalclipend) + if (x2 < portalclipstart || x1 >= portalclipend) return; if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) @@ -1740,20 +1708,17 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->numlights) { INT32 lightnum; -#ifdef ESLOPE // R_GetPlaneLight won't work on sloped lights! light = thing->subsector->sector->numlights - 1; + // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thing->x, thing->y) - : thing->subsector->sector->lightlist[lightnum].height; + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); if (h <= gzt) { light = lightnum - 1; break; } } -#else - light = R_GetPlaneLight(thing->subsector->sector, gzt, false); -#endif + //light = R_GetPlaneLight(thing->subsector->sector, gzt, false); lightnum = (*thing->subsector->sector->lightlist[light].lightlevel >> LIGHTSEGSHIFT); if (lightnum < 0) @@ -1896,7 +1861,6 @@ static void R_ProjectSprite(mobj_t *thing) static void R_ProjectPrecipitationSprite(precipmobj_t *thing) { fixed_t tr_x, tr_y; - fixed_t gxt, gyt; fixed_t tx, tz; fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! @@ -1917,21 +1881,16 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) tr_x = thing->x - viewx; tr_y = thing->y - viewy; - gxt = FixedMul(tr_x, viewcos); - gyt = -FixedMul(tr_y, viewsin); - - tz = gxt - gyt; + tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance // thing is behind view plane? if (tz < MINZ) return; - gxt = -FixedMul(tr_x, viewsin); - gyt = FixedMul(tr_y, viewcos); - tx = -(gyt + gxt); + tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // sideways distance // too far off the side? - if (abs(tx) > tz<<2) + if (abs(tx) > FixedMul(tz, fovtan)<<2) return; // aspect ratio stuff : @@ -1981,7 +1940,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // PORTAL SPRITE CLIPPING if (portalrender && portalclipline) { - if (x2 < portalclipstart || x1 > portalclipend) + if (x2 < portalclipstart || x1 >= portalclipend) return; if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) @@ -2293,7 +2252,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps entry->ffloor = ds->thicksides[i]; } } -#ifdef POLYOBJECTS_PLANES // Check for a polyobject plane, but only if this is a front line if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) { plane = ds->curline->polyseg->visplane; @@ -2309,7 +2267,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } ds->curline->polyseg->visplane = NULL; } -#endif if (ds->maskedtexturecol) { entry = R_CreateDrawNode(head); @@ -2357,7 +2314,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (tempskip) return; -#ifdef POLYOBJECTS_PLANES // find all the remaining polyobject planes and add them on the end of the list // probably this is a terrible idea if we wanted them to be sorted properly // but it works getting them in for now @@ -2378,7 +2334,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps // note: no seg is set, for what should be obvious reasons PolyObjects[i].visplane = NULL; } -#endif // No vissprites in this mask? if (mask->vissprites[1] - mask->vissprites[0] == 0) @@ -2403,14 +2358,9 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (rover->szt > r2->plane->low || rover->sz < r2->plane->high) continue; -#ifdef ESLOPE // Effective height may be different for each comparison in the case of slopes - if (r2->plane->slope) { - planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy); - planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy); - } else -#endif - planeobjectz = planecameraz = r2->plane->height; + planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height); + planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height); if (rover->mobjflags & MF_NOCLIPHEIGHT) { @@ -2468,21 +2418,10 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (scale <= rover->sortscale) continue; -#ifdef ESLOPE - if (*r2->ffloor->t_slope) { - topplaneobjectz = P_GetZAt(*r2->ffloor->t_slope, rover->gx, rover->gy); - topplanecameraz = P_GetZAt(*r2->ffloor->t_slope, viewx, viewy); - } else -#endif - topplaneobjectz = topplanecameraz = *r2->ffloor->topheight; - -#ifdef ESLOPE - if (*r2->ffloor->b_slope) { - botplaneobjectz = P_GetZAt(*r2->ffloor->b_slope, rover->gx, rover->gy); - botplanecameraz = P_GetZAt(*r2->ffloor->b_slope, viewx, viewy); - } else -#endif - botplaneobjectz = botplanecameraz = *r2->ffloor->bottomheight; + topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy); + topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy); + botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy); + botplanecameraz = P_GetFFloorBottomZAt(r2->ffloor, viewx, viewy); if ((topplanecameraz > viewz && botplanecameraz < viewz) || (topplanecameraz < viewz && rover->gzt < topplaneobjectz) || @@ -2566,6 +2505,8 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link) node->thickseg = NULL; node->ffloor = NULL; node->sprite = NULL; + + rs_numdrawnodes++; return node; } @@ -2964,795 +2905,3 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) free(heads); } - -// ========================================================================== -// -// SKINS CODE -// -// ========================================================================== - -INT32 numskins = 0; -skin_t skins[MAXSKINS]; -// FIXTHIS: don't work because it must be inistilised before the config load -//#define SKINVALUES -#ifdef SKINVALUES -CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; -#endif - -// -// P_GetSkinSprite2 -// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing. -// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version. -// - -UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) -{ - UINT8 super = 0, i = 0; - - if (!skin) - return 0; - - if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2) - return 0; - - while (!skin->sprites[spr2].numframes - && spr2 != SPR2_STND - && ++i < 32) // recursion limiter - { - if (spr2 & FF_SPR2SUPER) - { - super = FF_SPR2SUPER; - spr2 &= ~FF_SPR2SUPER; - continue; - } - - switch(spr2) - { - // Normal special cases. - case SPR2_JUMP: - spr2 = ((player - ? player->charflags - : skin->flags) - & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; - break; - case SPR2_TIRE: - spr2 = ((player - ? player->charability - : skin->ability) - == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; - break; - // Use the handy list, that's what it's there for! - default: - spr2 = spr2defaults[spr2]; - break; - } - - spr2 |= super; - } - - if (i >= 32) // probably an infinite loop... - return 0; - - return spr2; -} - -static void Sk_SetDefaultValue(skin_t *skin) -{ - INT32 i; - // - // set default skin values - // - memset(skin, 0, sizeof (skin_t)); - snprintf(skin->name, - sizeof skin->name, "skin %u", (UINT32)(skin-skins)); - skin->name[sizeof skin->name - 1] = '\0'; - skin->wadnum = INT16_MAX; - - skin->flags = 0; - - strcpy(skin->realname, "Someone"); - strcpy(skin->hudname, "???"); - - skin->starttranscolor = 96; - skin->prefcolor = SKINCOLOR_GREEN; - skin->supercolor = SKINCOLOR_SUPERGOLD1; - skin->prefoppositecolor = 0; // use tables - - skin->normalspeed = 36<runspeed = 28<thrustfactor = 5; - skin->accelstart = 96; - skin->acceleration = 40; - - skin->ability = CA_NONE; - skin->ability2 = CA2_SPINDASH; - skin->jumpfactor = FRACUNIT; - skin->actionspd = 30<mindash = 15<maxdash = 70<radius = mobjinfo[MT_PLAYER].radius; - skin->height = mobjinfo[MT_PLAYER].height; - skin->spinheight = FixedMul(skin->height, 2*FRACUNIT/3); - - skin->shieldscale = FRACUNIT; - skin->camerascale = FRACUNIT; - - skin->thokitem = -1; - skin->spinitem = -1; - skin->revitem = -1; - skin->followitem = 0; - - skin->highresscale = FRACUNIT; - skin->contspeed = 17; - skin->contangle = 0; - - skin->availability = 0; - - for (i = 0; i < sfx_skinsoundslot0; i++) - if (S_sfx[i].skinsound != -1) - skin->soundsid[S_sfx[i].skinsound] = i; -} - -// -// Initialize the basic skins -// -void R_InitSkins(void) -{ -#ifdef SKINVALUES - INT32 i; - - for (i = 0; i <= MAXSKINS; i++) - { - skin_cons_t[i].value = 0; - skin_cons_t[i].strvalue = NULL; - } -#endif - - // no default skin! - numskins = 0; -} - -UINT32 R_GetSkinAvailabilities(void) -{ - INT32 s; - UINT32 response = 0; - - for (s = 0; s < MAXSKINS; s++) - { - if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked) - response |= (1 << s); - } - return response; -} - -// returns true if available in circumstances, otherwise nope -// warning don't use with an invalid skinnum other than -1 which always returns true -boolean R_SkinUsable(INT32 playernum, INT32 skinnum) -{ - return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0... - || (!skins[skinnum].availability) - || (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked)) - || (modeattacking) // If you have someone else's run you might as well take a look - || (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1. - || (netgame && (cv_forceskin.value == skinnum)) // Force 2. - || (metalrecording && skinnum == 5) // Force 3. - ); -} - -// returns true if the skin name is found (loaded from pwad) -// warning return -1 if not found -INT32 R_SkinAvailable(const char *name) -{ - INT32 i; - - for (i = 0; i < numskins; i++) - { - // search in the skin list - if (stricmp(skins[i].name,name)==0) - return i; - } - return -1; -} - -// network code calls this when a 'skin change' is received -void SetPlayerSkin(INT32 playernum, const char *skinname) -{ - INT32 i = R_SkinAvailable(skinname); - player_t *player = &players[playernum]; - - if ((i != -1) && R_SkinUsable(playernum, i)) - { - SetPlayerSkinByNum(playernum, i); - return; - } - - if (P_IsLocalPlayer(player)) - CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname); - else if(server || IsPlayerAdmin(consoleplayer)) - CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); - - SetPlayerSkinByNum(playernum, 0); -} - -// Same as SetPlayerSkin, but uses the skin #. -// network code calls this when a 'skin change' is received -void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) -{ - player_t *player = &players[playernum]; - skin_t *skin = &skins[skinnum]; - UINT8 newcolor = 0; - - if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists! - { - player->skin = skinnum; - - player->camerascale = skin->camerascale; - player->shieldscale = skin->shieldscale; - - player->charability = (UINT8)skin->ability; - player->charability2 = (UINT8)skin->ability2; - - player->charflags = (UINT32)skin->flags; - - player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; - player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; - player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; - player->followitem = skin->followitem; - - if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff. - player->powers[pw_shield] &= SH_STACK; - - player->actionspd = skin->actionspd; - player->mindash = skin->mindash; - player->maxdash = skin->maxdash; - - player->normalspeed = skin->normalspeed; - player->runspeed = skin->runspeed; - player->thrustfactor = skin->thrustfactor; - player->accelstart = skin->accelstart; - player->acceleration = skin->acceleration; - - player->jumpfactor = skin->jumpfactor; - - player->height = skin->height; - player->spinheight = skin->spinheight; - - if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) - { - if (playernum == consoleplayer) - CV_StealthSetValue(&cv_playercolor, skin->prefcolor); - else if (playernum == secondarydisplayplayer) - CV_StealthSetValue(&cv_playercolor2, skin->prefcolor); - player->skincolor = newcolor = skin->prefcolor; - } - - if (player->followmobj) - { - P_RemoveMobj(player->followmobj); - P_SetTarget(&player->followmobj, NULL); - } - - if (player->mo) - { - fixed_t radius = FixedMul(skin->radius, player->mo->scale); - if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin. - { - skin = &skins[DEFAULTNIGHTSSKIN]; - player->followitem = skin->followitem; - if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) - newcolor = skin->prefcolor; // will be updated in thinker to flashing - } - player->mo->skin = skin; - if (newcolor) - player->mo->color = newcolor; - P_SetScale(player->mo, player->mo->scale); - player->mo->radius = radius; - - P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames - } - return; - } - - if (P_IsLocalPlayer(player)) - 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 %d not found\n", playernum, player_names[playernum], skinnum); - SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin -} - -// -// Add skins from a pwad, each skin preceded by 'S_SKIN' marker -// - -// Does the same is in w_wad, but check only for -// the first 6 characters (this is so we can have S_SKIN1, S_SKIN2.. -// for wad editors that don't like multiple resources of the same name) -// -static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) -{ - UINT16 i; - const char *S_SKIN = "S_SKIN"; - lumpinfo_t *lump_p; - - // scan forward, start at - if (startlump < wadfiles[wadid]->numlumps) - { - lump_p = wadfiles[wadid]->lumpinfo + startlump; - for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) - if (memcmp(lump_p->name,S_SKIN,6)==0) - return i; - } - return INT16_MAX; // not found -} - -#define HUDNAMEWRITE(value) STRBUFCPY(skin->hudname, value) - -// turn _ into spaces and . into katana dot -#define SYMBOLCONVERT(name) for (value = name; *value; value++)\ - {\ - if (*value == '_') *value = ' ';\ - else if (*value == '.') *value = '\x1E';\ - } - -// -// Patch skins from a pwad, each skin preceded by 'P_SKIN' marker -// - -// Does the same is in w_wad, but check only for -// the first 6 characters (this is so we can have P_SKIN1, P_SKIN2.. -// for wad editors that don't like multiple resources of the same name) -// -static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) -{ - UINT16 i; - const char *P_SKIN = "P_SKIN"; - lumpinfo_t *lump_p; - - // scan forward, start at - if (startlump < wadfiles[wadid]->numlumps) - { - lump_p = wadfiles[wadid]->lumpinfo + startlump; - for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) - if (memcmp(lump_p->name,P_SKIN,6)==0) - return i; - } - return INT16_MAX; // not found -} - -static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin) -{ - UINT16 newlastlump; - UINT8 sprite2; - - *lump += 1; // start after S_SKIN - *lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END - - // old wadding practices die hard -- stop at S_SKIN (or P_SKIN) or S_START if they come before S_END. - newlastlump = W_CheckForSkinMarkerInPwad(wadnum,*lump); - if (newlastlump < *lastlump) *lastlump = newlastlump; - newlastlump = W_CheckForPatchSkinMarkerInPwad(wadnum,*lump); - if (newlastlump < *lastlump) *lastlump = newlastlump; - newlastlump = W_CheckNumForNamePwad("S_START",wadnum,*lump); - if (newlastlump < *lastlump) *lastlump = newlastlump; - - // ...and let's handle super, too - newlastlump = W_CheckNumForNamePwad("S_SUPER",wadnum,*lump); - if (newlastlump < *lastlump) - { - newlastlump++; - // load all sprite sets we are aware of... for super! - for (sprite2 = 0; sprite2 < free_spr2; sprite2++) - R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump); - - newlastlump--; - *lastlump = newlastlump; // okay, make the normal sprite set loading end there - } - - // load all sprite sets we are aware of... for normal stuff. - for (sprite2 = 0; sprite2 < free_spr2; sprite2++) - R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[sprite2], wadnum, *lump, *lastlump); - - if (skin->sprites[0].numframes == 0) - I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]); -} - -// returns whether found appropriate property -static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) -{ - // custom translation table - if (!stricmp(stoken, "startcolor")) - skin->starttranscolor = atoi(value); - -#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); - // character type identification - FULLPROCESS(flags) - FULLPROCESS(ability) - FULLPROCESS(ability2) - - FULLPROCESS(thokitem) - FULLPROCESS(spinitem) - FULLPROCESS(revitem) - FULLPROCESS(followitem) -#undef FULLPROCESS - -#define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<field = atoi(value); - GETINT(thrustfactor) - GETINT(accelstart) - GETINT(acceleration) - GETINT(contspeed) - GETINT(contangle) -#undef GETINT - -#define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value); - GETSKINCOLOR(prefcolor) - GETSKINCOLOR(prefoppositecolor) -#undef GETSKINCOLOR - else if (!stricmp(stoken, "supercolor")) - skin->supercolor = R_GetSuperColorByName(value); - -#define GETFLOAT(field) else if (!stricmp(stoken, #field)) skin->field = FLOAT_TO_FIXED(atof(value)); - GETFLOAT(jumpfactor) - GETFLOAT(highresscale) - GETFLOAT(shieldscale) - GETFLOAT(camerascale) -#undef GETFLOAT - -#define GETFLAG(field) else if (!stricmp(stoken, #field)) { \ - strupr(value); \ - if (atoi(value) || value[0] == 'T' || value[0] == 'Y') \ - skin->flags |= (SF_##field); \ - else \ - skin->flags &= ~(SF_##field); \ -} - // parameters for individual character flags - // these are uppercase so they can be concatenated with SF_ - // 1, true, yes are all valid values - GETFLAG(SUPER) - GETFLAG(NOSUPERSPIN) - GETFLAG(NOSPINDASHDUST) - GETFLAG(HIRES) - GETFLAG(NOSKID) - GETFLAG(NOSPEEDADJUST) - GETFLAG(RUNONWATER) - GETFLAG(NOJUMPSPIN) - GETFLAG(NOJUMPDAMAGE) - GETFLAG(STOMPDAMAGE) - GETFLAG(MARIODAMAGE) - GETFLAG(MACHINE) - GETFLAG(DASHMODE) - GETFLAG(FASTEDGE) - GETFLAG(MULTIABILITY) - GETFLAG(NONIGHTSROTATION) -#undef GETFLAG - - else // let's check if it's a sound, otherwise error out - { - boolean found = false; - sfxenum_t i; - size_t stokenadjust; - - // Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.) - if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS* - stokenadjust = 2; - else // sfx_* - stokenadjust = 4; - - // Remove the prefix. (We can affect this directly since we're not going to use it again.) - if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS* - value += 2; - else // sfx_* - value += 4; - - // copy name of sounds that are remapped - // for this skin - for (i = 0; i < sfx_skinsoundslot0; i++) - { - if (!S_sfx[i].name) - continue; - if (S_sfx[i].skinsound != -1 - && !stricmp(S_sfx[i].name, - stoken + stokenadjust)) - { - skin->soundsid[S_sfx[i].skinsound] = - S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true); - found = true; - } - } - return found; - } - return true; -} - -// -// Find skin sprites, sounds & optional status bar face, & add them -// -void R_AddSkins(UINT16 wadnum) -{ - UINT16 lump, lastlump = 0; - char *buf; - char *buf2; - char *stoken; - char *value; - size_t size; - skin_t *skin; - boolean hudname, realname; - - // - // search for all skin markers in pwad - // - - while ((lump = W_CheckForSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) - { - // advance by default - lastlump = lump + 1; - - if (numskins >= MAXSKINS) - { - CONS_Debug(DBG_RENDER, "ignored skin (%d skins maximum)\n", MAXSKINS); - continue; // so we know how many skins couldn't be added - } - buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); - size = W_LumpLengthPwad(wadnum, lump); - - // for strtok - buf2 = malloc(size+1); - if (!buf2) - I_Error("R_AddSkins: No more free memory\n"); - M_Memcpy(buf2,buf,size); - buf2[size] = '\0'; - - // set defaults - skin = &skins[numskins]; - Sk_SetDefaultValue(skin); - skin->wadnum = wadnum; - hudname = realname = false; - // parse - stoken = strtok (buf2, "\r\n= "); - while (stoken) - { - if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#'))// skip comments - { - stoken = strtok(NULL, "\r\n"); // skip end of line - goto next_token; // find the real next token - } - - value = strtok(NULL, "\r\n= "); - - if (!value) - I_Error("R_AddSkins: syntax error in S_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); - - // Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines. - // Others can't go in there because we don't want them to be patchable. - if (!stricmp(stoken, "name")) - { - INT32 skinnum = R_SkinAvailable(value); - strlwr(value); - if (skinnum == -1) - STRBUFCPY(skin->name, value); - // the skin name must uniquely identify a single skin - // if the name is already used I make the name 'namex' - // using the default skin name's number set above - else - { - const size_t stringspace = - strlen(value) + sizeof (numskins) + 1; - char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL); - snprintf(value2, stringspace, - "%s%d", value, numskins); - value2[stringspace - 1] = '\0'; - if (R_SkinAvailable(value2) == -1) - // I'm lazy so if NEW name is already used I leave the 'skin x' - // default skin name set in Sk_SetDefaultValue - STRBUFCPY(skin->name, value2); - Z_Free(value2); - } - - // copy to hudname and fullname as a default. - if (!realname) - { - STRBUFCPY(skin->realname, skin->name); - for (value = skin->realname; *value; value++) - { - if (*value == '_') *value = ' '; // turn _ into spaces. - else if (*value == '.') *value = '\x1E'; // turn . into katana dot. - } - } - if (!hudname) - { - HUDNAMEWRITE(skin->name); - strupr(skin->hudname); - SYMBOLCONVERT(skin->hudname) - } - } - else if (!stricmp(stoken, "realname")) - { // Display name (eg. "Knuckles") - realname = true; - STRBUFCPY(skin->realname, value); - SYMBOLCONVERT(skin->realname) - if (!hudname) - HUDNAMEWRITE(skin->realname); - } - else if (!stricmp(stoken, "hudname")) - { // Life icon name (eg. "K.T.E") - hudname = true; - HUDNAMEWRITE(value); - SYMBOLCONVERT(skin->hudname) - if (!realname) - STRBUFCPY(skin->realname, skin->hudname); - } - else if (!stricmp(stoken, "availability")) - { - skin->availability = atoi(value); - if (skin->availability >= MAXUNLOCKABLES) - skin->availability = 0; - } - else if (!R_ProcessPatchableFields(skin, stoken, value)) - CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); - -next_token: - stoken = strtok(NULL, "\r\n= "); - } - free(buf2); - - // Add sprites - R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); - //ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere - - R_FlushTranslationColormapCache(); - - if (!skin->availability) // Safe to print... - CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); -#ifdef SKINVALUES - skin_cons_t[numskins].value = numskins; - skin_cons_t[numskins].strvalue = skin->name; -#endif - -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_AddPlayerModel(numskins); -#endif - - numskins++; - } - return; -} - -// -// Patch skin sprites -// -void R_PatchSkins(UINT16 wadnum) -{ - UINT16 lump, lastlump = 0; - char *buf; - char *buf2; - char *stoken; - char *value; - size_t size; - skin_t *skin; - boolean noskincomplain, realname, hudname; - - // - // search for all skin patch markers in pwad - // - - while ((lump = W_CheckForPatchSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) - { - INT32 skinnum = 0; - - // advance by default - lastlump = lump + 1; - - buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); - size = W_LumpLengthPwad(wadnum, lump); - - // for strtok - buf2 = malloc(size+1); - if (!buf2) - I_Error("R_PatchSkins: No more free memory\n"); - M_Memcpy(buf2,buf,size); - buf2[size] = '\0'; - - skin = NULL; - noskincomplain = realname = hudname = false; - - /* - Parse. Has more phases than the parser in R_AddSkins because it needs to have the patching name first (no default skin name is acceptible for patching, unlike skin creation) - */ - - stoken = strtok(buf2, "\r\n= "); - while (stoken) - { - if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#'))// skip comments - { - stoken = strtok(NULL, "\r\n"); // skip end of line - goto next_token; // find the real next token - } - - value = strtok(NULL, "\r\n= "); - - if (!value) - I_Error("R_PatchSkins: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); - - if (!skin) // Get the name! - { - if (!stricmp(stoken, "name")) - { - strlwr(value); - skinnum = R_SkinAvailable(value); - if (skinnum != -1) - skin = &skins[skinnum]; - else - { - CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); - noskincomplain = true; - } - } - } - else // Get the properties! - { - // Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines. - if (!stricmp(stoken, "realname")) - { // Display name (eg. "Knuckles") - realname = true; - STRBUFCPY(skin->realname, value); - SYMBOLCONVERT(skin->realname) - if (!hudname) - HUDNAMEWRITE(skin->realname); - } - else if (!stricmp(stoken, "hudname")) - { // Life icon name (eg. "K.T.E") - hudname = true; - HUDNAMEWRITE(value); - SYMBOLCONVERT(skin->hudname) - if (!realname) - STRBUFCPY(skin->realname, skin->hudname); - } - else if (!R_ProcessPatchableFields(skin, stoken, value)) - CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); - } - - if (!skin) - break; - -next_token: - stoken = strtok(NULL, "\r\n= "); - } - free(buf2); - - if (!skin) // Didn't include a name parameter? What a waste. - { - if (!noskincomplain) - CONS_Debug(DBG_SETUP, "R_PatchSkins: no skin name given in P_SKIN lump #%d (WAD %s)\n", lump, wadfiles[wadnum]->filename); - continue; - } - - // Patch sprites - R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); - //ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere - - R_FlushTranslationColormapCache(); - - if (!skin->availability) // Safe to print... - CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name); - } - return; -} - -#undef HUDNAMEWRITE -#undef SYMBOLCONVERT diff --git a/src/r_things.h b/src/r_things.h index 217179148..7a0fe3a60 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -14,26 +14,27 @@ #ifndef __R_THINGS__ #define __R_THINGS__ -#include "sounds.h" #include "r_plane.h" #include "r_patch.h" #include "r_portal.h" #include "r_defs.h" +#include "r_skins.h" -// number of sprite lumps for spritewidth,offset,topoffset lookup tables -// Fab: this is a hack : should allocate the lookup tables per sprite -#define MAXVISSPRITES 2048 // added 2-2-98 was 128 - -#define VISSPRITECHUNKBITS 6 // 2^6 = 64 sprites per chunk -#define VISSPRITESPERCHUNK (1 << VISSPRITECHUNKBITS) -#define VISSPRITEINDEXMASK (VISSPRITESPERCHUNK - 1) +// -------------- +// SPRITE LOADING +// -------------- #define FEETADJUST (4<dispoffset, affects ordering but not drawing } vissprite_t; +extern UINT32 visspritecount; + +// ---------- +// DRAW NODES +// ---------- + // A drawnode is something that points to a 3D floor, 3D side, or masked // middle texture. This is used for sorting with sprites. typedef struct drawnode_s @@ -241,23 +202,11 @@ typedef struct drawnode_s struct drawnode_s *prev; } drawnode_t; -extern INT32 numskins; -extern skin_t skins[MAXSKINS]; -extern UINT32 visspritecount; - -void SetPlayerSkin(INT32 playernum,const char *skinname); -void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 -boolean R_SkinUsable(INT32 playernum, INT32 skinnum); -UINT32 R_GetSkinAvailabilities(void); -INT32 R_SkinAvailable(const char *name); -void R_PatchSkins(UINT16 wadnum); -void R_AddSkins(UINT16 wadnum); - -UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player); - void R_InitDrawNodes(void); -char *GetPlayerFacePic(INT32 skinnum); +// ----------------------- +// SPRITE FRAME CHARACTERS +// ----------------------- // Functions to go from sprite character ID to frame number // for 2.1 compatibility this still uses the old 'A' + frame code diff --git a/src/s_sound.c b/src/s_sound.c index d84e20ab4..5ed9fd83a 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -27,7 +27,7 @@ extern INT32 msg_id; #include "g_game.h" #include "m_argv.h" #include "r_main.h" // R_PointToAngle2() used to calc stereo sep. -#include "r_things.h" // for skins +#include "r_skins.h" // for skins #include "i_system.h" #include "i_sound.h" #include "s_sound.h" @@ -40,7 +40,7 @@ extern INT32 msg_id; #include "m_misc.h" // for tunes command #include "m_cond.h" // for conditionsets -#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) +#ifdef HAVE_LUA_MUSICPLUS #include "lua_hook.h" // MusicChange hook #endif @@ -134,6 +134,7 @@ consvar_t cv_playmusicifunfocused = {"playmusicifunfocused", "No", CV_SAVE, CV_Y consvar_t cv_playsoundsifunfocused = {"playsoundsifunfocused", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; #ifdef HAVE_OPENMPT +openmpt_module *openmpt_mhandle = NULL; 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}; #endif @@ -1456,6 +1457,7 @@ musicdef_t soundtestsfx = { 0, // with no conditions 0, 0, + 0, false, NULL }; @@ -1651,6 +1653,8 @@ ReadMusicDefFields (UINT16 wadnum, int line, boolean fields, char *stoken, fixed_t bpmf = FLOAT_TO_FIXED(bpm); if (bpmf > 0) def->bpm = FixedDiv((60*TICRATE)<loop_ms = atoi(textline); } else { CONS_Alert(CONS_WARNING, "MUSICDEF: Invalid field '%s'. (file %s, line %d)\n", @@ -1672,7 +1676,7 @@ void S_LoadMusicDefs(UINT16 wadnum) char *lf; char *stoken; - size_t nlf; + size_t nlf = 0xFFFFFFFF; size_t ncr; musicdef_t *def = NULL; @@ -1907,6 +1911,10 @@ UINT32 S_GetMusicPosition(void) /// In this section: mazmazz doesn't know how to do dynamic arrays or struct pointers! /// ------------------------ +char music_stack_nextmusname[7]; +boolean music_stack_noposition = false; +UINT32 music_stack_fadeout = 0; +UINT32 music_stack_fadein = 0; static musicstack_t *music_stacks = NULL; static musicstack_t *last_music_stack = NULL; @@ -2045,7 +2053,7 @@ static musicstack_t *S_GetMusicStackEntry(UINT16 status, boolean fromfirst, INT1 if (!status || mst->status == status) { - if (P_EvaluateMusicStatus(mst->status)) + if (P_EvaluateMusicStatus(mst->status, mst->musname)) { if (!S_MusicExists(mst->musname, !midi_disabled, !digital_disabled)) // paranoia S_RemoveMusicStackEntry(mst); // then continue @@ -2262,6 +2270,8 @@ static void S_UnloadMusic(void) static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) { + musicdef_t *def; + if (S_MusicDisabled()) return false; @@ -2273,6 +2283,17 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) return false; } + /* set loop point from MUSICDEF */ + for (def = musicdefstart; def; def = def->next) + { + if (strcasecmp(def->name, music_name) == 0) + { + if (def->loop_ms) + S_SetMusicLoopPoint(def->loop_ms); + break; + } + } + S_InitMusicVolume(); // switch between digi and sequence volume if (S_MusicNotInFocus()) @@ -2314,7 +2335,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 return; strncpy(newmusic, mmusic, 7); -#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) +#ifdef HAVE_LUA_MUSICPLUS if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) return; #endif diff --git a/src/s_sound.h b/src/s_sound.h index 9a4cbe48b..3334fcb69 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,7 +22,7 @@ #ifdef HAVE_OPENMPT #include "libopenmpt/libopenmpt.h" -openmpt_module *openmpt_mhandle; +extern openmpt_module *openmpt_mhandle; #endif // mask used to indicate sound origin is player item pickup @@ -208,6 +208,7 @@ typedef struct musicdef_s INT16 soundtestcond; // +ve for map, -ve for conditionset, 0 for already here tic_t stoppingtics; fixed_t bpm; + UINT32 loop_ms;/* override LOOPPOINT/LOOPMS */ boolean allowed; // question marks or listenable on sound test? struct musicdef_s *next; } musicdef_t; @@ -261,10 +262,10 @@ typedef struct musicstack_s struct musicstack_s *next; } musicstack_t; -char music_stack_nextmusname[7]; -boolean music_stack_noposition; -UINT32 music_stack_fadeout; -UINT32 music_stack_fadein; +extern char music_stack_nextmusname[7]; +extern boolean music_stack_noposition; +extern UINT32 music_stack_fadeout; +extern UINT32 music_stack_fadein; void S_SetStackAdjustmentStart(void); void S_AdjustMusicStackTics(void); @@ -332,7 +333,7 @@ void S_StopSoundByNum(sfxenum_t sfxnum); #ifdef MUSICSLOT_COMPATIBILITY // For compatibility with code/scripts relying on older versions // This is a list of all the "special" slot names and their associated numbers -const char *compat_special_music_slots[16]; +extern const char *compat_special_music_slots[16]; #endif #endif diff --git a/src/screen.c b/src/screen.c index fcf6c6b0b..e7ff9e735 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -127,14 +127,12 @@ void SCR_SetDrawFuncs(void) #ifndef NOWATER spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8; #endif -#ifdef ESLOPE spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8; spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8; #ifndef NOWATER spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_8; #endif spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8; -#endif // Lactozilla: Non-powers-of-two spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8; @@ -145,14 +143,12 @@ void SCR_SetDrawFuncs(void) #ifndef NOWATER spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8; #endif -#ifdef ESLOPE spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8; #ifndef NOWATER spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8; #endif spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8; -#endif #ifdef RUSEASM if (R_ASM) @@ -450,6 +446,20 @@ static int target_renderer = 0; void SCR_ActuallyChangeRenderer(void) { setrenderneeded = target_renderer; + +#ifdef HWRENDER + // Well, it didn't even load anyway. + if ((vid_opengl_state == -1) && (setrenderneeded == render_opengl)) + { + if (M_CheckParm("-nogl")) + CONS_Alert(CONS_ERROR, "OpenGL rendering was disabled!\n"); + else + CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); + setrenderneeded = 0; + return; + } +#endif + // setting the same renderer twice WILL crash your game, so let's not, please if (rendermode == setrenderneeded) setrenderneeded = 0; @@ -464,7 +474,7 @@ void SCR_ChangeRenderer(void) { target_renderer = cv_renderer.value; #ifdef HWRENDER - if (M_CheckParm("-opengl")) + if (M_CheckParm("-opengl") && (vid_opengl_state == 1)) target_renderer = rendermode = render_opengl; else #endif @@ -516,6 +526,9 @@ void SCR_DisplayTicRate(void) INT32 ticcntcolor = 0; const INT32 h = vid.height-(8*vid.dupy); + if (gamestate == GS_NULL) + return; + for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i) fpsgraph[i % TICRATE] = false; @@ -528,10 +541,16 @@ void SCR_DisplayTicRate(void) if (totaltics <= TICRATE/2) ticcntcolor = V_REDMAP; else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP; - V_DrawString(vid.width-(72*vid.dupx), h, - V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); - V_DrawString(vid.width-(40*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d/%02u", totaltics, TICRATE)); + if (cv_ticrate.value == 2) // compact counter + V_DrawString(vid.width-(16*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d", totaltics)); + else if (cv_ticrate.value == 1) // full counter + { + V_DrawString(vid.width-(72*vid.dupx), h, + V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); + V_DrawString(vid.width-(40*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d/%02u", totaltics, TICRATE)); + } lasttic = ontic; } @@ -603,3 +622,51 @@ void SCR_ClosedCaptions(void) va("%c [%s]", dot, (closedcaptions[i].s->caption[0] ? closedcaptions[i].s->caption : closedcaptions[i].s->name))); } } + +void SCR_DisplayMarathonInfo(void) +{ + INT32 flags = V_SNAPTOBOTTOM; + static tic_t entertic, oldentertics = 0, antisplice[2] = {48,0}; + const char *str; +#if 0 // eh, this probably isn't going to be a problem + if (((signed)marathontime) < 0) + { + flags |= V_REDMAP; + str = "No waiting out the clock to submit a bogus time."; + } + else +#endif + { + entertic = I_GetTime(); + if (gamecomplete) + flags |= V_YELLOWMAP; + else if (marathonmode & MA_INGAME) + ; // see also G_Ticker + else if (marathonmode & MA_INIT) + marathonmode &= ~MA_INIT; + else + marathontime += entertic - oldentertics; + + // Create a sequence of primes such that their LCM is nice and big. +#define PRIMEV1 13 +#define PRIMEV2 17 // I can't believe it! I'm on TV! + antisplice[0] += (entertic - oldentertics)*PRIMEV2; + antisplice[0] %= PRIMEV1*((vid.width/vid.dupx)+1); + antisplice[1] += (entertic - oldentertics)*PRIMEV1; + antisplice[1] %= PRIMEV1*((vid.width/vid.dupx)+1); + str = va("%i:%02i:%02i.%02i", + G_TicsToHours(marathontime), + G_TicsToMinutes(marathontime, false), + G_TicsToSeconds(marathontime), + G_TicsToCentiseconds(marathontime)); + oldentertics = entertic; + } + V_DrawFill((antisplice[0]/PRIMEV1)-1, BASEVIDHEIGHT-8, 1, 8, V_SNAPTOBOTTOM|V_SNAPTOLEFT); + V_DrawFill((antisplice[0]/PRIMEV1), BASEVIDHEIGHT-8, 1, 8, V_SNAPTOBOTTOM|V_SNAPTOLEFT|31); + V_DrawFill(BASEVIDWIDTH-((antisplice[1]/PRIMEV1)-1), BASEVIDHEIGHT-8, 1, 8, V_SNAPTOBOTTOM|V_SNAPTORIGHT); + V_DrawFill(BASEVIDWIDTH-((antisplice[1]/PRIMEV1)), BASEVIDHEIGHT-8, 1, 8, V_SNAPTOBOTTOM|V_SNAPTORIGHT|31); +#undef PRIMEV1 +#undef PRIMEV2 + V_DrawPromptBack(-8, cons_backcolor.value); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-8, flags, str); +} diff --git a/src/screen.h b/src/screen.h index 02b336f75..91ec175f4 100644 --- a/src/screen.h +++ b/src/screen.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -140,13 +140,11 @@ enum #ifndef NOWATER SPANDRAWFUNC_WATER, #endif -#ifdef ESLOPE SPANDRAWFUNC_TILTED, SPANDRAWFUNC_TILTEDTRANS, SPANDRAWFUNC_TILTEDSPLAT, #ifndef NOWATER SPANDRAWFUNC_TILTEDWATER, -#endif #endif SPANDRAWFUNC_MAX @@ -208,5 +206,6 @@ FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height); void SCR_DisplayTicRate(void); void SCR_ClosedCaptions(void); void SCR_DisplayLocalPing(void); +void SCR_DisplayMarathonInfo(void); #undef DNWH #endif //__SCREEN_H__ diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index b334f6313..c24104b92 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -213,12 +213,14 @@ + + @@ -284,6 +286,7 @@ + @@ -336,6 +339,7 @@ + @@ -363,9 +367,11 @@ + + @@ -446,6 +452,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 3f61e8709..2f0aec7ca 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -180,6 +180,9 @@ F_Frame + + G_Game + G_Game @@ -216,6 +219,9 @@ Hw_Hardware + + Hw_Hardware + Hw_Hardware @@ -417,6 +423,9 @@ R_Rend + + R_Rend + R_Rend @@ -528,6 +537,9 @@ BLUA + + BLUA + BLUA @@ -597,6 +609,9 @@ F_Frame + + G_Game + G_Game @@ -624,6 +639,9 @@ Hw_Hardware + + Hw_Hardware + Hw_Hardware @@ -849,6 +867,9 @@ R_Rend + + R_Rend + R_Rend diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj index 3898aeba4..9ef4301cc 100644 --- a/src/sdl/Srb2SDL-vc9.vcproj +++ b/src/sdl/Srb2SDL-vc9.vcproj @@ -50,7 +50,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -145,7 +145,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -248,7 +248,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" StringPooling="true" RuntimeLibrary="0" PrecompiledHeaderFile=".\..\..\objs\VC9\$(Platform)\$(Configuration)\SDL\Srb2SDL-vc9.pch" @@ -350,7 +350,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" StringPooling="true" RuntimeLibrary="0" PrecompiledHeaderFile=".\..\..\objs\VC9\$(Platform)\$(Configuration)\SDL\Srb2SDL-vc9.pch" diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 5f040023a..416c8d2f5 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -75,14 +75,17 @@ void *hwSym(const char *funcName,void *handle) void *funcPointer = NULL; #ifdef HWRENDER if (0 == strcmp("SetPalette", funcName)) - funcPointer = &OglSdlSetPalette; + funcPointer = &OglSdlSetPalette; + GETFUNC(Init); GETFUNC(Draw2DLine); GETFUNC(DrawPolygon); + GETFUNC(DrawIndexedTriangles); GETFUNC(RenderSkyDome); GETFUNC(SetBlend); GETFUNC(ClearBuffer); GETFUNC(SetTexture); + GETFUNC(UpdateTexture); GETFUNC(ReadRect); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); @@ -91,7 +94,6 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(DrawModel); GETFUNC(CreateModelVBOs); GETFUNC(SetTransform); - GETFUNC(GetRenderVersion); GETFUNC(PostImgRedraw); GETFUNC(FlushScreenTextures); GETFUNC(StartScreenWipe); @@ -101,6 +103,16 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(MakeScreenTexture); GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); + + GETFUNC(LoadShaders); + GETFUNC(KillShaders); + GETFUNC(SetShader); + GETFUNC(UnSetShader); + + GETFUNC(SetShaderInfo); + GETFUNC(LoadCustomShader); + GETFUNC(InitCustomShaders); + #else //HWRENDER if (0 == strcmp("FinishUpdate", funcName)) return funcPointer; //&FinishUpdate; diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index 5d0009927..1dee379c0 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -27,7 +27,7 @@ #include #endif -#ifdef __unix__ +#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #include #endif @@ -103,6 +103,93 @@ static inline VOID MakeCodeWritable(VOID) } #endif +#ifdef LOGMESSAGES +static void InitLogging(void) +{ + const char *logdir = NULL; + time_t my_time; + struct tm * timeinfo; + const char *format; + const char *reldir; + int left; + boolean fileabs; +#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) + const char *link; +#endif + + logdir = D_Home(); + + my_time = time(NULL); + timeinfo = localtime(&my_time); + + if (M_CheckParm("-logfile") && M_IsNextParm()) + { + format = M_GetNextParm(); + fileabs = M_IsPathAbsolute(format); + } + else + { + format = "log-%Y-%m-%d_%H-%M-%S.txt"; + fileabs = false; + } + + if (fileabs) + { + strftime(logfilename, sizeof logfilename, format, timeinfo); + } + else + { + if (M_CheckParm("-logdir") && M_IsNextParm()) + reldir = M_GetNextParm(); + else + reldir = "logs"; + + if (M_IsPathAbsolute(reldir)) + { + left = snprintf(logfilename, sizeof logfilename, + "%s"PATHSEP, reldir); + } + else +#ifdef DEFAULTDIR + if (logdir) + { + left = snprintf(logfilename, sizeof logfilename, + "%s"PATHSEP DEFAULTDIR PATHSEP"%s"PATHSEP, logdir, reldir); + } + else +#endif/*DEFAULTDIR*/ + { + left = snprintf(logfilename, sizeof logfilename, + "."PATHSEP"%s"PATHSEP, reldir); + } + + strftime(&logfilename[left], sizeof logfilename - left, + format, timeinfo); + } + + M_MkdirEachUntil(logfilename, + M_PathParts(logdir) - 1, + M_PathParts(logfilename) - 1, 0755); + +#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) + logstream = fopen(logfilename, "w"); +#ifdef DEFAULTDIR + if (logdir) + link = va("%s/"DEFAULTDIR"/latest-log.txt", logdir); + else +#endif/*DEFAULTDIR*/ + link = "latest-log.txt"; + unlink(link); + if (symlink(logfilename, link) == -1) + { + I_OutputMsg("Error symlinking latest-log.txt: %s\n", strerror(errno)); + } +#else/*defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)*/ + logstream = fopen("latest-log.txt", "wt+"); +#endif/*defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)*/ +} +#endif + /** \brief The main function @@ -121,7 +208,6 @@ int SDL_main(int argc, char **argv) int main(int argc, char **argv) #endif { - const char *logdir = NULL; myargc = argc; myargv = argv; /// \todo pull out path to exe from this string @@ -135,90 +221,9 @@ int main(int argc, char **argv) #ifdef LOGMESSAGES if (!M_CheckParm("-nolog")) - { - time_t my_time; - struct tm * timeinfo; - const char *format; - const char *reldir; - int left; - boolean fileabs; -#ifdef __unix__ - const char *link; -#endif - - logdir = D_Home(); - - my_time = time(NULL); - timeinfo = localtime(&my_time); - - if (M_CheckParm("-logfile") && M_IsNextParm()) - { - format = M_GetNextParm(); - fileabs = M_IsPathAbsolute(format); - } - else - { - format = "log-%Y-%m-%d_%H-%M-%S.txt"; - fileabs = false; - } - - if (fileabs) - { - strftime(logfilename, sizeof logfilename, format, timeinfo); - } - else - { - if (M_CheckParm("-logdir") && M_IsNextParm()) - reldir = M_GetNextParm(); - else - reldir = "logs"; - - if (M_IsPathAbsolute(reldir)) - { - left = snprintf(logfilename, sizeof logfilename, - "%s"PATHSEP, reldir); - } - else -#ifdef DEFAULTDIR - if (logdir) - { - left = snprintf(logfilename, sizeof logfilename, - "%s"PATHSEP DEFAULTDIR PATHSEP"%s"PATHSEP, logdir, reldir); - } - else -#endif/*DEFAULTDIR*/ - { - left = snprintf(logfilename, sizeof logfilename, - "."PATHSEP"%s"PATHSEP, reldir); - } + InitLogging(); #endif/*LOGMESSAGES*/ - strftime(&logfilename[left], sizeof logfilename - left, - format, timeinfo); - } - - M_MkdirEachUntil(logfilename, - M_PathParts(logdir) - 1, - M_PathParts(logfilename) - 1, 0755); - -#ifdef __unix__ - logstream = fopen(logfilename, "w"); -#ifdef DEFAULTDIR - if (logdir) - link = va("%s/"DEFAULTDIR"/latest-log.txt", logdir); - else -#endif/*DEFAULTDIR*/ - link = "latest-log.txt"; - unlink(link); - if (symlink(logfilename, link) == -1) - { - I_OutputMsg("Error symlinking latest-log.txt: %s\n", strerror(errno)); - } -#else/*__unix__*/ - logstream = fopen("latest-log.txt", "wt+"); -#endif/*__unix__*/ - } - //I_OutputMsg("I_StartupSystem() ...\n"); I_StartupSystem(); #if defined (_WIN32) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 81420e757..27e015ef7 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -5,7 +5,7 @@ // // Copyright (C) 1993-1996 by id Software, Inc. // Portions Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -54,6 +54,12 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #include #endif +#if defined (_WIN32) +DWORD TimeFunction(int requested_frequency); +#else +int TimeFunction(int requested_frequency); +#endif + #include #ifdef _WIN32 #include @@ -178,6 +184,8 @@ static char returnWadPath[256]; #include "../m_argv.h" +#include "../m_menu.h" + #ifdef MAC_ALERT #include "macosx/mac_alert.h" #endif @@ -293,6 +301,7 @@ static void I_ReportSignal(int num, int coredumped) FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) { D_QuitNetGame(); // Fix server freezes + CL_AbortDownloadResume(); I_ReportSignal(num, 0); I_ShutdownSystem(); signal(num, SIG_DFL); //default signal action @@ -2060,9 +2069,11 @@ static p_timeGetTime pfntimeGetTime = NULL; // but lower precision on Windows NT // --------- -tic_t I_GetTime(void) +DWORD TimeFunction(int requested_frequency) { - tic_t newtics = 0; + DWORD newtics = 0; + // this var acts as a multiplier if sub-millisecond precision is asked but is not available + int excess_frequency = requested_frequency / 1000; if (!starttickcount) // high precision timer { @@ -2082,7 +2093,7 @@ tic_t I_GetTime(void) if (frequency.LowPart && QueryPerformanceCounter(&currtime)) { - newtics = (INT32)((currtime.QuadPart - basetime.QuadPart) * NEWTICRATE + newtics = (INT32)((currtime.QuadPart - basetime.QuadPart) * requested_frequency / frequency.QuadPart); } else if (pfntimeGetTime) @@ -2090,11 +2101,19 @@ tic_t I_GetTime(void) currtime.LowPart = pfntimeGetTime(); if (!basetime.LowPart) basetime.LowPart = currtime.LowPart; - newtics = ((currtime.LowPart - basetime.LowPart)/(1000/NEWTICRATE)); + if (requested_frequency > 1000) + newtics = currtime.LowPart - basetime.LowPart * excess_frequency; + else + newtics = (currtime.LowPart - basetime.LowPart)/(1000/requested_frequency); } } else - newtics = (GetTickCount() - starttickcount)/(1000/NEWTICRATE); + { + if (requested_frequency > 1000) + newtics = (GetTickCount() - starttickcount) * excess_frequency; + else + newtics = (GetTickCount() - starttickcount)/(1000/requested_frequency); + } return newtics; } @@ -2116,7 +2135,9 @@ static void I_ShutdownTimer(void) // I_GetTime // returns time in 1/TICRATE second tics // -tic_t I_GetTime (void) + +// millisecond precision only +int TimeFunction(int requested_frequency) { static Uint64 basetime = 0; Uint64 ticks = SDL_GetTicks(); @@ -2126,14 +2147,24 @@ tic_t I_GetTime (void) ticks -= basetime; - ticks = (ticks*TICRATE); + ticks = (ticks*requested_frequency); ticks = (ticks/1000); - return (tic_t)ticks; + return ticks; } #endif +tic_t I_GetTime(void) +{ + return TimeFunction(NEWTICRATE); +} + +int I_GetTimeMicros(void) +{ + return TimeFunction(1000000); +} + // //I_StartupTimer // @@ -2293,6 +2324,8 @@ void I_Quit(void) G_StopMetalRecording(false); D_QuitNetGame(); + CL_AbortDownloadResume(); + M_FreePlayerSetupColors(); I_ShutdownMusic(); I_ShutdownSound(); I_ShutdownCD(); @@ -2409,6 +2442,8 @@ void I_Error(const char *error, ...) G_StopMetalRecording(false); D_QuitNetGame(); + CL_AbortDownloadResume(); + M_FreePlayerSetupColors(); I_ShutdownMusic(); I_ShutdownSound(); I_ShutdownCD(); @@ -2484,7 +2519,7 @@ void I_RemoveExitFunc(void (*func)()) } } -#ifndef __unix__ +#if !(defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)) static void Shittycopyerror(const char *name) { I_OutputMsg( @@ -2524,7 +2559,7 @@ static void Shittylogcopy(void) Shittycopyerror(logfilename); } } -#endif/*__unix__*/ +#endif/*!(defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON))*/ // // Closes down everything. This includes restoring the initial @@ -2548,7 +2583,7 @@ void I_ShutdownSystem(void) if (logstream) { I_OutputMsg("I_ShutdownSystem(): end of logstream.\n"); -#ifndef __unix__ +#if !(defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)) Shittylogcopy(); #endif fclose(logstream); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 7af1863ab..01194a02f 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -4,7 +4,7 @@ // // Copyright (C) 1993-1996 by id Software, Inc. // Portions Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -73,6 +73,7 @@ #include "../console.h" #include "../command.h" #include "../r_main.h" +#include "../lua_hook.h" #include "sdlmain.h" #ifdef HWRENDER #include "../hardware/hw_main.h" @@ -93,7 +94,8 @@ static INT32 numVidModes = -1; */ static char vidModeName[33][32]; // allow 33 different modes -rendermode_t rendermode=render_soft; +rendermode_t rendermode = render_soft; +static rendermode_t chosenrendermode = render_soft; // set by command line arguments boolean highcolor = false; @@ -103,6 +105,7 @@ static consvar_t cv_stretch = {"stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff static consvar_t cv_alwaysgrabmouse = {"alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; UINT8 graphics_started = 0; // Is used in console.c and screen.c +INT32 vid_opengl_state = 0; // To disable fullscreen at startup; is set in VID_PrepareModeList boolean allow_fullscreen = false; @@ -174,7 +177,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen); //static void Impl_SetWindowName(const char *title); static void Impl_SetWindowIcon(void); -static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen) +static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool reposition) { static SDL_bool wasfullscreen = SDL_FALSE; Uint32 rmask; @@ -203,16 +206,18 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen) } // Reposition window only in windowed mode SDL_SetWindowSize(window, width, height); - SDL_SetWindowPosition(window, - SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(window)), - SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(window)) - ); + if (reposition) + { + SDL_SetWindowPosition(window, + SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(window)), + SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(window)) + ); + } } } else { Impl_CreateWindow(fullscreen); - Impl_SetWindowIcon(); wasfullscreen = fullscreen; SDL_SetWindowSize(window, width, height); if (fullscreen) @@ -353,11 +358,7 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code) case SDL_SCANCODE_RGUI: return KEY_RIGHTWIN; default: break; } -#ifdef HWRENDER - DBG_Printf("Unknown incoming scancode: %d, represented %c\n", - code, - SDL_GetKeyName(SDL_GetKeyFromScancode(code))); -#endif + return 0; } @@ -367,7 +368,10 @@ static boolean IgnoreMouse(void) return false; if (menuactive) return !M_MouseNeeded(); - if (paused || con_destlines || chat_on || gamestate != GS_LEVEL) + if (paused || con_destlines || chat_on) + return true; + if (gamestate != GS_LEVEL && gamestate != GS_INTERMISSION && + gamestate != GS_CONTINUING && gamestate != GS_CUTSCENE) return true; return false; } @@ -1054,8 +1058,9 @@ void I_GetEvent(void) M_SetupJoystickMenu(0); break; case SDL_QUIT: + if (Playing()) + LUAh_GameQuit(); I_Quit(); - M_QuitResponse('y'); break; } } @@ -1197,6 +1202,9 @@ void I_FinishUpdate(void) if (I_SkipFrame()) return; + if (marathonmode) + SCR_DisplayMarathonInfo(); + // draw captions if enabled if (cv_closedcaptioning.value) SCR_ClosedCaptions(); @@ -1435,7 +1443,7 @@ static SDL_bool Impl_CreateContext(void) { // Renderer-specific stuff #ifdef HWRENDER - if (rendermode == render_opengl) + if ((rendermode == render_opengl) && (vid_opengl_state != -1)) { if (!sdlglcontext) sdlglcontext = SDL_GL_CreateContext(window); @@ -1468,18 +1476,85 @@ static SDL_bool Impl_CreateContext(void) return SDL_TRUE; } +void VID_CheckGLLoaded(rendermode_t oldrender) +{ +#ifdef HWRENDER + if (vid_opengl_state == -1) // Well, it didn't work the first time anyway. + { + CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); + rendermode = oldrender; + if (chosenrendermode == render_opengl) // fallback to software + rendermode = render_soft; + if (setrenderneeded) + { + CV_StealthSetValue(&cv_renderer, oldrender); + CV_StealthSetValue(&cv_newrenderer, oldrender); + setrenderneeded = 0; + } + } +#endif +} + void VID_CheckRenderer(void) { + boolean rendererchanged = false; + boolean contextcreated = false; + rendermode_t oldrenderer = rendermode; + if (dedicated) return; if (setrenderneeded) { rendermode = setrenderneeded; - Impl_CreateContext(); + rendererchanged = true; + +#ifdef HWRENDER + if (rendermode == render_opengl) + { + VID_CheckGLLoaded(oldrenderer); + + // Initialise OpenGL before calling SDLSetMode!!! + // This is because SDLSetMode calls OglSdlSurface. + if (vid_opengl_state == 0) + { + VID_StartupOpenGL(); + // Loaded successfully! + if (vid_opengl_state == 1) + { + // Destroy the current window, if it exists. + if (window) + { + SDL_DestroyWindow(window); + window = NULL; + } + + // Destroy the current window rendering context, if that also exists. + if (renderer) + { + SDL_DestroyRenderer(renderer); + renderer = NULL; + } + + // Create a new window. + Impl_CreateWindow(USE_FULLSCREEN); + + // From there, the OpenGL context was already created. + contextcreated = true; + } + } + else if (vid_opengl_state == -1) + rendererchanged = false; + } +#endif + + if (!contextcreated) + Impl_CreateContext(); + + setrenderneeded = 0; } - SDLSetMode(vid.width, vid.height, USE_FULLSCREEN); + SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, (rendererchanged ? SDL_FALSE : SDL_TRUE)); Impl_VideoSetupBuffer(); if (rendermode == render_soft) @@ -1489,17 +1564,27 @@ void VID_CheckRenderer(void) SDL_FreeSurface(bufSurface); bufSurface = NULL; } + + if (rendererchanged) + { #ifdef HWRENDER - HWR_FreeTextureCache(); + if (vid_opengl_state == 1) // Only if OpenGL ever loaded! + HWR_FreeTextureCache(); #endif - SCR_SetDrawFuncs(); + SCR_SetDrawFuncs(); + } } #ifdef HWRENDER else if (rendermode == render_opengl) { - I_StartupHardwareGraphics(); - R_InitHardwareMode(); + if (rendererchanged) + { + R_InitHardwareMode(); + V_SetPalette(0); + } } +#else + (void)oldrenderer; #endif } @@ -1541,19 +1626,23 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) flags |= SDL_WINDOW_BORDERLESS; #ifdef HWRENDER - flags |= SDL_WINDOW_OPENGL; + if (vid_opengl_state == 1) + flags |= SDL_WINDOW_OPENGL; #endif // Create a window window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, realwidth, realheight, flags); + if (window == NULL) { CONS_Printf(M_GetText("Couldn't create window: %s\n"), SDL_GetError()); return SDL_FALSE; } + Impl_SetWindowIcon(); + return Impl_CreateContext(); } @@ -1570,12 +1659,8 @@ static void Impl_SetWindowName(const char *title) static void Impl_SetWindowIcon(void) { - if (window == NULL || icoSurface == NULL) - { - return; - } - //SDL2STUB(); // Monster Iestyn: why is this stubbed? - SDL_SetWindowIcon(window, icoSurface); + if (window && icoSurface) + SDL_SetWindowIcon(window, icoSurface); } static void Impl_VideoSetupSDLBuffer(void) @@ -1664,20 +1749,29 @@ void I_StartupGraphics(void) #ifdef HWRENDER if (M_CheckParm("-opengl")) - rendermode = render_opengl; + chosenrendermode = rendermode = render_opengl; else if (M_CheckParm("-software")) #endif - rendermode = render_soft; + chosenrendermode = rendermode = render_soft; usesdl2soft = M_CheckParm("-softblit"); borderlesswindow = M_CheckParm("-borderless"); //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2); VID_Command_ModeList_f(); + #ifdef HWRENDER - I_StartupHardwareGraphics(); + if (M_CheckParm("-nogl")) + vid_opengl_state = -1; // Don't startup OpenGL + else if (chosenrendermode == render_opengl) + VID_StartupOpenGL(); #endif + // Window icon +#ifdef HAVE_IMAGE + icoSurface = IMG_ReadXPMFromArray(SDL_icon_xpm); +#endif + // Fury: we do window initialization after GL setup to allow // SDL_GL_LoadLibrary to work well on Windows @@ -1696,11 +1790,6 @@ void I_StartupGraphics(void) #ifdef HAVE_TTF I_ShutdownTTF(); #endif - // Window icon -#ifdef HAVE_IMAGE - icoSurface = IMG_ReadXPMFromArray(SDL_icon_xpm); -#endif - Impl_SetWindowIcon(); VID_SetMode(VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT)); @@ -1730,20 +1819,23 @@ void I_StartupGraphics(void) graphics_started = true; } -void I_StartupHardwareGraphics(void) +void VID_StartupOpenGL(void) { #ifdef HWRENDER static boolean glstartup = false; if (!glstartup) { + CONS_Printf("VID_StartupOpenGL()...\n"); HWD.pfnInit = hwSym("Init",NULL); HWD.pfnFinishUpdate = NULL; HWD.pfnDraw2DLine = hwSym("Draw2DLine",NULL); HWD.pfnDrawPolygon = hwSym("DrawPolygon",NULL); + HWD.pfnDrawIndexedTriangles = hwSym("DrawIndexedTriangles",NULL); HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL); HWD.pfnSetBlend = hwSym("SetBlend",NULL); HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); + HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); @@ -1753,7 +1845,6 @@ void I_StartupHardwareGraphics(void) HWD.pfnDrawModel = hwSym("DrawModel",NULL); HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); HWD.pfnSetTransform = hwSym("SetTransform",NULL); - HWD.pfnGetRenderVersion = hwSym("GetRenderVersion",NULL); HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); @@ -1763,13 +1854,24 @@ void I_StartupHardwareGraphics(void) HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); - // check gl renderer lib - if (HWD.pfnGetRenderVersion() != VERSION) - I_Error("%s", M_GetText("The version of the renderer doesn't match the version of the executable\nBe sure you have installed SRB2 properly.\n")); - if (!HWD.pfnInit(I_Error)) // let load the OpenGL library + + HWD.pfnLoadShaders = hwSym("LoadShaders",NULL); + HWD.pfnKillShaders = hwSym("KillShaders",NULL); + HWD.pfnSetShader = hwSym("SetShader",NULL); + HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); + + HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); + HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); + HWD.pfnInitCustomShaders= hwSym("InitCustomShaders",NULL); + + vid_opengl_state = HWD.pfnInit() ? 1 : -1; // let load the OpenGL library + + if (vid_opengl_state == -1) + { rendermode = render_soft; - else - glstartup = true; + setrenderneeded = 0; + } + glstartup = true; } #endif } diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index 2b03cb8d4..745513eeb 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1219,7 +1219,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.2.1; + CURRENT_PROJECT_VERSION = 2.2.4; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1231,7 +1231,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.2.1; + CURRENT_PROJECT_VERSION = 2.2.4; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -1272,7 +1272,6 @@ HAVE_SDL, HAVE_MIXER, HAVE_PNG, - HAVE_BLUA, LUA_USE_POSIX, COMPVERSION, HWRENDER, @@ -1395,7 +1394,6 @@ HAVE_SDL, HAVE_MIXER, HAVE_PNG, - HAVE_BLUA, LUA_USE_POSIX, COMPVERSION, HWRENDER, diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index b60dab14c..ef34b266d 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -219,6 +219,28 @@ static void var_cleanup(void) internal_volume = 100; } + +static const char* get_zlib_error(int zErr) +{ + switch (zErr) + { + case Z_ERRNO: + return "Z_ERRNO"; + case Z_STREAM_ERROR: + return "Z_STREAM_ERROR"; + case Z_DATA_ERROR: + return "Z_DATA_ERROR"; + case Z_MEM_ERROR: + return "Z_MEM_ERROR"; + case Z_BUF_ERROR: + return "Z_BUF_ERROR"; + case Z_VERSION_ERROR: + return "Z_VERSION_ERROR"; + default: + return "unknown error"; + } +} + /// ------------------------ /// Audio System /// ------------------------ @@ -475,7 +497,7 @@ void *I_GetSfx(sfxinfo_t *sfx) zErr = inflate(&stream, Z_FINISH); if (zErr == Z_STREAM_END) { // Run GME on new data - if (!gme_open_data(inflatedData, inflatedLen, &emu, 44100)) + if (!gme_open_data(inflatedData, inflatedLen, &emu, SAMPLERATE)) { short *mem; UINT32 len; @@ -498,58 +520,18 @@ void *I_GetSfx(sfxinfo_t *sfx) } } else - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg); - } + CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", get_zlib_error(zErr), stream.msg); (void)inflateEnd(&stream); } else // Hold up, zlib's got a problem - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg); - } + CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", get_zlib_error(zErr), stream.msg); Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up #else return NULL; // No zlib support #endif } // Try to read it as a GME sound - else if (!gme_open_data(lump, sfx->length, &emu, 44100)) + else if (!gme_open_data(lump, sfx->length, &emu, SAMPLERATE)) { short *mem; UINT32 len; @@ -880,13 +862,18 @@ boolean I_SetSongSpeed(float speed) #ifdef HAVE_OPENMPT if (openmpt_mhandle) { - 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); +#if OPENMPT_API_VERSION_MAJOR < 1 && OPENMPT_API_VERSION_MINOR < 5 + { + // deprecated in 0.5.0 + char modspd[13]; + sprintf(modspd, "%g", speed); + openmpt_module_ctl_set(openmpt_mhandle, "play.tempo_factor", modspd); + } +#else + openmpt_module_ctl_set_floatingpoint(openmpt_mhandle, "play.tempo_factor", (double)speed); +#endif return true; } #else @@ -1170,77 +1157,30 @@ boolean I_LoadSong(char *data, size_t len) if (zErr == Z_OK) // We're good to go { zErr = inflate(&stream, Z_FINISH); - if (zErr == Z_STREAM_END) { + if (zErr == Z_STREAM_END) + { // Run GME on new data - if (!gme_open_data(inflatedData, inflatedLen, &gme, 44100)) + if (!gme_open_data(inflatedData, inflatedLen, &gme, SAMPLERATE)) { - gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; - gme_start_track(gme, 0); - current_track = 0; - gme_set_equalizer(gme, &eq); - Mix_HookMusic(mix_gme, gme); Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around return true; } } else - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg); - } + CONS_Alert(CONS_ERROR, "Encountered %s when running inflate: %s\n", get_zlib_error(zErr), stream.msg); (void)inflateEnd(&stream); } else // Hold up, zlib's got a problem - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg); - } + CONS_Alert(CONS_ERROR, "Encountered %s when running inflateInit: %s\n", get_zlib_error(zErr), stream.msg); Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up + return false; #else - CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); - return true; + CONS_Alert(CONS_ERROR, "Cannot decompress VGZ; no zlib support\n"); + return false; #endif } - else if (!gme_open_data(data, len, &gme, 44100)) - { - gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; - gme_set_equalizer(gme, &eq); + else if (!gme_open_data(data, len, &gme, SAMPLERATE)) return true; - } #endif #ifdef HAVE_MIXERX @@ -1355,6 +1295,8 @@ boolean I_PlaySong(boolean looping) #ifdef HAVE_LIBGME if (gme) { + gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; + gme_set_equalizer(gme, &eq); gme_start_track(gme, 0); current_track = 0; Mix_HookMusic(mix_gme, gme); diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 6c0dd35a5..edc69b21d 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -37,6 +37,7 @@ #ifdef HWRENDER #include "../hardware/r_opengl/r_opengl.h" +#include "../hardware/hw_main.h" #include "ogl_sdl.h" #include "../i_system.h" #include "hwsym_sdl.h" @@ -90,15 +91,15 @@ boolean LoadGL(void) const char *OGLLibname = NULL; const char *GLULibname = NULL; - if (M_CheckParm ("-OGLlib") && M_IsNextParm()) + if (M_CheckParm("-OGLlib") && M_IsNextParm()) OGLLibname = M_GetNextParm(); if (SDL_GL_LoadLibrary(OGLLibname) != 0) { - I_OutputMsg("Could not load OpenGL Library: %s\n" + CONS_Alert(CONS_ERROR, "Could not load OpenGL Library: %s\n" "Falling back to Software mode.\n", SDL_GetError()); - if (!M_CheckParm ("-OGLlib")) - I_OutputMsg("If you know what is the OpenGL library's name, use -OGLlib\n"); + if (!M_CheckParm("-OGLlib")) + CONS_Printf("If you know what is the OpenGL library's name, use -OGLlib\n"); return 0; } @@ -118,7 +119,7 @@ boolean LoadGL(void) GLULibname = NULL; #endif - if (M_CheckParm ("-GLUlib") && M_IsNextParm()) + if (M_CheckParm("-GLUlib") && M_IsNextParm()) GLULibname = M_GetNextParm(); if (GLULibname) @@ -128,15 +129,15 @@ boolean LoadGL(void) return SetupGLfunc(); else { - I_OutputMsg("Could not load GLU Library: %s\n", GLULibname); + CONS_Alert(CONS_ERROR, "Could not load GLU Library: %s\n", GLULibname); if (!M_CheckParm ("-GLUlib")) - I_OutputMsg("If you know what is the GLU library's name, use -GLUlib\n"); + CONS_Alert(CONS_ERROR, "If you know what is the GLU library's name, use -GLUlib\n"); } } else { - I_OutputMsg("Could not load GLU Library\n"); - I_OutputMsg("If you know what is the GLU library's name, use -GLUlib\n"); + CONS_Alert(CONS_ERROR, "Could not load GLU Library\n"); + CONS_Alert(CONS_ERROR, "If you know what is the GLU library's name, use -GLUlib\n"); } #endif return SetupGLfunc(); @@ -152,31 +153,29 @@ boolean LoadGL(void) */ boolean OglSdlSurface(INT32 w, INT32 h) { - INT32 cbpp; - const GLvoid *glvendor = NULL, *glrenderer = NULL, *glversion = NULL; + INT32 cbpp = cv_scr_depth.value < 16 ? 16 : cv_scr_depth.value; + static boolean first_init = false; - cbpp = cv_scr_depth.value < 16 ? 16 : cv_scr_depth.value; - - glvendor = pglGetString(GL_VENDOR); - // Get info and extensions. - //BP: why don't we make it earlier ? - //Hurdler: we cannot do that before intialising gl context - glrenderer = pglGetString(GL_RENDERER); - glversion = pglGetString(GL_VERSION); - gl_extensions = pglGetString(GL_EXTENSIONS); - - DBG_Printf("Vendor : %s\n", glvendor); - DBG_Printf("Renderer : %s\n", glrenderer); - DBG_Printf("Version : %s\n", glversion); - DBG_Printf("Extensions : %s\n", gl_extensions); oglflags = 0; + if (!first_init) + { + gl_version = pglGetString(GL_VERSION); + gl_renderer = pglGetString(GL_RENDERER); + gl_extensions = pglGetString(GL_EXTENSIONS); + + GL_DBG_Printf("OpenGL %s\n", gl_version); + GL_DBG_Printf("GPU: %s\n", gl_renderer); + GL_DBG_Printf("Extensions: %s\n", gl_extensions); + } + first_init = true; + if (isExtAvailable("GL_EXT_texture_filter_anisotropic", gl_extensions)) pglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maximumAnisotropy); else maximumAnisotropy = 1; - SetupGLFunc13(); + SetupGLFunc4(); granisotropicmode_cons_t[1].value = maximumAnisotropy; @@ -222,7 +221,7 @@ void OglSdlFinishUpdate(boolean waitvbl) HWR_DrawScreenFinalTexture(realwidth, realheight); } -EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette) +EXPORT void HWRAPI(OglSdlSetPalette) (RGBA_t *palette) { size_t palsize = (sizeof(RGBA_t) * 256); // on a palette change, you have to reload all of the textures diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h index 88d7d0b6c..748e30bae 100644 --- a/src/sdl/ogl_sdl.h +++ b/src/sdl/ogl_sdl.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index b8991293c..86e294fb5 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 2014-2019 by Sonic Team Junior. +// Copyright (C) 2014-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index bdafebfe9..e35506114 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// Copyright (C) 2006-2019 by Sonic Team Junior. +// Copyright (C) 2006-2020 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/sounds.c b/src/sounds.c index 720ba851e..9894fd13e 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,7 +15,7 @@ #include "i_sound.h" #include "sounds.h" #include "r_defs.h" -#include "r_things.h" +#include "r_skins.h" #include "z_zone.h" #include "w_wad.h" #include "lua_script.h" @@ -527,7 +527,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k8a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boing"}, {"s3k8b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful hit"}, {"s3k8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Humming power"}, - {"s3k8d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s3k8d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "/"}, {"s3k8e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accelerating"}, {"s3k8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Opening"}, {"s3k90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"}, diff --git a/src/sounds.h b/src/sounds.h index 039349d4f..e49dd2f3e 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/st_stuff.c b/src/st_stuff.c index c1b1ff6e6..3ab9a5eab 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -42,9 +42,7 @@ #include "hardware/hw_main.h" #endif -#ifdef HAVE_BLUA #include "lua_hud.h" -#endif UINT16 objectsdrawn = 0; @@ -458,7 +456,7 @@ boolean st_overlay; // // Supports different colors! woo! static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fixed_t s, INT32 a, - UINT32 num, patch_t **numpat, skincolors_t colornum) + UINT32 num, patch_t **numpat, skincolornum_t colornum) { fixed_t w = SHORT(numpat[0]->width)*s; const UINT8 *colormap; @@ -765,7 +763,7 @@ static void ST_drawTime(void) ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon, V_HUDTRANS); // Colon ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2, V_HUDTRANS); // Seconds - if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! + if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking || marathonmode) { ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod, V_HUDTRANS); // Period ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2, V_HUDTRANS); // Tics @@ -969,11 +967,7 @@ static void ST_drawLivesArea(void) V_DrawThinString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); // Power Stones collected - if (G_RingSlingerGametype() -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_powerstones) -#endif - ) + if (G_RingSlingerGametype() && LUA_HudEnabled(hud_powerstones)) { INT32 workx = hudinfo[HUD_LIVES].x+1, j; if ((leveltime & 1) && stplyr->powers[pw_invulnerability] && (stplyr->powers[pw_sneakers] == stplyr->powers[pw_invulnerability])) // hack; extremely unlikely to be activated unintentionally @@ -998,7 +992,7 @@ static void ST_drawLivesArea(void) static void ST_drawInput(void) { - const INT32 accent = V_SNAPTOLEFT|V_SNAPTOBOTTOM|(stplyr->skincolor ? Color_Index[stplyr->skincolor-1][4] : 0); + const INT32 accent = V_SNAPTOLEFT|V_SNAPTOBOTTOM|(stplyr->skincolor ? skincolors[stplyr->skincolor].ramp[4] : 0); INT32 col; UINT8 offs; @@ -1331,27 +1325,30 @@ void ST_drawTitleCard(void) { char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; char *subttl = mapheaderinfo[gamemap-1]->subttl; - INT32 actnum = mapheaderinfo[gamemap-1]->actnum; + UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; INT32 lvlttlxpos, ttlnumxpos, zonexpos; INT32 subttlxpos = BASEVIDWIDTH/2; INT32 ttlscroll = FixedInt(lt_scroll); INT32 zzticker; patch_t *actpat, *zigzag, *zztext; + UINT8 colornum; + const UINT8 *colormap; + + if (players[consoleplayer].skincolor) + colornum = players[consoleplayer].skincolor; + else + colornum = cv_playercolor.value; + + colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE); if (!G_IsTitleCardAvailable()) return; -#ifdef HAVE_BLUA if (!LUA_HudEnabled(hud_stagetitle)) goto luahook; -#endif if (lt_ticker >= (lt_endtime + TICRATE)) -#ifdef HAVE_BLUA goto luahook; -#else - return; -#endif if ((lt_ticker-lt_lasttic) > 1) lt_ticker = lt_lasttic+1; @@ -1376,16 +1373,21 @@ void ST_drawTitleCard(void) if (!splitscreen || (splitscreen && stplyr == &players[displayplayer])) { zzticker = lt_ticker; - V_DrawScaledPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag); - V_DrawScaledPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag); - V_DrawScaledPatch(FixedInt(lt_zigzag), (-zigzag->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext); - V_DrawScaledPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext); + V_DrawMappedPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); + V_DrawMappedPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); + V_DrawMappedPatch(FixedInt(lt_zigzag), (-zigzag->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); + V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); } if (actnum) { if (!splitscreen) - V_DrawScaledPatch(ttlnumxpos + ttlscroll, 104 - ttlscroll, 0, actpat); + { + if (actnum > 9) // slightly offset the act diamond for two-digit act numbers + V_DrawMappedPatch(ttlnumxpos + (V_LevelActNumWidth(actnum)/4) + ttlscroll, 104 - ttlscroll, 0, actpat, colormap); + else + V_DrawMappedPatch(ttlnumxpos + ttlscroll, 104 - ttlscroll, 0, actpat, colormap); + } V_DrawLevelActNum(ttlnumxpos + ttlscroll, 104, V_PERPLAYER, actnum); } @@ -1396,10 +1398,8 @@ void ST_drawTitleCard(void) lt_lasttic = lt_ticker; -#ifdef HAVE_BLUA luahook: LUAh_TitleCardHUD(stplyr); -#endif } // @@ -1444,13 +1444,13 @@ static void ST_drawPowerupHUD(void) if (stplyr->spectator || stplyr->playerstate != PST_LIVE) return; - + // --------- // Finish icon // --------- // Let's have a power-like icon to represent finishing the level! - if (stplyr->pflags & PF_FINISHED && cv_exitmove.value) + if (stplyr->pflags & PF_FINISHED && cv_exitmove.value && multiplayer) { finishoffs[q] = ICONSEP; V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, fnshico); @@ -1700,14 +1700,14 @@ static void ST_drawNightsRecords(void) // 2.0-1: [21:42] <+Rob> Beige - Lavender - Steel Blue - Peach - Orange - Purple - Silver - Yellow - Pink - Red - Blue - Green - Cyan - Gold /*#define NUMLINKCOLORS 14 -static skincolors_t linkColor[NUMLINKCOLORS] = +static skincolornum_t linkColor[NUMLINKCOLORS] = {SKINCOLOR_BEIGE, SKINCOLOR_LAVENDER, SKINCOLOR_AZURE, SKINCOLOR_PEACH, SKINCOLOR_ORANGE, SKINCOLOR_MAGENTA, SKINCOLOR_SILVER, SKINCOLOR_SUPERGOLD4, SKINCOLOR_PINK, SKINCOLOR_RED, SKINCOLOR_BLUE, SKINCOLOR_GREEN, SKINCOLOR_CYAN, SKINCOLOR_GOLD};*/ // 2.2 indev list: (unix time 1470866042) Emerald, Aqua, Cyan, Blue, Pastel, Purple, Magenta, Rosy, Red, Orange, Gold, Yellow, Peridot /*#define NUMLINKCOLORS 13 -static skincolors_t linkColor[NUMLINKCOLORS] = +static skincolornum_t linkColor[NUMLINKCOLORS] = {SKINCOLOR_EMERALD, SKINCOLOR_AQUA, SKINCOLOR_CYAN, SKINCOLOR_BLUE, SKINCOLOR_PASTEL, SKINCOLOR_PURPLE, SKINCOLOR_MAGENTA, SKINCOLOR_ROSY, SKINCOLOR_RED, SKINCOLOR_ORANGE, SKINCOLOR_GOLD, SKINCOLOR_YELLOW, SKINCOLOR_PERIDOT};*/ @@ -1716,7 +1716,7 @@ static skincolors_t linkColor[NUMLINKCOLORS] = // [20:00:25] Also Icy for the link freeze text color // [20:04:03] I would start it on lime /*#define NUMLINKCOLORS 18 -static skincolors_t linkColor[NUMLINKCOLORS] = +static skincolornum_t linkColor[NUMLINKCOLORS] = {SKINCOLOR_LIME, SKINCOLOR_EMERALD, SKINCOLOR_AQUA, SKINCOLOR_CYAN, SKINCOLOR_SKY, SKINCOLOR_SAPPHIRE, SKINCOLOR_PASTEL, SKINCOLOR_PURPLE, SKINCOLOR_BUBBLEGUM, SKINCOLOR_MAGENTA, SKINCOLOR_ROSY, SKINCOLOR_RUBY, SKINCOLOR_RED, SKINCOLOR_FLAME, SKINCOLOR_SUNSET, @@ -1724,7 +1724,7 @@ static skincolors_t linkColor[NUMLINKCOLORS] = // 2.2+ list for real this time: https://wiki.srb2.org/wiki/User:Rob/Sandbox (check history around 31/10/17, spoopy) #define NUMLINKCOLORS 12 -static skincolors_t linkColor[2][NUMLINKCOLORS] = { +static skincolornum_t linkColor[2][NUMLINKCOLORS] = { {SKINCOLOR_EMERALD, SKINCOLOR_AQUA, SKINCOLOR_SKY, SKINCOLOR_BLUE, SKINCOLOR_PURPLE, SKINCOLOR_MAGENTA, SKINCOLOR_ROSY, SKINCOLOR_RED, SKINCOLOR_ORANGE, SKINCOLOR_GOLD, SKINCOLOR_YELLOW, SKINCOLOR_PERIDOT}, {SKINCOLOR_SEAFOAM, SKINCOLOR_CYAN, SKINCOLOR_WAVE, SKINCOLOR_SAPPHIRE, SKINCOLOR_VAPOR, SKINCOLOR_BUBBLEGUM, @@ -1735,7 +1735,7 @@ static void ST_drawNiGHTSLink(void) static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0}; const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0); INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? 1 : 0); - skincolors_t colornum; + skincolornum_t colornum; fixed_t x, y, scale; if (sel != prevsel[q]) @@ -1785,11 +1785,7 @@ static void ST_drawNiGHTSHUD(void) const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS)); // Drill meter - if ( -#ifdef HAVE_BLUA - LUA_HudEnabled(hud_nightsdrill) && -#endif - stplyr->powers[pw_carry] == CR_NIGHTSMODE) + if (LUA_HudEnabled(hud_nightsdrill) && stplyr->powers[pw_carry] == CR_NIGHTSMODE) { INT32 locx = 16, locy = 180; INT32 dfill; @@ -1831,9 +1827,7 @@ static void ST_drawNiGHTSHUD(void) if (!oldspecialstage // Don't display when the score is showing (it popping up for a split second when exiting a map is intentional) && !(stplyr->texttimer && stplyr->textvar == 4) -#ifdef HAVE_BLUA && LUA_HudEnabled(hud_nightslink) -#endif && ((cv_debug & DBG_NIGHTSBASIC) || stplyr->linkcount > 1)) // When debugging, show "0 Link". { ST_drawNiGHTSLink(); @@ -1847,10 +1841,8 @@ static void ST_drawNiGHTSHUD(void) } // Begin drawing brackets/chip display -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_nightsspheres)) { -#endif ST_DrawTopLeftOverlayPatch(16, 8, nbracket); if (G_IsSpecialStage(gamemap)) ST_DrawTopLeftOverlayPatch(24, 16, ( @@ -1987,24 +1979,14 @@ static void ST_drawNiGHTSHUD(void) V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount); else V_DrawTallNum(68, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount); -#ifdef HAVE_BLUA } -#endif // Score - if (!stplyr->exiting && !oldspecialstage -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_nightsscore) -#endif - ) + if (!stplyr->exiting && !oldspecialstage && LUA_HudEnabled(hud_nightsscore)) ST_DrawNightsOverlayNum(304<marescore, nightsnum, SKINCOLOR_AZURE); - if (!stplyr->exiting -#ifdef HAVE_BLUA // TODO give this its own section for Lua - && LUA_HudEnabled(hud_nightsscore) -#endif - ) + if (!stplyr->exiting && LUA_HudEnabled(hud_nightsscore)) { if (modeattacking == ATTACKING_NIGHTS) { @@ -2027,11 +2009,7 @@ static void ST_drawNiGHTSHUD(void) } // Ideya time remaining - if (!stplyr->exiting && stplyr->nightstime > 0 -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_nightstime) -#endif - ) + if (!stplyr->exiting && stplyr->nightstime > 0 && LUA_HudEnabled(hud_nightstime)) { INT32 realnightstime = stplyr->nightstime/TICRATE; INT32 numbersize; @@ -2122,10 +2100,8 @@ static void ST_drawNiGHTSHUD(void) } // Records/extra text -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_nightsrecords)) -#endif - ST_drawNightsRecords(); + ST_drawNightsRecords(); } } @@ -2239,7 +2215,7 @@ static void ST_drawTextHUD(void) if (F_GetPromptHideHud(y)) return; - if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) + if (stplyr->spectator && (!G_CoopGametype() || stplyr->playerstate == PST_LIVE)) textHUDdraw(M_GetText("\x86""Spectator mode:")) if (circuitmap) @@ -2250,7 +2226,7 @@ static void ST_drawTextHUD(void) textHUDdraw(va("Lap:""\x82 %u/%d", stplyr->laps+1, cv_numlaps.value)) } - if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) + if (!G_CoopGametype() && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) { if (!splitscreen && !donef12) { @@ -2267,7 +2243,7 @@ static void ST_drawTextHUD(void) else textHUDdraw(M_GetText("\x82""JUMP:""\x80 Respawn")) } - else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) + else if (stplyr->spectator && (!G_CoopGametype() || stplyr->playerstate == PST_LIVE)) { if (!splitscreen && !donef12) { @@ -2314,7 +2290,7 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) } - if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && (stplyr->exiting || (stplyr->pflags & PF_FINISHED))) + if (G_CoopGametype() && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && (stplyr->exiting || (stplyr->pflags & PF_FINISHED))) { UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); if (numneeded) @@ -2363,20 +2339,19 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""You are blindfolded!")) textHUDdraw(M_GetText("Waiting for players to hide...")) } - else if (gametype == GT_HIDEANDSEEK) + else if (gametyperules & GTR_HIDEFROZEN) textHUDdraw(M_GetText("Hide before time runs out!")) else textHUDdraw(M_GetText("Flee before you are hunted!")) } - else if (gametype == GT_HIDEANDSEEK && !(stplyr->pflags & PF_TAGIT)) + else if ((gametyperules & GTR_HIDEFROZEN) && !(stplyr->pflags & PF_TAGIT)) { if (!splitscreen && !donef12) { textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) donef12 = true; } - if (gametyperules & GTR_HIDEFROZEN) - textHUDdraw(M_GetText("You cannot move while hiding.")) + textHUDdraw(M_GetText("You cannot move while hiding.")) } } @@ -2403,20 +2378,16 @@ static void ST_drawTeamHUD(void) else p = bmatcico; -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_teamscores)) -#endif - V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); if (gametyperules & GTR_TEAMFLAGS) p = rflagico; else p = rmatcico; -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_teamscores)) -#endif - V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); if (!(gametyperules & GTR_TEAMFLAGS)) goto num; @@ -2427,18 +2398,12 @@ static void ST_drawTeamHUD(void) // Show which flags aren't at base. for (i = 0; i < MAXPLAYERS; i++) { - if (players[i].gotflag & GF_BLUEFLAG // Blue flag isn't at base -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_teamscores) -#endif - ) + // Blue flag isn't at base + if (players[i].gotflag & GF_BLUEFLAG && LUA_HudEnabled(hud_teamscores)) V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon); - if (players[i].gotflag & GF_REDFLAG // Red flag isn't at base -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_teamscores) -#endif - ) + // Red flag isn't at base + if (players[i].gotflag & GF_REDFLAG && LUA_HudEnabled(hud_teamscores)) V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2); whichflag |= players[i].gotflag; @@ -2449,32 +2414,20 @@ static void ST_drawTeamHUD(void) // Display a countdown timer showing how much time left until the flag returns to base. { - if (blueflag && blueflag->fuse > 1 -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_teamscores) -#endif - ) + if (blueflag && blueflag->fuse > 1 && LUA_HudEnabled(hud_teamscores)) V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (blueflag->fuse / TICRATE))); - if (redflag && redflag->fuse > 1 -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_teamscores) -#endif - ) + if (redflag && redflag->fuse > 1 && LUA_HudEnabled(hud_teamscores)) V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE))); } } num: -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_teamscores)) -#endif - V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore)); + V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore)); -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_teamscores)) -#endif - V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore)); + V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore)); #undef SEP } @@ -2661,34 +2614,24 @@ static void ST_overlayDrawer(void) ST_drawNiGHTSHUD(); else { -#ifdef HAVE_BLUA if (LUA_HudEnabled(hud_score)) -#endif - ST_drawScore(); -#ifdef HAVE_BLUA + ST_drawScore(); if (LUA_HudEnabled(hud_time)) -#endif - ST_drawTime(); -#ifdef HAVE_BLUA + ST_drawTime(); if (LUA_HudEnabled(hud_rings)) -#endif - ST_drawRings(); + ST_drawRings(); - if (!modeattacking -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_lives) -#endif - ) + if (!modeattacking && LUA_HudEnabled(hud_lives)) ST_drawLivesArea(); } } // GAME OVER hud - if ((gametype == GT_COOP) + if (G_GametypeUsesCoopLives() && (netgame || multiplayer) && (cv_cooplives.value == 0)) ; - else if ((G_GametypeUsesLives() || gametype == GT_RACE) && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) + else if ((G_GametypeUsesLives() || ((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE)) && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) { INT32 i = MAXPLAYERS; INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1)); @@ -2753,11 +2696,7 @@ static void ST_overlayDrawer(void) // Draw Match-related stuff //\note Match HUD is drawn no matter what gametype. // ... just not if you're a spectator. - if (!stplyr->spectator -#ifdef HAVE_BLUA - && (LUA_HudEnabled(hud_weaponrings)) -#endif - ) + if (!stplyr->spectator && LUA_HudEnabled(hud_weaponrings)) ST_drawMatchHUD(); // Race HUD Stuff @@ -2798,20 +2737,14 @@ static void ST_overlayDrawer(void) else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2) ST_drawPowerupHUD(); // same as it ever was... -#ifdef HAVE_BLUA if (!(netgame || multiplayer) || !hu_showscores) LUAh_GameHUD(stplyr); -#endif // draw level title Tails if (stagetitle && (!WipeInAction) && (!WipeStageTitle)) ST_drawTitleCard(); - if (!hu_showscores && (netgame || multiplayer) -#ifdef HAVE_BLUA - && LUA_HudEnabled(hud_textspectator) -#endif - ) + if (!hu_showscores && (netgame || multiplayer) && LUA_HudEnabled(hud_textspectator)) ST_drawTextHUD(); if (modeattacking && !(demoplayback && hu_showscores)) diff --git a/src/st_stuff.h b/src/st_stuff.h index e4b21b2b0..4ea307d2b 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/strcasestr.c b/src/strcasestr.c index 4ff778bf1..b266278ed 100644 --- a/src/strcasestr.c +++ b/src/strcasestr.c @@ -2,7 +2,7 @@ strcasestr -- case insensitive substring searching function. */ /* -Copyright 2019 James R. +Copyright 2019-2020 James R. All rights reserved. Redistribution and use in source forms, with or without modification, is diff --git a/src/string.c b/src/string.c index dc30529cc..e430c5cc3 100644 --- a/src/string.c +++ b/src/string.c @@ -1,8 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by Graue. -// Copyright (C) 2006-2019 by Sonic Team Junior. -// Copyright (C) 2019 by James R. +// Copyright (C) 2006-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tables.c b/src/tables.c index 72dfaf0c3..70a1ecd0a 100644 --- a/src/tables.c +++ b/src/tables.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -72,7 +72,7 @@ static FUNCMATH angle_t AngleAdj(const fixed_t fa, const fixed_t wf, const angle_t adj = 0x77; const boolean fan = fa < 0; const fixed_t sl = FixedDiv(fa, wf*2); - const fixed_t lb = FixedRem(fa, wf*2); + const fixed_t lb = fa % (wf*2); const fixed_t lo = (wf*2)-lb; if (ra == 0) diff --git a/src/tables.h b/src/tables.h index 07e3cdf09..953d891ce 100644 --- a/src/tables.h +++ b/src/tables.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tmap.nas b/src/tmap.nas index 79452ab8c..106f38e96 100644 --- a/src/tmap.nas +++ b/src/tmap.nas @@ -1,7 +1,7 @@ ;; SONIC ROBO BLAST 2 ;;----------------------------------------------------------------------------- ;; Copyright (C) 1998-2000 by DooM Legacy Team. -;; Copyright (C) 1999-2019 by Sonic Team Junior. +;; Copyright (C) 1999-2020 by Sonic Team Junior. ;; ;; This program is free software distributed under the ;; terms of the GNU General Public License, version 2. diff --git a/src/tmap.s b/src/tmap.s index cdd65eee3..3a4cf2e1a 100644 --- a/src/tmap.s +++ b/src/tmap.s @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tmap_asm.s b/src/tmap_asm.s index 067318f30..3cd0f87cc 100644 --- a/src/tmap_asm.s +++ b/src/tmap_asm.s @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tmap_mmx.nas b/src/tmap_mmx.nas index 843419c65..15b97499d 100644 --- a/src/tmap_mmx.nas +++ b/src/tmap_mmx.nas @@ -1,7 +1,7 @@ ;; SONIC ROBO BLAST 2 ;;----------------------------------------------------------------------------- ;; Copyright (C) 1998-2000 by DOSDOOM. -;; Copyright (C) 2010-2019 by Sonic Team Junior. +;; Copyright (C) 2010-2020 by Sonic Team Junior. ;; ;; This program is free software distributed under the ;; terms of the GNU General Public License, version 2. diff --git a/src/tmap_vc.nas b/src/tmap_vc.nas index 72ed9a530..49eb21a6d 100644 --- a/src/tmap_vc.nas +++ b/src/tmap_vc.nas @@ -1,7 +1,7 @@ ;; SONIC ROBO BLAST 2 ;;----------------------------------------------------------------------------- ;; Copyright (C) 1998-2000 by DooM Legacy Team. -;; Copyright (C) 1999-2019 by Sonic Team Junior. +;; Copyright (C) 1999-2020 by Sonic Team Junior. ;; ;; This program is free software distributed under the ;; terms of the GNU General Public License, version 2. diff --git a/src/v_video.c b/src/v_video.c index a1e702f7e..b88c4838b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -42,7 +42,8 @@ UINT8 *screens[5]; // screens[3] = fade screen start // screens[4] = fade screen end, postimage tempoarary buffer -consvar_t cv_ticrate = {"showfps", "No", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t ticrate_cons_t[] = {{0, "No"}, {1, "Full"}, {2, "Compact"}, {0, NULL}}; +consvar_t cv_ticrate = {"showfps", "No", CV_SAVE, ticrate_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static void CV_palette_OnChange(void); @@ -417,7 +418,7 @@ void V_SetPalette(INT32 palettenum) LoadMapPalette(); #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) HWR_SetPalette(&pLocalPalette[palettenum*256]); #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) else @@ -431,7 +432,7 @@ void V_SetPaletteLump(const char *pal) { LoadPalette(pal); #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) HWR_SetPalette(pLocalPalette); #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) else @@ -528,7 +529,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca #ifdef HWRENDER //if (rendermode != render_soft && !con_startup) // Why? - if (rendermode != render_soft) + if (rendermode == render_opengl) { HWR_DrawStretchyFixedPatch((GLPatch_t *)patch, x, y, pscale, vscale, scrn, colormap); return; @@ -828,7 +829,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ #ifdef HWRENDER //if (rendermode != render_soft && !con_startup) // Not this again - if (rendermode != render_soft) + if (rendermode == render_opengl) { HWR_DrawCroppedPatch((GLPatch_t*)patch,x,y,pscale,scrn,sx,sy,w,h); return; @@ -1039,7 +1040,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ // V_DrawContinueIcon // Draw a mini player! If we can, that is. Otherwise we draw a star. // -void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor) +void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor) { if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CONTINUE) { @@ -1152,7 +1153,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) #ifdef HWRENDER //if (rendermode != render_soft && !con_startup) // Not this again - if (rendermode != render_soft) + if (rendermode == render_opengl) { HWR_DrawFill(x, y, w, h, c); return; @@ -1349,7 +1350,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) return; #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { UINT32 hwcolor = V_GetHWConsBackColor(); HWR_DrawConsoleFill(x, y, w, h, c, hwcolor); // we still use the regular color stuff but only for flags. actual draw color is "hwcolor" for this. @@ -1546,7 +1547,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U return; #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { // ughhhhh please can someone else do this? thanks ~toast 25/7/19 in 38 degrees centigrade w/o AC HWR_DrawFadeFill(x, y, w, h, c, color, strength); // toast two days later - left above comment in 'cause it's funny @@ -1708,7 +1709,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum) size_t size, lflatsize, flatshift; #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { HWR_DrawFlatFill(x, y, w, h, flatnum); return; @@ -1818,7 +1819,7 @@ void V_DrawPatchFill(patch_t *pat) void V_DrawFadeScreen(UINT16 color, UINT8 strength) { #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { HWR_FadeScreenMenuBack(color, strength); return; @@ -1847,7 +1848,7 @@ void V_DrawFadeConsBack(INT32 plines) UINT8 *deststop, *buf; #ifdef HWRENDER // not win32 only 19990829 by Kin - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { UINT32 hwcolor = V_GetHWConsBackColor(); HWR_DrawConsoleBack(hwcolor, plines); @@ -1869,7 +1870,10 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) if (color >= 256 && color < 512) { - boxheight = ((boxheight * 4) + (boxheight/2)*5); + if (boxheight < 0) + boxheight = -boxheight; + else // 4 lines of space plus gaps between and some leeway + boxheight = ((boxheight * 4) + (boxheight/2)*5); V_DrawFill((BASEVIDWIDTH-(vid.width/vid.dupx))/2, BASEVIDHEIGHT-boxheight, (vid.width/vid.dupx),boxheight, (color-256)|V_SNAPTOBOTTOM); return; } @@ -1880,7 +1884,7 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) color = cons_backcolor.value; #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { UINT32 hwcolor; switch (color) @@ -1916,8 +1920,11 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) // heavily simplified -- we don't need to know x or y position, // just the start and stop positions - deststop = screens[0] + vid.rowbytes * vid.height; - buf = deststop - vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); // 4 lines of space plus gaps between and some leeway + buf = deststop = screens[0] + vid.rowbytes * vid.height; + if (boxheight < 0) + buf += vid.rowbytes * boxheight; + else // 4 lines of space plus gaps between and some leeway + buf -= vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); for (; buf < deststop; ++buf) *buf = promptbgmap[*buf]; } @@ -2951,13 +2958,19 @@ void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits) } // Draw an act number for a level title -// Todo: actually draw two-digit numbers as two act num patches -void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, INT32 num) +void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num) { - if (num < 0 || num > 19) + if (num > 99) return; // not supported - V_DrawScaledPatch(x, y, flags, ttlnum[num]); + while (num > 0) + { + if (num > 9) // if there are two digits, draw second digit first + V_DrawScaledPatch(x + (V_LevelActNumWidth(num) - V_LevelActNumWidth(num%10)), y, flags, ttlnum[num%10]); + else + V_DrawScaledPatch(x, y, flags, ttlnum[num]); + num = num/10; + } } // Write a string using the credit font @@ -3338,13 +3351,21 @@ INT32 V_LevelNameHeight(const char *string) } // For ST_drawTitleCard -// Returns the width of the act num patch -INT32 V_LevelActNumWidth(INT32 num) +// Returns the width of the act num patch(es) +INT16 V_LevelActNumWidth(UINT8 num) { - if (num < 0 || num > 19) - return 0; // not a valid number + INT16 result = 0; - return SHORT(ttlnum[num]->width); + if (num == 0) + result = SHORT(ttlnum[num]->width); + + while (num > 0 && num <= 99) + { + result = result + SHORT(ttlnum[num%10]->width); + num = num/10; + } + + return result; } // @@ -3491,8 +3512,7 @@ void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) INT32 height, yoffset; #ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) + if (rendermode != render_soft) return; #endif @@ -3695,7 +3715,7 @@ void V_Init(void) #ifdef DEBUG CONS_Debug(DBG_RENDER, "V_Init done:\n"); - for (i = 0; i < NUMSCREENS+1; i++) + for (i = 0; i < NUMSCREENS; i++) CONS_Debug(DBG_RENDER, " screens[%d] = %x\n", i, screens[i]); #endif } diff --git a/src/v_video.h b/src/v_video.h index 8e671f918..9f7a9a9e9 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -160,7 +160,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue); void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap); void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); -void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor); +void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor); // Draw a linear block of pixels into the view buffer. void V_DrawBlock(INT32 x, INT32 y, INT32 scrn, INT32 width, INT32 height, const UINT8 *src); @@ -238,12 +238,12 @@ void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option // Draw tall nums, used for menu, HUD, intermission void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num); void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits); -void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, INT32 num); +void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num); // Find string width from lt_font chars INT32 V_LevelNameWidth(const char *string); INT32 V_LevelNameHeight(const char *string); -INT32 V_LevelActNumWidth(INT32 num); // act number width +INT16 V_LevelActNumWidth(UINT8 num); // act number width void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string); INT32 V_CreditStringWidth(const char *string); diff --git a/src/vid_copy.s b/src/vid_copy.s index d40510208..eae435ea4 100644 --- a/src/vid_copy.s +++ b/src/vid_copy.s @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/w_wad.c b/src/w_wad.c index 95531dda3..9af661b57 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -76,6 +76,10 @@ int snprintf(char *str, size_t n, const char *fmt, ...); //int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); #endif +#ifdef _DEBUG +#include "console.h" +#endif + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -92,7 +96,7 @@ typedef struct typedef struct lumpnum_cache_s { - char lumpname[8]; + char lumpname[32]; lumpnum_t lumpnum; } lumpnum_cache_t; @@ -114,13 +118,18 @@ void W_Shutdown(void) { while (numwadfiles--) { - fclose(wadfiles[numwadfiles]->handle); - Z_Free(wadfiles[numwadfiles]->filename); - while (wadfiles[numwadfiles]->numlumps--) - Z_Free(wadfiles[numwadfiles]->lumpinfo[wadfiles[numwadfiles]->numlumps].name2); + wadfile_t *wad = wadfiles[numwadfiles]; - Z_Free(wadfiles[numwadfiles]->lumpinfo); - Z_Free(wadfiles[numwadfiles]); + fclose(wad->handle); + Z_Free(wad->filename); + while (wad->numlumps--) + { + Z_Free(wad->lumpinfo[wad->numlumps].longname); + Z_Free(wad->lumpinfo[wad->numlumps].fullname); + } + + Z_Free(wad->lumpinfo); + Z_Free(wad); } } @@ -189,28 +198,34 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile) { UINT16 posStart, posEnd; -#ifdef HAVE_BLUA - posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0); + + posStart = W_CheckNumForFullNamePK3("Init.lua", wadnum, 0); if (posStart != INT16_MAX) { - posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); - posStart++; // first "lump" will be "Lua/" folder itself, so ignore it - for (; posStart < posEnd; posStart++) - LUA_LoadLump(wadnum, posStart); + LUA_LoadLump(wadnum, posStart, true); } -#endif + else + { + posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0); + if (posStart != INT16_MAX) + { + posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); + for (; posStart < posEnd; posStart++) + LUA_LoadLump(wadnum, posStart, true); + } + } + posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0); if (posStart != INT16_MAX) { posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart); - posStart++; // first "lump" will be "SOC/" folder itself, so ignore it for(; posStart < posEnd; posStart++) { lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart]; - size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name + size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name char *name = malloc(length + 1); - sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2); + sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname); name[length] = '\0'; CONS_Printf(M_GetText("Loading SOC from %s\n"), name); DEH_LoadDehackedLumpPwad(wadnum, posStart, mainfile); @@ -224,24 +239,22 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) { UINT16 lump; -#ifdef HAVE_BLUA // Find Lua scripts before SOCs to allow new A_Actions in SOC editing. { lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo; for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) if (memcmp(lump_p->name,"LUA_",4)==0) - LUA_LoadLump(wadnum, lump); + LUA_LoadLump(wadnum, lump, true); } -#endif { lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo; for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump { // shameless copy+paste of code from LUA_LoadLump - size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name + size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name char *name = malloc(length + 1); - sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2); + sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname); name[length] = '\0'; CONS_Printf(M_GetText("Loading SOC from %s\n"), name); @@ -343,10 +356,17 @@ static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const lumpinfo->size = ftell(handle); fseek(handle, 0, SEEK_SET); strcpy(lumpinfo->name, lumpname); + + // Allocate the lump's long name. + lumpinfo->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strcpy(lumpinfo->longname, lumpname); + lumpinfo->longname[8] = '\0'; + // Allocate the lump's full name. - lumpinfo->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); - strcpy(lumpinfo->name2, lumpname); - lumpinfo->name2[8] = '\0'; + lumpinfo->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strcpy(lumpinfo->fullname, lumpname); + lumpinfo->fullname[8] = '\0'; + *numlumps = 1; return lumpinfo; } @@ -433,10 +453,16 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen lump_p->compression = CM_NOCOMPRESSION; memset(lump_p->name, 0x00, 9); strncpy(lump_p->name, fileinfo->name, 8); + + // Allocate the lump's long name. + lump_p->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->longname, fileinfo->name, 8); + lump_p->longname[8] = '\0'; + // Allocate the lump's full name. - lump_p->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); - strncpy(lump_p->name2, fileinfo->name, 8); - lump_p->name2[8] = '\0'; + lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->fullname, fileinfo->name, 8); + lump_p->fullname[8] = '\0'; } free(fileinfov); *nlmp = numlumps; @@ -527,8 +553,8 @@ typedef struct zlentry_s static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) { zend_t zend; - zentry_t* zentries; - zentry_t* zentry; + zentry_t zentry; + zlentry_t zlentry; UINT16 numlumps = *nlmp; lumpinfo_t* lumpinfo; @@ -556,40 +582,36 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) numlumps = zend.entries; lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL); - zentry = zentries = malloc(numlumps * sizeof (*zentries)); fseek(handle, zend.cdiroffset, SEEK_SET); - for (i = 0; i < numlumps; i++, zentry++, lump_p++) + for (i = 0; i < numlumps; i++, lump_p++) { char* fullname; char* trimname; char* dotpos; - if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t)) + if (fread(&zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t)) { CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle)); Z_Free(lumpinfo); - free(zentries); return NULL; } - if (memcmp(zentry->signature, pat_central, 4)) + if (memcmp(zentry.signature, pat_central, 4)) { CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); Z_Free(lumpinfo); - free(zentries); return NULL; } - lump_p->position = zentry->offset + zentry->namelen + zentry->xtralen + sizeof(zlentry_t); - lump_p->disksize = zentry->compsize; - lump_p->size = zentry->size; + lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position + lump_p->disksize = zentry.compsize; + lump_p->size = zentry.size; - fullname = malloc(zentry->namelen + 1); - if (fgets(fullname, zentry->namelen + 1, handle) != fullname) + fullname = malloc(zentry.namelen + 1); + if (fgets(fullname, zentry.namelen + 1, handle) != fullname) { CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); Z_Free(lumpinfo); - free(zentries); free(fullname); return NULL; } @@ -606,12 +628,15 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) memset(lump_p->name, '\0', 9); // Making sure they're initialized to 0. Is it necessary? strncpy(lump_p->name, trimname, min(8, dotpos - trimname)); - lump_p->name2 = Z_Calloc(zentry->namelen + 1, PU_STATIC, NULL); - strncpy(lump_p->name2, fullname, zentry->namelen); + lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL); + strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); + + lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL); + strncpy(lump_p->fullname, fullname, zentry.namelen); free(fullname); - switch(zentry->compression) + switch(zentry.compression) { case 0: lump_p->compression = CM_NOCOMPRESSION; @@ -629,9 +654,29 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->compression = CM_UNSUPPORTED; break; } + + // skip and ignore comments/extra fields + if (fseek(handle, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) + { + CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); + Z_Free(lumpinfo); + return NULL; + } } - free(zentries); + // Adjust lump position values properly + for (i = 0, lump_p = lumpinfo; i < numlumps; i++, lump_p++) + { + // skip and ignore comments/extra fields + if ((fseek(handle, lump_p->position, SEEK_SET) != 0) || (fread(&zlentry, 1, sizeof(zlentry_t), handle) < sizeof(zlentry_t))) + { + CONS_Alert(CONS_ERROR, "Local headers for lump %s are corrupt\n", lump_p->fullname); + Z_Free(lumpinfo); + return NULL; + } + + lump_p->position += sizeof(zlentry_t) + zlentry.namelen + zlentry.xtralen; + } *nlmp = numlumps; return lumpinfo; @@ -670,7 +715,9 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) wadfile_t *wadfile; restype_t type; UINT16 numlumps = 0; +#ifndef NOMD5 size_t i; +#endif size_t packetsize; UINT8 md5sum[16]; boolean important; @@ -747,11 +794,9 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) case RET_SOC: lumpinfo = ResGetLumpsStandalone(handle, &numlumps, "OBJCTCFG"); break; -#ifdef HAVE_BLUA case RET_LUA: lumpinfo = ResGetLumpsStandalone(handle, &numlumps, "LUA_INIT"); break; -#endif case RET_PK3: lumpinfo = ResGetLumpsZip(handle, &numlumps); break; @@ -803,6 +848,15 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) wadfiles[numwadfiles] = wadfile; numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded +#ifdef HWRENDER + // Read shaders from file + if (rendermode == render_opengl && (vid_opengl_state == 1)) + { + HWR_ReadShaders(numwadfiles - 1, (type == RET_PK3)); + HWR_LoadShaders(); + } +#endif // HWRENDER + // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. switch (wadfile->type) { @@ -816,11 +870,9 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) CONS_Printf(M_GetText("Loading SOC from %s\n"), wadfile->filename); DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0, mainfile); break; -#ifdef HAVE_BLUA case RET_LUA: - LUA_LoadLump(numwadfiles - 1, 0); + LUA_LoadLump(numwadfiles - 1, 0, true); break; -#endif default: break; } @@ -891,16 +943,14 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum) UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; - static char uname[9]; - - memset(uname, 0x00, sizeof uname); - strncpy(uname, name, 8); - uname[8] = 0; - strupr(uname); + static char uname[8 + 1]; if (!TestValidLump(wad,0)) return INT16_MAX; + strlcpy(uname, name, sizeof uname); + strupr(uname); + // // scan forward // start at 'startlump', useful parameter when there are multiple @@ -910,7 +960,7 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) - if (memcmp(lump_p->name,uname,8) == 0) + if (!strncmp(lump_p->name, uname, sizeof(uname) - 1)) return i; } @@ -918,15 +968,66 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) return INT16_MAX; } +// +// Like W_CheckNumForNamePwad, but can find entries with long names +// +// Should be the only version, but that's not possible until we fix +// all the instances of non null-terminated strings in the codebase... +// +UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) +{ + UINT16 i; + static char uname[256 + 1]; + + if (!TestValidLump(wad,0)) + return INT16_MAX; + + strlcpy(uname, name, sizeof uname); + strupr(uname); + + // + // scan forward + // start at 'startlump', useful parameter when there are multiple + // resources with the same name + // + if (startlump < wadfiles[wad]->numlumps) + { + lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) + if (!strcmp(lump_p->longname, uname)) + return i; + } + + // not found. + return INT16_MAX; +} + +UINT16 +W_CheckNumForMarkerStartPwad (const char *name, UINT16 wad, UINT16 startlump) +{ + UINT16 marker; + marker = W_CheckNumForNamePwad(name, wad, startlump); + if (marker != INT16_MAX) + marker++; // Do not count the first marker + return marker; +} + // Look for the first lump from a folder. UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump) { + size_t name_length; INT32 i; lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; + name_length = strlen(name); for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) { - if (strnicmp(name, lump_p->name2, strlen(name)) == 0) + if (strnicmp(name, lump_p->fullname, name_length) == 0) + { + /* SLADE is special and puts a single directory entry. Skip that. */ + if (strlen(lump_p->fullname) == name_length) + i++; break; + } } return i; } @@ -940,7 +1041,7 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump) lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) { - if (strnicmp(name, lump_p->name2, strlen(name))) + if (strnicmp(name, lump_p->fullname, strlen(name))) break; } return i; @@ -954,7 +1055,7 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump) lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) { - if (!strnicmp(name, lump_p->name2, strlen(name))) + if (!strnicmp(name, lump_p->fullname, strlen(name))) { return i; } @@ -979,7 +1080,8 @@ lumpnum_t W_CheckNumForName(const char *name) // most recent entries first for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) { - if (strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) + if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8] + && strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) { lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); return lumpnumcache[lumpnumcacheindex].lumpnum; @@ -999,6 +1101,7 @@ lumpnum_t W_CheckNumForName(const char *name) { // Update the cache. lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); + memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8); lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check; @@ -1006,6 +1109,55 @@ lumpnum_t W_CheckNumForName(const char *name) } } +// +// Like W_CheckNumForName, but can find entries with long names +// +// Should be the only version, but that's not possible until we fix +// all the instances of non null-terminated strings in the codebase... +// +lumpnum_t W_CheckNumForLongName(const char *name) +{ + INT32 i; + lumpnum_t check = INT16_MAX; + + if (!*name) // some doofus gave us an empty string? + return LUMPERROR; + + // Check the lumpnumcache first. Loop backwards so that we check + // most recent entries first + for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) + { + if (strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) + { + lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); + return lumpnumcache[lumpnumcacheindex].lumpnum; + } + } + + // scan wad files backwards so patch lump files take precedence + for (i = numwadfiles - 1; i >= 0; i--) + { + check = W_CheckNumForLongNamePwad(name,(UINT16)i,0); + if (check != INT16_MAX) + break; //found it + } + + if (check == INT16_MAX) return LUMPERROR; + else + { + if (strlen(name) < 32) + { + // Update the cache. + lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); + memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); + strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32); + lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check; + } + + return (i << 16) + check; + } +} + // Look for valid map data through all added files in descendant order. // Get a map marker for WADs, and a standalone WAD file lump inside PK3s. // TODO: Make it search through cache first, maybe...? @@ -1029,7 +1181,7 @@ lumpnum_t W_CheckNumForMap(const char *name) else continue; // Now look for the specified map. - for (++lumpNum; lumpNum < end; lumpNum++) + for (; lumpNum < end; lumpNum++) if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) return (i<<16) + lumpNum; } @@ -1054,6 +1206,24 @@ lumpnum_t W_GetNumForName(const char *name) return i; } +// +// Like W_GetNumForName, but can find entries with long names +// +// Should be the only version, but that's not possible until we fix +// all the instances of non null-terminated strings in the codebase... +// +lumpnum_t W_GetNumForLongName(const char *name) +{ + lumpnum_t i; + + i = W_CheckNumForLongName(name); + + if (i == LUMPERROR) + I_Error("W_GetNumForLongName: %s not found!\n", name); + + return i; +} + // // W_CheckNumForNameInBlock // Checks only in blocks from blockstart lump to blockend lump @@ -1093,7 +1263,7 @@ UINT8 W_LumpExists(const char *name) { lumpinfo_t *lump_p = wadfiles[i]->lumpinfo; for (j = 0; j < wadfiles[i]->numlumps; ++j, ++lump_p) - if (fastcmp(lump_p->name,name)) + if (fastcmp(lump_p->longname, name)) return true; } return false; @@ -1124,7 +1294,7 @@ boolean W_IsLumpWad(lumpnum_t lumpnum) { if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3) { - const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->name2; + const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname; if (strlen(lumpfullName) < 4) return false; // can't possibly be a WAD can it? @@ -1142,7 +1312,7 @@ boolean W_IsLumpFolder(UINT16 wad, UINT16 lump) { if (wadfiles[wad]->type == RET_PK3) { - const char *name = wadfiles[wad]->lumpinfo[lump].name2; + const char *name = wadfiles[wad]->lumpinfo[lump].fullname; return (name[strlen(name)-1] == '/'); // folders end in '/' } @@ -1220,7 +1390,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si { size_t bytesread = fread(dest, 1, size, handle); if (R_IsLumpPNG((UINT8 *)dest, bytesread)) - W_ThrowPNGError(l->name2, wadfiles[wad]->filename); + W_ThrowPNGError(l->fullname, wadfiles[wad]->filename); return bytesread; } #else @@ -1262,7 +1432,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si Z_Free(decData); #ifdef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)dest, size)) - W_ThrowPNGError(l->name2, wadfiles[wad]->filename); + W_ThrowPNGError(l->fullname, wadfiles[wad]->filename); #endif return size; #else @@ -1325,7 +1495,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si #ifdef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)dest, size)) - W_ThrowPNGError(l->name2, wadfiles[wad]->filename); + W_ThrowPNGError(l->fullname, wadfiles[wad]->filename); #endif return size; } @@ -1471,21 +1641,6 @@ boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr) return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr); } -void W_FlushCachedPatches(void) -{ - if (needpatchflush) - { - Z_FreeTag(PU_CACHE); - Z_FreeTag(PU_PATCH); - Z_FreeTag(PU_HUDGFX); - Z_FreeTag(PU_HWRPATCHINFO); - Z_FreeTag(PU_HWRMODELTEXTURE); - Z_FreeTag(PU_HWRCACHE); - Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRMODELTEXTURE_UNLOCKED); - } - needpatchflush = false; -} - // ========================================================================== // W_CacheLumpName // ========================================================================== @@ -1509,15 +1664,60 @@ void *W_CacheLumpName(const char *name, INT32 tag) // Cache a patch into heap memory, convert the patch format as necessary // +void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) +{ + lumpcache_t *lumpcache = NULL; + + if (!TestValidLump(wad, lump)) + return NULL; + + lumpcache = wadfiles[wad]->patchcache; + + if (!lumpcache[lump]) + { + size_t len = W_LumpLengthPwad(wad, lump); + void *ptr, *lumpdata; +#ifndef NO_PNG_LUMPS + void *srcdata = NULL; +#endif + + ptr = Z_Malloc(len, tag, &lumpcache[lump]); + lumpdata = Z_Malloc(len, tag, NULL); + + // read the lump in full + W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); + +#ifndef NO_PNG_LUMPS + // lump is a png so convert it + if (R_IsLumpPNG((UINT8 *)lumpdata, len)) + { + size_t newlen; + srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen); + ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); + M_Memcpy(ptr, srcdata, newlen); + Z_Free(srcdata); + } + else // just copy it into the patch cache +#endif + M_Memcpy(ptr, lumpdata, len); + } + else + Z_ChangeTag(lumpcache[lump], tag); + + return lumpcache[lump]; +} + +void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag) +{ + return W_CacheSoftwarePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag); +} + void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { #ifdef HWRENDER GLPatch_t *grPatch; #endif - if (needpatchflush) - W_FlushCachedPatches(); - if (!TestValidLump(wad, lump)) return NULL; @@ -1526,39 +1726,7 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (rendermode == render_soft || rendermode == render_none) #endif { - lumpcache_t *lumpcache = wadfiles[wad]->patchcache; - if (!lumpcache[lump]) - { - size_t len = W_LumpLengthPwad(wad, lump); - void *ptr, *lumpdata; -#ifndef NO_PNG_LUMPS - void *srcdata = NULL; -#endif - - ptr = Z_Malloc(len, tag, &lumpcache[lump]); - lumpdata = Z_Malloc(len, tag, NULL); - - // read the lump in full - W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); - -#ifndef NO_PNG_LUMPS - // lump is a png so convert it - if (R_IsLumpPNG((UINT8 *)lumpdata, len)) - { - size_t newlen; - srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen); - ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); - M_Memcpy(ptr, srcdata, newlen); - Z_Free(srcdata); - } - else // just copy it into the patch cache -#endif - M_Memcpy(ptr, lumpdata, len); - } - else - Z_ChangeTag(lumpcache[lump], tag); - - return lumpcache[lump]; + return W_CacheSoftwarePatchNumPwad(wad, lump, tag); } #ifdef HWRENDER @@ -1598,7 +1766,7 @@ void W_UnlockCachedPatch(void *patch) // The hardware code does its own memory management, as its patches // have different lifetimes from software's. #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) HWR_UnlockCachedPatch((GLPatch_t*)patch); else #endif @@ -1615,6 +1783,17 @@ void *W_CachePatchName(const char *name, INT32 tag) return W_CachePatchNum(W_GetNumForName("MISSING"), tag); return W_CachePatchNum(num, tag); } + +void *W_CachePatchLongName(const char *name, INT32 tag) +{ + lumpnum_t num; + + num = W_CheckNumForLongName(name); + + if (num == LUMPERROR) + return W_CachePatchNum(W_GetNumForLongName("MISSING"), tag); + return W_CachePatchNum(num, tag); +} #ifndef NOMD5 #define MD5_LEN 16 @@ -1833,6 +2012,10 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) } free(fullname); + + // skip and ignore comments/extra fields + if (fseek(fp, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) + return true; } return true; @@ -1858,10 +2041,7 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, { // detect wad file by the absence of the other supported extensions if (stricmp(&filename[strlen(filename) - 4], ".soc") -#ifdef HAVE_BLUA - && stricmp(&filename[strlen(filename) - 4], ".lua") -#endif - ) + && stricmp(&filename[strlen(filename) - 4], ".lua")) { goodfile = W_VerifyWAD(handle, checklist, status); } diff --git a/src/w_wad.h b/src/w_wad.h index 439d12647..fddc65529 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -66,9 +66,10 @@ typedef struct { unsigned long position; // filelump_t filepos unsigned long disksize; // filelump_t size - char name[9]; // filelump_t name[] - char *name2; // Used by PK3s. Dynamically allocated name. - size_t size; // real (uncompressed) size + char name[9]; // filelump_t name[] e.g. "LongEntr" + char *longname; // e.g. "LongEntryName" + char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension" + size_t size; // real (uncompressed) size compmethod compression; // lump compression method } lumpinfo_t; @@ -155,6 +156,10 @@ const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNum(lumpnum_t lumpnum); UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad +UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump); + +/* Find the first lump after F_START for instance. */ +UINT16 W_CheckNumForMarkerStartPwad(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump); @@ -162,7 +167,9 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump) lumpnum_t W_CheckNumForMap(const char *name); lumpnum_t W_CheckNumForName(const char *name); +lumpnum_t W_CheckNumForLongName(const char *name); lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR +lumpnum_t W_GetNumForLongName(const char *name); lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend); UINT8 W_LumpExists(const char *name); // Lua uses this. @@ -190,12 +197,19 @@ boolean W_IsPatchCached(lumpnum_t lump, void *ptr); void *W_CacheLumpName(const char *name, INT32 tag); void *W_CachePatchName(const char *name, INT32 tag); +void *W_CachePatchLongName(const char *name, INT32 tag); -void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch_t -void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t +// Returns either a Software patch, or an OpenGL patch. +// Performs any necessary conversions from PNG images. +void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); +void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); + +// Returns a Software patch. +// Performs any necessary conversions from PNG images. +void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); +void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag); void W_UnlockCachedPatch(void *patch); -void W_FlushCachedPatches(void); void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5); diff --git a/src/win32/Srb2win-vc9.vcproj b/src/win32/Srb2win-vc9.vcproj index a64b8638c..4c17bb6f7 100644 --- a/src/win32/Srb2win-vc9.vcproj +++ b/src/win32/Srb2win-vc9.vcproj @@ -55,7 +55,7 @@ Optimization="0" OmitFramePointers="false" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="_DEBUG;_WINDOWS;USEASM;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="_DEBUG;_WINDOWS;USEASM;HAVE_PNG;COMPVERSION;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" RuntimeLibrary="1" EnableFunctionLevelLinking="true" @@ -153,7 +153,7 @@ Optimization="0" OmitFramePointers="false" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="_DEBUG;_WINDOWS;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="_DEBUG;_WINDOWS;HAVE_PNG;COMPVERSION;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" SmallerTypeCheck="true" @@ -256,7 +256,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="NDEBUG;_WINDOWS;USEASM;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="NDEBUG;_WINDOWS;USEASM;HAVE_PNG;COMPVERSION;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" StringPooling="true" RuntimeLibrary="0" EnableFunctionLevelLinking="true" @@ -356,7 +356,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="NDEBUG;_WINDOWS;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="NDEBUG;_WINDOWS;HAVE_PNG;COMPVERSION;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" StringPooling="true" RuntimeLibrary="0" EnableFunctionLevelLinking="true" diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index 8e7fdccc9..d7e3383b0 100644 --- a/src/win32/Srb2win.rc +++ b/src/win32/Srb2win.rc @@ -87,7 +87,7 @@ BEGIN VALUE "FileDescription", "Sonic Robo Blast 2\0" VALUE "FileVersion", VERSIONSTRING VALUE "InternalName", "srb2\0" - VALUE "LegalCopyright", "Copyright 1998-2019 by Sonic Team Junior\0" + VALUE "LegalCopyright", "Copyright 1998-2020 by Sonic Team Junior\0" VALUE "LegalTrademarks", "Sonic the Hedgehog and related characters are trademarks of Sega.\0" VALUE "OriginalFilename", "srb2win.exe\0" VALUE "PrivateBuild", "\0" diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c index 986eb32dc..3f6c5e290 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -106,6 +106,7 @@ static loadfunc_t hwdFuncTable[] = { {"SetBlend@4", &hwdriver.pfnSetBlend}, {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, {"SetTexture@4", &hwdriver.pfnSetTexture}, + {"UpdateTexture@4", &hwdriver.pfnUpdateTexture}, {"ReadRect@24", &hwdriver.pfnReadRect}, {"GClipRect@20", &hwdriver.pfnGClipRect}, {"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache}, @@ -120,7 +121,7 @@ static loadfunc_t hwdFuncTable[] = { {"FlushScreenTextures@0",&hwdriver.pfnFlushScreenTextures}, {"StartScreenWipe@0", &hwdriver.pfnStartScreenWipe}, {"EndScreenWipe@0", &hwdriver.pfnEndScreenWipe}, - {"DoScreenWipe@4", &hwdriver.pfnDoScreenWipe}, + {"DoScreenWipe@0", &hwdriver.pfnDoScreenWipe}, {"DrawIntermissionBG@0",&hwdriver.pfnDrawIntermissionBG}, {"MakeScreenTexture@0", &hwdriver.pfnMakeScreenTexture}, {"MakeScreenFinalTexture@0", &hwdriver.pfnMakeScreenFinalTexture}, @@ -137,6 +138,7 @@ static loadfunc_t hwdFuncTable[] = { {"SetBlend", &hwdriver.pfnSetBlend}, {"ClearBuffer", &hwdriver.pfnClearBuffer}, {"SetTexture", &hwdriver.pfnSetTexture}, + {"UpdateTexture", &hwdriver.pfnUpdateTexture}, {"ReadRect", &hwdriver.pfnReadRect}, {"GClipRect", &hwdriver.pfnGClipRect}, {"ClearMipMapCache", &hwdriver.pfnClearMipMapCache}, diff --git a/src/win32/win_main.c b/src/win32/win_main.c index 8a29f7e18..e1d90881b 100644 --- a/src/win32/win_main.c +++ b/src/win32/win_main.c @@ -643,37 +643,28 @@ int WINAPI WinMain (HINSTANCE hInstance, int nCmdShow) { int Result = -1; - -#if 0 - // Win95 and NT <4 don't have this, so link at runtime. - p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"),"IsDebuggerPresent"); -#endif - UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); -#if 0 -#ifdef BUGTRAP - // Try BugTrap first. - if((!pfnIsDebuggerPresent || !pfnIsDebuggerPresent()) && InitBugTrap()) - Result = HandledWinMain(hInstance); - else { -#endif - // Try Dr MinGW's exception handler. - if (!pfnIsDebuggerPresent || !pfnIsDebuggerPresent()) -#endif - LoadLibraryA("exchndl.dll"); - -#ifndef __MINGW32__ - prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo); -#endif - - Result = HandledWinMain(hInstance); +#if 0 + p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"),"IsDebuggerPresent"); + if((!pfnIsDebuggerPresent || !pfnIsDebuggerPresent()) +#ifdef BUGTRAP + && !InitBugTrap() +#endif + ) +#endif + { + LoadLibraryA("exchndl.dll"); + } + } +#ifndef __MINGW32__ + prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo); +#endif + Result = HandledWinMain(hInstance); #ifdef BUGTRAP - } // BT failure clause. - // This is safe even if BT didn't start. ShutdownBugTrap(); #endif diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 42733c309..a374a2587 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -54,6 +54,8 @@ #include "../screen.h" +#include "../m_menu.h" + // Wheel support for Win95/WinNT3.51 #include @@ -465,6 +467,7 @@ static void signal_handler(int num) char sigdef[64]; D_QuitNetGame(); // Fix server freezes + CL_AbortDownloadResume(); I_ShutdownSystem(); switch (num) @@ -650,6 +653,8 @@ void I_Error(const char *error, ...) G_StopMetalRecording(false); D_QuitNetGame(); + CL_AbortDownloadResume(); + M_FreePlayerSetupColors(); // shutdown everything that was started I_ShutdownSystem(); @@ -745,6 +750,9 @@ void I_Quit(void) // or something else that will be finished by I_ShutdownSystem(), // so do it before. D_QuitNetGame(); + CL_AbortDownloadResume(); + + M_FreePlayerSetupColors(); // shutdown everything that was started I_ShutdownSystem(); @@ -3199,7 +3207,7 @@ INT32 I_GetKey(void) // ----------------- #define DI_KEYBOARD_BUFFERSIZE 32 // number of data elements in keyboard buffer -void I_StartupKeyboard(void) +static void I_StartupKeyboard(void) { DIPROPDWORD dip; @@ -3435,6 +3443,8 @@ INT32 I_StartupSystem(void) // some 'more global than globals' things to initialize here ? graphics_started = keyboard_started = sound_started = cdaudio_started = false; + I_StartupKeyboard(); + #ifdef NDEBUG #ifdef BUGTRAP diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c index d0aab92b3..716f38089 100644 --- a/src/win32/win_vid.c +++ b/src/win32/win_vid.c @@ -56,6 +56,7 @@ static consvar_t cv_stretch = {"stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, static consvar_t cv_ontop = {"ontop", "Never", 0, CV_NeverOnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; boolean highcolor; +int vid_opengl_state = 0; static BOOL bDIBMode; // means we are using DIB instead of DirectDraw surfaces static LPBITMAPINFO bmiMain = NULL; @@ -239,10 +240,7 @@ void I_StartupGraphics(void) if (!dedicated) graphics_started = true; } -void I_StartupHardwareGraphics(void) -{ - // oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo y -} +void VID_StartupOpenGL(void){} // ------------------ // I_ShutdownGraphics @@ -328,7 +326,7 @@ static inline boolean I_SkipFrame(void) if (!paused) return false; //case GS_TIMEATTACK: -- sorry optimisation but now we have a cool level platter and that being laggardly looks terrible -#ifndef CLIENT_LOADINGSCREEN +#ifndef NONET /* FALLTHRU */ case GS_WAITINGPLAYERS: #endif @@ -368,6 +366,9 @@ void I_FinishUpdate(void) if (I_SkipFrame()) return; + if (marathonmode) + SCR_DisplayMarathonInfo(); + // draw captions if enabled if (cv_closedcaptioning.value) SCR_ClosedCaptions(); @@ -951,9 +952,10 @@ INT32 VID_SetMode(INT32 modenum) return 1; } -void VID_CheckRenderer(void) +void VID_CheckRenderer(void) {} +void VID_CheckGLLoaded(rendermode_t oldrender) { - // .............. + (void)oldrender; } // ======================================================================== diff --git a/src/y_inter.c b/src/y_inter.c index 214dee92e..58e0c4a88 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2004-2019 by Sonic Team Junior. +// Copyright (C) 2004-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -19,7 +19,7 @@ #include "i_video.h" #include "p_tick.h" #include "r_defs.h" -#include "r_things.h" +#include "r_skins.h" #include "s_sound.h" #include "st_stuff.h" #include "v_video.h" @@ -37,9 +37,7 @@ #include "m_cond.h" // condition sets #include "lua_hook.h" // IntermissionThinker hook -#ifdef HAVE_BLUA #include "lua_hud.h" -#endif #ifdef HWRENDER #include "hardware/hw_main.h" @@ -75,7 +73,7 @@ typedef union UINT32 score, total; // fake score, total UINT32 tics; // time - INT32 actnum; // act number being displayed + UINT8 actnum; // act number being displayed patch_t *ptotal; // TOTAL UINT8 gotlife; // Number of extra lives obtained } coop; @@ -101,7 +99,7 @@ typedef union UINT8 continues; patch_t *pcontinues; INT32 *playerchar; // Continue HUD - UINT8 *playercolor; + UINT16 *playercolor; UINT8 gotlife; // Number of extra lives obtained } spec; @@ -109,7 +107,7 @@ typedef union struct { UINT32 scores[MAXPLAYERS]; // Winner's score - UINT8 *color[MAXPLAYERS]; // Winner's color # + UINT16 *color[MAXPLAYERS]; // Winner's color # boolean spectator[MAXPLAYERS]; // Spectator list INT32 *character[MAXPLAYERS]; // Winner's character # INT32 num[MAXPLAYERS]; // Winner's player # @@ -123,7 +121,7 @@ typedef union struct { - UINT8 *color[MAXPLAYERS]; // Winner's color # + UINT16 *color[MAXPLAYERS]; // Winner's color # INT32 *character[MAXPLAYERS]; // Winner's character # INT32 num[MAXPLAYERS]; // Winner's player # char name[MAXPLAYERS][9]; // Winner's name @@ -229,8 +227,7 @@ static void Y_IntermissionTokenDrawer(void) // // Y_ConsiderScreenBuffer // -// Can we copy the current screen -// to a buffer? +// Can we copy the current screen to a buffer? // void Y_ConsiderScreenBuffer(void) { @@ -256,9 +253,7 @@ void Y_ConsiderScreenBuffer(void) // // Y_RescaleScreenBuffer // -// Write the rescaled source picture, -// to the destination picture that -// has the current screen's resolutions. +// Write the rescaled source picture, to the destination picture that has the current screen's resolutions. // static void Y_RescaleScreenBuffer(void) { @@ -325,18 +320,9 @@ void Y_IntermissionDrawer(void) // Bonus loops INT32 i; - if (rendermode == render_none) + if (intertype == int_none || rendermode == render_none) return; - if (intertype == int_none) - { -#ifdef HAVE_BLUA - LUAh_IntermissionHUD(); -#endif - return; - } - - if (!usebuffer) // Lactozilla: Renderer switching if (needpatchrecache) { @@ -377,18 +363,16 @@ void Y_IntermissionDrawer(void) { if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx == 400) V_DrawScaledPatch(0, 0, V_SNAPTOLEFT, widebgpatch); - else + else if (bgpatch) V_DrawScaledPatch(0, 0, 0, bgpatch); } } - else + else if (bgtile) V_DrawPatchFill(bgtile); -#ifdef HAVE_BLUA LUAh_IntermissionHUD(); if (!LUA_HudEnabled(hud_intermissiontally)) goto skiptallydrawer; -#endif dontdrawbg: if (intertype == int_coop) @@ -398,7 +382,7 @@ dontdrawbg: if (gottoken) // first to be behind everything else Y_IntermissionTokenDrawer(); - if (!splitscreen) + if (!splitscreen) // there's not enough room in splitscreen, don't even bother trying! { // draw score ST_DrawPatchFromHud(HUD_SCORE, sboscore); @@ -420,7 +404,7 @@ dontdrawbg: ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon); // Colon ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2); // Seconds - if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! + if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking || marathonmode) { ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics @@ -570,7 +554,7 @@ dontdrawbg: V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125+yoffset, 0, data.spec.score); // Draw continues! - if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay + if (continuesInSession /* && (data.spec.continues & 0x80) */) // Always draw when continues are a thing { UINT8 continues = data.spec.continues & 0x7F; @@ -944,11 +928,9 @@ dontdrawbg: } } -#ifdef HAVE_BLUA skiptallydrawer: if (!LUA_HudEnabled(hud_intermissionmessages)) return; -#endif if (timer) V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP, @@ -973,9 +955,7 @@ void Y_Ticker(void) if (paused || P_AutoPause()) return; -#ifdef HAVE_BLUA LUAh_IntermissionThinker(); -#endif intertic++; @@ -1014,7 +994,7 @@ void Y_Ticker(void) { INT32 i; UINT32 oldscore = data.coop.score; - boolean skip = false; + boolean skip = (marathonmode) ? true : false; boolean anybonuses = false; if (!intertic) // first time only @@ -1090,7 +1070,7 @@ void Y_Ticker(void) { INT32 i; UINT32 oldscore = data.spec.score; - boolean skip = false, super = false, anybonuses = false; + boolean skip = (marathonmode) ? true : false, super = false, anybonuses = false; if (!intertic) // first time only { @@ -1196,6 +1176,34 @@ void Y_Ticker(void) } } +// +// Y_DetermineIntermissionType +// +// Determines the intermission type from the current gametype. +// +void Y_DetermineIntermissionType(void) +{ + // set to int_none initially + intertype = int_none; + + if (intermissiontypes[gametype] != int_none) + intertype = intermissiontypes[gametype]; + else if (gametype == GT_COOP) + intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop; + else if (gametype == GT_TEAMMATCH) + intertype = int_teammatch; + else if (gametype == GT_MATCH + || gametype == GT_TAG + || gametype == GT_HIDEANDSEEK) + intertype = int_match; + else if (gametype == GT_RACE) + intertype = int_race; + else if (gametype == GT_COMPETITION) + intertype = int_comp; + else if (gametype == GT_CTF) + intertype = int_ctf; +} + // // Y_StartIntermission // @@ -1217,12 +1225,11 @@ void Y_StartIntermission(void) if (!multiplayer) { timer = 0; - intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop; } else { - if (cv_inttime.value == 0 && gametype == GT_COOP) + if (cv_inttime.value == 0 && ((intertype == int_coop) || (intertype == int_spec))) timer = 0; else { @@ -1231,23 +1238,6 @@ void Y_StartIntermission(void) if (!timer) timer = 1; } - - if (intermissiontypes[gametype] != int_none) - intertype = intermissiontypes[gametype]; - else if (gametype == GT_COOP) - intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop; - else if (gametype == GT_TEAMMATCH) - intertype = int_teammatch; - else if (gametype == GT_MATCH - || gametype == GT_TAG - || gametype == GT_HIDEANDSEEK) - intertype = int_match; - else if (gametype == GT_RACE) - intertype = int_race; - else if (gametype == GT_COMPETITION) - intertype = int_comp; - else if (gametype == GT_CTF) - intertype = int_ctf; } // We couldn't display the intermission even if we wanted to. diff --git a/src/y_inter.h b/src/y_inter.h index 5cf2cc1b8..859144b1d 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2004-2019 by Sonic Team Junior. +// Copyright (C) 2004-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -13,11 +13,15 @@ extern boolean usebuffer; void Y_IntermissionDrawer(void); void Y_Ticker(void); + void Y_StartIntermission(void); void Y_EndIntermission(void); + void Y_ConsiderScreenBuffer(void); void Y_CleanupScreenBuffer(void); +void Y_DetermineIntermissionType(void); + typedef enum { int_none, diff --git a/src/z_zone.c b/src/z_zone.c index e06f7bf1a..2387a1143 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by Graue. -// Copyright (C) 2006-2019 by Sonic Team Junior. +// Copyright (C) 2006-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -217,11 +217,9 @@ void Z_Free(void *ptr) CONS_Debug(DBG_MEMORY, "Z_Free at %s:%d\n", file, line); #endif -#ifdef HAVE_BLUA // anything that isn't by lua gets passed to lua just in case. if (block->tag != PU_LUA) LUA_InvalidateUserdata(ptr); -#endif // TODO: if zdebugging, make sure no other block has a user // that is about to be freed. @@ -501,17 +499,14 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) // Utility functions // ----------------- -// for renderer switching, free a bunch of stuff +// for renderer switching boolean needpatchflush = false; boolean needpatchrecache = false; // flush all patches from memory -// (also frees memory tagged with PU_CACHE) -// (which are not necessarily patches but I don't care) void Z_FlushCachedPatches(void) { CONS_Debug(DBG_RENDER, "Z_FlushCachedPatches()...\n"); - Z_FreeTag(PU_CACHE); Z_FreeTag(PU_PATCH); Z_FreeTag(PU_HUDGFX); Z_FreeTag(PU_HWRPATCHINFO); @@ -810,7 +805,7 @@ static void Command_Memfree_f(void) sizeu1(Z_TagsUsage(PU_PURGELEVEL, INT32_MAX)>>10)); #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_opengl) { CONS_Printf(M_GetText("Patch info headers: %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHINFO)>>10)); CONS_Printf(M_GetText("Mipmap patches : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHCOLMIPMAP)>>10)); diff --git a/src/z_zone.h b/src/z_zone.h index 250885e10..5cbcc6655 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. +// Copyright (C) 1999-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2.