diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg index 0ff044a6d..8f37aabaa 100644 --- a/extras/conf/udb/Includes/SRB222_common.cfg +++ b/extras/conf/udb/Includes/SRB222_common.cfg @@ -15,7 +15,7 @@ common ignoredextensions = "wad pk3 pk7 bak backup1 backup2 backup3 zip rar 7z"; // Default testing parameters - testparameters = "-file \"%AP\" \"%F\" -warp %L"; + testparameters = "-folder \"%AF\" -file \"%AA\" \"%F\" -warp %L"; testshortpaths = true; // Action special help @@ -26,7 +26,7 @@ common generalizedsectors = true; // Maximum safe map size check (0 means skip check) - safeboundary = 1; + safeboundary = 0; // Map boundaries. Map objects can only be placed within these boundaries leftboundary = -32768; @@ -40,6 +40,8 @@ common defaultflatscale = 1.0f; scaledtextureoffsets = true; + maxcolormapalpha = 25; + // Thing number for start position in 3D Mode start3dmode = 3328; @@ -68,137 +70,6 @@ common } } -mapformat_doom -{ - // The format interface handles the map data format - formatinterface = "DoomMapSetIO"; - - // Default nodebuilder configurations - defaultsavecompiler = "zennode_normal"; - defaulttestcompiler = "zennode_fast"; - - /* - 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 - 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; - - // THING TYPES - thingtypes - { - include("SRB222_things.cfg", "doom"); - } -} - mapformat_udmf { // The format interface handles the map data format @@ -222,9 +93,17 @@ mapformat_udmf { include("SRB222_misc.cfg", "universalfields"); } + + // Disable Doom-related modes that don't make sense for SRB2 + soundsupport = false; + automapsupport = false; // When this is set to true, sectors with the same tag will light up when a line is highlighted linetagindicatesectors = false; + localsidedeftextureoffsets = true; + distinctfloorandceilingbrightness = true; + + planeequationsupport = true; // Special linedefs include("SRB222_misc.cfg", "speciallinedefs_udmf"); @@ -240,6 +119,11 @@ mapformat_udmf include("SRB222_misc.cfg", "sectorflags"); } + sectorflagscategories + { + include("SRB222_misc.cfg", "sectorflagscategories"); + } + // DEFAULT SECTOR BRIGHTNESS LEVELS sectorbrightness { @@ -247,6 +131,7 @@ mapformat_udmf } damagetypes = "Generic Water Fire Lava Electric Spike DeathPitTilt DeathPitNoTilt Instakill SpecialStage"; + triggerertypes = "Player AllPlayers Mobj"; // LINEDEF FLAGS linedefflags @@ -282,7 +167,6 @@ mapformat_udmf // How to compare thing flags (for the stuck things error checker) thingflagscompare { - include("UDMF_misc.cfg", "thingflagscompare"); } // THING TYPES diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg index b526e84e7..621b4abd5 100644 --- a/extras/conf/udb/Includes/SRB222_linedefs.cfg +++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg @@ -1,1793 +1,3 @@ -doom -{ - misc - { - title = "Miscellaneous"; - - 0 - { - title = "None"; - prefix = "(0)"; - } - 1 - { - title = "Per-Sector Gravity"; - prefix = "(1)"; - } - 5 - { - title = "Camera Scanner "; - prefix = "(5)"; - } - 7 - { - title = "Sector Flat Alignment"; - prefix = "(7)"; - } - 10 - { - title = "Culling Plane"; - prefix = "(10)"; - } - 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)"; - } - 3 - { - title = "Zoom Tube Parameters"; - prefix = "(3)"; - } - 4 - { - title = "Speed Pad Parameters"; - prefix = "(4)"; - } - 8 - { - title = "Special Sector Properties"; - prefix = "(8)"; - } - 9 - { - title = "Chain Parameters"; - prefix = "(9)"; - } - 11 - { - title = "Rope Hang Parameters"; - prefix = "(11)"; - } - 12 - { - title = "Rock Spawner Parameters"; - prefix = "(12)"; - } - 14 - { - title = "Bustable Block Parameters"; - prefix = "(14)"; - } - 15 - { - title = "Fan Particle Spawner Parameters"; - prefix = "(15)"; - } - 16 - { - title = "Minecart Parameters"; - prefix = "(16)"; - } - 64 - { - title = "Continuously Appearing/Disappearing FOF"; - prefix = "(64)"; - } - 76 - { - title = "Make FOF Bouncy"; - prefix = "(76)"; - } - } - - polyobject - { - title = "PolyObject"; - - 20 - { - title = "First Line"; - prefix = "(20)"; - } - 21 - { - title = "Explicitly Include Line "; - prefix = "(21)"; - } - 22 - { - title = "Parameters"; - prefix = "(22)"; - } - 30 - { - title = "Waving Flag"; - prefix = "(30)"; - } - 31 - { - title = "Displacement by Front Sector"; - prefix = "(31)"; - } - 32 - { - title = "Angular Displacement by Front Sector"; - prefix = "(32)"; - } - } - - planemove - { - title = "Plane Movement"; - - 52 - { - title = "Continuously Falling Sector"; - prefix = "(52)"; - } - 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)"; - } - 60 - { - title = "Activate Moving Platform (Adjustable Speed)"; - prefix = "(60)"; - } - 61 - { - title = "Crusher (Ceiling to Floor)"; - prefix = "(61)"; - } - 62 - { - title = "Crusher (Floor to Ceiling)"; - prefix = "(62)"; - } - 66 - { - title = "Move Floor by Displacement"; - prefix = "(66)"; - } - 67 - { - title = "Move Ceiling by Displacement"; - prefix = "(67)"; - } - 68 - { - title = "Move Floor and Ceiling by Displacement"; - prefix = "(68)"; - } - } - - fofsolid - { - title = "FOF (solid)"; - - 100 - { - title = "Solid, Opaque"; - prefix = "(100)"; - } - 101 - { - title = "Solid, Opaque, No Shadow"; - prefix = "(101)"; - } - 102 - { - title = "Solid, Translucent"; - prefix = "(102)"; - } - 103 - { - title = "Solid, Sides Only"; - prefix = "(103)"; - } - 104 - { - title = "Solid, No Sides"; - prefix = "(104)"; - } - 105 - { - title = "Solid, Invisible"; - prefix = "(105)"; - } - 140 - { - title = "Intangible from Bottom, Opaque"; - prefix = "(140)"; - } - 141 - { - title = "Intangible from Bottom, Translucent"; - prefix = "(141)"; - } - 142 - { - title = "Intangible from Bottom, Translucent, No Sides"; - prefix = "(142)"; - } - 143 - { - title = "Intangible from Top, Opaque"; - prefix = "(143)"; - } - 144 - { - title = "Intangible from Top, Translucent"; - prefix = "(144)"; - } - 145 - { - title = "Intangible from Top, Translucent, No Sides"; - prefix = "(145)"; - } - 146 - { - title = "Only Tangible from Sides"; - prefix = "(146)"; - } - } - - fofintangible - { - title = "FOF (intangible)"; - - 120 - { - title = "Water, Opaque"; - prefix = "(120)"; - } - 121 - { - title = "Water, Translucent"; - prefix = "(121)"; - } - 122 - { - title = "Water, Opaque, No Sides"; - prefix = "(122)"; - } - 123 - { - title = "Water, Translucent, No Sides"; - prefix = "(123)"; - } - 124 - { - title = "Goo Water, Translucent"; - prefix = "(124)"; - } - 125 - { - title = "Goo Water, Translucent, No Sides"; - prefix = "(125)"; - } - 220 - { - title = "Intangible, Opaque"; - prefix = "(220)"; - } - 221 - { - title = "Intangible, Translucent"; - prefix = "(221)"; - } - 222 - { - title = "Intangible, Sides Only"; - prefix = "(222)"; - } - 223 - { - title = "Intangible, Invisible"; - prefix = "(223)"; - } - } - - fofmoving - { - title = "FOF (moving)"; - - 150 - { - title = "Air Bobbing"; - prefix = "(150)"; - } - 151 - { - title = "Air Bobbing (Adjustable)"; - prefix = "(151)"; - } - 152 - { - title = "Reverse Air Bobbing (Adjustable)"; - prefix = "(152)"; - } - 153 - { - title = "Dynamically Sinking Platform"; - prefix = "(153)"; - } - 160 - { - title = "Water Bobbing"; - prefix = "(160)"; - } - 190 - { - title = "Rising Platform, Solid, Opaque"; - prefix = "(190)"; - } - 191 - { - title = "Rising Platform, Solid, Opaque, No Shadow"; - prefix = "(191)"; - } - 192 - { - title = "Rising Platform, Solid, Translucent"; - prefix = "(192)"; - } - 193 - { - title = "Rising Platform, Solid, Invisible"; - prefix = "(193)"; - } - 194 - { - title = "Rising Platform, Intangible from Bottom, Opaque"; - prefix = "(194)"; - } - 195 - { - title = "Rising Platform, Intangible from Bottom, Translucent"; - prefix = "(195)"; - } - } - - fofcrumbling - { - title = "FOF (crumbling)"; - - 170 - { - title = "Crumbling, Respawn"; - prefix = "(170)"; - } - 171 - { - title = "Crumbling, No Respawn"; - prefix = "(171)"; - } - 172 - { - title = "Crumbling, Respawn, Intangible from Bottom"; - prefix = "(172)"; - } - 173 - { - title = "Crumbling, No Respawn, Intangible from Bottom"; - prefix = "(173)"; - } - 174 - { - title = "Crumbling, Respawn, Int. from Bottom, Translucent"; - prefix = "(174)"; - } - 175 - { - title = "Crumbling, No Respawn, Int. from Bottom, Translucent"; - prefix = "(175)"; - } - 176 - { - title = "Crumbling, Respawn, Floating, Bobbing"; - prefix = "(176)"; - } - 177 - { - title = "Crumbling, No Respawn, Floating, Bobbing"; - prefix = "(177)"; - } - 178 - { - title = "Crumbling, Respawn, Floating"; - prefix = "(178)"; - } - 179 - { - title = "Crumbling, No Respawn, Floating"; - prefix = "(179)"; - } - 180 - { - title = "Crumbling, Respawn, Air Bobbing"; - prefix = "(180)"; - } - } - - fofspecial - { - title = "FOF (special)"; - - 200 - { - title = "Light Block"; - prefix = "(200)"; - } - 201 - { - title = "Half Light Block"; - prefix = "(201)"; - } - 202 - { - title = "Fog Block"; - prefix = "(202)"; - } - 250 - { - title = "Mario Block"; - prefix = "(250)"; - } - 251 - { - title = "Thwomp Block"; - prefix = "(251)"; - } - 252 - { - title = "Shatter Block"; - prefix = "(252)"; - } - 253 - { - title = "Shatter Block, Translucent"; - prefix = "(253)"; - } - 254 - { - title = "Bustable Block"; - prefix = "(254)"; - } - 255 - { - title = "Spin-Bustable Block"; - prefix = "(255)"; - } - 256 - { - title = "Spin-Bustable Block, Translucent"; - prefix = "(256)"; - } - 257 - { - title = "Quicksand"; - prefix = "(257)"; - } - 258 - { - title = "Laser"; - prefix = "(258)"; - } - 259 - { - title = "Custom FOF"; - prefix = "(259)"; - } - } - - linedeftrigger - { - title = "Linedef Executor Trigger"; - - 300 - { - title = "Continuous"; - prefix = "(300)"; - } - 301 - { - title = "Each Time"; - prefix = "(301)"; - } - 302 - { - title = "Once"; - prefix = "(302)"; - } - 303 - { - title = "Ring Count - Continuous"; - prefix = "(303)"; - } - 304 - { - title = "Ring Count - Once"; - prefix = "(304)"; - } - 305 - { - title = "Character Ability - Continuous"; - prefix = "(305)"; - } - 306 - { - title = "Character Ability - Each Time"; - prefix = "(306)"; - } - 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)"; - } - 311 - { - title = "CTF Blue Team - Continuous"; - prefix = "(311)"; - } - 312 - { - title = "CTF Blue Team - Each Time"; - prefix = "(312)"; - } - 313 - { - title = "No More Enemies - Once"; - prefix = "(313)"; - } - 314 - { - title = "Number of Pushables - Continuous"; - prefix = "(314)"; - } - 315 - { - title = "Number of Pushables - Once"; - prefix = "(315)"; - } - 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)"; - } - 322 - { - title = "Trigger After X Calls - Each Time"; - prefix = "(322)"; - } - 323 - { - title = "NiGHTSerize - Each Time"; - prefix = "(323)"; - } - 324 - { - title = "NiGHTSerize - Once"; - prefix = "(324)"; - } - 325 - { - title = "De-NiGHTSerize - Each Time"; - prefix = "(325)"; - } - 326 - { - title = "De-NiGHTSerize - Once"; - prefix = "(326)"; - } - 327 - { - title = "NiGHTS Lap - Each Time"; - prefix = "(327)"; - } - 328 - { - title = "NiGHTS Lap - Once"; - prefix = "(328)"; - } - 329 - { - title = "Ideya Capture Touch - Each Time"; - prefix = "(329)"; - } - 330 - { - title = "Ideya Capture Touch - Once"; - prefix = "(330)"; - } - 331 - { - title = "Player Skin - Continuous"; - flags64text = "[6] Disable for this skin"; - prefix = "(331)"; - } - 332 - { - title = "Player Skin - Each Time"; - prefix = "(332)"; - } - 333 - { - title = "Player Skin - Once"; - prefix = "(333)"; - } - 334 - { - title = "Object Dye - Continuous"; - prefix = "(334)"; - } - 335 - { - title = "Object Dye - Each Time"; - prefix = "(335)"; - } - 336 - { - title = "Object Dye - Once"; - prefix = "(336)"; - } - 337 - { - title = "Emerald Check - Continuous"; - prefix = "(337)"; - } - 338 - { - title = "Emerald Check - Each Time"; - prefix = "(338)"; - } - 339 - { - title = "Emerald Check - Once"; - prefix = "(339)"; - } - 340 - { - title = "NiGHTS Mare - Continuous"; - prefix = "(340)"; - } - 341 - { - title = "NiGHTS Mare - Each Time"; - prefix = "(341)"; - } - 342 - { - title = "NiGHTS Mare - Once"; - prefix = "(342)"; - } - 343 - { - title = "Gravity Check - Continuous"; - prefix = "(343)"; - } - 344 - { - title = "Gravity Check - Each Time"; - prefix = "(344)"; - } - 345 - { - title = "Gravity Check - Once"; - prefix = "(345)"; - } - 399 - { - title = "Level Load"; - prefix = "(399)"; - } - } - - linedefexecsector - { - title = "Linedef Executor (sector)"; - - 400 - { - title = "Set Tagged Sector's Floor Height/Texture"; - prefix = "(400)"; - } - 401 - { - title = "Set Tagged Sector's Ceiling Height/Texture"; - prefix = "(401)"; - } - 402 - { - title = "Copy Light Level to Tagged Sectors"; - prefix = "(402)"; - } - 408 - { - title = "Set Tagged Sector's Flats"; - prefix = "(408)"; - } - 409 - { - title = "Change Tagged Sector's Tag"; - prefix = "(409)"; - } - 410 - { - title = "Change Front Sector's Tag"; - prefix = "(410)"; - } - 416 - { - title = "Start Adjustable Flickering Light"; - prefix = "(416)"; - } - 417 - { - title = "Start Adjustable Pulsating Light"; - prefix = "(417)"; - } - 418 - { - title = "Start Adjustable Blinking Light (unsynchronized)"; - prefix = "(418)"; - } - 419 - { - title = "Start Adjustable Blinking Light (synchronized)"; - prefix = "(419)"; - } - 420 - { - title = "Fade Light Level"; - prefix = "(420)"; - } - 421 - { - title = "Stop Lighting Effect"; - prefix = "(421)"; - } - 435 - { - title = "Change Plane Scroller Direction"; - prefix = "(435)"; - } - 467 - { - title = "Set Tagged Sector's Light Level"; - prefix = "(467)"; - } - } - - linedefexecplane - { - title = "Linedef Executor (plane movement)"; - - 403 - { - title = "Move Tagged Sector's Floor"; - prefix = "(403)"; - } - 404 - { - title = "Move Tagged Sector's Ceiling"; - prefix = "(404)"; - } - 405 - { - title = "Move Floor According to Front Texture Offsets"; - prefix = "(405)"; - } - 407 - { - title = "Move Ceiling According to Front Texture Offsets"; - prefix = "(407)"; - } - 411 - { - title = "Stop Plane Movement"; - prefix = "(411)"; - } - 428 - { - title = "Start Platform Movement"; - prefix = "(428)"; - } - 429 - { - title = "Crush Ceiling Once"; - prefix = "(429)"; - } - 430 - { - title = "Crush Floor Once"; - prefix = "(430)"; - } - 431 - { - title = "Crush Floor and Ceiling Once"; - prefix = "(431)"; - } - } - - linedefexecplayer - { - title = "Linedef Executor (player/object)"; - - 412 - { - title = "Teleporter"; - prefix = "(412)"; - } - 425 - { - title = "Change Object State"; - prefix = "(425)"; - } - 426 - { - title = "Stop Object"; - prefix = "(426)"; - } - 427 - { - title = "Award Score"; - prefix = "(427)"; - } - 432 - { - title = "Enable/Disable 2D Mode"; - prefix = "(432)"; - } - 433 - { - title = "Enable/Disable Gravity Flip"; - prefix = "(433)"; - } - 434 - { - title = "Award Power-Up"; - prefix = "(434)"; - } - 437 - { - title = "Disable Player Control"; - prefix = "(437)"; - } - 438 - { - title = "Change Object Size"; - prefix = "(438)"; - } - 442 - { - title = "Change Object Type State"; - prefix = "(442)"; - } - 457 - { - title = "Track Object's Angle"; - prefix = "(457)"; - } - 458 - { - title = "Stop Tracking Object's Angle"; - prefix = "(458)"; - } - 460 - { - title = "Award Rings"; - prefix = "(460)"; - } - 461 - { - title = "Spawn Object"; - prefix = "(461)"; - } - 462 - { - title = "Stop Timer/Exit Stage in Record Attack"; - prefix = "(462)"; - } - 463 - { - title = "Dye Object"; - prefix = "(463)"; - } - 464 - { - title = "Trigger Egg Capsule"; - prefix = "(464)"; - } - 466 - { - title = "Set Level Failure State"; - prefix = "(466)"; - } - } - - linedefexecmisc - { - title = "Linedef Executor (misc.)"; - - 413 - { - title = "Change Music"; - prefix = "(413)"; - } - 414 - { - title = "Play Sound Effect"; - prefix = "(414)"; - } - 415 - { - title = "Run Script"; - prefix = "(415)"; - } - 422 - { - title = "Switch to Cut-Away View"; - prefix = "(422)"; - } - 423 - { - title = "Change Sky"; - prefix = "(423)"; - } - 424 - { - title = "Change Weather"; - prefix = "(424)"; - } - 436 - { - title = "Shatter FOF"; - prefix = "(436)"; - } - 439 - { - title = "Change Tagged Linedef's Textures"; - prefix = "(439)"; - } - 440 - { - title = "Start Metal Sonic Race"; - prefix = "(440)"; - } - 441 - { - title = "Condition Set Trigger"; - prefix = "(441)"; - } - 443 - { - title = "Call Lua Function"; - prefix = "(443)"; - } - 444 - { - title = "Earthquake"; - prefix = "(444)"; - } - 445 - { - title = "Make FOF Disappear/Reappear"; - prefix = "(445)"; - } - 446 - { - title = "Make FOF Crumble"; - prefix = "(446)"; - } - 447 - { - title = "Change Tagged Sector's Colormap"; - prefix = "(447)"; - } - 448 - { - title = "Change Skybox"; - prefix = "(448)"; - } - 449 - { - title = "Enable Bosses with Parameter"; - prefix = "(449)"; - } - 450 - { - title = "Execute Linedef Executor (specific tag)"; - prefix = "(450)"; - } - 451 - { - title = "Execute Linedef Executor (random tag in range)"; - prefix = "(451)"; - } - 452 - { - title = "Set FOF Translucency"; - prefix = "(452)"; - } - 453 - { - title = "Fade FOF"; - prefix = "(453)"; - } - 454 - { - title = "Stop Fading FOF"; - prefix = "(454)"; - } - 455 - { - title = "Fade Tagged Sector's Colormap"; - prefix = "(455)"; - } - 456 - { - title = "Stop Fading Tagged Sector's Colormap"; - prefix = "(456)"; - } - 459 - { - title = "Control Text Prompt"; - prefix = "(459)"; - } - } - - linedefexecpoly - { - title = "Linedef Executor (polyobject)"; - - 480 - { - title = "Door Slide"; - prefix = "(480)"; - } - 481 - { - title = "Door Swing"; - prefix = "(481)"; - } - 482 - { - title = "Move"; - prefix = "(482)"; - } - 483 - { - title = "Move, Override"; - prefix = "(483)"; - } - 484 - { - title = "Rotate Right"; - prefix = "(484)"; - } - 485 - { - title = "Rotate Right, Override"; - prefix = "(485)"; - } - 486 - { - title = "Rotate Left"; - prefix = "(486)"; - } - 487 - { - title = "Rotate Left, Override"; - prefix = "(487)"; - } - 488 - { - title = "Move by Waypoints"; - prefix = "(488)"; - } - 489 - { - title = "Turn Invisible, Intangible"; - prefix = "(489)"; - } - 490 - { - title = "Turn Visible, Tangible"; - prefix = "(490)"; - } - 491 - { - title = "Set Translucency"; - prefix = "(491)"; - } - 492 - { - title = "Fade Translucency"; - prefix = "(492)"; - } - } - - 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)"; - } - 516 - { - title = "Scroll Floor and Ceiling Texture"; - prefix = "(516)"; - } - 517 - { - title = "Scroll Floor and Ceiling Texture (Accelerative)"; - prefix = "(517)"; - } - 518 - { - title = "Scroll Floor and Ceiling Texture (Displacement)"; - prefix = "(518)"; - } - 520 - { - title = "Carry Objects on Floor"; - prefix = "(520)"; - } - 521 - { - title = "Carry Objects on Floor (Accelerative)"; - prefix = "(521)"; - } - 522 - { - title = "Carry Objects on Floor (Displacement)"; - prefix = "(522)"; - } - 523 - { - title = "Carry Objects on Ceiling"; - prefix = "(523)"; - } - 524 - { - title = "Carry Objects on Ceiling (Accelerative)"; - prefix = "(524)"; - } - 525 - { - title = "Carry Objects on Ceiling (Displacement)"; - prefix = "(525)"; - } - 526 - { - title = "Carry Objects on Floor and Ceiling"; - prefix = "(526)"; - } - 527 - { - title = "Carry Objects on Floor and Ceiling (Accelerative)"; - prefix = "(527)"; - } - 528 - { - title = "Carry Objects on Floor and Ceiling (Displacement)"; - prefix = "(528)"; - } - 530 - { - title = "Scroll Floor Texture and Carry Objects"; - prefix = "(530)"; - } - 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)"; - } - 534 - { - title = "Scroll Ceiling Texture and Carry Objects (Accelerative)"; - prefix = "(534)"; - } - 535 - { - title = "Scroll Ceiling Texture and Carry Objects (Displacement)"; - prefix = "(535)"; - } - 536 - { - title = "Scroll Floor and Ceiling Texture and Carry Objects"; - prefix = "(536)"; - } - 537 - { - title = "Scroll Floor and Ceiling Texture and Carry Objects (Accelerative)"; - prefix = "(537)"; - } - 538 - { - title = "Scroll Floor and Ceiling Texture and Carry Objects (Displacement)"; - prefix = "(538)"; - } - } - - pusher - { - title = "Pusher"; - - 541 - { - title = "Wind"; - prefix = "(541)"; - } - 542 - { - title = "Upwards Wind"; - prefix = "(542)"; - } - 543 - { - title = "Downwards Wind"; - prefix = "(543)"; - } - 544 - { - title = "Current"; - prefix = "(544)"; - } - 545 - { - title = "Upwards Current"; - prefix = "(545)"; - } - 546 - { - title = "Downwards Current"; - prefix = "(546)"; - } - 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)"; - } - 701 - { - title = "Slope Frontside Ceiling"; - prefix = "(701)"; - } - 702 - { - title = "Slope Frontside Floor and Ceiling"; - prefix = "(702)"; - } - 703 - { - title = "Slope Frontside Floor and Backside Ceiling"; - prefix = "(703)"; -ยด } - 704 - { - title = "Slope Frontside Floor by 3 Tagged Vertex Things"; - prefix = "(704)"; - } - 705 - { - title = "Slope Frontside Ceiling by 3 Tagged Vertex Things"; - prefix = "(705)"; - } - 710 - { - title = "Slope Backside Floor"; - prefix = "(710)"; - } - 711 - { - title = "Slope Backside Ceiling"; - prefix = "(711)"; - } - 712 - { - title = "Slope Backside Floor and Ceiling"; - prefix = "(712)"; - } - 713 - { - title = "Slope Backside Floor and Frontside Ceiling"; - prefix = "(713)"; - } - 714 - { - title = "Slope Backside Floor by 3 Tagged Vertex Things"; - prefix = "(714)"; - } - 715 - { - title = "Slope Backside Ceiling by 3 Tagged Vertex Things"; - prefix = "(715)"; - } - 720 - { - title = "Copy Frontside Floor Slope from Line Tag"; - prefix = "(720)"; - } - 721 - { - title = "Copy Frontside Ceiling Slope from Line Tag"; - prefix = "(721)"; - } - 722 - { - title = "Copy Frontside Floor and Ceiling Slope from Line Tag"; - prefix = "(722)"; - } - 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)"; - } - 910 - { - title = "100% Additive"; - prefix = "(910)"; - } - 911 - { - title = "90% Additive"; - prefix = "(911)"; - } - 912 - { - title = "80% Additive"; - prefix = "(912)"; - } - 913 - { - title = "70% Additive"; - prefix = "(913)"; - } - 914 - { - title = "60% Additive"; - prefix = "(914)"; - } - 915 - { - title = "50% Additive"; - prefix = "(915)"; - } - 916 - { - title = "40% Additive"; - prefix = "(916)"; - } - 917 - { - title = "30% Additive"; - prefix = "(917)"; - } - 918 - { - title = "20% Additive"; - prefix = "(918)"; - } - 919 - { - title = "10% Additive"; - prefix = "(919)"; - } - 920 - { - title = "100% Subtractive"; - prefix = "(920)"; - } - 921 - { - title = "90% Subtractive"; - prefix = "(921)"; - } - 922 - { - title = "80% Subtractive"; - prefix = "(922)"; - } - 923 - { - title = "70% Subtractive"; - prefix = "(923)"; - } - 924 - { - title = "60% Subtractive"; - prefix = "(924)"; - } - 925 - { - title = "50% Subtractive"; - prefix = "(925)"; - } - 926 - { - title = "40% Subtractive"; - prefix = "(926)"; - } - 927 - { - title = "30% Subtractive"; - prefix = "(927)"; - } - 928 - { - title = "20% Subtractive"; - prefix = "(928)"; - } - 929 - { - title = "10% Subtractive"; - prefix = "(929)"; - } - 930 - { - title = "100% Reverse Subtractive"; - prefix = "(930)"; - } - 931 - { - title = "90% Reverse Subtractive"; - prefix = "(931)"; - } - 932 - { - title = "80% Reverse Subtractive"; - prefix = "(932)"; - } - 933 - { - title = "70% Reverse Subtractive"; - prefix = "(933)"; - } - 934 - { - title = "60% Reverse Subtractive"; - prefix = "(934)"; - } - 935 - { - title = "50% Reverse Subtractive"; - prefix = "(935)"; - } - 936 - { - title = "40% Reverse Subtractive"; - prefix = "(936)"; - } - 937 - { - title = "30% Reverse Subtractive"; - prefix = "(937)"; - } - 938 - { - title = "20% Reverse Subtractive"; - prefix = "(938)"; - } - 939 - { - title = "10% Reverse Subtractive"; - prefix = "(939)"; - } - 940 - { - title = "Modulate"; - prefix = "(940)"; - } - } -} - udmf { misc @@ -2502,6 +712,7 @@ udmf { title = "Solid"; prefix = "(100)"; + id = "srb2_fofsolid"; arg0 { title = "Target sector tag"; @@ -2544,6 +755,7 @@ udmf { title = "Water"; prefix = "(120)"; + id = "srb2_fofwater"; arg0 { title = "Target sector tag"; @@ -2580,6 +792,7 @@ udmf { title = "Air Bobbing"; prefix = "(150)"; + id = "srb2_fofsolidopaque"; arg0 { title = "Target sector tag"; @@ -2606,6 +819,7 @@ udmf { title = "Water Bobbing"; prefix = "(160)"; + id = "srb2_fofsolidopaque"; arg0 { title = "Target sector tag"; @@ -2617,6 +831,7 @@ udmf { title = "Crumbling"; prefix = "(170)"; + id = "srb2_fofcrumbling"; arg0 { title = "Target sector tag"; @@ -2653,11 +868,12 @@ udmf } } } - + 190 { title = "Rising"; prefix = "(190)"; + id = "srb2_fofsolid"; arg0 { title = "Target sector tag"; @@ -2714,6 +930,7 @@ udmf { title = "Light Block"; prefix = "(200)"; + id = "srb2_foflight"; arg0 { title = "Target sector tag"; @@ -2731,6 +948,7 @@ udmf { title = "Fog Block"; prefix = "(202)"; + id = "srb2_foffog"; arg0 { title = "Target sector tag"; @@ -2742,6 +960,7 @@ udmf { title = "Intangible"; prefix = "(220)"; + id = "srb2_fofintangible"; arg0 { title = "Target sector tag"; @@ -2778,6 +997,7 @@ udmf { title = "Intangible, Invisible"; prefix = "(223)"; + id = "srb2_fofintangibleinvisible"; arg0 { title = "Target sector tag"; @@ -2789,6 +1009,7 @@ udmf { title = "Mario Block"; prefix = "(250)"; + id = "srb2_fofsolidopaque"; arg0 { title = "Target sector tag"; @@ -2810,6 +1031,7 @@ udmf { title = "Thwomp Block"; prefix = "(251)"; + id = "srb2_fofsolidopaque"; arg0 { title = "Target sector tag"; @@ -2834,6 +1056,7 @@ udmf { title = "Bustable Block"; prefix = "(254)"; + id = "srb2_fofbustable"; arg0 { title = "Target sector tag"; @@ -2885,6 +1108,7 @@ udmf { title = "Quicksand"; prefix = "(257)"; + id = "srb2_fofsolidopaque"; arg0 { title = "Target sector tag"; @@ -2910,6 +1134,7 @@ udmf { title = "Laser"; prefix = "(258)"; + id = "srb2_foflaser"; arg0 { title = "Target sector tag"; @@ -2942,6 +1167,7 @@ udmf { title = "Custom"; prefix = "(259)"; + id = "srb2_fofcustom"; arg0 { title = "Target sector tag"; @@ -5686,6 +3912,7 @@ udmf { title = "Create Vertex-Based Slope"; prefix = "(704)"; + id = "srb2_vertexslope"; arg0 { title = "Plane"; @@ -5729,6 +3956,7 @@ udmf { title = "Copy Slope"; prefix = "(720)"; + id = "plane_copy"; arg0 { title = "Front floor tag"; diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg index ed0488a3f..e274fece6 100644 --- a/extras/conf/udb/Includes/SRB222_misc.cfg +++ b/extras/conf/udb/Includes/SRB222_misc.cfg @@ -1,24 +1,3 @@ -linedefflags -{ - 1 = "[0] Impassable"; - 2 = "[1] Block Enemies"; - 4 = "[2] Double-Sided"; - 8 = "[3] Upper Unpegged"; - 16 = "[4] Lower Unpegged"; - 32 = "[5] Slope Skew (E1)"; - 64 = "[6] Not Climbable"; - 128 = "[7] No Midtexture Skew (E2)"; - 256 = "[8] Peg Midtexture (E3)"; - 512 = "[9] Solid Midtexture (E4)"; - 1024 = "[10] Repeat Midtexture (E5)"; - 2048 = "[11] Netgame Only"; - 4096 = "[12] No Netgame"; - 8192 = "[13] Effect 6"; - 16384 = "[14] Bouncy Wall"; - 32768 = "[15] Transfer Line"; -} - - // Linedef flags UDMF translation table // This is needed for copy/paste and prefabs to work properly // When the UDMF field name is prefixed with ! it is inverted @@ -42,7 +21,6 @@ linedefflagstranslation 32768 = "transfer"; } - linedefflags_udmf { blocking = "Impassable"; @@ -74,19 +52,13 @@ linedefrenderstyles sectorflags { - colormapfog = "Fog Planes in Colormap"; - colormapfadesprites = "Fade Fullbright in Colormap"; - colormapprotected = "Protected Colormap"; - flipspecial_nofloor = "No Trigger on Floor Touch"; - flipspecial_ceiling = "Trigger on Ceiling Touch"; - triggerspecial_touch = "Trigger on Edge Touch"; - triggerspecial_headbump = "Trigger on Headbump"; - triggerline_plane = "Linedef Trigger Requires Plane Touch"; - triggerline_mobj = "Non-Pushables Can Trigger Linedef"; invertprecip = "Invert Precipitation"; gravityflip = "Flip Objects in Reverse Gravity"; heatwave = "Heat Wave"; noclipcamera = "Intangible to the Camera"; + colormapfog = "Fog Planes"; + colormapfadesprites = "Fade Fullbright"; + colormapprotected = "Protected from Tagging"; outerspace = "Space Countdown"; doublestepup = "Ramp Sector (double step-up/down)"; nostepdown = "Non-Ramp Sector (No step-down)"; @@ -104,23 +76,59 @@ sectorflags zoomtubeend = "Zoom Tube End"; finishline = "Circuit Finish Line"; ropehang = "Rope Hang"; + jumpflip = "Flip Gravity on Jump"; + gravityoverride = "Make Reverse Gravity Temporary"; + flipspecial_nofloor = "No Trigger on Floor Touch"; + flipspecial_ceiling = "Trigger on Ceiling Touch"; + triggerspecial_touch = "Trigger on Edge Touch"; + triggerspecial_headbump = "Trigger on Headbump"; + triggerline_plane = "Linedef Trigger Requires Plane Touch"; + triggerline_mobj = "Non-Pushables Can Trigger Linedef"; } -thingflags +sectorflagscategories { - 1 = "[1] Extra"; - 2 = "[2] Flip"; - 4 = "[4] Special"; - 8 = "[8] Ambush"; + invertprecip = "regular"; + gravityflip = "regular"; + heatwave = "regular"; + noclipcamera = "regular"; + colormapfog = "colormap"; + colormapfadesprites = "colormap"; + colormapprotected = "colormap"; + outerspace = "special"; + doublestepup = "special"; + nostepdown = "special"; + speedpad = "special"; + starpostactivator = "special"; + exit = "special"; + specialstagepit = "special"; + returnflag = "special"; + redteambase = "special"; + blueteambase = "special"; + fan = "special"; + supertransform = "special"; + forcespin = "special"; + zoomtubestart = "special"; + zoomtubeend = "special"; + finishline = "special"; + ropehang = "special"; + jumpflip = "special"; + gravityoverride = "special"; + flipspecial_nofloor = "trigger"; + flipspecial_ceiling = "trigger"; + triggerspecial_touch = "trigger"; + triggerspecial_headbump = "trigger"; + triggerline_plane = "trigger"; + triggerline_mobj = "trigger"; } // THING FLAGS thingflags_udmf { flip = "Flip"; + absolutez = "Absolute Z height"; } - // 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 @@ -130,9 +138,9 @@ thingflagstranslation 2 = "flip"; 4 = "special"; 8 = "ambush"; + 16 = "absolutez"; } - // DEFAULT SECTOR BRIGHTNESS LEVELS sectorbrightness { @@ -171,6 +179,8 @@ sectorbrightness 0; } +numbrightnesslevels = 32; + /* TEXTURES AND FLAT SOURCES This tells Doom Builder where to find the information for textures @@ -221,145 +231,18 @@ universalfields { sector { - lightalpha - { - type = 0; - default = 25; - } - - fadealpha - { - type = 0; - default = 25; - } - - fadestart - { - type = 0; - default = 0; - } - - fadeend - { - type = 0; - default = 33; - } - - foglighting - { - type = 3; - default = false; - } - - friction - { - type = 1; - default = 0.90625; - } - - triggertag - { - type = 15; - default = 0; - } - - triggerer - { - type = 2; - default = "Player"; - } } linedef { - arg5 - { - type = 0; - default = 0; - } - arg6 - { - type = 0; - default = 0; - } - arg7 - { - type = 0; - default = 0; - } - arg8 - { - type = 0; - default = 0; - } - arg9 - { - type = 0; - default = 0; - } - stringarg0 - { - type = 2; - default = ""; - } - stringarg1 - { - type = 2; - default = ""; - } - executordelay - { - type = 0; - default = 0; - } } sidedef { - repeatcnt - { - type = 0; - default = 0; - } } thing { - arg5 - { - type = 0; - default = 0; - } - arg6 - { - type = 0; - default = 0; - } - arg7 - { - type = 0; - default = 0; - } - arg8 - { - type = 0; - default = 0; - } - arg9 - { - type = 0; - default = 0; - } - stringarg0 - { - type = 2; - default = ""; - } - stringarg1 - { - type = 2; - default = ""; - } } } @@ -378,87 +261,6 @@ 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 @@ -682,48 +484,32 @@ thingsfilters } + //filter3 + //{ + // name = "Normal Gravity"; + // category = ""; + // type = -1; + // + // fields + // { + // 2 = false; + // } + //} - filter3 - { - name = "Normal Gravity"; - category = ""; - type = -1; - - fields - { - 2 = false; - } - - } - - - filter4 - { - name = "Reverse Gravity"; - category = ""; - type = -1; - - fields - { - 2 = true; - } - - } + //filter4 + //{ + // name = "Reverse Gravity"; + // category = ""; + // type = -1; + // + // fields + // { + // 2 = true; + // } + //} } // 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"; @@ -734,6 +520,8 @@ speciallinedefs_udmf lowerunpeggedflag = "dontpegbottom"; repeatmidtextureflag = "wrapmidtex"; pegmidtextureflag = "midpeg"; + slopeskewflag = "skewtd"; + nomidtextureskewflag = "noskew"; } scriptlumpnames diff --git a/extras/conf/udb/Includes/SRB222_sectors.cfg b/extras/conf/udb/Includes/SRB222_sectors.cfg deleted file mode 100644 index 5b3ad4155..000000000 --- a/extras/conf/udb/Includes/SRB222_sectors.cfg +++ /dev/null @@ -1,107 +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/Spheres Parameters "; - 176 = "Custom Global Gravity "; - 1280 = "Speed Pad"; - 1536 = "Flip Gravity on Jump"; - 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/Spheres Parameters "; - 176 = "Custom Global Gravity "; - } - - third - { - 0 = "Normal"; - 1280 = "Speed Pad"; - 1536 = "Flip Gravity on Jump"; - } - - 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"; - } -} diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg index b4508c91e..df08e3ac5 100644 --- a/extras/conf/udb/Includes/SRB222_things.cfg +++ b/extras/conf/udb/Includes/SRB222_things.cfg @@ -3,3175 +3,8 @@ // 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 -doom -{ - 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; - 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; - } - 103 - { - title = "Buzz (Gold)"; - sprite = "BUZZA1"; - width = 28; - height = 40; - } - 104 - { - title = "Buzz (Red)"; - sprite = "RBUZA1"; - width = 28; - height = 40; - } - 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; - } - 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; - } - 138 - { - title = "Banpyura"; - sprite = "CR2BA0"; - width = 24; - height = 32; - } - 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; - } - 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; - } - 136 - { - title = "Pyre Fly"; - sprite = "PYREA0"; - width = 24; - height = 34; - } - 137 - { - title = "Dragonbomber"; - sprite = "DRABA1"; - width = 28; - height = 48; - } - 105 - { - title = "Jetty-Syn Bomber"; - sprite = "JETBB1"; - width = 20; - height = 50; - } - 106 - { - title = "Jetty-Syn Gunner"; - sprite = "JETGB1"; - width = 20; - height = 48; - } - 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; - } - 133 - { - title = "Hangster"; - sprite = "HBATC1"; - width = 24; - height = 24; - hangs = 1; - } - 127 - { - title = "Hive Elemental"; - sprite = "HIVEA0"; - width = 32; - height = 80; - } - 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; - } - 201 - { - title = "Egg Slimer"; - sprite = "EGGNA1"; - width = 24; - height = 76; - } - 202 - { - title = "Sea Egg"; - sprite = "EGGOA1"; - width = 32; - height = 116; - } - 203 - { - title = "Egg Colosseum"; - sprite = "EGGPA1"; - width = 24; - height = 76; - } - 204 - { - title = "Fang"; - sprite = "FANGA1"; - width = 24; - height = 60; - } - 206 - { - title = "Brak Eggman (Old)"; - sprite = "BRAKB1"; - width = 48; - height = 160; - } - 207 - { - title = "Metal Sonic (Race)"; - sprite = "METLI1"; - width = 16; - height = 48; - } - 208 - { - title = "Metal Sonic (Battle)"; - sprite = "METLC1"; - width = 16; - height = 48; - } - 209 - { - title = "Brak Eggman"; - sprite = "BRAK01"; - width = 48; - height = 160; - } - 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; - sprite = "internal:eggmanway"; - } - 293 - { - title = "Metal Sonic Gather Point"; - sprite = "internal:metal"; - width = 8; - height = 16; - } - 294 - { - title = "Fang Waypoint"; - sprite = "internal:eggmanway"; - width = 8; - height = 16; - } - } - - rings - { - color = 14; // Yellow - title = "Rings and Weapon Panels"; - width = 24; - height = 24; - 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; - } - 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"; - } - 322 - { - title = "Emblem"; - sprite = "EMBMA0"; - width = 16; - height = 30; - } - } - - boxes - { - color = 7; // Gray - blocking = 2; - title = "Monitors"; - width = 18; - height = 40; - - 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"; - } - 410 - { - title = "Eggman"; - sprite = "TVEGA0"; - } - 411 - { - title = "Teleporter"; - sprite = "TVMXA0"; - } - 413 - { - title = "Gravity Boots"; - sprite = "TVGVA0"; - } - 414 - { - title = "CTF Team Ring Monitor (Red)"; - sprite = "TRRIA0"; - } - 415 - { - title = "CTF Team Ring Monitor (Blue)"; - sprite = "TBRIA0"; - } - 416 - { - title = "Recycler"; - sprite = "TVRCA0"; - } - 418 - { - title = "Score (1,000 Points)"; - sprite = "TV1KA0"; - } - 419 - { - title = "Score (10,000 Points)"; - sprite = "TVTKA0"; - } - 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; - - 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; - } - 501 - { - title = "Signpost"; - sprite = "SIGND0"; - width = 8; - height = 32; - } - 502 - { - arrow = 1; - title = "Star Post"; - sprite = "STPTA0M0"; - width = 64; - height = 128; - } - 520 - { - title = "Bomb Sphere"; - sprite = "SPHRD0"; - width = 16; - height = 24; - } - 521 - { - title = "Spikeball"; - sprite = "SPIKA0"; - width = 12; - height = 8; - } - 522 - { - title = "Wall Spike"; - sprite = "WSPKALAR"; - width = 16; - height = 14; - arrow = 1; - } - 523 - { - title = "Spike"; - sprite = "USPKA0"; - width = 8; - height = 32; - } - 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; - } - 541 - { - title = "Gas Jet"; - sprite = "STEMD0"; - width = 32; - } - 542 - { - title = "Bumper"; - sprite = "BUMPA0"; - width = 32; - height = 64; - } - 543 - { - title = "Balloon"; - sprite = "BLONA0"; - width = 32; - height = 64; - } - 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; - } - 556 - { - arrow = 1; - title = "Diagonal Red Spring"; - sprite = "RSPRD2"; - width = 16; - } - 557 - { - arrow = 1; - title = "Diagonal Blue Spring"; - sprite = "BSPRD2"; - width = 16; - } - 558 - { - arrow = 1; - title = "Horizontal Yellow Spring"; - sprite = "SSWYD2D8"; - width = 16; - height = 32; - } - 559 - { - arrow = 1; - title = "Horizontal Red Spring"; - sprite = "SSWRD2D8"; - width = 16; - height = 32; - } - 560 - { - arrow = 1; - title = "Horizontal Blue Spring"; - sprite = "SSWBD2D8"; - 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"; - width = 28; - height = 2; - } - 545 - { - arrow = 1; - title = "Red Boost Panel"; - sprite = "BSTRA0"; - 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; - } - 605 - { - title = "Circle of Rings (Big)"; - sprite = "RINGA0"; - width = 192; - } - 606 - { - title = "Circle of Blue Spheres"; - sprite = "SPHRA0"; - width = 96; - height = 192; - } - 607 - { - title = "Circle of Blue Spheres (Big)"; - sprite = "SPHRA0"; - width = 192; - } - 608 - { - title = "Circle of Rings and Spheres"; - sprite = "SPHRA0"; - width = 96; - height = 192; - } - 609 - { - title = "Circle of Rings and Spheres (Big)"; - sprite = "SPHRA0"; - width = 192; - } - } - - 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"; - } - - 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"; - } - - 754 - { - title = "Push Point"; - sprite = "GWLGA0"; - } - 755 - { - title = "Pull Point"; - sprite = "GWLRA0"; - } - 756 - { - title = "Blast Linedef Executor"; - sprite = "TOADA0"; - width = 32; - height = 16; - } - 757 - { - title = "Fan Particle Generator"; - sprite = "PRTLA0"; - width = 8; - height = 16; - } - 758 - { - title = "Object Angle Anchor"; - sprite = "internal:view"; - } - 760 - { - title = "PolyObject Anchor"; - sprite = "internal:polyanchor"; - } - 761 - { - title = "PolyObject Spawn Point"; - sprite = "internal:polycenter"; - } - 762 - { - title = "PolyObject Spawn Point (Crush)"; - sprite = "internal:polycentercrush"; - } - 780 - { - title = "Skybox View Point"; - sprite = "internal:skyb"; - } - } - - 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; - } - 1009 - { - arrow = 1; - blocking = 2; - title = "Gargoyle (Big)"; - sprite = "GARGB1"; - width = 32; - height = 80; - } - 1001 - { - title = "Seaweed"; - sprite = "SEWEA0"; - width = 24; - height = 56; - } - 1002 - { - title = "Dripping Water"; - sprite = "DRIPD0"; - width = 8; - height = 16; - hangs = 1; - } - 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; - } - 1008 - { - title = "Stalagmite (DSZ1)"; - sprite = "DSTGA0"; - width = 8; - height = 116; - } - 1010 - { - arrow = 1; - title = "Light Beam"; - sprite = "LIBEARAL"; - width = 16; - height = 16; - } - 1011 - { - title = "Stalagmite (DSZ2)"; - sprite = "DSTGA0"; - width = 8; - height = 116; - } - 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; - } - 1102 - { - arrow = 1; - blocking = 2; - title = "Eggman Statue"; - sprite = "ESTAA1"; - width = 32; - height = 240; - } - 1103 - { - title = "CEZ Flower"; - sprite = "FWR4A0"; - width = 16; - height = 40; - } - 1104 - { - title = "Mace Spawnpoint"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1105 - { - title = "Chain with Maces Spawnpoint"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1106 - { - title = "Chained Spring Spawnpoint"; - sprite = "YSPBA0"; - width = 17; - height = 34; - } - 1107 - { - title = "Chain Spawnpoint"; - sprite = "BMCHA0"; - width = 17; - height = 34; - } - 1108 - { - arrow = 1; - title = "Hidden Chain Spawnpoint"; - sprite = "internal:chain3"; - width = 17; - height = 34; - } - 1109 - { - title = "Firebar Spawnpoint"; - sprite = "BFBRA0"; - width = 17; - height = 34; - } - 1110 - { - title = "Custom Mace Spawnpoint"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1111 - { - arrow = 1; - blocking = 2; - title = "Crawla Statue"; - sprite = "CSTAA1"; - width = 16; - height = 40; - } - 1112 - { - arrow = 1; - blocking = 2; - title = "Lance-a-Bot Statue"; - sprite = "CBBSA1"; - width = 32; - height = 72; - } - 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; - } - 1120 - { - title = "Candle Pricket"; - sprite = "CNDLB0"; - width = 8; - height = 176; - } - 1121 - { - title = "Flame Holder"; - sprite = "FLMHA0"; - width = 24; - height = 80; - } - 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; - } - 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; - } - 1201 - { - title = "Tumbleweed (Small)"; - sprite = "STBLA0"; - width = 12; - height = 24; - } - 1202 - { - arrow = 1; - title = "Rock Spawner"; - sprite = "ROIAA0"; - width = 8; - height = 16; - } - 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; - } - 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; - } - 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; - } - 1301 - { - title = "Flame Jet (Vertical)"; - sprite = "internal:flamev"; - width = 16; - height = 40; - } - 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; - } - 1305 - { - title = "Rollout Rock"; - sprite = "PUMIA1A5"; - width = 30; - height = 60; - } - 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; - } - 1501 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Up)"; - sprite = "BGARA1"; - width = 16; - height = 40; - } - 1502 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Down)"; - sprite = "BGARA1"; - width = 16; - height = 40; - } - 1503 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Long)"; - sprite = "BGARA1"; - width = 16; - height = 40; - } - 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; - } - } - - 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 = "Nightopian"; - sprite = "NTPNA1"; - width = 16; - height = 40; - } - } - - nightstrk - { - color = 13; // Pink - title = "NiGHTS Track"; - width = 8; - height = 4096; - sprite = "UNKNA0"; - - 1700 - { - title = "Axis"; - sprite = "internal:axis1"; - circle = 1; - } - 1701 - { - title = "Axis Transfer"; - sprite = "internal:axis2"; - } - 1702 - { - title = "Axis Transfer Line"; - sprite = "internal:axis3"; - } - 1710 - { - title = "Ideya Capture"; - sprite = "CAPSA0"; - width = 72; - height = 144; - } - } - - nights - { - color = 13; // Pink - title = "NiGHTS Items"; - width = 16; - height = 32; - - 1703 - { - title = "Ideya Drone"; - sprite = "NDRNA1"; - width = 16; - height = 56; - } - 1704 - { - arrow = 1; - title = "NiGHTS Bumper"; - sprite = "NBMPG3G7"; - width = 32; - height = 64; - } - 1705 - { - arrow = 1; - title = "Hoop (Generic)"; - sprite = "HOOPA0"; - width = 80; - height = 160; - } - 1706 - { - title = "Blue Sphere"; - sprite = "SPHRA0"; - width = 16; - height = 24; - } - 1707 - { - title = "Super Paraloop"; - sprite = "NPRUA0"; - } - 1708 - { - title = "Drill Refill"; - sprite = "NPRUB0"; - } - 1709 - { - title = "Nightopian Helper"; - sprite = "NPRUC0"; - } - 1711 - { - title = "Extra Time"; - sprite = "NPRUD0"; - } - 1712 - { - title = "Link Freeze"; - sprite = "NPRUE0"; - } - 1713 - { - arrow = 1; - title = "Hoop (Customizable)"; - sprite = "HOOPA0"; - width = 80; - height = 160; - } - 1714 - { - title = "Ideya Anchor Point"; - sprite = "internal:axis1"; - width = 8; - height = 16; - } - } - - mario - { - color = 6; // Brown - title = "Mario"; - - 1800 - { - title = "Coin"; - sprite = "COINA0"; - width = 16; - height = 24; - } - 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; - } - 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; - } - 1853 - { - blocking = 2; - title = "Snowman (With Hat)"; - sprite = "XMS3B0"; - width = 16; - height = 80; - } - 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; - } - } - - 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; - } - 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; - } - 2007 - { - title = "Jack-o'-lantern 2"; - sprite = "PUMKB0"; - width = 16; - height = 40; - } - 2008 - { - title = "Jack-o'-lantern 3"; - sprite = "PUMKC0"; - width = 16; - height = 40; - } - 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; - } - 2105 - { - title = "Mistletoe"; - sprite = "XMS6A0"; - width = 52; - height = 106; - } - } - - tutorial - { - color = 10; // Green - title = "Tutorial"; - - 799 - { - title = "Tutorial Plant"; - sprite = "TUPFH0"; - width = 40; - height = 144; - } - } - - flickies - { - color = 10; // Green - title = "Flickies"; - width = 8; - height = 20; - - 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"; - } - 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"; - } - } -} - udmf { - editor - { - color = 15; // White - arrow = 1; - title = ""; - error = -1; - width = 8; - height = 16; - sort = 1; - - 3328 = "3D Mode Start"; - } starts { @@ -3974,7 +807,7 @@ udmf bosses { - color = 8; // Dark_Gray + color = 4; // Dark Red arrow = 1; title = "Bosses"; @@ -4355,95 +1188,185 @@ udmf width = 24; height = 24; sprite = "RINGA0"; - arg0 - { - title = "Float?"; - type = 11; - enum = "yesno"; - } 300 { title = "Ring"; sprite = "RINGA0"; width = 16; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 301 { title = "Bounce Ring"; - sprite = "internal:RNGBA0"; + sprite = "RNGBA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 302 { title = "Rail Ring"; - sprite = "internal:RNGRA0"; + sprite = "RNGRA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 303 { title = "Infinity Ring"; - sprite = "internal:RNGIA0"; + sprite = "RNGIA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 304 { title = "Automatic Ring"; - sprite = "internal:RNGAA0"; + sprite = "RNGAA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 305 { title = "Explosion Ring"; - sprite = "internal:RNGEA0"; + sprite = "RNGEA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 306 { title = "Scatter Ring"; - sprite = "internal:RNGSA0"; + sprite = "RNGSA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 307 { title = "Grenade Ring"; - sprite = "internal:RNGGA0"; + sprite = "RNGGA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 308 { title = "CTF Team Ring (Red)"; - sprite = "internal:RRNGA0"; + sprite = "internal:TRNGA0R"; width = 16; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 309 { title = "CTF Team Ring (Blue)"; - sprite = "internal:BRNGA0"; + sprite = "internal:TRNGA0B"; width = 16; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 330 { title = "Bounce Ring Panel"; - sprite = "internal:PIKBA0"; + sprite = "PIKBA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 331 { title = "Rail Ring Panel"; - sprite = "internal:PIKRA0"; + sprite = "PIKRA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 332 { title = "Automatic Ring Panel"; - sprite = "internal:PIKAA0"; + sprite = "PIKAA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 333 { title = "Explosion Ring Panel"; - sprite = "internal:PIKEA0"; + sprite = "PIKEA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 334 { title = "Scatter Ring Panel"; - sprite = "internal:PIKSA0"; + sprite = "PIKSA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } 335 { title = "Grenade Ring Panel"; - sprite = "internal:PIKGA0"; + sprite = "PIKGA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } } } @@ -4562,16 +1485,16 @@ udmf title = "Monitors"; width = 18; height = 40; - arg0 - { - title = "Death trigger tag"; - type = 15; - } 400 { title = "Super Ring (10 Rings)"; sprite = "TVRIA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4583,6 +1506,11 @@ udmf { title = "Pity Shield"; sprite = "TVPIA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4594,6 +1522,11 @@ udmf { title = "Attraction Shield"; sprite = "TVATA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4605,6 +1538,11 @@ udmf { title = "Force Shield"; sprite = "TVFOA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4616,6 +1554,11 @@ udmf { title = "Armageddon Shield"; sprite = "TVARA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4627,6 +1570,11 @@ udmf { title = "Whirlwind Shield"; sprite = "TVWWA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4638,6 +1586,11 @@ udmf { title = "Elemental Shield"; sprite = "TVELA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4649,6 +1602,11 @@ udmf { title = "Super Sneakers"; sprite = "TVSSA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4660,6 +1618,11 @@ udmf { title = "Invincibility"; sprite = "TVIVA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4671,6 +1634,11 @@ udmf { title = "Extra Life"; sprite = "TV1UA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4692,11 +1660,21 @@ udmf { title = "Eggman"; sprite = "TVEGA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 411 { title = "Teleporter"; sprite = "TVMXA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4708,21 +1686,41 @@ udmf { title = "Gravity Boots"; sprite = "TVGVA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 414 { title = "CTF Team Ring Monitor (Red)"; sprite = "TRRIA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 415 { title = "CTF Team Ring Monitor (Blue)"; sprite = "TBRIA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 416 { title = "Recycler"; sprite = "TVRCA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4734,16 +1732,31 @@ udmf { title = "Score (1,000 Points)"; sprite = "TV1KA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 419 { title = "Score (10,000 Points)"; sprite = "TVTKA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 420 { title = "Flame Shield"; sprite = "TVFLA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4755,6 +1768,11 @@ udmf { title = "Water Shield"; sprite = "TVBBA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4766,6 +1784,11 @@ udmf { title = "Lightning Shield"; sprite = "TVZPA0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } arg1 { title = "Respawn behavior"; @@ -4782,76 +1805,136 @@ udmf title = "Monitors (Respawning)"; width = 20; height = 44; - arg0 - { - title = "Death trigger tag"; - type = 15; - } 431 { title = "Pity Shield (Respawn)"; sprite = "TVPIB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 432 { title = "Attraction Shield (Respawn)"; sprite = "TVATB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 433 { title = "Force Shield (Respawn)"; sprite = "TVFOB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 434 { title = "Armageddon Shield (Respawn)"; sprite = "TVARB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 435 { title = "Whirlwind Shield (Respawn)"; sprite = "TVWWB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 436 { title = "Elemental Shield (Respawn)"; sprite = "TVELB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 437 { title = "Super Sneakers (Respawn)"; sprite = "TVSSB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 438 { title = "Invincibility (Respawn)"; sprite = "TVIVB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 440 { title = "Eggman (Respawn)"; sprite = "TVEGB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 443 { title = "Gravity Boots (Respawn)"; sprite = "TVGVB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 450 { title = "Flame Shield (Respawn)"; sprite = "TVFLB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 451 { title = "Water Shield (Respawn)"; sprite = "TVBBB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } 452 { title = "Lightning Shield (Respawn)"; sprite = "TVZPB0"; + arg0 + { + title = "Death trigger tag"; + type = 15; + } } } @@ -5235,13 +2318,13 @@ udmf { arrow = 0; title = "5 Vertical Rings (Yellow Spring)"; - sprite = "RINGA0"; + sprite = "internal:ringverticalyellow"; } 601 { arrow = 0; title = "5 Vertical Rings (Red Spring)"; - sprite = "RINGA0"; + sprite = "internal:ringverticalred"; height = 1024; } 602 @@ -5259,41 +2342,47 @@ udmf 604 { title = "Circle of Rings"; - sprite = "RINGA0"; + sprite = "internal:circlering"; width = 96; height = 192; + centerhitbox = true; } 605 { title = "Circle of Rings (Big)"; - sprite = "RINGA0"; + sprite = "internal:circlebigring"; width = 192; + centerhitbox = true; } 606 { title = "Circle of Blue Spheres"; - sprite = "SPHRA0"; + sprite = "internal:circlesphere"; width = 96; height = 192; + centerhitbox = true; } 607 { title = "Circle of Blue Spheres (Big)"; - sprite = "SPHRA0"; + sprite = "internal:circlebigsphere"; width = 192; + centerhitbox = true; } 608 { title = "Circle of Rings and Spheres"; - sprite = "SPHRA0"; + sprite = "internal:circleringsphere"; width = 96; height = 192; + centerhitbox = true; } 609 { title = "Circle of Rings and Spheres (Big)"; - sprite = "SPHRA0"; + sprite = "internal:circlebigringsphere"; width = 192; + centerhitbox = true; } 610 { @@ -5322,6 +2411,7 @@ udmf sprite = "RINGA0"; width = 96; height = 192; + centerhitbox = true; arg0 { title = "Number of items"; @@ -5429,7 +2519,7 @@ udmf 756 { title = "Blast Linedef Executor"; - sprite = "TOADA0"; + sprite = "internal:blastexec"; width = 32; height = 16; arg0 @@ -5441,7 +2531,7 @@ udmf 757 { title = "Fan Particle Generator"; - sprite = "PRTLA0"; + sprite = "internal:fanparticles"; width = 8; height = 16; arg0 @@ -5490,11 +2580,6 @@ udmf title = "PolyObject Spawn Point"; sprite = "internal:polycenter"; } - 762 - { - title = "PolyObject Spawn Point (Crush)"; - sprite = "internal:polycentercrush"; - } 780 { title = "Skybox View Point"; @@ -5514,7 +2599,7 @@ udmf greenflower { - color = 10; // Green + color = 2; // Green title = "Greenflower"; 800 @@ -5619,7 +2704,7 @@ udmf technohill { - color = 10; // Green + color = 2; // Green title = "Techno Hill"; 900 @@ -5663,7 +2748,7 @@ udmf deepsea { - color = 10; // Green + color = 2; // Green title = "Deep Sea"; 1000 @@ -5823,7 +2908,7 @@ udmf castleeggman { - color = 10; // Green + color = 2; // Green title = "Castle Eggman"; 1100 @@ -6386,7 +3471,7 @@ udmf aridcanyon { - color = 10; // Green + color = 2; // Green title = "Arid Canyon"; 1200 @@ -6511,6 +3596,7 @@ udmf sprite = "WWSGAR"; width = 22; height = 64; + wallsprite = true; } 1213 { @@ -6518,6 +3604,7 @@ udmf sprite = "WWS2AR"; width = 22; height = 64; + wallsprite = true; } 1214 { @@ -6525,6 +3612,7 @@ udmf sprite = "WWS3ALAR"; width = 16; height = 192; + wallsprite = true; } 1215 { @@ -6644,7 +3732,7 @@ udmf redvolcano { - color = 10; // Green + color = 2; // Green title = "Red Volcano"; 1300 @@ -6789,7 +3877,7 @@ udmf botanicserenity { - color = 10; // Green + color = 2; // Green title = "Botanic Serenity"; width = 16; height = 32; @@ -7032,7 +4120,7 @@ udmf azuretemple { - color = 10; // Green + color = 2; // Green title = "Azure Temple"; 1500 @@ -7144,7 +4232,7 @@ udmf dreamhill { - color = 10; // Green + color = 2; // Green title = "Dream Hill"; 1600 @@ -7178,8 +4266,8 @@ udmf nightstrk { - color = 13; // Pink - title = "NiGHTS Track"; + color = 16; // Light Pink + title = "NiGHTS Track & Misc."; width = 8; height = 4096; sprite = "UNKNA0"; @@ -7207,8 +4295,8 @@ udmf type = 11; enum { - 0 = "Clockwise"; - 1 = "Counterclockwise"; + 0 = "Counterclockwise"; + 1 = "Clockwise"; } } } @@ -7238,30 +4326,6 @@ udmf title = "Order"; } } - 1710 - { - title = "Ideya Capture"; - sprite = "CAPSA0"; - width = 72; - height = 144; - arg0 - { - title = "Mare"; - } - arg1 - { - title = "Required spheres"; - } - } - } - - nights - { - color = 13; // Pink - title = "NiGHTS Items"; - width = 16; - height = 32; - 1703 { title = "Ideya Drone"; @@ -7299,6 +4363,41 @@ udmf enum = "noyes"; } } + 1710 + { + title = "Ideya Capture"; + sprite = "CAPSA0"; + width = 72; + height = 144; + arg0 + { + title = "Mare"; + } + arg1 + { + title = "Required spheres"; + } + } + 1714 + { + title = "Ideya Anchor Point"; + sprite = "internal:ideya"; + width = 8; + height = 16; + arg0 + { + title = "Mare"; + } + } + } + + nights + { + color = 13; // Pink + title = "NiGHTS Items"; + width = 16; + height = 32; + 1704 { arrow = 1; @@ -7399,25 +4498,15 @@ udmf { arrow = 1; title = "Hoop"; - sprite = "HOOPA0"; + sprite = "internal:nightshoop"; width = 80; height = 160; + centerhitbox = true; arg0 { title = "Radius"; } } - 1714 - { - title = "Ideya Anchor Point"; - sprite = "internal:axis1"; - width = 8; - height = 16; - arg0 - { - title = "Mare"; - } - } } mario @@ -7528,7 +4617,7 @@ udmf christmasdisco { - color = 10; // Green + color = 2; // Green title = "Christmas & Disco"; 1850 @@ -7643,7 +4732,7 @@ udmf stalagmites { - color = 10; // Green + color = 2; // Green title = "Stalagmites"; width = 16; height = 40; @@ -7722,7 +4811,7 @@ udmf hauntedheights { - color = 10; // Green + color = 2; // Green title = "Haunted Heights"; 2000 @@ -7828,7 +4917,7 @@ udmf frozenhillside { - color = 10; // Green + color = 2; // Green title = "Frozen Hillside"; 2100 @@ -7883,7 +4972,7 @@ udmf tutorial { - color = 10; // Green + color = 2; // Green title = "Tutorial"; 799 @@ -7901,65 +4990,170 @@ udmf flickies { - color = 10; // Green + color = 2; // Green title = "Flickies"; width = 8; height = 20; - arg0 - { - title = "Radius"; - } - arg1 - { - title = "Flags"; - type = 12; - enum - { - 1 = "Move aimlessly"; - 2 = "No movement"; - 4 = "Hop"; - } - } 2200 { title = "Bluebird"; sprite = "FL01A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2201 { title = "Rabbit"; sprite = "FL02A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2202 { title = "Chicken"; sprite = "FL03A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2203 { title = "Seal"; sprite = "FL04A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2204 { title = "Pig"; sprite = "FL05A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2205 { title = "Chipmunk"; sprite = "FL06A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2206 { title = "Penguin"; sprite = "FL07A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2207 { title = "Fish"; sprite = "FL08A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } arg2 { title = "Color"; @@ -7989,51 +5183,214 @@ udmf { title = "Ram"; sprite = "FL09A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2209 { title = "Puffin"; sprite = "FL10A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2210 { title = "Cow"; sprite = "FL11A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2211 { title = "Rat"; sprite = "FL12A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2212 { title = "Bear"; sprite = "FL13A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2213 { title = "Dove"; sprite = "FL14A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2214 { title = "Cat"; sprite = "FL15A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2215 { title = "Canary"; sprite = "FL16A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2216 { title = "Spider"; sprite = "FS01A1"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } 2217 { title = "Bat"; sprite = "FS02A0"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } } } -} + + editor + { + color = 15; // White + arrow = 1; + title = "3D Mode Start"; + error = -1; + width = 8; + height = 16; + sort = 1; + + 3328 = "3D Mode Start"; + } +} \ No newline at end of file diff --git a/extras/conf/udb/SRB2_22Doom.cfg b/extras/conf/udb/SRB2_22Doom.cfg deleted file mode 100644 index 9e733aa39..000000000 --- a/extras/conf/udb/SRB2_22Doom.cfg +++ /dev/null @@ -1,32 +0,0 @@ -/************************************************************************\ - Ultimate Doom 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"); -} - -//Default things filters -thingsfilters -{ - include("Includes\\SRB222_misc.cfg", "thingsfilters"); -} \ No newline at end of file diff --git a/src/console.c b/src/console.c index 88e7bc2ae..6d273f620 100644 --- a/src/console.c +++ b/src/console.c @@ -395,16 +395,16 @@ static void CON_SetupColormaps(void) // 0x1 0x3 0x9 0xF colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185); - colset(yellowmap, 82, 82, 73, 73, 73, 64, 64, 64, 66, 66, 66, 66, 67, 67, 67, 68); - colset(lgreenmap, 96, 96, 98, 98, 98, 101, 101, 101, 104, 104, 104, 104, 106, 106, 106, 107); - colset(bluemap, 146, 146, 147, 147, 147, 149, 149, 149, 152, 152, 152, 152, 155, 155, 155, 157); - colset(redmap, 32, 32, 33, 33, 33, 35, 35, 35, 39, 39, 39, 39, 42, 42, 42, 44); + colset(yellowmap, 82, 82, 73, 73, 73, 74, 74, 74, 66, 66, 66, 66, 67, 67, 67, 68); + colset(lgreenmap, 96, 96, 98, 98, 98, 100, 100, 100, 103, 103, 103, 103, 105, 105, 105, 107); + colset(bluemap, 146, 146, 147, 147, 147, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 151); + colset(redmap, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 37, 37, 37, 39); colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60); colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136); colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165); colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125); - colset(peridotmap, 72, 72, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94); + colset(peridotmap, 73, 73, 188, 188, 188, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94); colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172); colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229); colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 64e5aff6b..ca9f4a24e 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1318,9 +1318,9 @@ static boolean CL_SendJoin(void) static INT32 FindRejoinerNum(SINT8 node) { - char strippednodeaddress[64]; + char addressbuffer[64]; const char *nodeaddress; - char *port; + const char *strippednodeaddress; INT32 i; // Make sure there is no dead dress before proceeding to the stripping @@ -1331,10 +1331,8 @@ static INT32 FindRejoinerNum(SINT8 node) return -1; // Strip the address of its port - strcpy(strippednodeaddress, nodeaddress); - port = strchr(strippednodeaddress, ':'); - if (port) - *port = '\0'; + strcpy(addressbuffer, nodeaddress); + strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL); // Check if any player matches the stripped address for (i = 0; i < MAXPLAYERS; i++) @@ -2487,7 +2485,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic { if (!snake) { - F_MenuPresTicker(true); // title sky + F_MenuPresTicker(); // title sky F_TitleScreenTicker(true); F_TitleScreenDrawer(); } @@ -3645,6 +3643,9 @@ void SV_ResetServer(void) CV_RevertNetVars(); + // Ensure synched when creating a new server + M_CopyGameData(serverGamedata, clientGamedata); + DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); } @@ -3768,14 +3769,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (server && I_GetNodeAddress) { + char addressbuffer[64]; 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'; + strcpy(addressbuffer, address); + strcpy(playeraddress[newplayernum], + I_NetSplitAddress(addressbuffer, NULL)); } } } diff --git a/src/d_main.c b/src/d_main.c index 6506c9d4e..5861f9886 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1350,6 +1350,9 @@ void D_SRB2Main(void) CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); Z_Init(); + clientGamedata = M_NewGameDataStruct(); + serverGamedata = M_NewGameDataStruct(); + // Do this up here so that WADs loaded through the command line can use ExecCfg COM_Init(); @@ -1479,7 +1482,9 @@ void D_SRB2Main(void) // confusion issues when loading mods. strlcpy(gamedatafilename, M_GetNextParm(), sizeof gamedatafilename); } - G_LoadGameData(); + + G_LoadGameData(clientGamedata); + M_CopyGameData(serverGamedata, clientGamedata); #if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen @@ -1710,7 +1715,7 @@ void D_SRB2Main(void) // ... unless you're in a dedicated server. Yes, technically this means you can view any level by // running a dedicated server and joining it yourself, but that's better than making dedicated server's // lives hell. - else if (!dedicated && M_MapLocked(pstartmap)) + else if (!dedicated && M_MapLocked(pstartmap, serverGamedata)) I_Error("You need to unlock this level before you can warp to it!\n"); else { diff --git a/src/d_net.c b/src/d_net.c index 7de3dba56..768c9ac7e 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -1207,26 +1207,32 @@ static void Internal_FreeNodenum(INT32 nodenum) (void)nodenum; } +char *I_NetSplitAddress(char *host, char **port) +{ + boolean v4 = (strchr(host, '.') != NULL); + + host = strtok(host, v4 ? ":" : "[]"); + + if (port) + *port = strtok(NULL, ":"); + + return host; +} + SINT8 I_NetMakeNode(const char *hostname) { SINT8 newnode = -1; if (I_NetMakeNodewPort) { char *localhostname = strdup(hostname); - char *t = localhostname; - const char *port; + char *port; if (!localhostname) return newnode; + // retrieve portnum from address! - strtok(localhostname, ":"); - port = strtok(NULL, ":"); + hostname = I_NetSplitAddress(localhostname, &port); - // remove the port in the hostname as we've it already - while ((*t != ':') && (*t != '\0')) - t++; - *t = '\0'; - - newnode = I_NetMakeNodewPort(localhostname, port); + newnode = I_NetMakeNodewPort(hostname, port); free(localhostname); } return newnode; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 80a084e16..af44e53d6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2036,7 +2036,7 @@ static void Command_Map_f(void) // ... unless you're in a dedicated server. Yes, technically this means you can view any level by // running a dedicated server and joining it yourself, but that's better than making dedicated server's // lives hell. - if (!dedicated && M_MapLocked(newmapnum)) + if (!dedicated && M_MapLocked(newmapnum, serverGamedata)) { CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n")); Z_Free(realmapname); @@ -3945,18 +3945,12 @@ void ItemFinder_OnChange(void) if (!cv_itemfinder.value) return; // it's fine. - if (!M_SecretUnlocked(SECRET_ITEMFINDER)) + if (!M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata)) { CONS_Printf(M_GetText("You haven't earned this yet.\n")); CV_StealthSetValue(&cv_itemfinder, 0); return; } - else if (netgame || multiplayer) - { - CONS_Printf(M_GetText("This only works in single player.\n")); - CV_StealthSetValue(&cv_itemfinder, 0); - return; - } } /** Deals with a pointlimit change by printing the change to the console. @@ -4305,7 +4299,7 @@ void D_GameTypeChanged(INT32 lastgametype) static void Ringslinger_OnChange(void) { - if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && cv_ringslinger.value && !cv_debug) + if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && cv_ringslinger.value && !cv_debug) { CONS_Printf(M_GetText("You haven't earned this yet.\n")); CV_StealthSetValue(&cv_ringslinger, 0); @@ -4318,7 +4312,7 @@ static void Ringslinger_OnChange(void) static void Gravity_OnChange(void) { - if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && !cv_debug + if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && !cv_debug && strcmp(cv_gravity.string, cv_gravity.defaultvalue)) { CONS_Printf(M_GetText("You haven't earned this yet.\n")); diff --git a/src/deh_lua.c b/src/deh_lua.c index 068fe4f23..6dabb7e2d 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -10,20 +10,7 @@ /// \file deh_lua.c /// \brief Lua SOC library -#include "g_game.h" -#include "s_sound.h" -#include "z_zone.h" -#include "m_menu.h" -#include "m_misc.h" -#include "p_local.h" -#include "st_stuff.h" -#include "fastcmp.h" -#include "lua_script.h" -#include "lua_libs.h" - -#include "dehacked.h" #include "deh_lua.h" -#include "deh_tables.h" // freeslot takes a name (string only!) // and allocates it to the appropriate free slot. @@ -89,6 +76,8 @@ static inline int lib_freeslot(lua_State *L) strncpy(sprnames[j],word,4); //sprnames[j][4] = 0; used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now. + // Lua needs to update the value in _G if it exists + LUA_UpdateSprName(word, j); lua_pushinteger(L, j); r++; break; @@ -219,18 +208,27 @@ static int lib_dummysuper(lua_State *L) return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;; } -static inline int lib_getenum(lua_State *L) +static void CacheAndPushConstant(lua_State *L, const char *name, lua_Integer value) { - const char *word, *p; + // "cache" into _G + lua_pushstring(L, name); + lua_pushinteger(L, value); + lua_rawset(L, LUA_GLOBALSINDEX); + // push + lua_pushinteger(L, value); +} + +// Search for a matching constant variable. +// Result is stored into _G for faster subsequent use. (Except for SPR_ in the SOC parser) +static int ScanConstants(lua_State *L, boolean mathlib, const char *word) +{ + const char *p; fixed_t i; - boolean mathlib = lua_toboolean(L, lua_upvalueindex(1)); - if (lua_type(L,2) != LUA_TSTRING) - return 0; - word = lua_tostring(L,2); + if (strlen(word) == 1) { // Assume sprite frame if length 1. if (*word >= 'A' && *word <= '~') { - lua_pushinteger(L, *word-'A'); + CacheAndPushConstant(L, word, *word-'A'); return 1; } if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); @@ -240,7 +238,7 @@ static inline int lib_getenum(lua_State *L) p = word+3; for (i = 0; MOBJFLAG_LIST[i]; i++) if (fastcmp(p, MOBJFLAG_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1< 0)))) +extern UINT8 shareEmblems; + extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations // For racing @@ -616,10 +569,6 @@ extern INT32 cheats; extern tic_t hidetime; -extern UINT32 timesBeaten; // # of times the game has been beaten. -extern UINT32 timesBeatenWithEmeralds; -extern UINT32 timesBeatenUltimate; - // =========================== // Internal parameters, fixed. // =========================== diff --git a/src/f_finale.c b/src/f_finale.c index 68b2641a1..f529b4564 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -63,7 +63,6 @@ static tic_t stoptimer; static boolean keypressed = false; // (no longer) De-Demo'd Title Screen -static INT32 menuanimtimer; // Title screen: background animation timing mobj_t *titlemapcameraref = NULL; // menu presentation state @@ -75,6 +74,8 @@ INT32 curbgyspeed; boolean curbghide; boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus +static fixed_t curbgx = 0; +static fixed_t curbgy = 0; static UINT8 curDemo = 0; static UINT32 demoDelayLeft; static UINT32 demoIdleLeft; @@ -1411,7 +1412,7 @@ boolean F_CreditResponder(event_t *event) break; } - if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug) + if (!(serverGamedata->timesBeaten) && !(netgame || multiplayer) && !cv_debug) return false; if (event->type != ev_keydown) @@ -1573,23 +1574,17 @@ void F_GameEvaluationDrawer(void) #if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables if (finalecount >= 5*TICRATE) { + INT32 startcoord = 32; V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); - if (netgame) - V_DrawString(8, 96, V_YELLOWMAP, "Multiplayer games\ncan't unlock\nextras!"); - else + for (i = 0; i < MAXUNLOCKABLES; i++) { - INT32 startcoord = 32; - - for (i = 0; i < MAXUNLOCKABLES; i++) + if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS + && unlockables[i].type && !unlockables[i].nocecho) { - if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS - && unlockables[i].type && !unlockables[i].nocecho) - { - if (unlockables[i].unlocked) - V_DrawString(8, startcoord, 0, unlockables[i].name); - startcoord += 8; - } + if (clientGamedata->unlocked[i]) + V_DrawString(8, startcoord, 0, unlockables[i].name); + startcoord += 8; } } } @@ -1648,28 +1643,27 @@ void F_GameEvaluationTicker(void) if (finalecount == 5*TICRATE) { - if (netgame || multiplayer) // modify this when we finally allow unlocking stuff in 2P + serverGamedata->timesBeaten++; + clientGamedata->timesBeaten++; + + if (ALL7EMERALDS(emeralds)) { - HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8); - HU_SetCEchoDuration(6); - HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Multiplayer games can't unlock extras!"); + serverGamedata->timesBeatenWithEmeralds++; + clientGamedata->timesBeatenWithEmeralds++; + } + + if (ultimatemode) + { + serverGamedata->timesBeatenUltimate++; + clientGamedata->timesBeatenUltimate++; + } + + M_SilentUpdateUnlockablesAndEmblems(serverGamedata); + + if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata)) S_StartSound(NULL, sfx_s3k68); - } - else - { - ++timesBeaten; - if (ALL7EMERALDS(emeralds)) - ++timesBeatenWithEmeralds; - - if (ultimatemode) - ++timesBeatenUltimate; - - if (M_UpdateUnlockablesAndExtraEmblems()) - S_StartSound(NULL, sfx_s3k68); - - G_SaveGameData(); - } + G_SaveGameData(clientGamedata); } } @@ -2183,7 +2177,7 @@ void F_EndingDrawer(void) //colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<'|(trans<= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); + V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((serverGamedata->timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); } if (finalecount > STOPPINGPOINT-(20+(2*TICRATE))) @@ -2249,7 +2243,8 @@ void F_GameEndTicker(void) void F_InitMenuPresValues(void) { - menuanimtimer = 0; + curbgx = 0; + curbgy = 0; prevMenuId = 0; activeMenuId = MainDef.menuid; @@ -2282,17 +2277,11 @@ void F_InitMenuPresValues(void) // // F_SkyScroll // -void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) +void F_SkyScroll(const char *patchname) { - INT32 xscrolled, x, xneg = (scrollxspeed > 0) - (scrollxspeed < 0), tilex; - INT32 yscrolled, y, yneg = (scrollyspeed > 0) - (scrollyspeed < 0), tiley; - boolean xispos = (scrollxspeed >= 0), yispos = (scrollyspeed >= 0); + INT32 x, basey = 0; INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - INT16 patwidth, patheight; - INT32 pw, ph; // scaled by dupz patch_t *pat; - INT32 i, j; - fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer; if (rendermode == render_none) return; @@ -2303,43 +2292,34 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) return; } - if (!scrollxspeed && !scrollyspeed) + pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY); + + if (!curbgxspeed && !curbgyspeed) { - V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY)); + V_DrawPatchFill(pat); + W_UnlockCachedPatch(pat); return; } - pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY); + // Modulo the background scrolling to prevent jumps from integer overflows + // We already load the background patch here, so we can modulo it here + // to avoid also having to load the patch in F_MenuPresTicker + curbgx %= pat->width * 16; + curbgy %= pat->height * 16; - patwidth = pat->width; - patheight = pat->height; - pw = patwidth * dupz; - ph = patheight * dupz; + // Ooh, fancy frame interpolation + x = ((curbgx*dupz) + FixedInt((rendertimefrac-FRACUNIT) * curbgxspeed*dupz)) / 16; + basey = ((curbgy*dupz) + FixedInt((rendertimefrac-FRACUNIT) * curbgyspeed*dupz)) / 16; - tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center - tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2; + if (x > 0) // Make sure that we don't leave the left or top sides empty + x -= pat->width * dupz; + if (basey > 0) + basey -= pat->height * dupz; - fracmenuanimtimer = (menuanimtimer * FRACUNIT) - (FRACUNIT - rendertimefrac); - xscrolltimer = ((fracmenuanimtimer*scrollxspeed)/16 + patwidth*xneg*FRACUNIT) % (patwidth * FRACUNIT); - yscrolltimer = ((fracmenuanimtimer*scrollyspeed)/16 + patheight*yneg*FRACUNIT) % (patheight * FRACUNIT); - - // coordinate offsets - xscrolled = FixedInt(xscrolltimer * dupz); - yscrolled = FixedInt(yscrolltimer * dupz); - - for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0; - i < tilex; - x += pw, i++) + for (; x < vid.width; x += pat->width * dupz) { - for (y = (yispos) ? -ph*(tiley-1)+ph : 0, j = 0; - j < tiley; - y += ph, j++) - { - V_DrawScaledPatch( - (xispos) ? xscrolled - x : x + xscrolled, - (yispos) ? yscrolled - y : y + yscrolled, - V_NOSCALESTART, pat); - } + for (INT32 y = basey; y < vid.height; y += pat->height * dupz) + V_DrawScaledPatch(x, y, V_NOSCALESTART, pat); } W_UnlockCachedPatch(pat); @@ -2662,7 +2642,7 @@ void F_TitleScreenDrawer(void) if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + F_SkyScroll(curbgname); // Don't draw outside of the title screen, or if the patch isn't there. if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) @@ -3417,10 +3397,10 @@ luahook: // separate animation timer for backgrounds, since we also count // during GS_TIMEATTACK -void F_MenuPresTicker(boolean run) +void F_MenuPresTicker(void) { - if (run) - menuanimtimer++; + curbgx += curbgxspeed; + curbgy += curbgyspeed; } // (no longer) De-Demo'd Title Screen diff --git a/src/f_finale.h b/src/f_finale.h index 6ea1b5537..7f53bfbad 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -40,7 +40,7 @@ void F_TextPromptTicker(void); void F_GameEndDrawer(void); void F_IntroDrawer(void); void F_TitleScreenDrawer(void); -void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname); +void F_SkyScroll(const char *patchname); void F_GameEvaluationDrawer(void); void F_StartGameEvaluation(void); @@ -131,7 +131,7 @@ extern UINT16 curtttics; #define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0]) void F_InitMenuPresValues(void); -void F_MenuPresTicker(boolean run); +void F_MenuPresTicker(void); // // WIPE diff --git a/src/g_game.c b/src/g_game.c index 7386b2a84..b23980044 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -185,18 +185,6 @@ INT32 tokenbits; // Used for setting token bits // Old Special Stage INT32 sstimer; // Time allotted in the special stage -tic_t totalplaytime; -boolean gamedataloaded = false; - -// Time attack data for levels -// These are dynamically allocated for space reasons now -recorddata_t *mainrecords[NUMMAPS] = {NULL}; -nightsdata_t *nightsrecords[NUMMAPS] = {NULL}; -UINT8 mapvisited[NUMMAPS]; - -// Temporary holding place for nights data for the current map -nightsdata_t ntemprecords; - UINT32 bluescore, redscore; // CTF and Team Match team scores // ring count... for PERFECT! @@ -227,6 +215,7 @@ 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 shareEmblems = 0; // Set to 1 to share all picked up emblems in multiplayer UINT8 introtoplay; UINT8 creditscutscene; @@ -252,11 +241,6 @@ INT32 cheats; //for multiplayer cheat commands tic_t hidetime; -// Grading -UINT32 timesBeaten; -UINT32 timesBeatenWithEmeralds; -UINT32 timesBeatenUltimate; - typedef struct joystickvector2_s { INT32 xaxis; @@ -452,86 +436,86 @@ INT16 rw_maximums[NUM_WEAPONS] = }; // Allocation for time and nights data -void G_AllocMainRecordData(INT16 i) +void G_AllocMainRecordData(INT16 i, gamedata_t *data) { - if (!mainrecords[i]) - mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL); - memset(mainrecords[i], 0, sizeof(recorddata_t)); + if (!data->mainrecords[i]) + data->mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL); + memset(data->mainrecords[i], 0, sizeof(recorddata_t)); } -void G_AllocNightsRecordData(INT16 i) +void G_AllocNightsRecordData(INT16 i, gamedata_t *data) { - if (!nightsrecords[i]) - nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL); - memset(nightsrecords[i], 0, sizeof(nightsdata_t)); + if (!data->nightsrecords[i]) + data->nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL); + memset(data->nightsrecords[i], 0, sizeof(nightsdata_t)); } // MAKE SURE YOU SAVE DATA BEFORE CALLING THIS -void G_ClearRecords(void) +void G_ClearRecords(gamedata_t *data) { INT16 i; for (i = 0; i < NUMMAPS; ++i) { - if (mainrecords[i]) + if (data->mainrecords[i]) { - Z_Free(mainrecords[i]); - mainrecords[i] = NULL; + Z_Free(data->mainrecords[i]); + data->mainrecords[i] = NULL; } - if (nightsrecords[i]) + if (data->nightsrecords[i]) { - Z_Free(nightsrecords[i]); - nightsrecords[i] = NULL; + Z_Free(data->nightsrecords[i]); + data->nightsrecords[i] = NULL; } } } // For easy retrieval of records -UINT32 G_GetBestScore(INT16 map) +UINT32 G_GetBestScore(INT16 map, gamedata_t *data) { - if (!mainrecords[map-1]) + if (!data->mainrecords[map-1]) return 0; - return mainrecords[map-1]->score; + return data->mainrecords[map-1]->score; } -tic_t G_GetBestTime(INT16 map) +tic_t G_GetBestTime(INT16 map, gamedata_t *data) { - if (!mainrecords[map-1] || mainrecords[map-1]->time <= 0) + if (!data->mainrecords[map-1] || data->mainrecords[map-1]->time <= 0) return (tic_t)UINT32_MAX; - return mainrecords[map-1]->time; + return data->mainrecords[map-1]->time; } -UINT16 G_GetBestRings(INT16 map) +UINT16 G_GetBestRings(INT16 map, gamedata_t *data) { - if (!mainrecords[map-1]) + if (!data->mainrecords[map-1]) return 0; - return mainrecords[map-1]->rings; + return data->mainrecords[map-1]->rings; } -UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare) +UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data) { - if (!nightsrecords[map-1]) + if (!data->nightsrecords[map-1]) return 0; - return nightsrecords[map-1]->score[mare]; + return data->nightsrecords[map-1]->score[mare]; } -tic_t G_GetBestNightsTime(INT16 map, UINT8 mare) +tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data) { - if (!nightsrecords[map-1] || nightsrecords[map-1]->time[mare] <= 0) + if (!data->nightsrecords[map-1] || data->nightsrecords[map-1]->time[mare] <= 0) return (tic_t)UINT32_MAX; - return nightsrecords[map-1]->time[mare]; + return data->nightsrecords[map-1]->time[mare]; } -UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare) +UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data) { - if (!nightsrecords[map-1]) + if (!data->nightsrecords[map-1]) return 0; - return nightsrecords[map-1]->grade[mare]; + return data->nightsrecords[map-1]->grade[mare]; } // For easy adding of NiGHTS records @@ -553,7 +537,7 @@ void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare) // Update replay files/data, etc. for Record Attack // See G_SetNightsRecords for NiGHTS Attack. // -static void G_UpdateRecordReplays(void) +static void G_UpdateRecordReplays(gamedata_t *data) { const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; char *gpath; @@ -561,17 +545,17 @@ static void G_UpdateRecordReplays(void) UINT8 earnedEmblems; // Record new best time - if (!mainrecords[gamemap-1]) - G_AllocMainRecordData(gamemap-1); + if (!data->mainrecords[gamemap-1]) + G_AllocMainRecordData(gamemap-1, data); - if (players[consoleplayer].score > mainrecords[gamemap-1]->score) - mainrecords[gamemap-1]->score = players[consoleplayer].score; + if (players[consoleplayer].score > data->mainrecords[gamemap-1]->score) + data->mainrecords[gamemap-1]->score = players[consoleplayer].score; - if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time)) - mainrecords[gamemap-1]->time = players[consoleplayer].realtime; + if ((data->mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < data->mainrecords[gamemap-1]->time)) + data->mainrecords[gamemap-1]->time = players[consoleplayer].realtime; - if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings) - mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); + if ((UINT16)(players[consoleplayer].rings) > data->mainrecords[gamemap-1]->rings) + data->mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); // Save demo! bestdemo[255] = '\0'; @@ -627,14 +611,14 @@ static void G_UpdateRecordReplays(void) free(gpath); // Check emblems when level data is updated - if ((earnedEmblems = M_CheckLevelEmblems())) + if ((earnedEmblems = M_CheckLevelEmblems(data))) CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); // Update timeattack menu's replay availability. Nextmap_OnChange(); } -void G_SetNightsRecords(void) +void G_SetNightsRecords(gamedata_t *data) { INT32 i; UINT32 totalscore = 0; @@ -675,9 +659,9 @@ void G_SetNightsRecords(void) { nightsdata_t *maprecords; - if (!nightsrecords[gamemap-1]) - G_AllocNightsRecordData(gamemap-1); - maprecords = nightsrecords[gamemap-1]; + if (!data->nightsrecords[gamemap-1]) + G_AllocNightsRecordData(gamemap-1, data); + maprecords = data->nightsrecords[gamemap-1]; if (maprecords->nummares != ntemprecords.nummares) maprecords->nummares = ntemprecords.nummares; @@ -739,7 +723,7 @@ void G_SetNightsRecords(void) } free(gpath); - if ((earnedEmblems = M_CheckLevelEmblems())) + if ((earnedEmblems = M_CheckLevelEmblems(data))) CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); // If the mare count changed, this will update the score display @@ -2407,7 +2391,8 @@ void G_Ticker(boolean run) break; case GS_TIMEATTACK: - F_MenuPresTicker(run); + if (run) + F_MenuPresTicker(); break; case GS_INTRO: @@ -2455,7 +2440,8 @@ void G_Ticker(boolean run) // then intentionally fall through /* FALLTHRU */ case GS_WAITINGPLAYERS: - F_MenuPresTicker(run); + if (run) + F_MenuPresTicker(); F_TitleScreenTicker(run); break; @@ -3169,6 +3155,9 @@ void G_DoReborn(INT32 playernum) if (resetlevel) { + // Don't give completion emblems for reloading the level... + stagefailed = true; + // reload the level from scratch if (countdowntimeup) { @@ -3838,7 +3827,7 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) for (ix = 0; ix < NUMMAPS; ix++) if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags && ix != pprevmap // Don't pick the same map. - && (dedicated || !M_MapLocked(ix+1)) // Don't pick locked maps. + && (dedicated || !M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps. ) okmaps[numokmaps++] = ix; @@ -3855,40 +3844,52 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) // // G_UpdateVisited // -static void G_UpdateVisited(void) +static void G_UpdateVisited(gamedata_t *data, boolean silent) { boolean spec = G_IsSpecialStage(gamemap); // Update visitation flags? - if (!multiplayer && !demoplayback && (gametype == GT_COOP) // SP/RA/NiGHTS mode + if (!demoplayback + && G_CoopGametype() // Campaign mode && !stagefailed) // Did not fail the stage { UINT8 earnedEmblems; // Update visitation flags - mapvisited[gamemap-1] |= MV_BEATEN; + data->mapvisited[gamemap-1] |= MV_BEATEN; + // eh, what the hell if (ultimatemode) - mapvisited[gamemap-1] |= MV_ULTIMATE; + data->mapvisited[gamemap-1] |= MV_ULTIMATE; + // may seem incorrect but IS possible in what the main game uses as mp special stages, and nummaprings will be -1 in NiGHTS if (nummaprings > 0 && players[consoleplayer].rings >= nummaprings) { - mapvisited[gamemap-1] |= MV_PERFECT; + data->mapvisited[gamemap-1] |= MV_PERFECT; if (modeattacking) - mapvisited[gamemap-1] |= MV_PERFECTRA; + data->mapvisited[gamemap-1] |= MV_PERFECTRA; } + if (!spec) { // not available to special stages because they can only really be done in one order in an unmodified game, so impossible for first six and trivial for seventh if (ALL7EMERALDS(emeralds)) - mapvisited[gamemap-1] |= MV_ALLEMERALDS; + data->mapvisited[gamemap-1] |= MV_ALLEMERALDS; } - if (modeattacking == ATTACKING_RECORD) - G_UpdateRecordReplays(); - else if (modeattacking == ATTACKING_NIGHTS) - G_SetNightsRecords(); + if (silent) + { + if (modeattacking) + M_CheckLevelEmblems(data); + } + else + { + if (modeattacking == ATTACKING_RECORD) + G_UpdateRecordReplays(data); + else if (modeattacking == ATTACKING_NIGHTS) + G_SetNightsRecords(data); + } - if ((earnedEmblems = M_CompletionEmblems())) + if ((earnedEmblems = M_CompletionEmblems(data)) && !silent) CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); } } @@ -4091,7 +4092,8 @@ static void G_DoCompleted(void) if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none)) { - G_UpdateVisited(); + G_UpdateVisited(serverGamedata, true); + G_UpdateVisited(clientGamedata, false); G_HandleSaveLevel(); G_AfterIntermission(); } @@ -4100,7 +4102,8 @@ static void G_DoCompleted(void) G_SetGamestate(GS_INTERMISSION); Y_StartIntermission(); Y_LoadIntermissionData(); - G_UpdateVisited(); + G_UpdateVisited(serverGamedata, true); + G_UpdateVisited(clientGamedata, false); G_HandleSaveLevel(); } } @@ -4287,7 +4290,7 @@ void G_LoadGameSettings(void) // G_LoadGameData // Loads the main data file, which stores information such as emblems found, etc. -void G_LoadGameData(void) +void G_LoadGameData(gamedata_t *data) { size_t length; INT32 i, j; @@ -4304,13 +4307,13 @@ void G_LoadGameData(void) INT32 curmare; // Stop saving, until we successfully load it again. - gamedataloaded = false; + data->loaded = false; // Clear things so previously read gamedata doesn't transfer // to new gamedata - G_ClearRecords(); // main and nights records - M_ClearSecrets(); // emblems, unlocks, maps visited, etc - totalplaytime = 0; // total play time (separate from all) + G_ClearRecords(data); // main and nights records + M_ClearSecrets(data); // emblems, unlocks, maps visited, etc + data->totalplaytime = 0; // total play time (separate from all) if (M_CheckParm("-nodata")) { @@ -4321,7 +4324,7 @@ void G_LoadGameData(void) if (M_CheckParm("-resetdata")) { // Don't load, but do save. (essentially, reset) - gamedataloaded = true; + data->loaded = true; return; } @@ -4329,7 +4332,7 @@ void G_LoadGameData(void) if (!length) { // No gamedata. We can save a new one. - gamedataloaded = true; + data->loaded = true; return; } @@ -4352,7 +4355,7 @@ void G_LoadGameData(void) I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } - totalplaytime = READUINT32(save_p); + data->totalplaytime = READUINT32(save_p); #ifdef COMPAT_GAMEDATA_ID if (versionID == COMPAT_GAMEDATA_ID) @@ -4386,7 +4389,7 @@ void G_LoadGameData(void) // TODO put another cipher on these things? meh, I don't care... for (i = 0; i < NUMMAPS; i++) - if ((mapvisited[i] = READUINT8(save_p)) > MV_MAX) + if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) goto datacorrupt; // To save space, use one bit per collected/achieved/unlocked flag @@ -4394,34 +4397,34 @@ void G_LoadGameData(void) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) - emblemlocations[j+i].collected = ((rtemp >> j) & 1); + data->collected[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXEXTRAEMBLEMS;) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) - extraemblems[j+i].collected = ((rtemp >> j) & 1); + data->extraCollected[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXUNLOCKABLES;) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) - unlockables[j+i].unlocked = ((rtemp >> j) & 1); + data->unlocked[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXCONDITIONSETS;) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) - conditionSets[j+i].achieved = ((rtemp >> j) & 1); + data->achieved[j+i] = ((rtemp >> j) & 1); i += j; } - timesBeaten = READUINT32(save_p); - timesBeatenWithEmeralds = READUINT32(save_p); - timesBeatenUltimate = READUINT32(save_p); + data->timesBeaten = READUINT32(save_p); + data->timesBeatenWithEmeralds = READUINT32(save_p); + data->timesBeatenUltimate = READUINT32(save_p); // Main records for (i = 0; i < NUMMAPS; ++i) @@ -4436,10 +4439,10 @@ void G_LoadGameData(void) if (recscore || rectime || recrings) { - G_AllocMainRecordData((INT16)i); - mainrecords[i]->score = recscore; - mainrecords[i]->time = rectime; - mainrecords[i]->rings = recrings; + G_AllocMainRecordData((INT16)i, data); + data->mainrecords[i]->score = recscore; + data->mainrecords[i]->time = rectime; + data->mainrecords[i]->rings = recrings; } } @@ -4449,19 +4452,21 @@ void G_LoadGameData(void) if ((recmares = READUINT8(save_p)) == 0) continue; - G_AllocNightsRecordData((INT16)i); + G_AllocNightsRecordData((INT16)i, data); for (curmare = 0; curmare < (recmares+1); ++curmare) { - nightsrecords[i]->score[curmare] = READUINT32(save_p); - nightsrecords[i]->grade[curmare] = READUINT8(save_p); - nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); + data->nightsrecords[i]->score[curmare] = READUINT32(save_p); + data->nightsrecords[i]->grade[curmare] = READUINT8(save_p); + data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); - if (nightsrecords[i]->grade[curmare] > GRADE_S) + if (data->nightsrecords[i]->grade[curmare] > GRADE_S) + { goto datacorrupt; + } } - nightsrecords[i]->nummares = recmares; + data->nightsrecords[i]->nummares = recmares; } // done @@ -4472,10 +4477,11 @@ void G_LoadGameData(void) // It used to do this much earlier, but this would cause the gamedata to // save over itself when it I_Errors from the corruption landing point below, // which can accidentally delete players' legitimate data if the code ever has any tiny mistakes! - gamedataloaded = true; + data->loaded = true; // Silent update unlockables in case they're out of sync with conditions - M_SilentUpdateUnlockablesAndEmblems(); + M_SilentUpdateUnlockablesAndEmblems(data); + M_SilentUpdateSkinAvailabilites(); return; @@ -4495,7 +4501,7 @@ void G_LoadGameData(void) // G_SaveGameData // Saves the main data file, which stores information such as emblems found, etc. -void G_SaveGameData(void) +void G_SaveGameData(gamedata_t *data) { size_t length; INT32 i, j; @@ -4503,7 +4509,7 @@ void G_SaveGameData(void) INT32 curmare; - if (!gamedataloaded) + if (!data->loaded) return; // If never loaded (-nodata), don't save save_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE); @@ -4523,20 +4529,20 @@ void G_SaveGameData(void) // Version test WRITEUINT32(save_p, GAMEDATA_ID); - WRITEUINT32(save_p, totalplaytime); + WRITEUINT32(save_p, data->totalplaytime); WRITEUINT32(save_p, quickncasehash(timeattackfolder, sizeof timeattackfolder)); // TODO put another cipher on these things? meh, I don't care... for (i = 0; i < NUMMAPS; i++) - WRITEUINT8(save_p, (mapvisited[i] & MV_MAX)); + WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX)); // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) { btemp = 0; for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) - btemp |= (emblemlocations[j+i].collected << j); + btemp |= (data->collected[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } @@ -4544,7 +4550,7 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) - btemp |= (extraemblems[j+i].collected << j); + btemp |= (data->extraCollected[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } @@ -4552,7 +4558,7 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) - btemp |= (unlockables[j+i].unlocked << j); + btemp |= (data->unlocked[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } @@ -4560,23 +4566,23 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) - btemp |= (conditionSets[j+i].achieved << j); + btemp |= (data->achieved[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } - WRITEUINT32(save_p, timesBeaten); - WRITEUINT32(save_p, timesBeatenWithEmeralds); - WRITEUINT32(save_p, timesBeatenUltimate); + WRITEUINT32(save_p, data->timesBeaten); + WRITEUINT32(save_p, data->timesBeatenWithEmeralds); + WRITEUINT32(save_p, data->timesBeatenUltimate); // Main records for (i = 0; i < NUMMAPS; i++) { - if (mainrecords[i]) + if (data->mainrecords[i]) { - WRITEUINT32(save_p, mainrecords[i]->score); - WRITEUINT32(save_p, mainrecords[i]->time); - WRITEUINT16(save_p, mainrecords[i]->rings); + WRITEUINT32(save_p, data->mainrecords[i]->score); + WRITEUINT32(save_p, data->mainrecords[i]->time); + WRITEUINT16(save_p, data->mainrecords[i]->rings); } else { @@ -4590,19 +4596,19 @@ void G_SaveGameData(void) // NiGHTS records for (i = 0; i < NUMMAPS; i++) { - if (!nightsrecords[i] || !nightsrecords[i]->nummares) + if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) { WRITEUINT8(save_p, 0); continue; } - WRITEUINT8(save_p, nightsrecords[i]->nummares); + WRITEUINT8(save_p, data->nightsrecords[i]->nummares); - for (curmare = 0; curmare < (nightsrecords[i]->nummares + 1); ++curmare) + for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare) { - WRITEUINT32(save_p, nightsrecords[i]->score[curmare]); - WRITEUINT8(save_p, nightsrecords[i]->grade[curmare]); - WRITEUINT32(save_p, nightsrecords[i]->time[curmare]); + WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]); + WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]); + WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]); } } diff --git a/src/g_game.h b/src/g_game.h index 144360db4..6cda7ca9c 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -19,6 +19,7 @@ #include "d_event.h" #include "g_demo.h" #include "m_cheat.h" // objectplacing +#include "m_cond.h" extern char gamedatafilename[64]; extern char timeattackfolder[64]; @@ -183,7 +184,7 @@ boolean G_IsTitleCardAvailable(void); // 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_SaveGameData(gamedata_t *data); void G_SaveGame(UINT32 slot, INT16 mapnum); @@ -239,7 +240,7 @@ void G_SetModeAttackRetryFlag(void); void G_ClearModeAttackRetryFlag(void); boolean G_GetModeAttackRetryFlag(void); -void G_LoadGameData(void); +void G_LoadGameData(gamedata_t *data); void G_LoadGameSettings(void); void G_SetGameModified(boolean silent); @@ -248,19 +249,19 @@ void G_SetUsedCheats(boolean silent); void G_SetGamestate(gamestate_t newstate); // Gamedata record shit -void G_AllocMainRecordData(INT16 i); -void G_AllocNightsRecordData(INT16 i); -void G_ClearRecords(void); +void G_AllocMainRecordData(INT16 i, gamedata_t *data); +void G_AllocNightsRecordData(INT16 i, gamedata_t *data); +void G_ClearRecords(gamedata_t *data); -UINT32 G_GetBestScore(INT16 map); -tic_t G_GetBestTime(INT16 map); -UINT16 G_GetBestRings(INT16 map); -UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare); -tic_t G_GetBestNightsTime(INT16 map, UINT8 mare); -UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare); +UINT32 G_GetBestScore(INT16 map, gamedata_t *data); +tic_t G_GetBestTime(INT16 map, gamedata_t *data); +UINT16 G_GetBestRings(INT16 map, gamedata_t *data); +UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data); +tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data); +UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data); void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare); -void G_SetNightsRecords(void); +void G_SetNightsRecords(gamedata_t *data); FUNCMATH INT32 G_TicsToHours(tic_t tics); FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 0b5d41c4f..c2390519e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1153,7 +1153,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom else texturevpeg = gl_backsector->ceilingheight + textureheight[gl_toptexture] - gl_frontsector->ceilingheight; - texturevpeg += gl_sidedef->rowoffset; + texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top; // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway texturevpeg %= textureheight[gl_toptexture]; @@ -1162,8 +1162,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_top) * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_top) * grTex->scaleX; // Adjust t value for sloped walls if (!(gl_linedef->flags & ML_SKEWTD)) @@ -1213,7 +1213,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom else texturevpeg = gl_frontsector->floorheight - gl_backsector->floorheight; - texturevpeg += gl_sidedef->rowoffset; + texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bot; // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway texturevpeg %= textureheight[gl_bottomtexture]; @@ -1222,8 +1222,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_backsector->floorheight - gl_frontsector->floorheight) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_bot) * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_bot) * grTex->scaleX; // Adjust t value for sloped walls if (!(gl_linedef->flags & ML_SKEWTD)) @@ -1333,13 +1333,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // Peg it to the floor if (gl_linedef->flags & ML_MIDPEG) { - polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset; + polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid; polytop = polybottom + midtexheight; } // Peg it to the ceiling else { - polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset; + polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid; polybottom = polytop - midtexheight; } @@ -1350,9 +1350,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // Skew the texture, but peg it to the floor else if (gl_linedef->flags & ML_MIDPEG) { - polybottom = popenbottom + gl_sidedef->rowoffset; + polybottom = popenbottom + gl_sidedef->rowoffset + gl_sidedef->offsety_mid; polytop = polybottom + midtexheight; - polybottomslope = popenbottomslope + gl_sidedef->rowoffset; + polybottomslope = popenbottomslope + gl_sidedef->rowoffset + gl_sidedef->offsety_mid; polytopslope = polybottomslope + midtexheight; } // Skew it according to the ceiling's slope @@ -1407,12 +1407,12 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // Left side wallVerts[3].t = texturevpeg * grTex->scaleY; wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; + wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX; // Right side wallVerts[2].t = texturevpegslope * grTex->scaleY; wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX; // set top/bottom coords // Take the texture peg into account, rather than changing the offsets past @@ -1474,19 +1474,19 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // PEGGING if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW)) - texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset; + texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset + gl_sidedef->offsety_mid; else if (gl_linedef->flags & ML_DONTPEGBOTTOM) - texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset; + texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset + gl_sidedef->offsety_mid; else // top of texture at top - texturevpeg = gl_sidedef->rowoffset; + texturevpeg = gl_sidedef->rowoffset + gl_sidedef->offsety_mid; grTex = HWR_GetTexture(gl_midtexture); wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX; // Texture correction for slopes if (gl_linedef->flags & ML_NOSKEW) { @@ -1634,13 +1634,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // -- Monster Iestyn 26/06/18 if (newline) { - texturevpeg = sides[newline->sidenum[0]].rowoffset; + texturevpeg = sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid; attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM); slopeskew = !!(newline->flags & ML_SKEWTD); } else { - texturevpeg = sides[rover->master->sidenum[0]].rowoffset; + texturevpeg = sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid; attachtobottom = !!(gl_linedef->flags & ML_DONTPEGBOTTOM); slopeskew = !!(rover->master->flags & ML_SKEWTD); } @@ -1672,8 +1672,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom } } - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX; } if (rover->fofflags & FOF_FOG) { @@ -1785,17 +1785,17 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (newline) { - wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY; + wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid) * grTex->scaleY; + wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) + sides[newline->sidenum[0]].offsety_mid) * grTex->scaleY; } else { - wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY; + wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid) * grTex->scaleY; + wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid)) * grTex->scaleY; } - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX; } if (rover->fofflags & FOF_FOG) @@ -3606,6 +3606,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) scalemul = FixedMul(FRACUNIT - floordiff/640, scale); scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); + if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs + scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale)); fscale = FIXED_TO_FLOAT(scalemul); fx = FIXED_TO_FLOAT(interp.x); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 6b1d0c6fc..38e8e8fc4 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1660,7 +1660,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #endif // SRB2CBTODO: MD2 scaling support - finalscale *= FIXED_TO_FLOAT(spr->mobj->scale); + finalscale *= FIXED_TO_FLOAT(interp.scale); p.flip = atransform.flip; #ifdef USE_FTRANSFORM_MIRROR diff --git a/src/http-mserv.c b/src/http-mserv.c index b4dba0db9..b7032e89a 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -216,7 +216,11 @@ HMS_connect (const char *format, ...) curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + +#ifndef NO_IPV6 + if (M_CheckParm("-noipv6")) +#endif + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 55ebe0d4d..091e2b2fb 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2862,18 +2862,6 @@ static void HU_DrawRankings(void) V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value)); } } - else if (gametyperankings[gametype] == GT_COOP) - { - INT32 totalscore = 0; - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - totalscore += players[i].score; - } - - V_DrawCenteredString(256, 8, 0, "TOTAL SCORE"); - V_DrawCenteredString(256, 16, 0, va("%u", totalscore)); - } else { if (circuitmap) @@ -2996,7 +2984,7 @@ static void HU_DrawCoopOverlay(void) if (LUA_HudEnabled(hud_tabemblems)) { - V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(), numemblems+numextraemblems)); + V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(clientGamedata), numemblems+numextraemblems)); V_DrawScaledPatch(128, 144 - emblemicon->height/4, 0, emblemicon); } @@ -3029,6 +3017,15 @@ static void HU_DrawNetplayCoopOverlay(void) V_DrawSmallScaledPatch(148, 6, 0, tokenicon); } + if (G_CoopGametype() && LUA_HudEnabled(hud_tabemblems)) + { + V_DrawCenteredString(256, 14, 0, "/"); + V_DrawString(256 + 4, 14, 0, va("%d", numemblems + numextraemblems)); + V_DrawRightAlignedString(256 - 4, 14, 0, va("%d", M_CountEmblems(clientGamedata))); + + V_DrawSmallScaledPatch(256 - (emblemicon->width / 4), 6, 0, emblemicon); + } + if (!LUA_HudEnabled(hud_coopemeralds)) return; diff --git a/src/i_net.h b/src/i_net.h index 9f2c38c7b..12a07f183 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -109,6 +109,17 @@ extern boolean (*I_NetCanSend)(void); */ extern void (*I_NetFreeNodenum)(INT32 nodenum); +/** + \brief split a string into address and port + + \param address string to split + + \param port double pointer to hold port component (optional) + + \return address component +*/ +extern char *I_NetSplitAddress(char *address, char **port); + /** \brief open a connection with specified address \param address address to connect to diff --git a/src/i_tcp.c b/src/i_tcp.c index 3820155b8..d95b381f4 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -340,8 +340,14 @@ static inline void I_UPnP_rem(const char *port, const char * servicetype) static const char *SOCK_AddrToStr(mysockaddr_t *sk) { - static char s[64]; // 255.255.255.255:65535 or IPv6:65535 + static char s[64]; // 255.255.255.255:65535 or + // [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535 #ifdef HAVE_NTOP +#ifdef HAVE_IPV6 + int v6 = (sk->any.sa_family == AF_INET6); +#else + int v6 = 0; +#endif void *addr; if(sk->any.sa_family == AF_INET) @@ -355,14 +361,21 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) if(addr == NULL) sprintf(s, "No address"); - else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL) + else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL) sprintf(s, "Unknown family type, error #%u", errno); #ifdef HAVE_IPV6 - else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0) - strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); + else if(sk->any.sa_family == AF_INET6) + { + s[0] = '['; + strcat(s, "]"); + + if (sk->ip6.sin6_port != 0) + strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); + } #endif else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0) strcat(s, va(":%d", ntohs(sk->ip4.sin_port))); + #else if (sk->any.sa_family == AF_INET) { @@ -427,7 +440,7 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) && (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port)); #ifdef HAVE_IPV6 else if (b->any.sa_family == AF_INET6) - return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) + return !memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) && (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port)); #endif else @@ -735,8 +748,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen unsigned long trueval = true; #endif mysockaddr_t straddr; - struct sockaddr_in sin; - socklen_t len = sizeof(sin); + socklen_t len = sizeof(straddr); if (s == (SOCKET_TYPE)ERRSOCKET) return (SOCKET_TYPE)ERRSOCKET; @@ -754,14 +766,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen } #endif - straddr.any = *addr; + memcpy(&straddr, addr, addrlen); I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr)); if (family == AF_INET) { - mysockaddr_t tmpaddr; - tmpaddr.any = *addr ; - if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY)) + if (straddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY)) { opt = true; opts = (socklen_t)sizeof(opt); @@ -778,7 +788,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen #ifdef HAVE_IPV6 else if (family == AF_INET6) { - if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL + if (memcmp(&straddr.ip6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL { opt = true; opts = (socklen_t)sizeof(opt); @@ -788,7 +798,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen // make it IPv6 ony opt = true; opts = (socklen_t)sizeof(opt); - if (setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts)) + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts)) { CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore } @@ -830,10 +840,17 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); } - if (getsockname(s, (struct sockaddr *)&sin, &len) == -1) + if (getsockname(s, &straddr.any, &len) == -1) CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n")); else - current_port = (UINT16)ntohs(sin.sin_port); + { + if (family == AF_INET) + current_port = (UINT16)ntohs(straddr.ip4.sin_port); +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + current_port = (UINT16)ntohs(straddr.ip6.sin6_port); +#endif + } return s; } @@ -844,7 +861,7 @@ static boolean UDP_Socket(void) struct my_addrinfo *ai, *runp, hints; int gaie; #ifdef HAVE_IPV6 - const INT32 b_ipv6 = M_CheckParm("-ipv6"); + const INT32 b_ipv6 = !M_CheckParm("-noipv6"); #endif const char *serv; @@ -1156,6 +1173,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) SINT8 newnode = -1; struct my_addrinfo *ai = NULL, *runp, hints; int gaie; + size_t i; if (!port || !port[0]) port = DEFAULTPORT; @@ -1183,13 +1201,24 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) while (runp != NULL) { - // find ip of the server - if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0) + // test ip address of server + for (i = 0; i < mysocketses; ++i) { - memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen); - break; + /* sendto tests that there is a network to this + address */ + if (runp->ai_addr->sa_family == myfamily[i] && + sendto(mysockets[i], NULL, 0, 0, + runp->ai_addr, runp->ai_addrlen) == 0) + { + memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen); + break; + } } - runp = runp->ai_next; + + if (i < mysocketses) + runp = runp->ai_next; + else + break; } I_freeaddrinfo(ai); return newnode; diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index dcaad1416..1d15b3b14 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -566,27 +566,59 @@ static luaL_Reg lib[] = { {NULL, NULL} }; +enum cvar_e +{ + cvar_name, + cvar_defaultvalue, + cvar_flags, + cvar_value, + cvar_string, + cvar_changed, +}; + +static const char *const cvar_opt[] = { + "name", + "defaultvalue", + "flags", + "value", + "string", + "changed", + NULL, +}; + +static int cvar_fields_ref = LUA_NOREF; + static int cvar_get(lua_State *L) { consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR); - const char *field = luaL_checkstring(L, 2); + enum cvar_e field = Lua_optoption(L, 2, -1, cvar_fields_ref); - if(fastcmp(field,"name")) + switch (field) + { + case cvar_name: lua_pushstring(L, cvar->name); - else if(fastcmp(field,"defaultvalue")) + break; + case cvar_defaultvalue: lua_pushstring(L, cvar->defaultvalue); - else if(fastcmp(field,"flags")) + break; + case cvar_flags: lua_pushinteger(L, cvar->flags); - else if(fastcmp(field,"value")) + break; + case cvar_value: lua_pushinteger(L, cvar->value); - else if(fastcmp(field,"string")) + break; + case cvar_string: lua_pushstring(L, cvar->string); - else if(fastcmp(field,"changed")) + break; + case cvar_changed: lua_pushboolean(L, cvar->changed); - else if (devparm) - return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); - else - return 0; + break; + default: + if (devparm) + return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); + else + return 0; + } return 1; } @@ -598,6 +630,8 @@ int LUA_ConsoleLib(lua_State *L) lua_setfield(L, -2, "__index"); lua_pop(L,1); + cvar_fields_ref = Lua_CreateFieldTable(L, cvar_opt); + // Set empty registry tables lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "COM_Command"); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 1a0599757..c7f67e93a 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -95,6 +95,8 @@ static const char *const patch_opt[] = { "topoffset", NULL}; +static int patch_fields_ref = LUA_NOREF; + // alignment types for v.drawString enum align { align_left = 0, @@ -196,6 +198,8 @@ static const char *const camera_opt[] = { "momz", NULL}; +static int camera_fields_ref = LUA_NOREF; + static int lib_getHudInfo(lua_State *L) { UINT32 i; @@ -276,7 +280,7 @@ static int colormap_get(lua_State *L) static int patch_get(lua_State *L) { patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); - enum patch field = luaL_checkoption(L, 2, NULL, patch_opt); + enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref); // patches are invalidated when switching renderers if (!patch) { @@ -316,7 +320,7 @@ static int patch_set(lua_State *L) static int camera_get(lua_State *L) { camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); - enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); + enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref); // cameras should always be valid unless I'm a nutter I_Assert(cam != NULL); @@ -372,7 +376,7 @@ static int camera_get(lua_State *L) static int camera_set(lua_State *L) { camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); - enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); + enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref); I_Assert(cam != NULL); @@ -1444,6 +1448,8 @@ int LUA_HudLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + patch_fields_ref = Lua_CreateFieldTable(L, patch_opt); + luaL_newmetatable(L, META_CAMERA); lua_pushcfunction(L, camera_get); lua_setfield(L, -2, "__index"); @@ -1452,6 +1458,8 @@ int LUA_HudLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + camera_fields_ref = Lua_CreateFieldTable(L, camera_opt); + luaL_register(L, "hud", lib_hud); return 0; } diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 7388632d3..fb07ccebb 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -1106,75 +1106,161 @@ static int lib_mobjinfolen(lua_State *L) return 1; } +enum mobjinfo_e +{ + mobjinfo_doomednum, + mobjinfo_spawnstate, + mobjinfo_spawnhealth, + mobjinfo_seestate, + mobjinfo_seesound, + mobjinfo_reactiontime, + mobjinfo_attacksound, + mobjinfo_painstate, + mobjinfo_painchance, + mobjinfo_painsound, + mobjinfo_meleestate, + mobjinfo_missilestate, + mobjinfo_deathstate, + mobjinfo_xdeathstate, + mobjinfo_deathsound, + mobjinfo_speed, + mobjinfo_radius, + mobjinfo_height, + mobjinfo_dispoffset, + mobjinfo_mass, + mobjinfo_damage, + mobjinfo_activesound, + mobjinfo_flags, + mobjinfo_raisestate, +}; + +const char *const mobjinfo_opt[] = { + "doomednum", + "spawnstate", + "spawnhealth", + "seestate", + "seesound", + "reactiontime", + "attacksound", + "painstate", + "painchance", + "painsound", + "meleestate", + "missilestate", + "deathstate", + "xdeathstate", + "deathsound", + "speed", + "radius", + "height", + "dispoffset", + "mass", + "damage", + "activesound", + "flags", + "raisestate", + NULL, +}; + +static int mobjinfo_fields_ref = LUA_NOREF; + // mobjinfo_t *, field -> number static int mobjinfo_get(lua_State *L) { mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); - const char *field = luaL_checkstring(L, 2); + enum mobjinfo_e field = luaL_checkoption(L, 2, mobjinfo_opt[0], mobjinfo_opt); I_Assert(info != NULL); I_Assert(info >= mobjinfo); - if (fastcmp(field,"doomednum")) + switch (field) + { + case mobjinfo_doomednum: lua_pushinteger(L, info->doomednum); - else if (fastcmp(field,"spawnstate")) + break; + case mobjinfo_spawnstate: lua_pushinteger(L, info->spawnstate); - else if (fastcmp(field,"spawnhealth")) + break; + case mobjinfo_spawnhealth: lua_pushinteger(L, info->spawnhealth); - else if (fastcmp(field,"seestate")) + break; + case mobjinfo_seestate: lua_pushinteger(L, info->seestate); - else if (fastcmp(field,"seesound")) + break; + case mobjinfo_seesound: lua_pushinteger(L, info->seesound); - else if (fastcmp(field,"reactiontime")) + break; + case mobjinfo_reactiontime: lua_pushinteger(L, info->reactiontime); - else if (fastcmp(field,"attacksound")) + break; + case mobjinfo_attacksound: lua_pushinteger(L, info->attacksound); - else if (fastcmp(field,"painstate")) + break; + case mobjinfo_painstate: lua_pushinteger(L, info->painstate); - else if (fastcmp(field,"painchance")) + break; + case mobjinfo_painchance: lua_pushinteger(L, info->painchance); - else if (fastcmp(field,"painsound")) + break; + case mobjinfo_painsound: lua_pushinteger(L, info->painsound); - else if (fastcmp(field,"meleestate")) + break; + case mobjinfo_meleestate: lua_pushinteger(L, info->meleestate); - else if (fastcmp(field,"missilestate")) + break; + case mobjinfo_missilestate: lua_pushinteger(L, info->missilestate); - else if (fastcmp(field,"deathstate")) + break; + case mobjinfo_deathstate: lua_pushinteger(L, info->deathstate); - else if (fastcmp(field,"xdeathstate")) + break; + case mobjinfo_xdeathstate: lua_pushinteger(L, info->xdeathstate); - else if (fastcmp(field,"deathsound")) + break; + case mobjinfo_deathsound: lua_pushinteger(L, info->deathsound); - else if (fastcmp(field,"speed")) + break; + case mobjinfo_speed: lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not... - else if (fastcmp(field,"radius")) + break; + case mobjinfo_radius: lua_pushfixed(L, info->radius); - else if (fastcmp(field,"height")) + break; + case mobjinfo_height: lua_pushfixed(L, info->height); - else if (fastcmp(field,"dispoffset")) + break; + case mobjinfo_dispoffset: lua_pushinteger(L, info->dispoffset); - else if (fastcmp(field,"mass")) + break; + case mobjinfo_mass: lua_pushinteger(L, info->mass); - else if (fastcmp(field,"damage")) + break; + case mobjinfo_damage: lua_pushinteger(L, info->damage); - else if (fastcmp(field,"activesound")) + break; + case mobjinfo_activesound: lua_pushinteger(L, info->activesound); - else if (fastcmp(field,"flags")) + break; + case mobjinfo_flags: lua_pushinteger(L, info->flags); - else if (fastcmp(field,"raisestate")) + break; + case mobjinfo_raisestate: lua_pushinteger(L, info->raisestate); - else { + break; + default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, info); lua_rawget(L, -2); if (!lua_istable(L, -1)) { // no extra values table - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2)); return 0; } - lua_getfield(L, -1, field); + lua_pushvalue(L, 2); // field name + lua_gettable(L, -2); if (lua_isnil(L, -1)) // no value for this field - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2)); + break; } return 1; } @@ -1183,7 +1269,7 @@ static int mobjinfo_get(lua_State *L) static int mobjinfo_set(lua_State *L) { mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); - const char *field = luaL_checkstring(L, 2); + enum mobjinfo_e field = Lua_optoption(L, 2, -1, mobjinfo_fields_ref); if (hud_running) return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!"); @@ -1193,55 +1279,81 @@ static int mobjinfo_set(lua_State *L) I_Assert(info != NULL); I_Assert(info >= mobjinfo); - if (fastcmp(field,"doomednum")) + switch (field) + { + case mobjinfo_doomednum: info->doomednum = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"spawnstate")) + break; + case mobjinfo_spawnstate: info->spawnstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"spawnhealth")) + break; + case mobjinfo_spawnhealth: info->spawnhealth = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"seestate")) + break; + case mobjinfo_seestate: info->seestate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"seesound")) + break; + case mobjinfo_seesound: info->seesound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"reactiontime")) + break; + case mobjinfo_reactiontime: info->reactiontime = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"attacksound")) + break; + case mobjinfo_attacksound: info->attacksound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"painstate")) + break; + case mobjinfo_painstate: info->painstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"painchance")) + break; + case mobjinfo_painchance: info->painchance = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"painsound")) + break; + case mobjinfo_painsound: info->painsound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"meleestate")) + break; + case mobjinfo_meleestate: info->meleestate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"missilestate")) + break; + case mobjinfo_missilestate: info->missilestate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"deathstate")) + break; + case mobjinfo_deathstate: info->deathstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"xdeathstate")) + break; + case mobjinfo_xdeathstate: info->xdeathstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"deathsound")) + break; + case mobjinfo_deathsound: info->deathsound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"speed")) + break; + case mobjinfo_speed: info->speed = luaL_checkfixed(L, 3); - else if (fastcmp(field,"radius")) + break; + case mobjinfo_radius: info->radius = luaL_checkfixed(L, 3); - else if (fastcmp(field,"height")) + break; + case mobjinfo_height: info->height = luaL_checkfixed(L, 3); - else if (fastcmp(field,"dispoffset")) + break; + case mobjinfo_dispoffset: info->dispoffset = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"mass")) + break; + case mobjinfo_mass: info->mass = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"damage")) + break; + case mobjinfo_damage: info->damage = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"activesound")) + break; + case mobjinfo_activesound: info->activesound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"flags")) + break; + case mobjinfo_flags: info->flags = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"raisestate")) + break; + case mobjinfo_raisestate: info->raisestate = luaL_checkinteger(L, 3); - else { + break; + default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, info); @@ -1249,18 +1361,17 @@ static int mobjinfo_set(lua_State *L) if (lua_isnil(L, -1)) { // This index doesn't have a table for extra values yet, let's make one. lua_pop(L, 1); - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", lua_tostring(L, 2)); lua_newtable(L); lua_pushlightuserdata(L, info); lua_pushvalue(L, -2); // ext value table lua_rawset(L, -4); // LREG_EXTVARS table } + lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // value to store - lua_setfield(L, -2, field); + lua_settable(L, -3); lua_pop(L, 2); } - //else - //return luaL_error(L, LUA_QL("mobjinfo_t") " has no field named " LUA_QS, field); return 0; } @@ -1788,6 +1899,8 @@ int LUA_InfoLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + mobjinfo_fields_ref = Lua_CreateFieldTable(L, mobjinfo_opt); + luaL_newmetatable(L, META_SKINCOLOR); lua_pushcfunction(L, skincolor_get); lua_setfield(L, -2, "__index"); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 898651520..f73b3c7d2 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -88,6 +88,8 @@ static const char *const sector_opt[] = { "gravity", NULL}; +static int sector_fields_ref = LUA_NOREF; + enum subsector_e { subsector_valid = 0, subsector_sector, @@ -104,6 +106,8 @@ static const char *const subsector_opt[] = { "polyList", NULL}; +static int subsector_fields_ref = LUA_NOREF; + enum line_e { line_valid = 0, line_v1, @@ -156,10 +160,18 @@ static const char *const line_opt[] = { "callcount", NULL}; +static int line_fields_ref = LUA_NOREF; + enum side_e { side_valid = 0, side_textureoffset, side_rowoffset, + side_offsetx_top, + side_offsety_top, + side_offsetx_mid, + side_offsety_mid, + side_offsetx_bot, + side_offsety_bot, side_toptexture, side_bottomtexture, side_midtexture, @@ -174,6 +186,12 @@ static const char *const side_opt[] = { "valid", "textureoffset", "rowoffset", + "offsetx_top", + "offsety_top", + "offsetx_mid", + "offsety_mid", + "offsetx_bot", + "offsety_bot", "toptexture", "bottomtexture", "midtexture", @@ -184,6 +202,8 @@ static const char *const side_opt[] = { "text", NULL}; +static int side_fields_ref = LUA_NOREF; + enum vertex_e { vertex_valid = 0, vertex_x, @@ -204,6 +224,8 @@ static const char *const vertex_opt[] = { "ceilingzset", NULL}; +static int vertex_fields_ref = LUA_NOREF; + enum ffloor_e { ffloor_valid = 0, ffloor_topheight, @@ -256,6 +278,8 @@ static const char *const ffloor_opt[] = { "bouncestrength", NULL}; +static int ffloor_fields_ref = LUA_NOREF; + #ifdef HAVE_LUA_SEGS enum seg_e { seg_valid = 0, @@ -285,6 +309,8 @@ static const char *const seg_opt[] = { "polyseg", NULL}; +static int seg_fields_ref = LUA_NOREF; + enum node_e { node_valid = 0, node_x, @@ -305,6 +331,8 @@ static const char *const node_opt[] = { "children", NULL}; +static int node_fields_ref = LUA_NOREF; + enum nodechild_e { nodechild_valid = 0, nodechild_right, @@ -356,6 +384,8 @@ static const char *const slope_opt[] = { "flags", NULL}; +static int slope_fields_ref = LUA_NOREF; + // shared by both vector2_t and vector3_t enum vector_e { vector_x = 0, @@ -575,7 +605,7 @@ static int sectorlines_num(lua_State *L) static int sector_get(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); + enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref); INT16 i; if (!sector) @@ -697,7 +727,7 @@ static int sector_get(lua_State *L) static int sector_set(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); + enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref); if (!sector) return luaL_error(L, "accessed sector_t doesn't exist anymore."); @@ -814,7 +844,7 @@ static int sector_num(lua_State *L) static int subsector_get(lua_State *L) { subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); - enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt); + enum subsector_e field = Lua_optoption(L, 2, subsector_valid, subsector_fields_ref); if (!subsector) { @@ -898,7 +928,7 @@ static int linestringargs_len(lua_State *L) static int line_get(lua_State *L) { line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE)); - enum line_e field = luaL_checkoption(L, 2, line_opt[0], line_opt); + enum line_e field = Lua_optoption(L, 2, line_valid, line_fields_ref); if (!line) { @@ -1057,7 +1087,7 @@ static int sidenum_get(lua_State *L) static int side_get(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); - enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); + enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref); if (!side) { @@ -1079,6 +1109,24 @@ static int side_get(lua_State *L) case side_rowoffset: lua_pushfixed(L, side->rowoffset); return 1; + case side_offsetx_top: + lua_pushfixed(L, side->offsetx_top); + return 1; + case side_offsety_top: + lua_pushfixed(L, side->offsety_top); + return 1; + case side_offsetx_mid: + lua_pushfixed(L, side->offsetx_mid); + return 1; + case side_offsety_mid: + lua_pushfixed(L, side->offsety_mid); + return 1; + case side_offsetx_bot: + lua_pushfixed(L, side->offsetx_bot); + return 1; + case side_offsety_bot: + lua_pushfixed(L, side->offsety_bot); + return 1; case side_toptexture: lua_pushinteger(L, side->toptexture); return 1; @@ -1110,7 +1158,7 @@ static int side_get(lua_State *L) static int side_set(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); - enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); + enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref); if (!side) { @@ -1136,6 +1184,24 @@ static int side_set(lua_State *L) case side_rowoffset: side->rowoffset = luaL_checkfixed(L, 3); break; + case side_offsetx_top: + side->offsetx_top = luaL_checkfixed(L, 3); + break; + case side_offsety_top: + side->offsety_top = luaL_checkfixed(L, 3); + break; + case side_offsetx_mid: + side->offsetx_mid = luaL_checkfixed(L, 3); + break; + case side_offsety_mid: + side->offsety_mid = luaL_checkfixed(L, 3); + break; + case side_offsetx_bot: + side->offsetx_bot = luaL_checkfixed(L, 3); + break; + case side_offsety_bot: + side->offsety_bot = luaL_checkfixed(L, 3); + break; case side_toptexture: side->toptexture = luaL_checkinteger(L, 3); break; @@ -1166,7 +1232,7 @@ static int side_num(lua_State *L) static int vertex_get(lua_State *L) { vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)); - enum vertex_e field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt); + enum vertex_e field = Lua_optoption(L, 2, vertex_valid, vertex_fields_ref); if (!vertex) { @@ -1220,7 +1286,7 @@ static int vertex_num(lua_State *L) static int seg_get(lua_State *L) { seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG)); - enum seg_e field = luaL_checkoption(L, 2, seg_opt[0], seg_opt); + enum seg_e field = Lua_optoption(L, 2, seg_valid, seg_fields_ref); if (!seg) { @@ -1284,7 +1350,7 @@ static int seg_num(lua_State *L) static int node_get(lua_State *L) { node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE)); - enum node_e field = luaL_checkoption(L, 2, node_opt[0], node_opt); + enum node_e field = Lua_optoption(L, 2, node_valid, node_fields_ref); if (!node) { @@ -1920,7 +1986,7 @@ static INT32 P_GetOldFOFFlags(ffloor_t *fflr) static int ffloor_get(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); - enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref); INT16 i; if (!ffloor) @@ -2102,7 +2168,7 @@ static void P_SetOldFOFFlags(ffloor_t *fflr, oldffloortype_e oldflags) static int ffloor_set(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); - enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref); if (!ffloor) return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); @@ -2197,7 +2263,7 @@ static int ffloor_set(lua_State *L) static int slope_get(lua_State *L) { pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); - enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt); + enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref); if (!slope) { @@ -2241,7 +2307,7 @@ static int slope_get(lua_State *L) static int slope_set(lua_State *L) { pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); - enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt); + enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref); if (!slope) return luaL_error(L, "accessed pslope_t doesn't exist anymore."); @@ -2405,110 +2471,258 @@ static int lib_nummapheaders(lua_State *L) // mapheader_t // ///////////////// +enum mapheaderinfo_e +{ + mapheaderinfo_lvlttl, + mapheaderinfo_subttl, + mapheaderinfo_actnum, + mapheaderinfo_typeoflevel, + mapheaderinfo_nextlevel, + mapheaderinfo_marathonnext, + mapheaderinfo_keywords, + mapheaderinfo_musname, + mapheaderinfo_mustrack, + mapheaderinfo_muspos, + mapheaderinfo_musinterfadeout, + mapheaderinfo_musintername, + mapheaderinfo_muspostbossname, + mapheaderinfo_muspostbosstrack, + mapheaderinfo_muspostbosspos, + mapheaderinfo_muspostbossfadein, + mapheaderinfo_musforcereset, + mapheaderinfo_forcecharacter, + mapheaderinfo_weather, + mapheaderinfo_skynum, + mapheaderinfo_skybox_scalex, + mapheaderinfo_skybox_scaley, + mapheaderinfo_skybox_scalez, + mapheaderinfo_interscreen, + mapheaderinfo_runsoc, + mapheaderinfo_scriptname, + mapheaderinfo_precutscenenum, + mapheaderinfo_cutscenenum, + mapheaderinfo_countdown, + mapheaderinfo_palette, + mapheaderinfo_numlaps, + mapheaderinfo_unlockrequired, + mapheaderinfo_levelselect, + mapheaderinfo_bonustype, + mapheaderinfo_ltzzpatch, + mapheaderinfo_ltzztext, + mapheaderinfo_ltactdiamond, + mapheaderinfo_maxbonuslives, + mapheaderinfo_levelflags, + mapheaderinfo_menuflags, + mapheaderinfo_selectheading, + mapheaderinfo_startrings, + mapheaderinfo_sstimer, + mapheaderinfo_ssspheres, + mapheaderinfo_gravity, +}; + +static const char *const mapheaderinfo_opt[] = { + "lvlttl", + "subttl", + "actnum", + "typeoflevel", + "nextlevel", + "marathonnext", + "keywords", + "musname", + "mustrack", + "muspos", + "musinterfadeout", + "musintername", + "muspostbossname", + "muspostbosstrack", + "muspostbosspos", + "muspostbossfadein", + "musforcereset", + "forcecharacter", + "weather", + "skynum", + "skybox_scalex", + "skybox_scaley", + "skybox_scalez", + "interscreen", + "runsoc", + "scriptname", + "precutscenenum", + "cutscenenum", + "countdown", + "palette", + "numlaps", + "unlockrequired", + "levelselect", + "bonustype", + "ltzzpatch", + "ltzztext", + "ltactdiamond", + "maxbonuslives", + "levelflags", + "menuflags", + "selectheading", + "startrings", + "sstimer", + "ssspheres", + "gravity", + NULL, +}; + +static int mapheaderinfo_fields_ref = LUA_NOREF; + static int mapheaderinfo_get(lua_State *L) { mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); - const char *field = luaL_checkstring(L, 2); + enum mapheaderinfo_e field = Lua_optoption(L, 2, -1, mapheaderinfo_fields_ref); INT16 i; - if (fastcmp(field,"lvlttl")) + + switch (field) + { + case mapheaderinfo_lvlttl: lua_pushstring(L, header->lvlttl); - else if (fastcmp(field,"subttl")) + break; + case mapheaderinfo_subttl: lua_pushstring(L, header->subttl); - else if (fastcmp(field,"actnum")) + break; + case mapheaderinfo_actnum: lua_pushinteger(L, header->actnum); - else if (fastcmp(field,"typeoflevel")) + break; + case mapheaderinfo_typeoflevel: lua_pushinteger(L, header->typeoflevel); - else if (fastcmp(field,"nextlevel")) + break; + case mapheaderinfo_nextlevel: lua_pushinteger(L, header->nextlevel); - else if (fastcmp(field,"marathonnext")) + break; + case mapheaderinfo_marathonnext: lua_pushinteger(L, header->marathonnext); - else if (fastcmp(field,"keywords")) + break; + case mapheaderinfo_keywords: lua_pushstring(L, header->keywords); - else if (fastcmp(field,"musname")) + break; + case mapheaderinfo_musname: lua_pushstring(L, header->musname); - else if (fastcmp(field,"mustrack")) + break; + case mapheaderinfo_mustrack: lua_pushinteger(L, header->mustrack); - else if (fastcmp(field,"muspos")) + break; + case mapheaderinfo_muspos: lua_pushinteger(L, header->muspos); - else if (fastcmp(field,"musinterfadeout")) + break; + case mapheaderinfo_musinterfadeout: lua_pushinteger(L, header->musinterfadeout); - else if (fastcmp(field,"musintername")) + break; + case mapheaderinfo_musintername: lua_pushstring(L, header->musintername); - else if (fastcmp(field,"muspostbossname")) + break; + case mapheaderinfo_muspostbossname: lua_pushstring(L, header->muspostbossname); - else if (fastcmp(field,"muspostbosstrack")) + break; + case mapheaderinfo_muspostbosstrack: lua_pushinteger(L, header->muspostbosstrack); - else if (fastcmp(field,"muspostbosspos")) + break; + case mapheaderinfo_muspostbosspos: lua_pushinteger(L, header->muspostbosspos); - else if (fastcmp(field,"muspostbossfadein")) + break; + case mapheaderinfo_muspostbossfadein: lua_pushinteger(L, header->muspostbossfadein); - else if (fastcmp(field,"musforcereset")) + break; + case mapheaderinfo_musforcereset: lua_pushinteger(L, header->musforcereset); - else if (fastcmp(field,"forcecharacter")) + break; + case mapheaderinfo_forcecharacter: lua_pushstring(L, header->forcecharacter); - else if (fastcmp(field,"weather")) + break; + case mapheaderinfo_weather: lua_pushinteger(L, header->weather); - else if (fastcmp(field,"skynum")) + break; + case mapheaderinfo_skynum: lua_pushinteger(L, header->skynum); - else if (fastcmp(field,"skybox_scalex")) + break; + case mapheaderinfo_skybox_scalex: lua_pushinteger(L, header->skybox_scalex); - else if (fastcmp(field,"skybox_scaley")) + break; + case mapheaderinfo_skybox_scaley: lua_pushinteger(L, header->skybox_scaley); - else if (fastcmp(field,"skybox_scalez")) + break; + case mapheaderinfo_skybox_scalez: lua_pushinteger(L, header->skybox_scalez); - else if (fastcmp(field,"interscreen")) { + break; + case mapheaderinfo_interscreen: for (i = 0; i < 8; i++) if (!header->interscreen[i]) break; lua_pushlstring(L, header->interscreen, i); - } else if (fastcmp(field,"runsoc")) + break; + case mapheaderinfo_runsoc: lua_pushstring(L, header->runsoc); - else if (fastcmp(field,"scriptname")) + break; + case mapheaderinfo_scriptname: lua_pushstring(L, header->scriptname); - else if (fastcmp(field,"precutscenenum")) + break; + case mapheaderinfo_precutscenenum: lua_pushinteger(L, header->precutscenenum); - else if (fastcmp(field,"cutscenenum")) + break; + case mapheaderinfo_cutscenenum: lua_pushinteger(L, header->cutscenenum); - else if (fastcmp(field,"countdown")) + break; + case mapheaderinfo_countdown: lua_pushinteger(L, header->countdown); - else if (fastcmp(field,"palette")) + break; + case mapheaderinfo_palette: lua_pushinteger(L, header->palette); - else if (fastcmp(field,"numlaps")) + break; + case mapheaderinfo_numlaps: lua_pushinteger(L, header->numlaps); - else if (fastcmp(field,"unlockrequired")) + break; + case mapheaderinfo_unlockrequired: lua_pushinteger(L, header->unlockrequired); - else if (fastcmp(field,"levelselect")) + break; + case mapheaderinfo_levelselect: lua_pushinteger(L, header->levelselect); - else if (fastcmp(field,"bonustype")) + break; + case mapheaderinfo_bonustype: lua_pushinteger(L, header->bonustype); - else if (fastcmp(field,"ltzzpatch")) + break; + case mapheaderinfo_ltzzpatch: lua_pushstring(L, header->ltzzpatch); - else if (fastcmp(field,"ltzztext")) + break; + case mapheaderinfo_ltzztext: lua_pushstring(L, header->ltzztext); - else if (fastcmp(field,"ltactdiamond")) + break; + case mapheaderinfo_ltactdiamond: lua_pushstring(L, header->ltactdiamond); - else if (fastcmp(field,"maxbonuslives")) + break; + case mapheaderinfo_maxbonuslives: lua_pushinteger(L, header->maxbonuslives); - else if (fastcmp(field,"levelflags")) + break; + case mapheaderinfo_levelflags: lua_pushinteger(L, header->levelflags); - else if (fastcmp(field,"menuflags")) + break; + case mapheaderinfo_menuflags: lua_pushinteger(L, header->menuflags); - else if (fastcmp(field,"selectheading")) + break; + case mapheaderinfo_selectheading: lua_pushstring(L, header->selectheading); - else if (fastcmp(field,"startrings")) + break; + case mapheaderinfo_startrings: lua_pushinteger(L, header->startrings); - else if (fastcmp(field, "sstimer")) + break; + case mapheaderinfo_sstimer: lua_pushinteger(L, header->sstimer); - else if (fastcmp(field, "ssspheres")) + break; + case mapheaderinfo_ssspheres: lua_pushinteger(L, header->ssspheres); - else if (fastcmp(field, "gravity")) + break; + case mapheaderinfo_gravity: lua_pushfixed(L, header->gravity); + break; // TODO add support for reading numGradedMares and grades - else { + default: // Read custom vars now // (note: don't include the "LUA." in your lua scripts!) UINT8 j = 0; - for (;j < header->numCustomOptions && !fastcmp(field, header->customopts[j].option); ++j); + for (;j < header->numCustomOptions && !fastcmp(lua_tostring(L, 2), header->customopts[j].option); ++j); if(j < header->numCustomOptions) lua_pushstring(L, header->customopts[j].value); @@ -2539,6 +2753,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + sector_fields_ref = Lua_CreateFieldTable(L, sector_opt); + luaL_newmetatable(L, META_SUBSECTOR); lua_pushcfunction(L, subsector_get); lua_setfield(L, -2, "__index"); @@ -2547,6 +2763,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt); + luaL_newmetatable(L, META_LINE); lua_pushcfunction(L, line_get); lua_setfield(L, -2, "__index"); @@ -2555,6 +2773,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + line_fields_ref = Lua_CreateFieldTable(L, line_opt); + luaL_newmetatable(L, META_LINEARGS); lua_pushcfunction(L, lineargs_get); lua_setfield(L, -2, "__index"); @@ -2587,6 +2807,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + side_fields_ref = Lua_CreateFieldTable(L, side_opt); + luaL_newmetatable(L, META_VERTEX); lua_pushcfunction(L, vertex_get); lua_setfield(L, -2, "__index"); @@ -2595,6 +2817,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + vertex_fields_ref = Lua_CreateFieldTable(L, vertex_opt); + luaL_newmetatable(L, META_FFLOOR); lua_pushcfunction(L, ffloor_get); lua_setfield(L, -2, "__index"); @@ -2603,6 +2827,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L, 1); + ffloor_fields_ref = Lua_CreateFieldTable(L, ffloor_opt); + #ifdef HAVE_LUA_SEGS luaL_newmetatable(L, META_SEG); lua_pushcfunction(L, seg_get); @@ -2612,6 +2838,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + seg_fields_ref = Lua_CreateFieldTable(L, seg_opt); + luaL_newmetatable(L, META_NODE); lua_pushcfunction(L, node_get); lua_setfield(L, -2, "__index"); @@ -2620,6 +2848,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + node_fields_ref = Lua_CreateFieldTable(L, node_opt); + luaL_newmetatable(L, META_NODEBBOX); //lua_pushcfunction(L, nodebbox_get); //lua_setfield(L, -2, "__index"); @@ -2646,6 +2876,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L, 1); + slope_fields_ref = Lua_CreateFieldTable(L, slope_opt); + luaL_newmetatable(L, META_VECTOR2); lua_pushcfunction(L, vector2_get); lua_setfield(L, -2, "__index"); @@ -2664,6 +2896,8 @@ int LUA_MapLib(lua_State *L) //lua_setfield(L, -2, "__len"); lua_pop(L, 1); + mapheaderinfo_fields_ref = Lua_CreateFieldTable(L, mapheaderinfo_opt); + LUA_PushTaggableObjectArray(L, "sectors", lib_iterateSectors, lib_getSector, diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 5c2b8b4d3..09d244c91 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -179,10 +179,12 @@ static const char *const mobj_opt[] = { #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) +static int mobj_fields_ref = LUA_NOREF; + static int mobj_get(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - enum mobj_e field = Lua_optoption(L, 2, NULL, mobj_opt); + enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref); lua_settop(L, 2); if (!mo || !ISINLEVEL) { @@ -467,7 +469,7 @@ static int mobj_get(lua_State *L) static int mobj_set(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - enum mobj_e field = Lua_optoption(L, 2, mobj_opt[0], mobj_opt); + enum mobj_e field = Lua_optoption(L, 2, mobj_valid, mobj_fields_ref); lua_settop(L, 3); INLEVEL @@ -876,14 +878,55 @@ static int thingstringargs_len(lua_State *L) return 1; } +enum mapthing_e { + mapthing_valid = 0, + mapthing_x, + mapthing_y, + mapthing_angle, + mapthing_pitch, + mapthing_roll, + mapthing_type, + mapthing_options, + mapthing_scale, + mapthing_z, + mapthing_extrainfo, + mapthing_tag, + mapthing_taglist, + mapthing_args, + mapthing_stringargs, + mapthing_mobj, +}; + +const char *const mapthing_opt[] = { + "valid", + "x", + "y", + "angle", + "pitch", + "roll", + "type", + "options", + "scale", + "z", + "extrainfo", + "tag", + "taglist", + "args", + "stringargs", + "mobj", + NULL, +}; + +static int mapthing_fields_ref = LUA_NOREF; + static int mapthing_get(lua_State *L) { mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); - const char *field = luaL_checkstring(L, 2); - lua_Integer number; + enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref); + lua_settop(L, 2); if (!mt) { - if (fastcmp(field,"valid")) { + if (field == mapthing_valid) { lua_pushboolean(L, false); return 1; } @@ -892,62 +935,71 @@ static int mapthing_get(lua_State *L) return 0; } - if (fastcmp(field,"valid")) { - lua_pushboolean(L, true); - return 1; - } else if(fastcmp(field,"x")) - number = mt->x; - else if(fastcmp(field,"y")) - number = mt->y; - else if(fastcmp(field,"angle")) - number = mt->angle; - else if(fastcmp(field,"pitch")) - number = mt->pitch; - else if(fastcmp(field,"roll")) - number = mt->roll; - else if(fastcmp(field,"type")) - number = mt->type; - else if(fastcmp(field,"options")) - number = mt->options; - else if(fastcmp(field,"scale")) - number = mt->scale; - else if(fastcmp(field,"z")) - number = mt->z; - else if(fastcmp(field,"extrainfo")) - number = mt->extrainfo; - else if(fastcmp(field,"tag")) - number = Tag_FGet(&mt->tags); - else if(fastcmp(field,"taglist")) + switch (field) { - LUA_PushUserdata(L, &mt->tags, META_TAGLIST); - return 1; + case mapthing_valid: + lua_pushboolean(L, true); + break; + case mapthing_x: + lua_pushinteger(L, mt->x); + break; + case mapthing_y: + lua_pushinteger(L, mt->y); + break; + case mapthing_angle: + lua_pushinteger(L, mt->angle); + break; + case mapthing_pitch: + lua_pushinteger(L, mt->pitch); + break; + case mapthing_roll: + lua_pushinteger(L, mt->roll); + break; + case mapthing_type: + lua_pushinteger(L, mt->type); + break; + case mapthing_options: + lua_pushinteger(L, mt->options); + break; + case mapthing_scale: + lua_pushinteger(L, mt->scale); + break; + case mapthing_z: + lua_pushinteger(L, mt->z); + break; + case mapthing_extrainfo: + lua_pushinteger(L, mt->extrainfo); + break; + case mapthing_tag: + lua_pushinteger(L, Tag_FGet(&mt->tags)); + break; + case mapthing_taglist: + LUA_PushUserdata(L, &mt->tags, META_TAGLIST); + break; + case mapthing_args: + LUA_PushUserdata(L, mt->args, META_THINGARGS); + break; + case mapthing_stringargs: + LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS); + break; + case mapthing_mobj: + LUA_PushUserdata(L, mt->mobj, META_MOBJ); + break; + default: + if (devparm) + return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); + else + return 0; } - else if(fastcmp(field,"args")) - { - LUA_PushUserdata(L, mt->args, META_THINGARGS); - return 1; - } - else if(fastcmp(field,"stringargs")) - { - LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS); - return 1; - } - else if(fastcmp(field,"mobj")) { - LUA_PushUserdata(L, mt->mobj, META_MOBJ); - return 1; - } else if (devparm) - return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); - else - return 0; - lua_pushinteger(L, number); return 1; } static int mapthing_set(lua_State *L) { mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); - const char *field = luaL_checkstring(L, 2); + enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref); + lua_settop(L, 3); if (!mt) return luaL_error(L, "accessed mapthing_t doesn't exist anymore."); @@ -957,39 +1009,52 @@ static int mapthing_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter mapthing_t in CMD building code!"); - if(fastcmp(field,"x")) - mt->x = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"y")) - mt->y = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"angle")) - mt->angle = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"pitch")) - mt->pitch = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"roll")) - mt->roll = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"type")) - mt->type = (UINT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"options")) - mt->options = (UINT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"scale")) - mt->scale = luaL_checkfixed(L, 3); - else if(fastcmp(field,"z")) - mt->z = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"extrainfo")) + switch (field) { - INT32 extrainfo = luaL_checkinteger(L, 3); - if (extrainfo & ~15) - return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15); - mt->extrainfo = (UINT8)extrainfo; + case mapthing_x: + mt->x = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_y: + mt->y = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_angle: + mt->angle = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_pitch: + mt->pitch = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_roll: + mt->roll = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_type: + mt->type = (UINT16)luaL_checkinteger(L, 3); + break; + case mapthing_options: + mt->options = (UINT16)luaL_checkinteger(L, 3); + break; + case mapthing_scale: + mt->scale = luaL_checkfixed(L, 3); + break; + case mapthing_z: + mt->z = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_extrainfo: + INT32 extrainfo = luaL_checkinteger(L, 3); + if (extrainfo & ~15) + return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15); + mt->extrainfo = (UINT8)extrainfo; + break; + case mapthing_tag: + Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); + break; + case mapthing_taglist: + return LUA_ErrSetDirectly(L, "mapthing_t", "taglist"); + case mapthing_mobj: + mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + break; + default: + return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); } - else if (fastcmp(field,"tag")) - Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); - else if (fastcmp(field,"taglist")) - return LUA_ErrSetDirectly(L, "mapthing_t", "taglist"); - else if(fastcmp(field,"mobj")) - mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); - else - return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); return 0; } @@ -1051,6 +1116,8 @@ int LUA_MobjLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + mobj_fields_ref = Lua_CreateFieldTable(L, mobj_opt); + luaL_newmetatable(L, META_THINGARGS); lua_pushcfunction(L, thingargs_get); lua_setfield(L, -2, "__index"); @@ -1078,6 +1145,8 @@ int LUA_MobjLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); + mapthing_fields_ref = Lua_CreateFieldTable(L, mapthing_opt); + LUA_PushTaggableObjectArray(L, "mapthings", lib_iterateMapthings, lib_getMapthing, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index f79b1e45e..1c3b4f46c 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -80,322 +80,764 @@ static int lib_lenPlayer(lua_State *L) return 1; } +enum player_e +{ + player_valid, + player_name, + player_realmo, + player_mo, + player_cmd, + player_playerstate, + player_camerascale, + player_shieldscale, + player_viewz, + player_viewheight, + player_deltaviewheight, + player_bob, + player_viewrollangle, + player_aiming, + player_drawangle, + player_rings, + player_spheres, + player_pity, + player_currentweapon, + player_ringweapons, + player_ammoremoval, + player_ammoremovaltimer, + player_ammoremovalweapon, + player_powers, + player_pflags, + player_panim, + player_flashcount, + player_flashpal, + player_skincolor, + player_skin, + player_availabilities, + player_score, + player_dashspeed, + player_normalspeed, + player_runspeed, + player_thrustfactor, + player_accelstart, + player_acceleration, + player_charability, + player_charability2, + player_charflags, + player_thokitem, + player_spinitem, + player_revitem, + player_followitem, + player_followmobj, + player_actionspd, + player_mindash, + player_maxdash, + player_jumpfactor, + player_height, + player_spinheight, + player_lives, + player_continues, + player_xtralife, + player_gotcontinue, + player_speed, + player_secondjump, + player_fly1, + player_scoreadd, + player_glidetime, + player_climbing, + player_deadtimer, + player_exiting, + player_homing, + player_dashmode, + player_skidtime, + player_cmomx, + player_cmomy, + player_rmomx, + player_rmomy, + player_numboxes, + player_totalring, + player_realtime, + player_laps, + player_ctfteam, + player_gotflag, + player_weapondelay, + player_tossdelay, + player_starpostx, + player_starposty, + player_starpostz, + player_starpostnum, + player_starposttime, + player_starpostangle, + player_starpostscale, + player_angle_pos, + player_old_angle_pos, + player_axis1, + player_axis2, + player_bumpertime, + player_flyangle, + player_drilltimer, + player_linkcount, + player_linktimer, + player_anotherflyangle, + player_nightstime, + player_drillmeter, + player_drilldelay, + player_bonustime, + player_capsule, + player_drone, + player_oldscale, + player_mare, + player_marelap, + player_marebonuslap, + player_marebegunat, + player_startedtime, + player_finishedtime, + player_lapbegunat, + player_lapstartedtime, + player_finishedspheres, + player_finishedrings, + player_marescore, + player_lastmarescore, + player_totalmarescore, + player_lastmare, + player_lastmarelap, + player_lastmarebonuslap, + player_totalmarelap, + player_totalmarebonuslap, + player_maxlink, + player_texttimer, + player_textvar, + player_lastsidehit, + player_lastlinehit, + player_losstime, + player_timeshit, + player_onconveyor, + player_awayviewmobj, + player_awayviewtics, + player_awayviewaiming, + player_spectator, + player_outofcoop, + player_bot, + player_botleader, + player_lastbuttons, + player_blocked, + player_jointime, + player_quittime, +#ifdef HWRENDER + player_fovadd, +#endif +}; + +static const char *const player_opt[] = { + "valid", + "name", + "realmo", + "mo", + "cmd", + "playerstate", + "camerascale", + "shieldscale", + "viewz", + "viewheight", + "deltaviewheight", + "bob", + "viewrollangle", + "aiming", + "drawangle", + "rings", + "spheres", + "pity", + "currentweapon", + "ringweapons", + "ammoremoval", + "ammoremovaltimer", + "ammoremovalweapon", + "powers", + "pflags", + "panim", + "flashcount", + "flashpal", + "skincolor", + "skin", + "availabilities", + "score", + "dashspeed", + "normalspeed", + "runspeed", + "thrustfactor", + "accelstart", + "acceleration", + "charability", + "charability2", + "charflags", + "thokitem", + "spinitem", + "revitem", + "followitem", + "followmobj", + "actionspd", + "mindash", + "maxdash", + "jumpfactor", + "height", + "spinheight", + "lives", + "continues", + "xtralife", + "gotcontinue", + "speed", + "secondjump", + "fly1", + "scoreadd", + "glidetime", + "climbing", + "deadtimer", + "exiting", + "homing", + "dashmode", + "skidtime", + "cmomx", + "cmomy", + "rmomx", + "rmomy", + "numboxes", + "totalring", + "realtime", + "laps", + "ctfteam", + "gotflag", + "weapondelay", + "tossdelay", + "starpostx", + "starposty", + "starpostz", + "starpostnum", + "starposttime", + "starpostangle", + "starpostscale", + "angle_pos", + "old_angle_pos", + "axis1", + "axis2", + "bumpertime", + "flyangle", + "drilltimer", + "linkcount", + "linktimer", + "anotherflyangle", + "nightstime", + "drillmeter", + "drilldelay", + "bonustime", + "capsule", + "drone", + "oldscale", + "mare", + "marelap", + "marebonuslap", + "marebegunat", + "startedtime", + "finishedtime", + "lapbegunat", + "lapstartedtime", + "finishedspheres", + "finishedrings", + "marescore", + "lastmarescore", + "totalmarescore", + "lastmare", + "lastmarelap", + "lastmarebonuslap", + "totalmarelap", + "totalmarebonuslap", + "maxlink", + "texttimer", + "textvar", + "lastsidehit", + "lastlinehit", + "losstime", + "timeshit", + "onconveyor", + "awayviewmobj", + "awayviewtics", + "awayviewaiming", + "spectator", + "outofcoop", + "bot", + "botleader", + "lastbuttons", + "blocked", + "jointime", + "quittime", +#ifdef HWRENDER + "fovadd", +#endif + NULL, +}; + +static int player_fields_ref = LUA_NOREF; + static int player_get(lua_State *L) { player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - const char *field = luaL_checkstring(L, 2); + enum player_e field = Lua_optoption(L, 2, -1, player_fields_ref); + lua_settop(L, 2); - if (!plr) { - if (fastcmp(field,"valid")) { + if (!plr) + { + if (field == player_valid) + { lua_pushboolean(L, false); return 1; } return LUA_ErrInvalid(L, "player_t"); } - if (fastcmp(field,"valid")) + switch (field) + { + case player_valid: lua_pushboolean(L, true); - else if (fastcmp(field,"name")) + break; + case player_name: lua_pushstring(L, player_names[plr-players]); - else if (fastcmp(field,"realmo")) + break; + case player_realmo: LUA_PushUserdata(L, plr->mo, META_MOBJ); + break; // Kept for backward-compatibility // Should be fixed to work like "realmo" later - else if (fastcmp(field,"mo")) - { + case player_mo: if (plr->spectator) lua_pushnil(L); else LUA_PushUserdata(L, plr->mo, META_MOBJ); - } - else if (fastcmp(field,"cmd")) + break; + case player_cmd: LUA_PushUserdata(L, &plr->cmd, META_TICCMD); - else if (fastcmp(field,"playerstate")) + break; + case player_playerstate: lua_pushinteger(L, plr->playerstate); - else if (fastcmp(field,"camerascale")) + break; + case player_camerascale: lua_pushfixed(L, plr->camerascale); - else if (fastcmp(field,"shieldscale")) + break; + case player_shieldscale: lua_pushfixed(L, plr->shieldscale); - else if (fastcmp(field,"viewz")) + break; + case player_viewz: lua_pushfixed(L, plr->viewz); - else if (fastcmp(field,"viewheight")) + break; + case player_viewheight: lua_pushfixed(L, plr->viewheight); - else if (fastcmp(field,"deltaviewheight")) + break; + case player_deltaviewheight: lua_pushfixed(L, plr->deltaviewheight); - else if (fastcmp(field,"bob")) + break; + case player_bob: lua_pushfixed(L, plr->bob); - else if (fastcmp(field,"viewrollangle")) + break; + case player_viewrollangle: lua_pushangle(L, plr->viewrollangle); - else if (fastcmp(field,"aiming")) + break; + case player_aiming: lua_pushangle(L, plr->aiming); - else if (fastcmp(field,"drawangle")) + break; + case player_drawangle: lua_pushangle(L, plr->drawangle); - else if (fastcmp(field,"rings")) + break; + case player_rings: lua_pushinteger(L, plr->rings); - else if (fastcmp(field,"spheres")) + break; + case player_spheres: lua_pushinteger(L, plr->spheres); - else if (fastcmp(field,"pity")) + break; + case player_pity: lua_pushinteger(L, plr->pity); - else if (fastcmp(field,"currentweapon")) + break; + case player_currentweapon: lua_pushinteger(L, plr->currentweapon); - else if (fastcmp(field,"ringweapons")) + break; + case player_ringweapons: lua_pushinteger(L, plr->ringweapons); - else if (fastcmp(field,"ammoremoval")) + break; + case player_ammoremoval: lua_pushinteger(L, plr->ammoremoval); - else if (fastcmp(field,"ammoremovaltimer")) + break; + case player_ammoremovaltimer: lua_pushinteger(L, plr->ammoremovaltimer); - else if (fastcmp(field,"ammoremovalweapon")) + break; + case player_ammoremovalweapon: lua_pushinteger(L, plr->ammoremovalweapon); - else if (fastcmp(field,"powers")) + break; + case player_powers: LUA_PushUserdata(L, plr->powers, META_POWERS); - else if (fastcmp(field,"pflags")) + break; + case player_pflags: lua_pushinteger(L, plr->pflags); - else if (fastcmp(field,"panim")) + break; + case player_panim: lua_pushinteger(L, plr->panim); - else if (fastcmp(field,"flashcount")) + break; + case player_flashcount: lua_pushinteger(L, plr->flashcount); - else if (fastcmp(field,"flashpal")) + break; + case player_flashpal: lua_pushinteger(L, plr->flashpal); - else if (fastcmp(field,"skincolor")) + break; + case player_skincolor: lua_pushinteger(L, plr->skincolor); - else if (fastcmp(field,"skin")) + break; + case player_skin: lua_pushinteger(L, plr->skin); - else if (fastcmp(field,"availabilities")) + break; + case player_availabilities: lua_pushinteger(L, plr->availabilities); - else if (fastcmp(field,"score")) + break; + case player_score: lua_pushinteger(L, plr->score); - else if (fastcmp(field,"dashspeed")) + break; + case player_dashspeed: lua_pushfixed(L, plr->dashspeed); - else if (fastcmp(field,"normalspeed")) + break; + case player_normalspeed: lua_pushfixed(L, plr->normalspeed); - else if (fastcmp(field,"runspeed")) + break; + case player_runspeed: lua_pushfixed(L, plr->runspeed); - else if (fastcmp(field,"thrustfactor")) + break; + case player_thrustfactor: lua_pushinteger(L, plr->thrustfactor); - else if (fastcmp(field,"accelstart")) + break; + case player_accelstart: lua_pushinteger(L, plr->accelstart); - else if (fastcmp(field,"acceleration")) + break; + case player_acceleration: lua_pushinteger(L, plr->acceleration); - else if (fastcmp(field,"charability")) + break; + case player_charability: lua_pushinteger(L, plr->charability); - else if (fastcmp(field,"charability2")) + break; + case player_charability2: lua_pushinteger(L, plr->charability2); - else if (fastcmp(field,"charflags")) + break; + case player_charflags: lua_pushinteger(L, plr->charflags); - else if (fastcmp(field,"thokitem")) + break; + case player_thokitem: lua_pushinteger(L, plr->thokitem); - else if (fastcmp(field,"spinitem")) + break; + case player_spinitem: lua_pushinteger(L, plr->spinitem); - else if (fastcmp(field,"revitem")) + break; + case player_revitem: lua_pushinteger(L, plr->revitem); - else if (fastcmp(field,"followitem")) + break; + case player_followitem: lua_pushinteger(L, plr->followitem); - else if (fastcmp(field,"followmobj")) + break; + case player_followmobj: LUA_PushUserdata(L, plr->followmobj, META_MOBJ); - else if (fastcmp(field,"actionspd")) + break; + case player_actionspd: lua_pushfixed(L, plr->actionspd); - else if (fastcmp(field,"mindash")) + break; + case player_mindash: lua_pushfixed(L, plr->mindash); - else if (fastcmp(field,"maxdash")) + break; + case player_maxdash: lua_pushfixed(L, plr->maxdash); - else if (fastcmp(field,"jumpfactor")) + break; + case player_jumpfactor: lua_pushfixed(L, plr->jumpfactor); - else if (fastcmp(field,"height")) + break; + case player_height: lua_pushfixed(L, plr->height); - else if (fastcmp(field,"spinheight")) + break; + case player_spinheight: lua_pushfixed(L, plr->spinheight); - else if (fastcmp(field,"lives")) + break; + case player_lives: lua_pushinteger(L, plr->lives); - else if (fastcmp(field,"continues")) + break; + case player_continues: lua_pushinteger(L, plr->continues); - else if (fastcmp(field,"xtralife")) + break; + case player_xtralife: lua_pushinteger(L, plr->xtralife); - else if (fastcmp(field,"gotcontinue")) + break; + case player_gotcontinue: lua_pushinteger(L, plr->gotcontinue); - else if (fastcmp(field,"speed")) + break; + case player_speed: lua_pushfixed(L, plr->speed); - else if (fastcmp(field,"secondjump")) + break; + case player_secondjump: lua_pushinteger(L, plr->secondjump); - else if (fastcmp(field,"fly1")) + break; + case player_fly1: lua_pushinteger(L, plr->fly1); - else if (fastcmp(field,"scoreadd")) + break; + case player_scoreadd: lua_pushinteger(L, plr->scoreadd); - else if (fastcmp(field,"glidetime")) + break; + case player_glidetime: lua_pushinteger(L, plr->glidetime); - else if (fastcmp(field,"climbing")) + break; + case player_climbing: lua_pushinteger(L, plr->climbing); - else if (fastcmp(field,"deadtimer")) + break; + case player_deadtimer: lua_pushinteger(L, plr->deadtimer); - else if (fastcmp(field,"exiting")) + break; + case player_exiting: lua_pushinteger(L, plr->exiting); - else if (fastcmp(field,"homing")) + break; + case player_homing: lua_pushinteger(L, plr->homing); - else if (fastcmp(field,"dashmode")) + break; + case player_dashmode: lua_pushinteger(L, plr->dashmode); - else if (fastcmp(field,"skidtime")) + break; + case player_skidtime: lua_pushinteger(L, plr->skidtime); - else if (fastcmp(field,"cmomx")) + break; + case player_cmomx: lua_pushfixed(L, plr->cmomx); - else if (fastcmp(field,"cmomy")) + break; + case player_cmomy: lua_pushfixed(L, plr->cmomy); - else if (fastcmp(field,"rmomx")) + break; + case player_rmomx: lua_pushfixed(L, plr->rmomx); - else if (fastcmp(field,"rmomy")) + break; + case player_rmomy: lua_pushfixed(L, plr->rmomy); - else if (fastcmp(field,"numboxes")) + break; + case player_numboxes: lua_pushinteger(L, plr->numboxes); - else if (fastcmp(field,"totalring")) + break; + case player_totalring: lua_pushinteger(L, plr->totalring); - else if (fastcmp(field,"realtime")) + break; + case player_realtime: lua_pushinteger(L, plr->realtime); - else if (fastcmp(field,"laps")) + break; + case player_laps: lua_pushinteger(L, plr->laps); - else if (fastcmp(field,"ctfteam")) + break; + case player_ctfteam: lua_pushinteger(L, plr->ctfteam); - else if (fastcmp(field,"gotflag")) + break; + case player_gotflag: lua_pushinteger(L, plr->gotflag); - else if (fastcmp(field,"weapondelay")) + break; + case player_weapondelay: lua_pushinteger(L, plr->weapondelay); - else if (fastcmp(field,"tossdelay")) + break; + case player_tossdelay: lua_pushinteger(L, plr->tossdelay); - else if (fastcmp(field,"starpostx")) + break; + case player_starpostx: lua_pushinteger(L, plr->starpostx); - else if (fastcmp(field,"starposty")) + break; + case player_starposty: lua_pushinteger(L, plr->starposty); - else if (fastcmp(field,"starpostz")) + break; + case player_starpostz: lua_pushinteger(L, plr->starpostz); - else if (fastcmp(field,"starpostnum")) + break; + case player_starpostnum: lua_pushinteger(L, plr->starpostnum); - else if (fastcmp(field,"starposttime")) + break; + case player_starposttime: lua_pushinteger(L, plr->starposttime); - else if (fastcmp(field,"starpostangle")) + break; + case player_starpostangle: lua_pushangle(L, plr->starpostangle); - else if (fastcmp(field,"starpostscale")) + break; + case player_starpostscale: lua_pushfixed(L, plr->starpostscale); - else if (fastcmp(field,"angle_pos")) + break; + case player_angle_pos: lua_pushangle(L, plr->angle_pos); - else if (fastcmp(field,"old_angle_pos")) + break; + case player_old_angle_pos: lua_pushangle(L, plr->old_angle_pos); - else if (fastcmp(field,"axis1")) + break; + case player_axis1: LUA_PushUserdata(L, plr->axis1, META_MOBJ); - else if (fastcmp(field,"axis2")) + break; + case player_axis2: LUA_PushUserdata(L, plr->axis2, META_MOBJ); - else if (fastcmp(field,"bumpertime")) + break; + case player_bumpertime: lua_pushinteger(L, plr->bumpertime); - else if (fastcmp(field,"flyangle")) + break; + case player_flyangle: lua_pushinteger(L, plr->flyangle); - else if (fastcmp(field,"drilltimer")) + break; + case player_drilltimer: lua_pushinteger(L, plr->drilltimer); - else if (fastcmp(field,"linkcount")) + break; + case player_linkcount: lua_pushinteger(L, plr->linkcount); - else if (fastcmp(field,"linktimer")) + break; + case player_linktimer: lua_pushinteger(L, plr->linktimer); - else if (fastcmp(field,"anotherflyangle")) + break; + case player_anotherflyangle: lua_pushinteger(L, plr->anotherflyangle); - else if (fastcmp(field,"nightstime")) + break; + case player_nightstime: lua_pushinteger(L, plr->nightstime); - else if (fastcmp(field,"drillmeter")) + break; + case player_drillmeter: lua_pushinteger(L, plr->drillmeter); - else if (fastcmp(field,"drilldelay")) + break; + case player_drilldelay: lua_pushinteger(L, plr->drilldelay); - else if (fastcmp(field,"bonustime")) + break; + case player_bonustime: lua_pushboolean(L, plr->bonustime); - else if (fastcmp(field,"capsule")) + break; + case player_capsule: LUA_PushUserdata(L, plr->capsule, META_MOBJ); - else if (fastcmp(field,"drone")) + break; + case player_drone: LUA_PushUserdata(L, plr->drone, META_MOBJ); - else if (fastcmp(field,"oldscale")) + break; + case player_oldscale: lua_pushfixed(L, plr->oldscale); - else if (fastcmp(field,"mare")) + break; + case player_mare: lua_pushinteger(L, plr->mare); - else if (fastcmp(field,"marelap")) + break; + case player_marelap: lua_pushinteger(L, plr->marelap); - else if (fastcmp(field,"marebonuslap")) + break; + case player_marebonuslap: lua_pushinteger(L, plr->marebonuslap); - else if (fastcmp(field,"marebegunat")) + break; + case player_marebegunat: lua_pushinteger(L, plr->marebegunat); - else if (fastcmp(field,"startedtime")) + break; + case player_startedtime: lua_pushinteger(L, plr->startedtime); - else if (fastcmp(field,"finishedtime")) + break; + case player_finishedtime: lua_pushinteger(L, plr->finishedtime); - else if (fastcmp(field,"lapbegunat")) + break; + case player_lapbegunat: lua_pushinteger(L, plr->lapbegunat); - else if (fastcmp(field,"lapstartedtime")) + break; + case player_lapstartedtime: lua_pushinteger(L, plr->lapstartedtime); - else if (fastcmp(field,"finishedspheres")) + break; + case player_finishedspheres: lua_pushinteger(L, plr->finishedspheres); - else if (fastcmp(field,"finishedrings")) + break; + case player_finishedrings: lua_pushinteger(L, plr->finishedrings); - else if (fastcmp(field,"marescore")) + break; + case player_marescore: lua_pushinteger(L, plr->marescore); - else if (fastcmp(field,"lastmarescore")) + break; + case player_lastmarescore: lua_pushinteger(L, plr->lastmarescore); - else if (fastcmp(field,"totalmarescore")) + break; + case player_totalmarescore: lua_pushinteger(L, plr->totalmarescore); - else if (fastcmp(field,"lastmare")) + break; + case player_lastmare: lua_pushinteger(L, plr->lastmare); - else if (fastcmp(field,"lastmarelap")) + break; + case player_lastmarelap: lua_pushinteger(L, plr->lastmarelap); - else if (fastcmp(field,"lastmarebonuslap")) + break; + case player_lastmarebonuslap: lua_pushinteger(L, plr->lastmarebonuslap); - else if (fastcmp(field,"totalmarelap")) + break; + case player_totalmarelap: lua_pushinteger(L, plr->totalmarelap); - else if (fastcmp(field,"totalmarebonuslap")) + break; + case player_totalmarebonuslap: lua_pushinteger(L, plr->totalmarebonuslap); - else if (fastcmp(field,"maxlink")) + break; + case player_maxlink: lua_pushinteger(L, plr->maxlink); - else if (fastcmp(field,"texttimer")) + break; + case player_texttimer: lua_pushinteger(L, plr->texttimer); - else if (fastcmp(field,"textvar")) + break; + case player_textvar: lua_pushinteger(L, plr->textvar); - else if (fastcmp(field,"lastsidehit")) + break; + case player_lastsidehit: lua_pushinteger(L, plr->lastsidehit); - else if (fastcmp(field,"lastlinehit")) + break; + case player_lastlinehit: lua_pushinteger(L, plr->lastlinehit); - else if (fastcmp(field,"losstime")) + break; + case player_losstime: lua_pushinteger(L, plr->losstime); - else if (fastcmp(field,"timeshit")) + break; + case player_timeshit: lua_pushinteger(L, plr->timeshit); - else if (fastcmp(field,"onconveyor")) + break; + case player_onconveyor: lua_pushinteger(L, plr->onconveyor); - else if (fastcmp(field,"awayviewmobj")) + break; + case player_awayviewmobj: LUA_PushUserdata(L, plr->awayviewmobj, META_MOBJ); - else if (fastcmp(field,"awayviewtics")) + break; + case player_awayviewtics: lua_pushinteger(L, plr->awayviewtics); - else if (fastcmp(field,"awayviewaiming")) + break; + case player_awayviewaiming: lua_pushangle(L, plr->awayviewaiming); - else if (fastcmp(field,"spectator")) + break; + case player_spectator: lua_pushboolean(L, plr->spectator); - else if (fastcmp(field,"outofcoop")) + break; + case player_outofcoop: lua_pushboolean(L, plr->outofcoop); - else if (fastcmp(field,"bot")) + break; + case player_bot: lua_pushinteger(L, plr->bot); - else if (fastcmp(field,"botleader")) + break; + case player_botleader: LUA_PushUserdata(L, plr->botleader, META_PLAYER); - else if (fastcmp(field,"lastbuttons")) + break; + case player_lastbuttons: lua_pushinteger(L, plr->lastbuttons); - else if (fastcmp(field,"blocked")) + break; + case player_blocked: lua_pushboolean(L, plr->blocked); - else if (fastcmp(field,"jointime")) + break; + case player_jointime: lua_pushinteger(L, plr->jointime); - else if (fastcmp(field,"quittime")) + break; + case player_quittime: lua_pushinteger(L, plr->quittime); + break; #ifdef HWRENDER - else if (fastcmp(field,"fovadd")) + case player_fovadd: lua_pushfixed(L, plr->fovadd); + break; #endif - else { + default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, plr); lua_rawget(L, -2); if (!lua_istable(L, -1)) { // no extra values table - CONS_Debug(DBG_LUA, M_GetText("'%s' has no extvars table or field named '%s'; returning nil.\n"), "player_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no extvars table or field named '%s'; returning nil.\n"), "player_t", lua_tostring(L, 2)); return 0; } - lua_getfield(L, -1, field); + lua_pushvalue(L, 2); // field name + lua_gettable(L, -2); if (lua_isnil(L, -1)) // no value for this field - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "player_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "player_t", lua_tostring(L, 2)); + break; } return 1; @@ -405,7 +847,7 @@ static int player_get(lua_State *L) static int player_set(lua_State *L) { player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - const char *field = luaL_checkstring(L, 2); + enum player_e field = Lua_optoption(L, 2, player_cmd, player_fields_ref); if (!plr) return LUA_ErrInvalid(L, "player_t"); @@ -414,297 +856,424 @@ static int player_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter player_t in CMD building code!"); - if (fastcmp(field,"mo") || fastcmp(field,"realmo")) { + switch (field) + { + case player_mo: + case player_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 + break; } - else if (fastcmp(field,"cmd")) + case player_cmd: return NOSET; - else if (fastcmp(field,"playerstate")) + case player_playerstate: plr->playerstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"camerascale")) + break; + case player_camerascale: plr->camerascale = luaL_checkfixed(L, 3); - else if (fastcmp(field,"shieldscale")) + break; + case player_shieldscale: plr->shieldscale = luaL_checkfixed(L, 3); - else if (fastcmp(field,"viewz")) + break; + case player_viewz: plr->viewz = luaL_checkfixed(L, 3); - else if (fastcmp(field,"viewheight")) + break; + case player_viewheight: plr->viewheight = luaL_checkfixed(L, 3); - else if (fastcmp(field,"deltaviewheight")) + break; + case player_deltaviewheight: plr->deltaviewheight = luaL_checkfixed(L, 3); - else if (fastcmp(field,"bob")) + break; + case player_bob: plr->bob = luaL_checkfixed(L, 3); - else if (fastcmp(field,"viewrollangle")) + break; + case player_viewrollangle: plr->viewrollangle = luaL_checkangle(L, 3); - else if (fastcmp(field,"aiming")) { + break; + case player_aiming: + { plr->aiming = luaL_checkangle(L, 3); if (plr == &players[consoleplayer]) localaiming = plr->aiming; else if (plr == &players[secondarydisplayplayer]) localaiming2 = plr->aiming; + break; } - else if (fastcmp(field,"drawangle")) + case player_drawangle: plr->drawangle = luaL_checkangle(L, 3); - else if (fastcmp(field,"rings")) + break; + case player_rings: plr->rings = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"spheres")) + break; + case player_spheres: plr->spheres = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"pity")) + break; + case player_pity: plr->pity = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"currentweapon")) + break; + case player_currentweapon: plr->currentweapon = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"ringweapons")) + break; + case player_ringweapons: plr->ringweapons = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"ammoremoval")) + break; + case player_ammoremoval: plr->ammoremoval = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"ammoremovaltimer")) + break; + case player_ammoremovaltimer: plr->ammoremovaltimer = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"ammoremovalweapon")) + break; + case player_ammoremovalweapon: plr->ammoremovalweapon = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"powers")) + break; + case player_powers: return NOSET; - else if (fastcmp(field,"pflags")) + case player_pflags: plr->pflags = luaL_checkinteger(L, 3); - else if (fastcmp(field,"panim")) + break; + case player_panim: plr->panim = luaL_checkinteger(L, 3); - else if (fastcmp(field,"flashcount")) + break; + case player_flashcount: plr->flashcount = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"flashpal")) + break; + case player_flashpal: plr->flashpal = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"skincolor")) + break; + case player_skincolor: { 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; + break; } - else if (fastcmp(field,"skin")) + case player_skin: return NOSET; - else if (fastcmp(field,"availabilities")) + case player_availabilities: return NOSET; - else if (fastcmp(field,"score")) + case player_score: plr->score = (UINT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"dashspeed")) + break; + case player_dashspeed: plr->dashspeed = luaL_checkfixed(L, 3); - else if (fastcmp(field,"normalspeed")) + break; + case player_normalspeed: plr->normalspeed = luaL_checkfixed(L, 3); - else if (fastcmp(field,"runspeed")) + break; + case player_runspeed: plr->runspeed = luaL_checkfixed(L, 3); - else if (fastcmp(field,"thrustfactor")) + break; + case player_thrustfactor: plr->thrustfactor = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"accelstart")) + break; + case player_accelstart: plr->accelstart = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"acceleration")) + break; + case player_acceleration: plr->acceleration = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"charability")) + break; + case player_charability: plr->charability = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"charability2")) + break; + case player_charability2: plr->charability2 = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"charflags")) + break; + case player_charflags: plr->charflags = (UINT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"thokitem")) + break; + case player_thokitem: plr->thokitem = luaL_checkinteger(L, 3); - else if (fastcmp(field,"spinitem")) + break; + case player_spinitem: plr->spinitem = luaL_checkinteger(L, 3); - else if (fastcmp(field,"revitem")) + break; + case player_revitem: plr->revitem = luaL_checkinteger(L, 3); - else if (fastcmp(field,"followitem")) + break; + case player_followitem: plr->followitem = luaL_checkinteger(L, 3); - else if (fastcmp(field,"followmobj")) + break; + case player_followmobj: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->followmobj, mo); + break; } - else if (fastcmp(field,"actionspd")) + case player_actionspd: plr->actionspd = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"mindash")) + break; + case player_mindash: plr->mindash = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"maxdash")) + break; + case player_maxdash: plr->maxdash = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"jumpfactor")) + break; + case player_jumpfactor: plr->jumpfactor = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"height")) + break; + case player_height: plr->height = luaL_checkfixed(L, 3); - else if (fastcmp(field,"spinheight")) + break; + case player_spinheight: plr->spinheight = luaL_checkfixed(L, 3); - else if (fastcmp(field,"lives")) + break; + case player_lives: plr->lives = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"continues")) + break; + case player_continues: plr->continues = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"xtralife")) + break; + case player_xtralife: plr->xtralife = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"gotcontinue")) + break; + case player_gotcontinue: plr->gotcontinue = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"speed")) + break; + case player_speed: plr->speed = luaL_checkfixed(L, 3); - else if (fastcmp(field,"secondjump")) + break; + case player_secondjump: plr->secondjump = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"fly1")) + break; + case player_fly1: plr->fly1 = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"scoreadd")) + break; + case player_scoreadd: plr->scoreadd = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"glidetime")) + break; + case player_glidetime: plr->glidetime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"climbing")) + break; + case player_climbing: plr->climbing = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"deadtimer")) + break; + case player_deadtimer: plr->deadtimer = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"exiting")) + break; + case player_exiting: plr->exiting = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"homing")) + break; + case player_homing: plr->homing = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"dashmode")) + break; + case player_dashmode: plr->dashmode = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"skidtime")) + break; + case player_skidtime: plr->skidtime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"cmomx")) + break; + case player_cmomx: plr->cmomx = luaL_checkfixed(L, 3); - else if (fastcmp(field,"cmomy")) + break; + case player_cmomy: plr->cmomy = luaL_checkfixed(L, 3); - else if (fastcmp(field,"rmomx")) + break; + case player_rmomx: plr->rmomx = luaL_checkfixed(L, 3); - else if (fastcmp(field,"rmomy")) + break; + case player_rmomy: plr->rmomy = luaL_checkfixed(L, 3); - else if (fastcmp(field,"numboxes")) + break; + case player_numboxes: plr->numboxes = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"totalring")) + break; + case player_totalring: plr->totalring = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"realtime")) + break; + case player_realtime: plr->realtime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"laps")) + break; + case player_laps: plr->laps = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"ctfteam")) + break; + case player_ctfteam: plr->ctfteam = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"gotflag")) + break; + case player_gotflag: plr->gotflag = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"weapondelay")) + break; + case player_weapondelay: plr->weapondelay = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"tossdelay")) + break; + case player_tossdelay: plr->tossdelay = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"starpostx")) + break; + case player_starpostx: plr->starpostx = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"starposty")) + break; + case player_starposty: plr->starposty = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"starpostz")) + break; + case player_starpostz: plr->starpostz = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"starpostnum")) + break; + case player_starpostnum: plr->starpostnum = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"starposttime")) + break; + case player_starposttime: plr->starposttime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"starpostangle")) + break; + case player_starpostangle: plr->starpostangle = luaL_checkangle(L, 3); - else if (fastcmp(field,"starpostscale")) + break; + case player_starpostscale: plr->starpostscale = luaL_checkfixed(L, 3); - else if (fastcmp(field,"angle_pos")) + break; + case player_angle_pos: plr->angle_pos = luaL_checkangle(L, 3); - else if (fastcmp(field,"old_angle_pos")) + break; + case player_old_angle_pos: plr->old_angle_pos = luaL_checkangle(L, 3); - else if (fastcmp(field,"axis1")) + break; + case player_axis1: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->axis1, mo); + break; } - else if (fastcmp(field,"axis2")) + case player_axis2: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->axis2, mo); + break; } - else if (fastcmp(field,"bumpertime")) + case player_bumpertime: plr->bumpertime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"flyangle")) + break; + case player_flyangle: plr->flyangle = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"drilltimer")) + break; + case player_drilltimer: plr->drilltimer = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"linkcount")) + break; + case player_linkcount: plr->linkcount = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"linktimer")) + break; + case player_linktimer: plr->linktimer = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"anotherflyangle")) + break; + case player_anotherflyangle: plr->anotherflyangle = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"nightstime")) + break; + case player_nightstime: plr->nightstime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"drillmeter")) + break; + case player_drillmeter: plr->drillmeter = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"drilldelay")) + break; + case player_drilldelay: plr->drilldelay = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"bonustime")) + break; + case player_bonustime: plr->bonustime = luaL_checkboolean(L, 3); - else if (fastcmp(field,"capsule")) + break; + case player_capsule: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->capsule, mo); + break; } - else if (fastcmp(field,"drone")) + case player_drone: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->drone, mo); + break; } - else if (fastcmp(field,"oldscale")) + case player_oldscale: plr->oldscale = luaL_checkfixed(L, 3); - else if (fastcmp(field,"mare")) + break; + case player_mare: plr->mare = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"marelap")) + break; + case player_marelap: plr->marelap = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"marebonuslap")) + break; + case player_marebonuslap: plr->marebonuslap = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"marebegunat")) + break; + case player_marebegunat: plr->marebegunat = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"startedtime")) + break; + case player_startedtime: plr->startedtime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"finishedtime")) + break; + case player_finishedtime: plr->finishedtime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lapbegunat")) + break; + case player_lapbegunat: plr->lapbegunat = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lapstartedtime")) + break; + case player_lapstartedtime: plr->lapstartedtime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"finishedspheres")) + break; + case player_finishedspheres: plr->finishedspheres = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"finishedrings")) + break; + case player_finishedrings: plr->finishedrings = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"marescore")) + break; + case player_marescore: plr->marescore = (UINT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lastmarescore")) + break; + case player_lastmarescore: plr->lastmarescore = (UINT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"totalmarescore")) + break; + case player_totalmarescore: plr->totalmarescore = (UINT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lastmare")) + break; + case player_lastmare: plr->lastmare = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lastmarelap")) + break; + case player_lastmarelap: plr->lastmarelap = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lastmarebonuslap")) + break; + case player_lastmarebonuslap: plr->lastmarebonuslap = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"totalmarelap")) + break; + case player_totalmarelap: plr->totalmarelap = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"totalmarebonuslap")) + break; + case player_totalmarebonuslap: plr->totalmarebonuslap = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"maxlink")) + break; + case player_maxlink: plr->maxlink = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"texttimer")) + break; + case player_texttimer: plr->texttimer = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"textvar")) + break; + case player_textvar: plr->textvar = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lastsidehit")) + break; + case player_lastsidehit: plr->lastsidehit = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"lastlinehit")) + break; + case player_lastlinehit: plr->lastlinehit = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"losstime")) + break; + case player_losstime: plr->losstime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"timeshit")) + break; + case player_timeshit: plr->timeshit = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"onconveyor")) + break; + case player_onconveyor: plr->onconveyor = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"awayviewmobj")) + break; + case player_awayviewmobj: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) @@ -714,41 +1283,50 @@ static int player_set(lua_State *L) P_ResetCamera(plr, &camera); // reset p1 camera on p1 getting an awayviewmobj else if (splitscreen && plr == &players[secondarydisplayplayer]) P_ResetCamera(plr, &camera2); // reset p2 camera on p2 getting an awayviewmobj + break; } - else if (fastcmp(field,"awayviewtics")) - { + case player_awayviewtics: plr->awayviewtics = (INT32)luaL_checkinteger(L, 3); if (plr->awayviewtics && !plr->awayviewmobj) // awayviewtics must ALWAYS have an awayviewmobj set!! P_SetTarget(&plr->awayviewmobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now. - } - else if (fastcmp(field,"awayviewaiming")) + break; + case player_awayviewaiming: plr->awayviewaiming = luaL_checkangle(L, 3); - else if (fastcmp(field,"spectator")) + break; + case player_spectator: plr->spectator = lua_toboolean(L, 3); - else if (fastcmp(field,"outofcoop")) + break; + case player_outofcoop: plr->outofcoop = lua_toboolean(L, 3); - else if (fastcmp(field,"bot")) + break; + case player_bot: return NOSET; - else if (fastcmp(field,"botleader")) + case player_botleader: { player_t *player = NULL; if (!lua_isnil(L, 3)) player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); plr->botleader = player; + break; } - else if (fastcmp(field,"lastbuttons")) + case player_lastbuttons: plr->lastbuttons = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"blocked")) + break; + case player_blocked: plr->blocked = (UINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"jointime")) + break; + case player_jointime: plr->jointime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"quittime")) + break; + case player_quittime: plr->quittime = (tic_t)luaL_checkinteger(L, 3); + break; #ifdef HWRENDER - else if (fastcmp(field,"fovadd")) + case player_fovadd: plr->fovadd = luaL_checkfixed(L, 3); + break; #endif - else { + default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, plr); @@ -756,15 +1334,17 @@ static int player_set(lua_State *L) if (lua_isnil(L, -1)) { // This index doesn't have a table for extra values yet, let's make one. lua_pop(L, 1); - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "player_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "player_t", lua_tostring(L, 2)); lua_newtable(L); lua_pushlightuserdata(L, plr); lua_pushvalue(L, -2); // ext value table lua_rawset(L, -4); // LREG_EXTVARS table } + lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // value to store - lua_setfield(L, -2, field); + lua_settable(L, -3); lua_pop(L, 2); + break; } return 0; @@ -818,27 +1398,58 @@ static int power_len(lua_State *L) #define NOFIELD luaL_error(L, LUA_QL("ticcmd_t") " has no field named " LUA_QS, field) #define NOSET luaL_error(L, LUA_QL("ticcmd_t") " field " LUA_QS " should not be set directly.", field) +enum ticcmd_e +{ + ticcmd_forwardmove, + ticcmd_sidemove, + ticcmd_angleturn, + ticcmd_aiming, + ticcmd_buttons, + ticcmd_latency, +}; + +static const char *const ticcmd_opt[] = { + "forwardmove", + "sidemove", + "angleturn", + "aiming", + "buttons", + "latency", + NULL, +}; + +static int ticcmd_fields_ref = LUA_NOREF; + static int ticcmd_get(lua_State *L) { ticcmd_t *cmd = *((ticcmd_t **)luaL_checkudata(L, 1, META_TICCMD)); - const char *field = luaL_checkstring(L, 2); + enum ticcmd_e field = Lua_optoption(L, 2, -1, ticcmd_fields_ref); if (!cmd) return LUA_ErrInvalid(L, "player_t"); - if (fastcmp(field,"forwardmove")) + switch (field) + { + case ticcmd_forwardmove: lua_pushinteger(L, cmd->forwardmove); - else if (fastcmp(field,"sidemove")) + break; + case ticcmd_sidemove: lua_pushinteger(L, cmd->sidemove); - else if (fastcmp(field,"angleturn")) + break; + case ticcmd_angleturn: lua_pushinteger(L, cmd->angleturn); - else if (fastcmp(field,"aiming")) + break; + case ticcmd_aiming: lua_pushinteger(L, cmd->aiming); - else if (fastcmp(field,"buttons")) + break; + case ticcmd_buttons: lua_pushinteger(L, cmd->buttons); - else if (fastcmp(field,"latency")) + break; + case ticcmd_latency: lua_pushinteger(L, cmd->latency); - else + break; + default: return NOFIELD; + } return 1; } @@ -846,27 +1457,35 @@ static int ticcmd_get(lua_State *L) static int ticcmd_set(lua_State *L) { ticcmd_t *cmd = *((ticcmd_t **)luaL_checkudata(L, 1, META_TICCMD)); - const char *field = luaL_checkstring(L, 2); + enum ticcmd_e field = Lua_optoption(L, 2, -1, ticcmd_fields_ref); if (!cmd) return LUA_ErrInvalid(L, "ticcmd_t"); if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); - if (fastcmp(field,"forwardmove")) + switch (field) + { + case ticcmd_forwardmove: cmd->forwardmove = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"sidemove")) + break; + case ticcmd_sidemove: cmd->sidemove = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"angleturn")) + break; + case ticcmd_angleturn: cmd->angleturn = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"aiming")) + break; + case ticcmd_aiming: cmd->aiming = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"buttons")) + break; + case ticcmd_buttons: cmd->buttons = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"latency")) + break; + case ticcmd_latency: return NOSET; - else + default: return NOFIELD; + } return 0; } @@ -887,6 +1506,8 @@ int LUA_PlayerLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); + player_fields_ref = Lua_CreateFieldTable(L, player_opt); + luaL_newmetatable(L, META_POWERS); lua_pushcfunction(L, power_get); lua_setfield(L, -2, "__index"); @@ -906,6 +1527,8 @@ int LUA_PlayerLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + ticcmd_fields_ref = Lua_CreateFieldTable(L, ticcmd_opt); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getPlayer); diff --git a/src/lua_script.c b/src/lua_script.c index 9c7636ebe..6893265d5 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -306,6 +306,18 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushinteger(L, ammoremovaltics); return 1; // end timers + } else if (fastcmp(word,"use1upSound")) { + lua_pushinteger(L, use1upSound); + return 1; + } else if (fastcmp(word,"maxXtraLife")) { + lua_pushinteger(L, maxXtraLife); + return 1; + } else if (fastcmp(word,"useContinues")) { + lua_pushinteger(L, useContinues); + return 1; + } else if (fastcmp(word,"shareEmblems")) { + lua_pushinteger(L, shareEmblems); + return 1; } else if (fastcmp(word,"gametype")) { lua_pushinteger(L, gametype); return 1; @@ -698,20 +710,23 @@ void LUA_DumpFile(const char *filename) fixed_t LUA_EvalMath(const char *word) { - lua_State *L = NULL; + static lua_State *L = NULL; char buf[1024], *b; const char *p; fixed_t res = 0; - // make a new state so SOC can't interefere with scripts - // allocate state - L = lua_newstate(LUA_Alloc, NULL); - lua_atpanic(L, LUA_Panic); + if (!L) + { + // make a new state so SOC can't interefere with scripts + // allocate state + L = lua_newstate(LUA_Alloc, NULL); + lua_atpanic(L, LUA_Panic); - // open only enum lib - lua_pushcfunction(L, LUA_EnumLib); - lua_pushboolean(L, true); - lua_call(L, 1, 0); + // open only enum lib + lua_pushcfunction(L, LUA_EnumLib); + lua_pushboolean(L, true); + lua_call(L, 1, 0); + } // change ^ into ^^ for Lua. strcpy(buf, "return "); @@ -736,8 +751,6 @@ fixed_t LUA_EvalMath(const char *word) else res = lua_tointeger(L, -1); - // clean up and return. - lua_close(L); return res; } @@ -1716,17 +1729,39 @@ void LUA_UnArchive(void) } // For mobj_t, player_t, etc. to take custom variables. -int Lua_optoption(lua_State *L, int narg, - const char *def, const char *const lst[]) +int Lua_optoption(lua_State *L, int narg, int def, int list_ref) { - const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); - int i; - for (i=0; lst[i]; i++) - if (fastcmp(lst[i], name)) - return i; + if (lua_isnoneornil(L, narg)) + return def; + + I_Assert(lua_checkstack(L, 2)); + luaL_checkstring(L, narg); + + lua_rawgeti(L, LUA_REGISTRYINDEX, list_ref); + I_Assert(lua_istable(L, -1)); + lua_pushvalue(L, narg); + lua_rawget(L, -2); + + if (lua_isnumber(L, -1)) + return lua_tointeger(L, -1); return -1; } +int Lua_CreateFieldTable(lua_State *L, const char *const lst[]) +{ + int i; + + lua_newtable(L); + for (i = 0; lst[i] != NULL; i++) + { + lua_pushstring(L, lst[i]); + lua_pushinteger(L, i); + lua_settable(L, -3); + } + + return luaL_ref(L, LUA_REGISTRYINDEX); +} + void LUA_PushTaggableObjectArray ( lua_State *L, const char *field, diff --git a/src/lua_script.h b/src/lua_script.h index fe04e5e60..d0b06a719 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -57,8 +57,8 @@ int LUA_PushGlobals(lua_State *L, const char *word); int LUA_CheckGlobals(lua_State *L, const char *word); void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void LUA_CVarChanged(void *cvar); // lua_consolelib.c -int Lua_optoption(lua_State *L, int narg, - const char *def, const char *const lst[]); +int Lua_optoption(lua_State *L, int narg, int def, int list_ref); +int Lua_CreateFieldTable(lua_State *L, const char *const lst[]); void LUA_HookNetArchive(lua_CFunction archFunc); void LUA_PushTaggableObjectArray diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index 5c21b04c3..b7890a6c7 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -55,6 +55,7 @@ enum skin { skin_soundsid, skin_sprites }; + static const char *const skin_opt[] = { "valid", "name", @@ -95,10 +96,12 @@ static const char *const skin_opt[] = { #define UNIMPLEMENTED luaL_error(L, LUA_QL("skin_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", skin_opt[field]) +static int skin_fields_ref = LUA_NOREF; + static int skin_get(lua_State *L) { skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN)); - enum skin field = luaL_checkoption(L, 2, NULL, skin_opt); + enum skin field = Lua_optoption(L, 2, -1, skin_fields_ref); // skins are always valid, only added, never removed I_Assert(skin != NULL); @@ -376,6 +379,8 @@ int LUA_SkinLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); + skin_fields_ref = Lua_CreateFieldTable(L, skin_opt); + luaL_newmetatable(L, META_SOUNDSID); lua_pushcfunction(L, soundsid_get); lua_setfield(L, -2, "__index"); diff --git a/src/m_cheat.c b/src/m_cheat.c index 9d257b48b..e370335f8 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -79,9 +79,9 @@ static UINT8 cheatf_warp(void) // Temporarily unlock stuff. G_SetUsedCheats(false); - unlockables[31].unlocked = true; // credits - unlockables[30].unlocked = true; // sound test - unlockables[28].unlocked = true; // level select + clientGamedata->unlocked[31] = true; // credits + clientGamedata->unlocked[30] = true; // sound test + clientGamedata->unlocked[28] = true; // level select // Refresh secrets menu existing. M_ClearMenus(true); @@ -102,7 +102,7 @@ static UINT8 cheatf_devmode(void) // Just unlock all the things and turn on -debug and console devmode. G_SetUsedCheats(false); for (i = 0; i < MAXUNLOCKABLES; i++) - unlockables[i].unlocked = true; + clientGamedata->unlocked[i] = true; devparm = true; cv_debug |= 0x8000; @@ -238,7 +238,7 @@ boolean cht_Responder(event_t *ev) } // Console cheat commands rely on these a lot... -#define REQUIRE_PANDORA if (!M_SecretUnlocked(SECRET_PANDORA) && !cv_debug)\ +#define REQUIRE_PANDORA if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !cv_debug)\ { CONS_Printf(M_GetText("You haven't earned this yet.\n")); return; } #define REQUIRE_DEVMODE if (!cv_debug)\ diff --git a/src/m_cond.c b/src/m_cond.c index bd6faadfd..a54988f67 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -21,6 +21,9 @@ #include "r_skins.h" // numskins #include "r_draw.h" // R_GetColorByName +gamedata_t *clientGamedata; // Our gamedata +gamedata_t *serverGamedata; // Server's gamedata + // Map triggers for linedef executors // 32 triggers, one bit each UINT32 unlocktriggers; @@ -41,6 +44,70 @@ unlockable_t unlockables[MAXUNLOCKABLES]; INT32 numemblems = 0; INT32 numextraemblems = 0; +// Temporary holding place for nights data for the current map +nightsdata_t ntemprecords; + +// Create a new gamedata_t, for start-up +gamedata_t *M_NewGameDataStruct(void) +{ + gamedata_t *data = Z_Calloc(sizeof (*data), PU_STATIC, NULL); + M_ClearSecrets(data); + G_ClearRecords(data); + return data; +} + +void M_CopyGameData(gamedata_t *dest, gamedata_t *src) +{ + INT32 i, j; + + M_ClearSecrets(dest); + G_ClearRecords(dest); + + dest->loaded = src->loaded; + dest->totalplaytime = src->totalplaytime; + + dest->timesBeaten = src->timesBeaten; + dest->timesBeatenWithEmeralds = src->timesBeatenWithEmeralds; + dest->timesBeatenUltimate = src->timesBeatenUltimate; + + memcpy(dest->achieved, src->achieved, sizeof(dest->achieved)); + memcpy(dest->collected, src->collected, sizeof(dest->collected)); + memcpy(dest->extraCollected, src->extraCollected, sizeof(dest->extraCollected)); + memcpy(dest->unlocked, src->unlocked, sizeof(dest->unlocked)); + + memcpy(dest->mapvisited, src->mapvisited, sizeof(dest->mapvisited)); + + // Main records + for (i = 0; i < NUMMAPS; ++i) + { + if (!src->mainrecords[i]) + continue; + + G_AllocMainRecordData((INT16)i, dest); + dest->mainrecords[i]->score = src->mainrecords[i]->score; + dest->mainrecords[i]->time = src->mainrecords[i]->time; + dest->mainrecords[i]->rings = src->mainrecords[i]->rings; + } + + // Nights records + for (i = 0; i < NUMMAPS; ++i) + { + if (!src->nightsrecords[i] || !src->nightsrecords[i]->nummares) + continue; + + G_AllocNightsRecordData((INT16)i, dest); + + for (j = 0; j < (src->nightsrecords[i]->nummares + 1); j++) + { + dest->nightsrecords[i]->score[j] = src->nightsrecords[i]->score[j]; + dest->nightsrecords[i]->grade[j] = src->nightsrecords[i]->grade[j]; + dest->nightsrecords[i]->time[j] = src->nightsrecords[i]->time[j]; + } + + dest->nightsrecords[i]->nummares = src->nightsrecords[i]->nummares; + } +} + void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2) { condition_t *cond; @@ -70,89 +137,90 @@ void M_ClearConditionSet(UINT8 set) conditionSets[set - 1].condition = NULL; conditionSets[set - 1].numconditions = 0; } - conditionSets[set - 1].achieved = false; + clientGamedata->achieved[set - 1] = serverGamedata->achieved[set - 1] = false; } // Clear ALL secrets. -void M_ClearSecrets(void) +void M_ClearSecrets(gamedata_t *data) { INT32 i; - memset(mapvisited, 0, sizeof(mapvisited)); + memset(data->mapvisited, 0, sizeof(data->mapvisited)); for (i = 0; i < MAXEMBLEMS; ++i) - emblemlocations[i].collected = false; + data->collected[i] = false; for (i = 0; i < MAXEXTRAEMBLEMS; ++i) - extraemblems[i].collected = false; + data->extraCollected[i] = false; for (i = 0; i < MAXUNLOCKABLES; ++i) - unlockables[i].unlocked = false; + data->unlocked[i] = false; for (i = 0; i < MAXCONDITIONSETS; ++i) - conditionSets[i].achieved = false; + data->achieved[i] = false; - timesBeaten = timesBeatenWithEmeralds = timesBeatenUltimate = 0; + data->timesBeaten = data->timesBeatenWithEmeralds = data->timesBeatenUltimate = 0; // Re-unlock any always unlocked things - M_SilentUpdateUnlockablesAndEmblems(); + M_SilentUpdateUnlockablesAndEmblems(data); + M_SilentUpdateSkinAvailabilites(); } // ---------------------- // Condition set checking // ---------------------- -static UINT8 M_CheckCondition(condition_t *cn) +static UINT8 M_CheckCondition(condition_t *cn, gamedata_t *data) { switch (cn->type) { case UC_PLAYTIME: // Requires total playing time >= x - return (totalplaytime >= (unsigned)cn->requirement); + return (data->totalplaytime >= (unsigned)cn->requirement); case UC_GAMECLEAR: // Requires game beaten >= x times - return (timesBeaten >= (unsigned)cn->requirement); + return (data->timesBeaten >= (unsigned)cn->requirement); case UC_ALLEMERALDS: // Requires game beaten with all 7 emeralds >= x times - return (timesBeatenWithEmeralds >= (unsigned)cn->requirement); + return (data->timesBeatenWithEmeralds >= (unsigned)cn->requirement); case UC_ULTIMATECLEAR: // Requires game beaten on ultimate >= x times (in other words, never) - return (timesBeatenUltimate >= (unsigned)cn->requirement); + return (data->timesBeatenUltimate >= (unsigned)cn->requirement); case UC_OVERALLSCORE: // Requires overall score >= x - return (M_GotHighEnoughScore(cn->requirement)); + return (M_GotHighEnoughScore(cn->requirement, data)); case UC_OVERALLTIME: // Requires overall time <= x - return (M_GotLowEnoughTime(cn->requirement)); + return (M_GotLowEnoughTime(cn->requirement, data)); case UC_OVERALLRINGS: // Requires overall rings >= x - return (M_GotHighEnoughRings(cn->requirement)); + return (M_GotHighEnoughRings(cn->requirement, data)); case UC_MAPVISITED: // Requires map x to be visited - return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED); + return ((data->mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED); case UC_MAPBEATEN: // Requires map x to be beaten - return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN); + return ((data->mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN); case UC_MAPALLEMERALDS: // Requires map x to be beaten with all emeralds in possession - return ((mapvisited[cn->requirement - 1] & MV_ALLEMERALDS) == MV_ALLEMERALDS); + return ((data->mapvisited[cn->requirement - 1] & MV_ALLEMERALDS) == MV_ALLEMERALDS); case UC_MAPULTIMATE: // Requires map x to be beaten on ultimate - return ((mapvisited[cn->requirement - 1] & MV_ULTIMATE) == MV_ULTIMATE); + return ((data->mapvisited[cn->requirement - 1] & MV_ULTIMATE) == MV_ULTIMATE); case UC_MAPPERFECT: // Requires map x to be beaten with a perfect bonus - return ((mapvisited[cn->requirement - 1] & MV_PERFECT) == MV_PERFECT); + return ((data->mapvisited[cn->requirement - 1] & MV_PERFECT) == MV_PERFECT); case UC_MAPSCORE: // Requires score on map >= x - return (G_GetBestScore(cn->extrainfo1) >= (unsigned)cn->requirement); + return (G_GetBestScore(cn->extrainfo1, data) >= (unsigned)cn->requirement); case UC_MAPTIME: // Requires time on map <= x - return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement); + return (G_GetBestTime(cn->extrainfo1, data) <= (unsigned)cn->requirement); case UC_MAPRINGS: // Requires rings on map >= x - return (G_GetBestRings(cn->extrainfo1) >= cn->requirement); + return (G_GetBestRings(cn->extrainfo1, data) >= cn->requirement); case UC_NIGHTSSCORE: - return (G_GetBestNightsScore(cn->extrainfo1, (UINT8)cn->extrainfo2) >= (unsigned)cn->requirement); + return (G_GetBestNightsScore(cn->extrainfo1, (UINT8)cn->extrainfo2, data) >= (unsigned)cn->requirement); case UC_NIGHTSTIME: - return (G_GetBestNightsTime(cn->extrainfo1, (UINT8)cn->extrainfo2) <= (unsigned)cn->requirement); + return (G_GetBestNightsTime(cn->extrainfo1, (UINT8)cn->extrainfo2, data) <= (unsigned)cn->requirement); case UC_NIGHTSGRADE: - return (G_GetBestNightsGrade(cn->extrainfo1, (UINT8)cn->extrainfo2) >= cn->requirement); + return (G_GetBestNightsGrade(cn->extrainfo1, (UINT8)cn->extrainfo2, data) >= cn->requirement); case UC_TRIGGER: // requires map trigger set return !!(unlocktriggers & (1 << cn->requirement)); case UC_TOTALEMBLEMS: // Requires number of emblems >= x - return (M_GotEnoughEmblems(cn->requirement)); + return (M_GotEnoughEmblems(cn->requirement, data)); case UC_EMBLEM: // Requires emblem x to be obtained - return emblemlocations[cn->requirement-1].collected; + return data->collected[cn->requirement-1]; case UC_EXTRAEMBLEM: // Requires extra emblem x to be obtained - return extraemblems[cn->requirement-1].collected; + return data->extraCollected[cn->requirement-1]; case UC_CONDITIONSET: // requires condition set x to already be achieved - return M_Achieved(cn->requirement-1); + return M_Achieved(cn->requirement-1, data); } return false; } -static UINT8 M_CheckConditionSet(conditionset_t *c) +static UINT8 M_CheckConditionSet(conditionset_t *c, gamedata_t *data) { UINT32 i; UINT32 lastID = 0; @@ -173,13 +241,13 @@ static UINT8 M_CheckConditionSet(conditionset_t *c) continue; lastID = cn->id; - achievedSoFar = M_CheckCondition(cn); + achievedSoFar = M_CheckCondition(cn, data); } return achievedSoFar; } -void M_CheckUnlockConditions(void) +void M_CheckUnlockConditions(gamedata_t *data) { INT32 i; conditionset_t *c; @@ -187,27 +255,27 @@ void M_CheckUnlockConditions(void) for (i = 0; i < MAXCONDITIONSETS; ++i) { c = &conditionSets[i]; - if (!c->numconditions || c->achieved) + if (!c->numconditions || data->achieved[i]) continue; - c->achieved = (M_CheckConditionSet(c)); + data->achieved[i] = (M_CheckConditionSet(c, data)); } } -UINT8 M_UpdateUnlockablesAndExtraEmblems(void) +UINT8 M_UpdateUnlockablesAndExtraEmblems(gamedata_t *data) { INT32 i; char cechoText[992] = ""; UINT8 cechoLines = 0; - M_CheckUnlockConditions(); + M_CheckUnlockConditions(data); // Go through extra emblems for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected || !extraemblems[i].conditionset) + if (data->extraCollected[i] || !extraemblems[i].conditionset) continue; - if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false) + if ((data->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1, data)) != false) { strcat(cechoText, va(M_GetText("Got \"%s\" emblem!\\"), extraemblems[i].name)); ++cechoLines; @@ -217,14 +285,14 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void) // Fun part: if any of those unlocked we need to go through the // unlock conditions AGAIN just in case an emblem reward was reached if (cechoLines) - M_CheckUnlockConditions(); + M_CheckUnlockConditions(data); // Go through unlockables for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (unlockables[i].unlocked || !unlockables[i].conditionset) + if (data->unlocked[i] || !unlockables[i].conditionset) continue; - if ((unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1)) != false) + if ((data->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1, data)) != false) { if (unlockables[i].nocecho) continue; @@ -248,45 +316,50 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void) HU_DoCEcho(slashed); return true; } + return false; } // Used when loading gamedata to make sure all unlocks are synched with conditions -void M_SilentUpdateUnlockablesAndEmblems(void) +void M_SilentUpdateUnlockablesAndEmblems(gamedata_t *data) { INT32 i; boolean checkAgain = false; // Just in case they aren't to sync - M_CheckUnlockConditions(); - M_CheckLevelEmblems(); + M_CheckUnlockConditions(data); + M_CheckLevelEmblems(data); + M_CompletionEmblems(data); // Go through extra emblems for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected || !extraemblems[i].conditionset) + if (data->extraCollected[i] || !extraemblems[i].conditionset) continue; - if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false) + if ((data->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1, data)) != false) checkAgain = true; } // check again if extra emblems unlocked, blah blah, etc if (checkAgain) - M_CheckUnlockConditions(); + M_CheckUnlockConditions(data); // Go through unlockables for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (unlockables[i].unlocked || !unlockables[i].conditionset) + if (data->unlocked[i] || !unlockables[i].conditionset) continue; - unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1); + data->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1, data); } +} +void M_SilentUpdateSkinAvailabilites(void) +{ players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p } // Emblem unlocking shit -UINT8 M_CheckLevelEmblems(void) +UINT8 M_CheckLevelEmblems(gamedata_t *data) { INT32 i; INT32 valToReach; @@ -297,7 +370,7 @@ UINT8 M_CheckLevelEmblems(void) // Update Score, Time, Rings emblems for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].type <= ET_SKIN || emblemlocations[i].type == ET_MAP || emblemlocations[i].collected) + if (emblemlocations[i].type <= ET_SKIN || emblemlocations[i].type == ET_MAP || data->collected[i]) continue; levelnum = emblemlocations[i].level; @@ -306,32 +379,32 @@ UINT8 M_CheckLevelEmblems(void) switch (emblemlocations[i].type) { case ET_SCORE: // Requires score on map >= x - res = (G_GetBestScore(levelnum) >= (unsigned)valToReach); + res = (G_GetBestScore(levelnum, data) >= (unsigned)valToReach); break; case ET_TIME: // Requires time on map <= x - res = (G_GetBestTime(levelnum) <= (unsigned)valToReach); + res = (G_GetBestTime(levelnum, data) <= (unsigned)valToReach); break; case ET_RINGS: // Requires rings on map >= x - res = (G_GetBestRings(levelnum) >= valToReach); + res = (G_GetBestRings(levelnum, data) >= valToReach); break; case ET_NGRADE: // Requires NiGHTS grade on map >= x - res = (G_GetBestNightsGrade(levelnum, 0) >= valToReach); + res = (G_GetBestNightsGrade(levelnum, 0, data) >= valToReach); break; case ET_NTIME: // Requires NiGHTS time on map <= x - res = (G_GetBestNightsTime(levelnum, 0) <= (unsigned)valToReach); + res = (G_GetBestNightsTime(levelnum, 0, data) <= (unsigned)valToReach); break; default: // unreachable but shuts the compiler up. continue; } - emblemlocations[i].collected = res; + data->collected[i] = res; if (res) ++somethingUnlocked; } return somethingUnlocked; } -UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough. +UINT8 M_CompletionEmblems(gamedata_t *data) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough. { INT32 i; INT32 embtype; @@ -342,7 +415,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].type != ET_MAP || emblemlocations[i].collected) + if (emblemlocations[i].type != ET_MAP || data->collected[i]) continue; levelnum = emblemlocations[i].level; @@ -358,9 +431,9 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa if (embtype & ME_PERFECT) flags |= MV_PERFECT; - res = ((mapvisited[levelnum - 1] & flags) == flags); + res = ((data->mapvisited[levelnum - 1] & flags) == flags); - emblemlocations[i].collected = res; + data->collected[i] = res; if (res) ++somethingUnlocked; } @@ -370,48 +443,54 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa // ------------------- // Quick unlock checks // ------------------- -UINT8 M_AnySecretUnlocked(void) +UINT8 M_AnySecretUnlocked(gamedata_t *data) { INT32 i; for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (!unlockables[i].nocecho && unlockables[i].unlocked) + if (!unlockables[i].nocecho && data->unlocked[i]) return true; } return false; } -UINT8 M_SecretUnlocked(INT32 type) +UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data) { INT32 i; for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (unlockables[i].type == type && unlockables[i].unlocked) + if (unlockables[i].type == type && data->unlocked[i]) return true; } return false; } -UINT8 M_MapLocked(INT32 mapnum) +UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data) { if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0) + { return false; - if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked) + } + + if (!data->unlocked[mapheaderinfo[mapnum-1]->unlockrequired]) + { return true; + } + return false; } -INT32 M_CountEmblems(void) +INT32 M_CountEmblems(gamedata_t *data) { INT32 found = 0, i; for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].collected) + if (data->collected[i]) found++; } for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected) + if (data->extraCollected[i]) found++; } return found; @@ -423,23 +502,23 @@ INT32 M_CountEmblems(void) // Theoretically faster than using M_CountEmblems() // Stops when it reaches the target number of emblems. -UINT8 M_GotEnoughEmblems(INT32 number) +UINT8 M_GotEnoughEmblems(INT32 number, gamedata_t *data) { INT32 i, gottenemblems = 0; for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].collected) + if (data->collected[i]) if (++gottenemblems >= number) return true; } for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected) + if (data->extraCollected[i]) if (++gottenemblems >= number) return true; } return false; } -UINT8 M_GotHighEnoughScore(INT32 tscore) +UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data) { INT32 mscore = 0; INT32 i; @@ -448,16 +527,16 @@ UINT8 M_GotHighEnoughScore(INT32 tscore) { if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; - if (!mainrecords[i]) + if (!data->mainrecords[i]) continue; - if ((mscore += mainrecords[i]->score) > tscore) + if ((mscore += data->mainrecords[i]->score) > tscore) return true; } return false; } -UINT8 M_GotLowEnoughTime(INT32 tictime) +UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data) { INT32 curtics = 0; INT32 i; @@ -467,15 +546,15 @@ UINT8 M_GotLowEnoughTime(INT32 tictime) if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; - if (!mainrecords[i] || !mainrecords[i]->time) + if (!data->mainrecords[i] || !data->mainrecords[i]->time) return false; - else if ((curtics += mainrecords[i]->time) > tictime) + else if ((curtics += data->mainrecords[i]->time) > tictime) return false; } return true; } -UINT8 M_GotHighEnoughRings(INT32 trings) +UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data) { INT32 mrings = 0; INT32 i; @@ -484,10 +563,10 @@ UINT8 M_GotHighEnoughRings(INT32 trings) { if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; - if (!mainrecords[i]) + if (!data->mainrecords[i]) continue; - if ((mrings += mainrecords[i]->rings) > trings) + if ((mrings += data->mainrecords[i]->rings) > trings) return true; } return false; diff --git a/src/m_cond.h b/src/m_cond.h index d49dc920b..6a3da79ec 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -10,7 +10,11 @@ /// \file m_cond.h /// \brief Unlockable condition system for SRB2 version 2.1 +#ifndef __M_COND__ +#define __M_COND__ + #include "doomdef.h" +#include "doomdata.h" // -------- // Typedefs @@ -61,8 +65,6 @@ typedef struct { UINT32 numconditions; /// <- number of conditions. condition_t *condition; /// <- All conditionals to be checked. - UINT8 achieved; /// <- Whether this conditional has been achieved already or not. - /// (Conditional checking is skipped if true -- it's assumed you can't relock an unlockable) } conditionset_t; // Emblem information @@ -94,7 +96,6 @@ typedef struct INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin) char *stringVar; ///< String version char hint[110]; ///< Hint for emblem hints menu - UINT8 collected; ///< Do you have this emblem? } emblem_t; typedef struct { @@ -104,7 +105,6 @@ typedef struct UINT8 showconditionset; ///< Condition set that shows this emblem. UINT8 sprite; ///< emblem sprite to use, 0 - 25 UINT16 color; ///< skincolor to use - UINT8 collected; ///< Do you have this emblem? } extraemblem_t; // Unlockable information @@ -120,7 +120,6 @@ typedef struct char *stringVar; UINT8 nocecho; UINT8 nochecklist; - UINT8 unlocked; } unlockable_t; #define SECRET_NONE -6 // Does nil. Use with levels locked by UnlockRequired @@ -143,6 +142,83 @@ typedef struct #define MAXEXTRAEMBLEMS 16 #define MAXUNLOCKABLES 32 +/** Time attack information, currently a very small structure. + */ +typedef struct +{ + tic_t time; ///< Time in which the level was finished. + UINT32 score; ///< Score when the level was finished. + UINT16 rings; ///< Rings when the level was finished. +} recorddata_t; + +/** Setup for one NiGHTS map. + * These are dynamically allocated because I am insane + */ +#define GRADE_F 0 +#define GRADE_E 1 +#define GRADE_D 2 +#define GRADE_C 3 +#define GRADE_B 4 +#define GRADE_A 5 +#define GRADE_S 6 + +typedef struct +{ + // 8 mares, 1 overall (0) + UINT8 nummares; + UINT32 score[9]; + UINT8 grade[9]; + tic_t time[9]; +} nightsdata_t; + +// mapvisited is now a set of flags that says what we've done in the map. +#define MV_VISITED 1 +#define MV_BEATEN 2 +#define MV_ALLEMERALDS 4 +#define MV_ULTIMATE 8 +#define MV_PERFECT 16 +#define MV_PERFECTRA 32 +#define MV_MAX 63 // used in gamedata check, update whenever MV's are added + +// Temporary holding place for nights data for the current map +extern nightsdata_t ntemprecords; + +// GAMEDATA STRUCTURE +// Everything that would get saved in gamedata.dat +typedef struct +{ + // WHENEVER OR NOT WE'RE READY TO SAVE + boolean loaded; + + // CONDITION SETS ACHIEVED + boolean achieved[MAXCONDITIONSETS]; + + // EMBLEMS COLLECTED + boolean collected[MAXEMBLEMS]; + + // EXTRA EMBLEMS COLLECTED + boolean extraCollected[MAXEXTRAEMBLEMS]; + + // UNLOCKABLES UNLOCKED + boolean unlocked[MAXUNLOCKABLES]; + + // TIME ATTACK DATA + recorddata_t *mainrecords[NUMMAPS]; + nightsdata_t *nightsrecords[NUMMAPS]; + UINT8 mapvisited[NUMMAPS]; + + // # OF TIMES THE GAME HAS BEEN BEATEN + UINT32 timesBeaten; + UINT32 timesBeatenWithEmeralds; + UINT32 timesBeatenUltimate; + + // PLAY TIME + UINT32 totalplaytime; +} gamedata_t; + +extern gamedata_t *clientGamedata; +extern gamedata_t *serverGamedata; + extern conditionset_t conditionSets[MAXCONDITIONSETS]; extern emblem_t emblemlocations[MAXEMBLEMS]; extern extraemblem_t extraemblems[MAXEXTRAEMBLEMS]; @@ -153,25 +229,30 @@ extern INT32 numextraemblems; extern UINT32 unlocktriggers; +gamedata_t *M_NewGameDataStruct(void); +void M_CopyGameData(gamedata_t *dest, gamedata_t *src); + // Condition set setup void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2); // Clearing secrets void M_ClearConditionSet(UINT8 set); -void M_ClearSecrets(void); +void M_ClearSecrets(gamedata_t *data); // Updating conditions and unlockables -void M_CheckUnlockConditions(void); -UINT8 M_UpdateUnlockablesAndExtraEmblems(void); -void M_SilentUpdateUnlockablesAndEmblems(void); -UINT8 M_CheckLevelEmblems(void); -UINT8 M_CompletionEmblems(void); +void M_CheckUnlockConditions(gamedata_t *data); +UINT8 M_UpdateUnlockablesAndExtraEmblems(gamedata_t *data); +void M_SilentUpdateUnlockablesAndEmblems(gamedata_t *data); +UINT8 M_CheckLevelEmblems(gamedata_t *data); +UINT8 M_CompletionEmblems(gamedata_t *data); + +void M_SilentUpdateSkinAvailabilites(void); // Checking unlockable status -UINT8 M_AnySecretUnlocked(void); -UINT8 M_SecretUnlocked(INT32 type); -UINT8 M_MapLocked(INT32 mapnum); -INT32 M_CountEmblems(void); +UINT8 M_AnySecretUnlocked(gamedata_t *data); +UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data); +UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data); +INT32 M_CountEmblems(gamedata_t *data); // Emblem shit emblem_t *M_GetLevelEmblems(INT32 mapnum); @@ -183,12 +264,14 @@ const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big); // If you're looking to compare stats for unlocks or what not, use these // They stop checking upon reaching the target number so they // should be (theoretically?) slightly faster. -UINT8 M_GotEnoughEmblems(INT32 number); -UINT8 M_GotHighEnoughScore(INT32 tscore); -UINT8 M_GotLowEnoughTime(INT32 tictime); -UINT8 M_GotHighEnoughRings(INT32 trings); +UINT8 M_GotEnoughEmblems(INT32 number, gamedata_t *data); +UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data); +UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data); +UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data); INT32 M_UnlockableSkinNum(unlockable_t *unlock); INT32 M_EmblemSkinNum(emblem_t *emblem); -#define M_Achieved(a) ((a) >= MAXCONDITIONSETS || conditionSets[a].achieved) +#define M_Achieved(a, data) ((a) >= MAXCONDITIONSETS || data->achieved[a]) + +#endif diff --git a/src/m_menu.c b/src/m_menu.c index 64a1c9404..f9f52335d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -241,6 +241,7 @@ static void M_EmblemHints(INT32 choice); static void M_HandleEmblemHints(INT32 choice); UINT32 hintpage = 1; static void M_HandleChecklist(INT32 choice); +static void M_PauseLevelSelect(INT32 choice); menu_t SR_MainDef, SR_UnlockChecklistDef; static UINT8 check_on; @@ -554,26 +555,30 @@ static menuitem_t MPauseMenu[] = { {IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8}, {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, - {IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_MapChange, 24}, + {IT_STRING | IT_CALL, NULL, "Emblem Hints...", M_EmblemHints, 24}, + {IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_MapChange, 32}, - {IT_STRING | IT_CALL, NULL, "Continue", M_SelectableClearMenus,40}, - {IT_STRING | IT_CALL, NULL, "Player 1 Setup", M_SetupMultiPlayer, 48}, // splitscreen - {IT_STRING | IT_CALL, NULL, "Player 2 Setup", M_SetupMultiPlayer2, 56}, // splitscreen + {IT_STRING | IT_CALL, NULL, "Continue", M_SelectableClearMenus,48}, - {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, - {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, - {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48}, - {IT_STRING | IT_CALL, NULL, "Player Setup", M_SetupMultiPlayer, 56}, // alone - {IT_STRING | IT_CALL, NULL, "Options", M_Options, 64}, + {IT_STRING | IT_CALL, NULL, "Player 1 Setup", M_SetupMultiPlayer, 56}, // splitscreen + {IT_STRING | IT_CALL, NULL, "Player 2 Setup", M_SetupMultiPlayer2, 64}, - {IT_STRING | IT_CALL, NULL, "Return to Title", M_EndGame, 80}, - {IT_STRING | IT_CALL, NULL, "Quit Game", M_QuitSRB2, 88}, + {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 56}, // alone + {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 56}, + {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 56}, + {IT_STRING | IT_CALL, NULL, "Player Setup", M_SetupMultiPlayer, 64}, + + {IT_STRING | IT_CALL, NULL, "Options", M_Options, 72}, + + {IT_STRING | IT_CALL, NULL, "Return to Title", M_EndGame, 88}, + {IT_STRING | IT_CALL, NULL, "Quit Game", M_QuitSRB2, 96}, }; typedef enum { mpause_addons = 0, mpause_scramble, + mpause_hints, mpause_switchmap, mpause_continue, @@ -597,7 +602,7 @@ static menuitem_t SPauseMenu[] = // Pandora's Box will be shifted up if both options are available {IT_CALL | IT_STRING, NULL, "Pandora's Box...", M_PandorasBox, 16}, {IT_CALL | IT_STRING, NULL, "Emblem Hints...", M_EmblemHints, 24}, - {IT_CALL | IT_STRING, NULL, "Level Select...", M_LoadGameLevelSelect, 32}, + {IT_CALL | IT_STRING, NULL, "Level Select...", M_PauseLevelSelect, 32}, {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48}, {IT_CALL | IT_STRING, NULL, "Retry", M_Retry, 56}, @@ -970,7 +975,7 @@ static menuitem_t MP_MainMenu[] = { {IT_HEADER, NULL, "Join a game", NULL, 0}, {IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenuModChecks, 12}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 22}, + {IT_STRING|IT_KEYHANDLER, NULL, "Specify server address:", M_HandleConnectIP, 22}, {IT_HEADER, NULL, "Host a game", NULL, 54}, {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 66}, {IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 76}, @@ -1824,6 +1829,10 @@ menu_t SP_LevelSelectDef = MAPPLATTERMENUSTYLE( MTREE4(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER, MN_SP_LEVELSELECT), NULL, SP_LevelSelectMenu); +menu_t SP_PauseLevelSelectDef = MAPPLATTERMENUSTYLE( + MTREE4(MN_SP_MAIN, MN_SP_LOAD, MN_SP_PLAYER, MN_SP_LEVELSELECT), + NULL, SP_LevelSelectMenu); + menu_t SP_LevelStatsDef = { MTREE2(MN_SP_MAIN, MN_SP_LEVELSTATS), @@ -2284,6 +2293,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt); // Nextmap. Used for Level select. void Nextmap_OnChange(void) { + gamedata_t *data = clientGamedata; char *leveltitle; char tabase[256]; #ifdef OLDNREPLAYNAME @@ -2301,7 +2311,7 @@ void Nextmap_OnChange(void) { CV_StealthSetValue(&cv_dummymares, 0); // Hide the record changing CVAR if only one mare is available. - if (!nightsrecords[cv_nextmap.value-1] || nightsrecords[cv_nextmap.value-1]->nummares < 2) + if (!data->nightsrecords[cv_nextmap.value-1] || data->nightsrecords[cv_nextmap.value-1]->nummares < 2) SP_NightsAttackMenu[narecords].status = IT_DISABLED; else SP_NightsAttackMenu[narecords].status = IT_STRING|IT_CVAR; @@ -2432,14 +2442,15 @@ void Nextmap_OnChange(void) static void Dummymares_OnChange(void) { - if (!nightsrecords[cv_nextmap.value-1]) + gamedata_t *data = clientGamedata; + if (!data->nightsrecords[cv_nextmap.value-1]) { CV_StealthSetValue(&cv_dummymares, 0); return; } else { - UINT8 mares = nightsrecords[cv_nextmap.value-1]->nummares; + UINT8 mares = data->nightsrecords[cv_nextmap.value-1]->nummares; if (cv_dummymares.value < 0) CV_StealthSetValue(&cv_dummymares, mares); @@ -3670,9 +3681,9 @@ void M_StartControlPanel(void) if (!Playing()) { // Secret menu! - MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked()) ? 76 : 84; - MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked()) ? 84 : 92; - MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked(clientGamedata)) ? 76 : 84; + MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked(clientGamedata)) ? 84 : 92; + MainMenu[secrets].status = (M_AnySecretUnlocked(clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); currentMenu = &MainDef; itemOn = singleplr; @@ -3680,14 +3691,14 @@ void M_StartControlPanel(void) else if (modeattacking) { currentMenu = &MAPauseDef; - MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); itemOn = mapause_continue; } else if (!(netgame || multiplayer)) // Single Player { if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff. { - SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_GRAYEDOUT) : (IT_DISABLED); + SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata)) ? (IT_GRAYEDOUT) : (IT_DISABLED); SPauseMenu[spause_retry].status = IT_GRAYEDOUT; } else @@ -3696,7 +3707,7 @@ void M_StartControlPanel(void) if (players[consoleplayer].playerstate != PST_LIVE) ++numlives; - SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); // The list of things that can disable retrying is (was?) a little too complex // for me to want to use the short if statement syntax @@ -3707,10 +3718,10 @@ void M_StartControlPanel(void) } // We can always use level select though. :33 - SPauseMenu[spause_levelselect].status = (gamecomplete == 1) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + SPauseMenu[spause_levelselect].status = (maplistoption != 0) ? (IT_STRING | IT_CALL) : (IT_DISABLED); // And emblem hints. - SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !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) @@ -3745,12 +3756,10 @@ void M_StartControlPanel(void) if (splitscreen) { MPauseMenu[mpause_psetupsplit].status = MPauseMenu[mpause_psetupsplit2].status = IT_STRING | IT_CALL; - MPauseMenu[mpause_psetup].text = "Player 1 Setup"; } else { MPauseMenu[mpause_psetup].status = IT_STRING | IT_CALL; - MPauseMenu[mpause_psetup].text = "Player Setup"; if (G_GametypeHasTeams()) MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; @@ -3760,6 +3769,8 @@ void M_StartControlPanel(void) MPauseMenu[mpause_spectate].status = IT_GRAYEDOUT; } + MPauseMenu[mpause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && G_CoopGametype()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + currentMenu = &MPauseDef; itemOn = mpause_continue; } @@ -4259,7 +4270,7 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y, boolean norecordatt x -= 4; lasttype = curtype; - if (emblem->collected) + if (clientGamedata->collected[emblem - emblemlocations]) V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else @@ -4692,7 +4703,9 @@ static void M_DrawGenericScrollMenu(void) static void M_DrawPauseMenu(void) { - if (!netgame && !multiplayer && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)) + gamedata_t *data = clientGamedata; + + if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) { emblem_t *emblem_detail[3] = {NULL, NULL, NULL}; char emblem_text[3][20]; @@ -4720,7 +4733,7 @@ static void M_DrawPauseMenu(void) { case ET_SCORE: snprintf(targettext, 9, "%d", emblem->var); - snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap)); + snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap, data)); targettext[8] = 0; currenttext[8] = 0; @@ -4734,7 +4747,7 @@ static void M_DrawPauseMenu(void) G_TicsToSeconds((tic_t)emblemslot), G_TicsToCentiseconds((tic_t)emblemslot)); - emblemslot = (INT32)G_GetBestTime(gamemap); // dumb hack pt ii + emblemslot = (INT32)G_GetBestTime(gamemap, data); // dumb hack pt ii if ((tic_t)emblemslot == UINT32_MAX) snprintf(currenttext, 9, "-:--.--"); else @@ -4750,7 +4763,7 @@ static void M_DrawPauseMenu(void) break; case ET_RINGS: snprintf(targettext, 9, "%d", emblem->var); - snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap)); + snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap, data)); targettext[8] = 0; currenttext[8] = 0; @@ -4758,8 +4771,8 @@ static void M_DrawPauseMenu(void) emblemslot = 2; break; case ET_NGRADE: - snprintf(targettext, 9, "%u", P_GetScoreForGradeOverall(gamemap, emblem->var)); - snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0)); + snprintf(targettext, 9, "%u", P_GetScoreForGrade(gamemap, 0, emblem->var)); + snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0, data)); targettext[8] = 0; currenttext[8] = 0; @@ -4773,7 +4786,7 @@ static void M_DrawPauseMenu(void) G_TicsToSeconds((tic_t)emblemslot), G_TicsToCentiseconds((tic_t)emblemslot)); - emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0); // dumb hack pt iv + emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0, data); // dumb hack pt iv if ((tic_t)emblemslot == UINT32_MAX) snprintf(currenttext, 9, "-:--.--"); else @@ -4807,7 +4820,7 @@ static void M_DrawPauseMenu(void) if (!emblem) continue; - if (emblem->collected) + if (data->collected[emblem - emblemlocations]) V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else @@ -5019,7 +5032,9 @@ static void M_PatchSkinNameTable(void) // static boolean M_LevelAvailableOnPlatter(INT32 mapnum) { - if (M_MapLocked(mapnum+1)) + gamedata_t *data = serverGamedata; + + if (M_MapLocked(mapnum+1, data)) return false; // not unlocked switch (levellistmode) @@ -5032,7 +5047,7 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum) return true; #ifndef DEVELOP - if (mapvisited[mapnum]) // MV_MP + if (data->mapvisited[mapnum]) #endif return true; @@ -5040,7 +5055,7 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum) case LLM_RECORDATTACK: case LLM_NIGHTSATTACK: #ifndef DEVELOP - if (mapvisited[mapnum] & MV_MAX) + if (data->mapvisited[mapnum]) return true; if (mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED) @@ -5071,7 +5086,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt) if (!mapheaderinfo[mapnum]->lvlttl[0]) return false; - /*if (M_MapLocked(mapnum+1)) + /*if (M_MapLocked(mapnum+1, serverGamedata)) return false; // not unlocked*/ switch (levellistmode) @@ -5966,7 +5981,7 @@ static void M_DrawLevelPlatterMenu(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) { - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + F_SkyScroll(curbgname); // Draw and animate foreground if (!strncmp("RECATKBG", curbgname, 8)) M_DrawRecordAttackForeground(); @@ -6228,7 +6243,7 @@ static void M_DrawMessageMenu(void) } else { - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + F_SkyScroll(curbgname); if (!strncmp("RECATKBG", curbgname, 8)) M_DrawRecordAttackForeground(); } @@ -6904,7 +6919,7 @@ static void M_HandleAddons(INT32 choice) closefilemenu(true); // secrets disabled by addfile... - MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + MainMenu[secrets].status = (M_AnySecretUnlocked(clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); @@ -7118,6 +7133,7 @@ static void M_DestroyRobots(INT32 choice) static void M_LevelSelectWarp(INT32 choice) { boolean fromloadgame = (currentMenu == &SP_LevelSelectDef); + boolean frompause = (currentMenu == &SP_PauseLevelSelectDef); (void)choice; @@ -7128,7 +7144,6 @@ static void M_LevelSelectWarp(INT32 choice) } startmap = (INT16)(cv_nextmap.value); - fromlevelselect = true; if (fromloadgame) @@ -7136,7 +7151,20 @@ static void M_LevelSelectWarp(INT32 choice) else { cursaveslot = 0; - M_SetupChoosePlayer(0); + + if (frompause) + { + M_ClearMenus(true); + + G_DeferedInitNew(false, G_BuildMapName(startmap), cv_skin.value, false, fromlevelselect); // Not sure about using cv_skin here, but it seems fine in testing. + COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this + + if (levelselect.rows) + Z_Free(levelselect.rows); + levelselect.rows = NULL; + } + else + M_SetupChoosePlayer(0); } } @@ -7150,7 +7178,9 @@ static boolean checklist_cangodown; // uuuueeerggghhhh HACK static void M_HandleChecklist(INT32 choice) { + gamedata_t *data = clientGamedata; INT32 j; + switch (choice) { case KEY_DOWNARROW: @@ -7167,7 +7197,7 @@ static void M_HandleChecklist(INT32 choice) continue; if (unlockables[j].conditionset > MAXCONDITIONSETS) continue; - if (!unlockables[j].unlocked && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset)) + if (!data->unlocked[j] && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset, data)) continue; if (unlockables[j].conditionset == unlockables[check_on].conditionset) continue; @@ -7192,7 +7222,7 @@ static void M_HandleChecklist(INT32 choice) continue; if (unlockables[j].conditionset > MAXCONDITIONSETS) continue; - if (!unlockables[j].unlocked && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset)) + if (!data->unlocked[j] && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset, data)) continue; if (j && unlockables[j].conditionset == unlockables[j-1].conditionset) continue; @@ -7218,6 +7248,9 @@ static void M_HandleChecklist(INT32 choice) static void M_DrawChecklist(void) { + gamedata_t *data = clientGamedata; + INT32 emblemCount = M_CountEmblems(data); + INT32 i = check_on, j = 0, y = currentMenu->y, emblems = numemblems+numextraemblems; UINT32 condnum, previd, maxcond; condition_t *cond; @@ -7228,7 +7261,7 @@ static void M_DrawChecklist(void) // draw emblem counter if (emblems > 0) { - V_DrawString(42, 20, (emblems == M_CountEmblems()) ? V_GREENMAP : 0, va("%d/%d", M_CountEmblems(), emblems)); + V_DrawString(42, 20, (emblems == emblemCount) ? V_GREENMAP : 0, va("%d/%d", emblemCount, emblems)); V_DrawSmallScaledPatch(28, 20, 0, W_CachePatchName("EMBLICON", PU_PATCH)); } @@ -7239,13 +7272,13 @@ static void M_DrawChecklist(void) { if (unlockables[i].name[0] == 0 //|| unlockables[i].nochecklist || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS - || (!unlockables[i].unlocked && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset))) + || (!data->unlocked[i] && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset, data))) { i += 1; continue; } - V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name))); + V_DrawString(currentMenu->x, y, ((data->unlocked[i]) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((data->unlocked[i] || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name))); for (j = i+1; j < MAXUNLOCKABLES; j++) { @@ -7323,7 +7356,7 @@ static void M_DrawChecklist(void) if (title) { - const char *level = ((M_MapLocked(cond[condnum].requirement) || !((mapheaderinfo[cond[condnum].requirement-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].requirement-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title); + const char *level = ((M_MapLocked(cond[condnum].requirement, data) || !((mapheaderinfo[cond[condnum].requirement-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].requirement-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title); switch (cond[condnum].type) { @@ -7356,7 +7389,7 @@ static void M_DrawChecklist(void) if (title) { - const char *level = ((M_MapLocked(cond[condnum].extrainfo1) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title); + const char *level = ((M_MapLocked(cond[condnum].extrainfo1, data) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title); switch (cond[condnum].type) { @@ -7425,7 +7458,7 @@ static void M_DrawChecklist(void) if (title) { - const char *level = ((M_MapLocked(cond[condnum].extrainfo1) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title); + const char *level = ((M_MapLocked(cond[condnum].extrainfo1, data) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title); switch (cond[condnum].type) { @@ -7488,7 +7521,7 @@ static void M_DrawChecklist(void) /*V_DrawString(160, 8+(24*j), V_RETURN8, V_WordWrap(160, 292, 0, unlockables[i].objective)); - if (unlockables[i].unlocked) + if (data->unlocked[i]) V_DrawString(308, 8+(24*j), V_YELLOWMAP, "Y"); else V_DrawString(308, 8+(24*j), V_YELLOWMAP, "N");*/ @@ -7517,7 +7550,7 @@ static void M_EmblemHints(INT32 choice) (void)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); + SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata)) ? (IT_CVAR|IT_STRING) : (IT_SECRET); hintpage = 1; SR_EmblemHintDef.prevMenu = currentMenu; M_SetupNextMenu(&SR_EmblemHintDef); @@ -7577,7 +7610,7 @@ static void M_DrawEmblemHints(void) if (totalemblems >= ((hintpage-1)*(NUMHINTS*2) + 1) && totalemblems < (hintpage*NUMHINTS*2)+1){ - if (emblem->collected) + if (clientGamedata->collected[i]) { collected = V_GREENMAP; V_DrawMappedPatch(x, y+4, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH), @@ -7647,6 +7680,26 @@ static void M_HandleEmblemHints(INT32 choice) } +static void M_PauseLevelSelect(INT32 choice) +{ + (void)choice; + + SP_PauseLevelSelectDef.prevMenu = currentMenu; + levellistmode = LLM_LEVELSELECT; + + // maplistoption is NOT specified, so that this + // transfers the level select list from the menu + // used to enter the game to the pause menu. + + if (!M_PrepareLevelPlatter(-1, true)) + { + M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING); + return; + } + + M_SetupNextMenu(&SP_PauseLevelSelectDef); +} + /*static void M_DrawSkyRoom(void) { INT32 i, y = 0; @@ -8117,7 +8170,7 @@ static void M_SecretsMenu(INT32 choice) SR_MainMenu[i].status = IT_SECRET; - if (unlockables[ul].unlocked) + if (clientGamedata->unlocked[ul]) { switch (unlockables[ul].type) { @@ -8154,6 +8207,7 @@ INT32 ultimate_selectable = false; static void M_NewGame(void) { fromlevelselect = false; + maplistoption = 0; startmap = spstage_start; CV_SetValue(&cv_newgametype, GT_COOP); // Graue 09-08-2004 @@ -8165,6 +8219,7 @@ static void M_CustomWarp(INT32 choice) { INT32 ul = skyRoomMenuTranslations[choice-1]; + maplistoption = 0; startmap = (INT16)(unlockables[ul].variable); M_SetupChoosePlayer(0); @@ -8216,7 +8271,7 @@ static void M_SinglePlayerMenu(INT32 choice) levellistmode = LLM_RECORDATTACK; if (M_GametypeHasLevels(-1)) - SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; + SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK, clientGamedata)) ? IT_CALL|IT_STRING : IT_SECRET; else // If Record Attack is nonexistent in the current add-on... { SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the Record Attack option... @@ -8226,7 +8281,7 @@ static void M_SinglePlayerMenu(INT32 choice) levellistmode = LLM_NIGHTSATTACK; if (M_GametypeHasLevels(-1)) - SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET; + SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE, clientGamedata)) ? IT_CALL|IT_STRING : IT_SECRET; else // If NiGHTS Mode is nonexistent in the current add-on... { SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the NiGHTS Mode option... @@ -8249,7 +8304,7 @@ static void M_SinglePlayerMenu(INT32 choice) SP_MainMenu[spnightsmode] .alphaKey += 8; } else // Otherwise, if Marathon Run is allowed and Record Attack is unlocked, unlock Marathon Run! - SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET; + SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK, clientGamedata)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET; if (tutorialmap) // If there's a tutorial available in the current add-on... @@ -8357,6 +8412,7 @@ static void M_StartTutorial(INT32 choice) M_ClearMenus(true); gamecomplete = 0; cursaveslot = 0; + maplistoption = 0; G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false); } @@ -8719,6 +8775,10 @@ static void M_LoadSelect(INT32 choice) { (void)choice; + // Reset here, if we want a level select + // M_LoadGameLevelSelect will set it for us. + maplistoption = 0; + if (saveSlotSelected == NOSAVESLOT) //last slot is play without saving { M_NewGame(); @@ -9626,7 +9686,7 @@ static void M_Statistics(INT32 choice) if (!(mapheaderinfo[i]->typeoflevel & TOL_SP) || (mapheaderinfo[i]->menuflags & LF2_HIDEINSTATS)) continue; - if (!(mapvisited[i] & MV_MAX)) + if (!(clientGamedata->mapvisited[i] & MV_MAX)) continue; statsMapList[j++] = i; @@ -9643,6 +9703,7 @@ static void M_Statistics(INT32 choice) static void M_DrawStatsMaps(int location) { + gamedata_t *data = clientGamedata; INT32 y = 80, i = -1; INT16 mnum; extraemblem_t *exemblem; @@ -9710,14 +9771,14 @@ static void M_DrawStatsMaps(int location) { exemblem = &extraemblems[i]; - if (exemblem->collected) + if (data->extraCollected[i]) V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE)); else V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_PATCH)); V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, - (!exemblem->collected && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset)) + (!data->extraCollected[i] && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset, data)) ? M_CreateSecretMenuOption(exemblem->description) : exemblem->description); } @@ -9734,6 +9795,7 @@ bottomarrow: static void M_DrawLevelStats(void) { + gamedata_t *data = clientGamedata; char beststr[40]; tic_t besttime = 0; @@ -9748,9 +9810,9 @@ static void M_DrawLevelStats(void) V_DrawString(20, 24, V_YELLOWMAP, "Total Play Time:"); V_DrawCenteredString(BASEVIDWIDTH/2, 32, 0, va("%i hours, %i minutes, %i seconds", - G_TicsToHours(totalplaytime), - G_TicsToMinutes(totalplaytime, false), - G_TicsToSeconds(totalplaytime))); + G_TicsToHours(data->totalplaytime), + G_TicsToMinutes(data->totalplaytime, false), + G_TicsToSeconds(data->totalplaytime))); for (i = 0; i < NUMMAPS; i++) { @@ -9759,25 +9821,25 @@ static void M_DrawLevelStats(void) if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; - if (!mainrecords[i]) + if (!data->mainrecords[i]) { mapsunfinished++; bestunfinished[0] = bestunfinished[1] = bestunfinished[2] = true; continue; } - if (mainrecords[i]->score > 0) - bestscore += mainrecords[i]->score; + if (data->mainrecords[i]->score > 0) + bestscore += data->mainrecords[i]->score; else mapunfinished = bestunfinished[0] = true; - if (mainrecords[i]->time > 0) - besttime += mainrecords[i]->time; + if (data->mainrecords[i]->time > 0) + besttime += data->mainrecords[i]->time; else mapunfinished = bestunfinished[1] = true; - if (mainrecords[i]->rings > 0) - bestrings += mainrecords[i]->rings; + if (data->mainrecords[i]->rings > 0) + bestrings += data->mainrecords[i]->rings; else mapunfinished = bestunfinished[2] = true; @@ -9792,7 +9854,7 @@ static void M_DrawLevelStats(void) else V_DrawString(20, 56, V_GREENMAP, "(complete)"); - V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems)); + V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(data), numemblems+numextraemblems)); V_DrawSmallScaledPatch(20, 64, 0, W_CachePatchName("EMBLICON", PU_PATCH)); sprintf(beststr, "%u", bestscore); @@ -9859,6 +9921,7 @@ static void M_HandleLevelStats(INT32 choice) // Drawing function for Time Attack void M_DrawTimeAttackMenu(void) { + gamedata_t *data = clientGamedata; INT32 i, x, y, empatx, empaty, cursory = 0; UINT16 dispstatus; patch_t *PictureOfUrFace; // my WHAT @@ -9875,7 +9938,7 @@ void M_DrawTimeAttackMenu(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) { - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + F_SkyScroll(curbgname); // Draw and animate foreground if (!strncmp("RECATKBG", curbgname, 8)) M_DrawRecordAttackForeground(); @@ -10017,7 +10080,7 @@ void M_DrawTimeAttackMenu(void) empatx = empatch->leftoffset / 2; empaty = empatch->topoffset / 2; - if (em->collected) + if (data->collected[em - emblemlocations]) V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch, R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else @@ -10030,34 +10093,34 @@ void M_DrawTimeAttackMenu(void) // Draw in-level emblems. M_DrawMapEmblems(cv_nextmap.value, 288, 28, true); - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->score) + if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->score) sprintf(beststr, "(none)"); else - sprintf(beststr, "%u", mainrecords[cv_nextmap.value-1]->score); + sprintf(beststr, "%u", data->mainrecords[cv_nextmap.value-1]->score); V_DrawString(104-72, 33+lsheadingheight/2, V_YELLOWMAP, "SCORE:"); V_DrawRightAlignedString(104+64, 33+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); V_DrawRightAlignedString(104+72, 43+lsheadingheight/2, V_ALLOWLOWERCASE, reqscore); - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time) + if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->time) sprintf(beststr, "(none)"); else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->time, true), - G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time), - G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time)); + sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(data->mainrecords[cv_nextmap.value-1]->time, true), + G_TicsToSeconds(data->mainrecords[cv_nextmap.value-1]->time), + G_TicsToCentiseconds(data->mainrecords[cv_nextmap.value-1]->time)); V_DrawString(104-72, 53+lsheadingheight/2, V_YELLOWMAP, "TIME:"); V_DrawRightAlignedString(104+64, 53+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); V_DrawRightAlignedString(104+72, 63+lsheadingheight/2, V_ALLOWLOWERCASE, reqtime); - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->rings) + if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->rings) sprintf(beststr, "(none)"); else - sprintf(beststr, "%hu", mainrecords[cv_nextmap.value-1]->rings); + sprintf(beststr, "%hu", data->mainrecords[cv_nextmap.value-1]->rings); V_DrawString(104-72, 73+lsheadingheight/2, V_YELLOWMAP, "RINGS:"); - V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((mapvisited[cv_nextmap.value-1] & MV_PERFECTRA) ? V_YELLOWMAP : 0), beststr); + V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((data->mapvisited[cv_nextmap.value-1] & MV_PERFECTRA) ? V_YELLOWMAP : 0), beststr); V_DrawRightAlignedString(104+72, 83+lsheadingheight/2, V_ALLOWLOWERCASE, reqrings); } @@ -10151,6 +10214,7 @@ static void M_TimeAttack(INT32 choice) // Drawing function for Nights Attack void M_DrawNightsAttackMenu(void) { + gamedata_t *data = clientGamedata; INT32 i, x, y, cursory = 0; UINT16 dispstatus; @@ -10217,10 +10281,10 @@ void M_DrawNightsAttackMenu(void) lumpnum_t lumpnum; char beststr[40]; - //UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0); - UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value); - UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value); - tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value); + //UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0, data); + UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value, data); + UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value, data); + tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value, data); M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false); @@ -10301,7 +10365,7 @@ void M_DrawNightsAttackMenu(void) goto skipThisOne; } - if (em->collected) + if (data->collected[em - emblemlocations]) V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else @@ -10655,6 +10719,7 @@ static void M_Marathon(INT32 choice) } fromlevelselect = false; + maplistoption = 0; startmap = spmarathon_start; CV_SetValue(&cv_newgametype, GT_COOP); // Graue 09-08-2004 @@ -11673,35 +11738,19 @@ static void M_StartServerMenu(INT32 choice) #define CONNIP_LEN 128 static char setupm_ip[CONNIP_LEN]; - #define DOTS "... " -// Draw the funky Connect IP menu. Tails 11-19-2002 -// So much work for such a little thing! -static void M_DrawMPMainMenu(void) +static void M_DrawConnectIP(void) { INT32 x = currentMenu->x; - INT32 y = currentMenu->y; + INT32 y = currentMenu->y + 22; + const INT32 boxwidth = /*16*8 + 6*/ (BASEVIDWIDTH - 2*(x+5)); const INT32 maxstrwidth = boxwidth - 5; char *drawnstr = malloc(sizeof(setupm_ip)); char *drawnstr_orig = drawnstr; boolean drawthin, shorten = false; - // use generic drawer for cursor, items and title - M_DrawGenericMenu(); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66, - ((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS)); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76, - ((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)"); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116, - ((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)"); - - y += 22; - V_DrawFill(x+5, y+4+5, boxwidth, 8+6, 159); strcpy(drawnstr, setupm_ip); @@ -11749,6 +11798,28 @@ static void M_DrawMPMainMenu(void) free(drawnstr_orig); } +// Draw the funky Connect IP menu. Tails 11-19-2002 +// So much work for such a little thing! +static void M_DrawMPMainMenu(void) +{ + INT32 x = currentMenu->x; + INT32 y = currentMenu->y; + + // use generic drawer for cursor, items and title + M_DrawGenericMenu(); + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66, + ((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS)); + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76, + ((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)"); + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116, + ((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)"); + + M_DrawConnectIP(); +} + #undef DOTS // Tails 11-19-2002 @@ -11886,7 +11957,11 @@ static void M_HandleConnectIP(INT32 choice) break; // Rudimentary number and period enforcing - also allows letters so hostnames can be used instead - if ((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z')) + // and square brackets for RFC 2732 IPv6 addresses + if ((choice >= '-' && choice <= ':') || + (choice == '[' || choice == ']') || + (choice >= 'A' && choice <= 'Z') || + (choice >= 'a' && choice <= 'z')) { S_StartSound(NULL,sfx_menu1); // Tails setupm_ip[l] = (char)choice; @@ -12544,12 +12619,12 @@ static void M_EraseDataResponse(INT32 ch) // Delete the data if (erasecontext != 1) - G_ClearRecords(); + G_ClearRecords(clientGamedata); if (erasecontext != 0) - M_ClearSecrets(); + M_ClearSecrets(clientGamedata); if (erasecontext == 2) { - totalplaytime = 0; + clientGamedata->totalplaytime = 0; F_StartIntro(); } BwehHehHe(); diff --git a/src/m_random.c b/src/m_random.c index 3d0774a60..8b5138b9c 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -14,12 +14,11 @@ #include "doomdef.h" #include "doomtype.h" -#include "doomstat.h" // totalplaytime #include "m_random.h" #include "m_fixed.h" - +#include "m_cond.h" // totalplaytime // --------------------------- // RNG functions (not synched) @@ -252,5 +251,5 @@ void P_SetRandSeedD(const char *rfile, INT32 rline, UINT32 seed) */ UINT32 M_RandomizedSeed(void) { - return ((totalplaytime & 0xFFFF) << 16)|M_RandomFixed(); + return ((serverGamedata->totalplaytime & 0xFFFF) << 16) | M_RandomFixed(); } diff --git a/src/mserv.h b/src/mserv.h index 1c8d742d8..07253da85 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -33,7 +33,7 @@ typedef union typedef struct { msg_header_t header; - char ip[16]; + char ip[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; char port[8]; char name[32]; INT32 room; diff --git a/src/p_inter.c b/src/p_inter.c index 873448dcd..046a0a198 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -164,6 +164,62 @@ boolean P_CanPickupItem(player_t *player, boolean weapon) return true; } +boolean P_CanPickupEmblem(player_t *player, INT32 emblemID) +{ + emblem_t *emblem = NULL; + + if (emblemID < 0 || emblemID >= numemblems) + { + // Invalid emblem ID, can't pickup. + return false; + } + + emblem = &emblemlocations[emblemID]; + + if (demoplayback) + { + // Never collect emblems in replays. + return false; + } + + if (player->bot && player->bot != BOT_MPAI) + { + // Your little lap-dog can't grab these for you. + return false; + } + + if (emblem->type == ET_SKIN) + { + INT32 skinnum = M_EmblemSkinNum(emblem); + + if (player->skin != skinnum) + { + // Incorrect skin to pick up this emblem. + return false; + } + } + + return true; +} + +boolean P_EmblemWasCollected(INT32 emblemID) +{ + if (emblemID < 0 || emblemID >= numemblems) + { + // Invalid emblem ID, can't pickup. + return true; + } + + if (shareEmblems && !serverGamedata->collected[emblemID]) + { + // It can be worth collecting again if we're sharing emblems + // and the server doesn't have it. + return false; + } + + return clientGamedata->collected[emblemID]; +} + // // P_DoNightsScore // @@ -563,7 +619,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->momx = special->momy = special->momz = 0; P_GivePlayerSpheres(player, 1); - if (special->type == MT_BLUESPHERE) + if (special->type == MT_BLUESPHERE || special->type == MT_FLINGBLUESPHERE) { special->destscale = ((player->powers[pw_carry] == CR_NIGHTSMODE) ? 4 : 2)*special->scale; if (states[special->info->deathstate].tics > 0) @@ -738,13 +794,70 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Secret emblem thingy case MT_EMBLEM: { - if (demoplayback || (player->bot && player->bot != BOT_MPAI) || special->health <= 0 || special->health > MAXEMBLEMS) - return; - emblemlocations[special->health-1].collected = true; + const boolean toucherIsServer = ((player - players) == serverplayer); + const boolean consoleIsServer = (consoleplayer == serverplayer); + boolean prevCollected = false; - M_UpdateUnlockablesAndExtraEmblems(); - G_SaveGameData(); - break; + if ((special->flags2 & MF2_NIGHTSPULL) + && (toucher == special->tracer)) + { + // Since collecting may not remove the object, + // we need to manually stop it from chasing. + P_SetTarget(&special->tracer, NULL); + special->flags2 &= ~MF2_NIGHTSPULL; + special->movefactor = 0; + special->momx = special->momy = special->momz = 0; + } + + if (!P_CanPickupEmblem(player, special->health - 1)) + { + return; + } + + prevCollected = P_EmblemWasCollected(special->health - 1); + + if (toucherIsServer || shareEmblems) + { + serverGamedata->collected[special->health-1] = true; + M_SilentUpdateUnlockablesAndEmblems(serverGamedata); + } + + if (P_IsLocalPlayer(player) || (consoleIsServer && shareEmblems)) + { + clientGamedata->collected[special->health-1] = true; + M_UpdateUnlockablesAndExtraEmblems(clientGamedata); + G_SaveGameData(clientGamedata); + } + + if (netgame) + { + // This always spawns the object to prevent mobjnum issues, + // but makes the effect invisible to whoever it doesn't matter to. + mobj_t *spark = P_SpawnMobjFromMobj(special, 0, 0, 0, MT_SPARK); + + if (prevCollected == false && P_EmblemWasCollected(special->health - 1) == true) + { + // Play the sound if it was collected. + S_StartSound((shareEmblems ? NULL : special), special->info->deathsound); + } + else + { + // We didn't collect it, make it invisible to us. + spark->flags2 |= MF2_DONTDRAW; + } + + return; + } + else + { + if (prevCollected == false && P_EmblemWasCollected(special->health - 1) == true) + { + // Disappear when collecting for local games. + break; + } + + return; + } } // CTF Flags diff --git a/src/p_local.h b/src/p_local.h index cc060e4ee..3c84d6fe2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -510,6 +510,8 @@ void P_ClearStarPost(INT32 postnum); void P_ResetStarposts(void); boolean P_CanPickupItem(player_t *player, boolean weapon); +boolean P_CanPickupEmblem(player_t *player, INT32 emblemID); +boolean P_EmblemWasCollected(INT32 emblemID); void P_DoNightsScore(player_t *player); void P_DoMatchSuper(player_t *player); diff --git a/src/p_map.c b/src/p_map.c index 27d5ea781..aa2bda90d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2728,8 +2728,22 @@ increment_move fixed_t thingtop; floatok = false; - if (radius < MAXRADIUS/2) - radius = MAXRADIUS/2; + // This makes sure that there are no freezes from computing extremely small movements. + // Originally was MAXRADIUS/2, but that can cause some bad inconsistencies for small players. + radius = max(radius, thing->scale); + + // And we also have to prevent Big Large (tm) movements, as those can skip too far + // across slopes and cause us to fail step up checks on them when we otherwise shouldn't. + radius = min(radius, 16 * thing->scale); + + // (This whole "step" system is flawed; it was OK before, but the addition of slopes has + // exposed the problems with doing it like this. The right thing to do would be to use + // raycasting for physics to fix colliding in weird order, double-checking collisions, + // randomly colliding with slopes instead of going up them, etc. I don't feel like porting + // that from RR, as its both a huge sweeping change and still incomplete at the time of + // writing. Clamping radius to make our steps more precise will work just fine as long + // as you keep all of your crazy intentions to poke any of the other deep-rooted movement + // code to yourself. -- Sal 6/5/2023) do { if (thing->flags & MF_NOCLIP) { @@ -4242,13 +4256,11 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 dama // the way it was and call P_CheckSector (? was P_ChangeSector - Graue) again // to undo the changes. // -static boolean crushchange; -static boolean nofit; // // PIT_ChangeSector // -static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) +static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush, boolean crunch) { mobj_t *killer = NULL; //If a thing is both pushable and vulnerable, it doesn't block the crusher because it gets killed. @@ -4272,11 +4284,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) if (thing->z + thing->height > thing->ceilingz && thing->z <= thing->ceilingz) { if (immunepushable && thing->z + thing->height > thing->subsector->sector->ceilingheight) - { - //Thing is a pushable and blocks the moving ceiling - nofit = true; - return false; - } + return false; //Thing is a pushable and blocks the moving ceiling //Check FOFs in the sector if (thing->subsector->sector->ffloors && (realcrush || immunepushable)) @@ -4288,47 +4296,54 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) for (rover = thing->subsector->sector->ffloors; rover; rover = rover->next) { - if (!(((rover->fofflags & FOF_BLOCKPLAYER) && thing->player) - || ((rover->fofflags & FOF_BLOCKOTHERS) && !thing->player)) || !(rover->fofflags & FOF_EXISTS)) + thinker_t *think; + + if (!(rover->fofflags & FOF_EXISTS)) + continue; + if (thing->player && !(rover->fofflags & FOF_BLOCKPLAYER)) + continue; + if (!thing->player && !(rover->fofflags & FOF_BLOCKOTHERS)) continue; topheight = *rover->topheight; bottomheight = *rover->bottomheight; - //topheight = P_GetFFloorTopZAt (rover, thing->x, thing->y); - //bottomheight = P_GetFFloorBottomZAt(rover, thing->x, thing->y); + + if (bottomheight > thing->ceilingz) + continue; delta1 = thing->z - (bottomheight + topheight)/2; delta2 = thingtop - (bottomheight + topheight)/2; - if (bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2)) + if (abs(delta1) < abs(delta2)) + continue; + + if (immunepushable) + return false; //FOF is blocked by pushable + + if (!realcrush) + continue; + + //If the thing was crushed by a crumbling FOF, reward the player who made it crumble! + for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next) { - if (immunepushable) - { - //FOF is blocked by pushable - nofit = true; - return false; - } - else - { - //If the thing was crushed by a crumbling FOF, reward the player who made it crumble! - thinker_t *think; - crumble_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; + if (think->function.acp1 != (actionf_p1)T_StartCrumble) + continue; - crumbler = (crumble_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) - { - killer = crumbler->player->mo; - } - } - } + if (!crumbler->player) + continue; + if (!crumbler->player->mo) + continue; + if (crumbler->player->mo == thing) + continue; + if (crumbler->actionsector != thing->subsector->sector) + continue; + if (crumbler->sector != rover->master->frontsector) + continue; + + killer = crumbler->player->mo; } } } @@ -4344,24 +4359,139 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) } } - if (realcrush && crushchange) + if (realcrush && crunch) P_DamageMobj(thing, NULL, NULL, 1, 0); // keep checking (crush other things) return true; } +static boolean P_CheckSectorPolyObjects(sector_t *sector, boolean realcrush, boolean crunch) +{ + size_t i; + + // Sal: This stupid function chain is required to fix polyobjects not being able to crush. + // Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead + validcount++; + + for (i = 0; i < sector->linecount; i++) + { + INT32 x, y; + polyobj_t *po = sector->lines[i]->polyobj; + + if (!po) + continue; + if (po->validcount == validcount) + continue; // skip if already checked + if (!(po->flags & POF_SOLID)) + continue; + if (po->lines[0]->backsector != sector) // Make sure you're currently checking the control sector + continue; + + po->validcount = validcount; + + for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y) + { + for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x) + { + mobj_t *mo; + + if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) + continue; + + mo = blocklinks[y * bmapwidth + x]; + + for (; mo; mo = mo->bnext) + { + // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect + + if (!P_MobjInsidePolyobj(po, mo)) + continue; + + if (!PIT_ChangeSector(mo, realcrush, crunch) && !realcrush) + return false; + } + } + } + } + + return true; +} + +static boolean P_CheckTouchingThinglist(sector_t *sector, boolean realcrush, boolean crunch) +{ + msecnode_t *n; + + for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) + n->visited = false; + + do + { + for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list + { + if (n->visited) + continue; + + n->visited = true; // mark thing as processed + + if (n->m_thing->flags & MF_NOBLOCKMAP) //jff 4/7/98 don't do these + continue; + + if (!PIT_ChangeSector(n->m_thing, realcrush, crunch) && !realcrush) // process it + return false; + + break; // exit and start over + } + } while (n); // repeat from scratch until all things left are marked valid + + return true; +} + +static boolean P_CheckSectorFFloors(sector_t *sector, boolean realcrush, boolean crunch) +{ + sector_t *sec; + size_t i; + + if (!sector->numattached) + return true; + + for (i = 0; i < sector->numattached; i++) + { + sec = §ors[sector->attached[i]]; + + sec->moved = true; + + P_RecalcPrecipInSector(sec); + + if (!sector->attachedsolid[i]) + continue; + + if (!P_CheckTouchingThinglist(sec, realcrush, crunch)) + return false; + } + + return true; +} + +static boolean P_CheckSectorHelper(sector_t *sector, boolean realcrush, boolean crunch) +{ + if (!P_CheckSectorPolyObjects(sector, realcrush, crunch)) + return false; + + if (!P_CheckSectorFFloors(sector, realcrush, crunch)) + return false; + + // Mark all things invalid + sector->moved = true; + + return P_CheckTouchingThinglist(sector, realcrush, crunch); +} + // // P_CheckSector // boolean P_CheckSector(sector_t *sector, boolean crunch) { - msecnode_t *n; - size_t i; - - nofit = false; - crushchange = crunch; - // killough 4/4/98: scan list front-to-back until empty or exhausted, // restarting from beginning after each thing is processed. Avoids // crashes, and is sure to examine all things in the sector, and only @@ -4370,218 +4500,14 @@ boolean P_CheckSector(sector_t *sector, boolean crunch) // // killough 4/7/98: simplified to avoid using complicated counter - // First, let's see if anything will keep it from crushing. - - // Sal: This stupid function chain is required to fix polyobjects not being able to crush. - // Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead - validcount++; - - for (i = 0; i < sector->linecount; i++) - { - if (sector->lines[i]->polyobj) - { - polyobj_t *po = sector->lines[i]->polyobj; - if (po->validcount == validcount) - continue; // skip if already checked - if (!(po->flags & POF_SOLID)) - continue; - if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector - { - INT32 x, y; - po->validcount = validcount; - - for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y) - { - for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x) - { - mobj_t *mo; - - if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) - continue; - - mo = blocklinks[y * bmapwidth + x]; - - for (; mo; mo = mo->bnext) - { - // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect - - if (!P_MobjInsidePolyobj(po, mo)) - continue; - - if (!PIT_ChangeSector(mo, false)) - { - nofit = true; - return nofit; - } - } - } - } - } - } - } - - if (sector->numattached) - { - sector_t *sec; - for (i = 0; i < sector->numattached; i++) - { - sec = §ors[sector->attached[i]]; - for (n = sec->touching_thinglist; n; n = n->m_thinglist_next) - n->visited = false; - - sec->moved = true; - - P_RecalcPrecipInSector(sec); - - if (!sector->attachedsolid[i]) - continue; - - do - { - for (n = sec->touching_thinglist; n; n = n->m_thinglist_next) - if (!n->visited) - { - n->visited = true; - if (!(n->m_thing->flags & MF_NOBLOCKMAP)) - { - if (!PIT_ChangeSector(n->m_thing, false)) - { - nofit = true; - return nofit; - } - } - break; - } - } while (n); - } - } - - // Mark all things invalid - sector->moved = true; - - for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) - n->visited = false; - - do - { - for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list - if (!n->visited) // unprocessed thing found - { - n->visited = true; // mark thing as processed - if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these - { - if (!PIT_ChangeSector(n->m_thing, false)) // process it - { - nofit = true; - return nofit; - } - } - break; // exit and start over - } - } while (n); // repeat from scratch until all things left are marked valid + if (!P_CheckSectorHelper(sector, false, crunch)) + return true; // Nothing blocked us, so lets crush for real! + P_CheckSectorHelper(sector, true, crunch); - // Sal: This stupid function chain is required to fix polyobjects not being able to crush. - // Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead - validcount++; - - for (i = 0; i < sector->linecount; i++) - { - if (sector->lines[i]->polyobj) - { - polyobj_t *po = sector->lines[i]->polyobj; - if (po->validcount == validcount) - continue; // skip if already checked - if (!(po->flags & POF_SOLID)) - continue; - if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector - { - INT32 x, y; - po->validcount = validcount; - - for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y) - { - for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x) - { - mobj_t *mo; - - if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) - continue; - - mo = blocklinks[y * bmapwidth + x]; - - for (; mo; mo = mo->bnext) - { - // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect - - if (!P_MobjInsidePolyobj(po, mo)) - continue; - - PIT_ChangeSector(mo, true); - return nofit; - } - } - } - } - } - } - if (sector->numattached) - { - sector_t *sec; - for (i = 0; i < sector->numattached; i++) - { - sec = §ors[sector->attached[i]]; - for (n = sec->touching_thinglist; n; n = n->m_thinglist_next) - n->visited = false; - - sec->moved = true; - - P_RecalcPrecipInSector(sec); - - if (!sector->attachedsolid[i]) - continue; - - do - { - for (n = sec->touching_thinglist; n; n = n->m_thinglist_next) - if (!n->visited) - { - n->visited = true; - if (!(n->m_thing->flags & MF_NOBLOCKMAP)) - { - PIT_ChangeSector(n->m_thing, true); - return nofit; - } - break; - } - } while (n); - } - } - - // Mark all things invalid - sector->moved = true; - - for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) - n->visited = false; - - do - { - for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list - if (!n->visited) // unprocessed thing found - { - n->visited = true; // mark thing as processed - if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these - { - PIT_ChangeSector(n->m_thing, true); // process it - return nofit; - } - break; // exit and start over - } - } while (n); // repeat from scratch until all things left are marked valid - - return nofit; + return false; } /* diff --git a/src/p_maputl.c b/src/p_maputl.c index b6a320730..e36d5fd72 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -509,26 +509,26 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) // on non-solid polyobjects should NEVER happen in the future if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) { if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat - texbottom = back->floorheight + side->rowoffset; - textop = back->ceilingheight + side->rowoffset; + texbottom = back->floorheight + side->rowoffset + side->offsety_mid; + textop = back->ceilingheight + side->rowoffset + side->offsety_mid; } else if (linedef->flags & ML_MIDTEX) { - texbottom = back->floorheight + side->rowoffset; + texbottom = back->floorheight + side->rowoffset + side->offsety_mid; textop = texbottom + texheight*(side->repeatcnt+1); } else { - textop = back->ceilingheight + side->rowoffset; + textop = back->ceilingheight + side->rowoffset + side->offsety_mid; texbottom = textop - texheight*(side->repeatcnt+1); } } else #endif { if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat - texbottom = openbottom + side->rowoffset; - textop = opentop + side->rowoffset; + texbottom = openbottom + side->rowoffset + side->offsety_mid; + textop = opentop + side->rowoffset + side->offsety_mid; } else if (linedef->flags & ML_MIDPEG) { - texbottom = openbottom + side->rowoffset; + texbottom = openbottom + side->rowoffset + side->offsety_mid; textop = texbottom + texheight*(side->repeatcnt+1); } else { - textop = opentop + side->rowoffset; + textop = opentop + side->rowoffset + side->offsety_mid; texbottom = textop - texheight*(side->repeatcnt+1); } } diff --git a/src/p_mobj.c b/src/p_mobj.c index eeaf54776..3eab29c09 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3139,7 +3139,8 @@ boolean P_SceneryZMovement(mobj_t *mo) if (P_CheckDeathPitCollide(mo)) { - P_RemoveMobj(mo); + if (mo->type != MT_GHOST) // ghosts play death animations instead, so don't remove them + P_RemoveMobj(mo); return false; } @@ -9716,6 +9717,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) A_AttractChase(mobj); break; case MT_EMBLEM: + if (P_EmblemWasCollected(mobj->health - 1) || !P_CanPickupEmblem(&players[consoleplayer], mobj->health - 1)) + mobj->frame |= (tr_trans50 << FF_TRANSSHIFT); + else + mobj->frame &= ~FF_TRANSMASK; + if (mobj->flags2 & MF2_NIGHTSPULL) P_NightsItemChase(mobj); break; @@ -12005,8 +12011,8 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) break; case MT_EMBLEM: - if (netgame || multiplayer) - return false; // Single player (You're next on my shit list) + if (!G_CoopGametype()) + return false; // Gametype's not right break; default: break; @@ -12150,7 +12156,6 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) INT32 j; emblem_t* emblem = M_GetLevelEmblems(gamemap); skincolornum_t emcolor; - boolean validEmblem = true; while (emblem) { @@ -12175,42 +12180,19 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting mobj->color = (UINT16)emcolor; - validEmblem = !emblemlocations[j].collected; + mobj->frame &= ~FF_TRANSMASK; - if (emblemlocations[j].type == ET_SKIN) + if (emblemlocations[j].type == ET_GLOBAL) { - INT32 skinnum = M_EmblemSkinNum(&emblemlocations[j]); - - if (players[0].skin != skinnum) + mobj->reactiontime = emblemlocations[j].var; + if (emblemlocations[j].var & GE_NIGHTSITEM) { - validEmblem = false; + mobj->flags |= MF_NIGHTSITEM; + mobj->flags &= ~MF_SPECIAL; + mobj->flags2 |= MF2_DONTDRAW; } } - if (validEmblem == false) - { - P_UnsetThingPosition(mobj); - mobj->flags |= MF_NOCLIP; - mobj->flags &= ~MF_SPECIAL; - mobj->flags |= MF_NOBLOCKMAP; - mobj->frame |= (tr_trans50 << FF_TRANSSHIFT); - P_SetThingPosition(mobj); - } - else - { - mobj->frame &= ~FF_TRANSMASK; - - if (emblemlocations[j].type == ET_GLOBAL) - { - mobj->reactiontime = emblemlocations[j].var; - if (emblemlocations[j].var & GE_NIGHTSITEM) - { - mobj->flags |= MF_NIGHTSITEM; - mobj->flags &= ~MF_SPECIAL; - mobj->flags2 |= MF2_DONTDRAW; - } - } - } return true; } @@ -13706,7 +13688,6 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) UINT8 numitemtypes; if (!udmf) return; - CONS_Printf("Itemstring: %s\n", mthing->stringargs[0]); P_ParseItemTypes(mthing->stringargs[0], itemtypes, &numitemtypes); P_SpawnItemCircle(mthing, itemtypes, numitemtypes, mthing->args[0], mthing->args[1] << FRACBITS, bonustime); return; diff --git a/src/p_saveg.c b/src/p_saveg.c index 8c8a78322..c18319c69 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -47,6 +47,7 @@ UINT8 *save_p; #define ARCHIVEBLOCK_POBJS 0x7F928546 #define ARCHIVEBLOCK_THINKERS 0x7F37037C #define ARCHIVEBLOCK_SPECIALS 0x7F228378 +#define ARCHIVEBLOCK_EMBLEMS 0x7F4A5445 // Note: This cannot be bigger // than an UINT16 @@ -4339,6 +4340,8 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT32(save_p, hidetime); + WRITEUINT32(save_p, unlocktriggers); + // Is it paused? if (paused) WRITEUINT8(save_p, 0x2f); @@ -4437,6 +4440,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) hidetime = READUINT32(save_p); + unlocktriggers = READUINT32(save_p); + // Is it paused? if (READUINT8(save_p) == 0x2f) paused = true; @@ -4444,6 +4449,224 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) return true; } + +static inline void P_NetArchiveEmblems(void) +{ + gamedata_t *data = serverGamedata; + INT32 i, j; + UINT8 btemp; + INT32 curmare; + + WRITEUINT32(save_p, ARCHIVEBLOCK_EMBLEMS); + + // These should be synchronized before savegame loading by the wad files being the same anyway, + // but just in case, for now, we'll leave them here for testing. It would be very bad if they mismatch. + WRITEUINT8(save_p, (UINT8)savemoddata); + WRITEINT32(save_p, numemblems); + WRITEINT32(save_p, numextraemblems); + + // The rest of this is lifted straight from G_SaveGameData in g_game.c + // TODO: Optimize this to only send information about emblems, unlocks, etc. which actually exist + // There is no need to go all the way up to MAXEMBLEMS when wads are guaranteed to be the same. + + WRITEUINT32(save_p, data->totalplaytime); + + // TODO put another cipher on these things? meh, I don't care... + for (i = 0; i < NUMMAPS; i++) + WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX)); + + // To save space, use one bit per collected/achieved/unlocked flag + for (i = 0; i < MAXEMBLEMS;) + { + btemp = 0; + for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) + btemp |= (data->collected[j+i] << j); + WRITEUINT8(save_p, btemp); + i += j; + } + for (i = 0; i < MAXEXTRAEMBLEMS;) + { + btemp = 0; + for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) + btemp |= (data->extraCollected[j+i] << j); + WRITEUINT8(save_p, btemp); + i += j; + } + for (i = 0; i < MAXUNLOCKABLES;) + { + btemp = 0; + for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) + btemp |= (data->unlocked[j+i] << j); + WRITEUINT8(save_p, btemp); + i += j; + } + for (i = 0; i < MAXCONDITIONSETS;) + { + btemp = 0; + for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) + btemp |= (data->achieved[j+i] << j); + WRITEUINT8(save_p, btemp); + i += j; + } + + WRITEUINT32(save_p, data->timesBeaten); + WRITEUINT32(save_p, data->timesBeatenWithEmeralds); + WRITEUINT32(save_p, data->timesBeatenUltimate); + + // Main records + for (i = 0; i < NUMMAPS; i++) + { + if (data->mainrecords[i]) + { + WRITEUINT32(save_p, data->mainrecords[i]->score); + WRITEUINT32(save_p, data->mainrecords[i]->time); + WRITEUINT16(save_p, data->mainrecords[i]->rings); + } + else + { + WRITEUINT32(save_p, 0); + WRITEUINT32(save_p, 0); + WRITEUINT16(save_p, 0); + } + } + + // NiGHTS records + for (i = 0; i < NUMMAPS; i++) + { + if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) + { + WRITEUINT8(save_p, 0); + continue; + } + + WRITEUINT8(save_p, data->nightsrecords[i]->nummares); + + for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare) + { + WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]); + WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]); + WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]); + } + } +} + +static inline void P_NetUnArchiveEmblems(void) +{ + gamedata_t *data = serverGamedata; + INT32 i, j; + UINT8 rtemp; + UINT32 recscore; + tic_t rectime; + UINT16 recrings; + UINT8 recmares; + INT32 curmare; + + if (READUINT32(save_p) != ARCHIVEBLOCK_EMBLEMS) + I_Error("Bad $$$.sav at archive block Emblems"); + + savemoddata = (boolean)READUINT8(save_p); // this one is actually necessary because savemoddata stays false otherwise for some reason. + + if (numemblems != READINT32(save_p)) + I_Error("numemblems mismatch"); + if (numextraemblems != READINT32(save_p)) + I_Error("numextraemblems mismatch"); + + // This shouldn't happen, but if something really fucked up happens and you transfer + // the SERVER player's gamedata over your own CLIENT gamedata, + // then this prevents it from being saved over yours. + data->loaded = false; + + M_ClearSecrets(data); + G_ClearRecords(data); + + // The rest of this is lifted straight from G_LoadGameData in g_game.c + // TODO: Optimize this to only read information about emblems, unlocks, etc. which actually exist + // There is no need to go all the way up to MAXEMBLEMS when wads are guaranteed to be the same. + + data->totalplaytime = READUINT32(save_p); + + // TODO put another cipher on these things? meh, I don't care... + for (i = 0; i < NUMMAPS; i++) + if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) + I_Error("Bad $$$.sav dearchiving Emblems"); + + // To save space, use one bit per collected/achieved/unlocked flag + for (i = 0; i < MAXEMBLEMS;) + { + rtemp = READUINT8(save_p); + for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) + data->collected[j+i] = ((rtemp >> j) & 1); + i += j; + } + for (i = 0; i < MAXEXTRAEMBLEMS;) + { + rtemp = READUINT8(save_p); + for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) + data->extraCollected[j+i] = ((rtemp >> j) & 1); + i += j; + } + for (i = 0; i < MAXUNLOCKABLES;) + { + rtemp = READUINT8(save_p); + for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) + data->unlocked[j+i] = ((rtemp >> j) & 1); + i += j; + } + for (i = 0; i < MAXCONDITIONSETS;) + { + rtemp = READUINT8(save_p); + for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) + data->achieved[j+i] = ((rtemp >> j) & 1); + i += j; + } + + data->timesBeaten = READUINT32(save_p); + data->timesBeatenWithEmeralds = READUINT32(save_p); + data->timesBeatenUltimate = READUINT32(save_p); + + // Main records + for (i = 0; i < NUMMAPS; ++i) + { + recscore = READUINT32(save_p); + rectime = (tic_t)READUINT32(save_p); + recrings = READUINT16(save_p); + + if (recrings > 10000 || recscore > MAXSCORE) + I_Error("Bad $$$.sav dearchiving Emblems"); + + if (recscore || rectime || recrings) + { + G_AllocMainRecordData((INT16)i, data); + data->mainrecords[i]->score = recscore; + data->mainrecords[i]->time = rectime; + data->mainrecords[i]->rings = recrings; + } + } + + // Nights records + for (i = 0; i < NUMMAPS; ++i) + { + if ((recmares = READUINT8(save_p)) == 0) + continue; + + G_AllocNightsRecordData((INT16)i, data); + + for (curmare = 0; curmare < (recmares+1); ++curmare) + { + data->nightsrecords[i]->score[curmare] = READUINT32(save_p); + data->nightsrecords[i]->grade[curmare] = READUINT8(save_p); + data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); + + if (data->nightsrecords[i]->grade[curmare] > GRADE_S) + { + I_Error("Bad $$$.sav dearchiving Emblems"); + } + } + + data->nightsrecords[i]->nummares = recmares; + } +} + static inline void P_ArchiveLuabanksAndConsistency(void) { UINT8 i, banksinuse = NUM_LUABANKS; @@ -4507,6 +4730,7 @@ void P_SaveNetGame(boolean resending) CV_SaveNetVars(&save_p); P_NetArchiveMisc(resending); + P_NetArchiveEmblems(); // Assign the mobjnumber for pointer tracking for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -4559,6 +4783,7 @@ boolean P_LoadNetGame(boolean reloading) CV_LoadNetVars(&save_p); if (!P_NetUnArchiveMisc(reloading)) return false; + P_NetUnArchiveEmblems(); P_NetUnArchivePlayers(); if (gamestate == GS_LEVEL) { diff --git a/src/p_setup.c b/src/p_setup.c index c8b0936b8..a10326986 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -876,7 +876,7 @@ static void P_SpawnMapThings(boolean spawnemblems) size_t i; mapthing_t *mt; - // Spawn axis points first so they are at the front of the list for fast searching. + // Spawn axis points first so they are at the front of the list for fast searching. for (i = 0, mt = mapthings; i < nummapthings; i++, mt++) { switch (mt->type) @@ -1240,6 +1240,9 @@ static void P_LoadSidedefs(UINT8 *data) } sd->rowoffset = SHORT(msd->rowoffset)<offsetx_top = sd->offsetx_mid = sd->offsetx_bot = 0; + sd->offsety_top = sd->offsety_mid = sd->offsety_bot = 0; + P_SetSidedefSector(i, SHORT(msd->sector)); // Special info stored in texture fields! @@ -1777,6 +1780,18 @@ static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char sides[i].textureoffset = atol(val)<> FRACBITS); if (wsides[i].rowoffset != 0) fprintf(f, "offsety = %d;\n", wsides[i].rowoffset >> FRACBITS); + if (wsides[i].offsetx_top != 0) + fprintf(f, "offsetx_top = %d;\n", wsides[i].offsetx_top >> FRACBITS); + if (wsides[i].offsety_top != 0) + fprintf(f, "offsety_top = %d;\n", wsides[i].offsety_top >> FRACBITS); + if (wsides[i].offsetx_mid != 0) + fprintf(f, "offsetx_mid = %d;\n", wsides[i].offsetx_mid >> FRACBITS); + if (wsides[i].offsety_mid != 0) + fprintf(f, "offsety_mid = %d;\n", wsides[i].offsety_mid >> FRACBITS); + if (wsides[i].offsetx_bot != 0) + fprintf(f, "offsetx_bottom = %d;\n", wsides[i].offsetx_bot >> FRACBITS); + if (wsides[i].offsety_bot != 0) + fprintf(f, "offsety_bottom = %d;\n", wsides[i].offsety_bot >> FRACBITS); if (wsides[i].toptexture > 0 && wsides[i].toptexture < numtextures) fprintf(f, "texturetop = \"%.*s\";\n", 8, textures[wsides[i].toptexture]->name); if (wsides[i].bottomtexture > 0 && wsides[i].bottomtexture < numtextures) @@ -2828,6 +2855,8 @@ static void P_LoadTextmap(void) // Defaults. sd->textureoffset = 0; sd->rowoffset = 0; + sd->offsetx_top = sd->offsetx_mid = sd->offsetx_bot = 0; + sd->offsety_top = sd->offsety_mid = sd->offsety_bot = 0; sd->toptexture = R_TextureNumForName("-"); sd->midtexture = R_TextureNumForName("-"); sd->bottomtexture = R_TextureNumForName("-"); @@ -7460,7 +7489,7 @@ static void P_WriteLetter(void) { char *buf, *b; - if (!unlockables[28].unlocked) // pandora's box + if (!serverGamedata->unlocked[28]) // pandora's box return; if (modeattacking) @@ -7804,10 +7833,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) nextmapoverride = 0; skipstats = 0; - if (!(netgame || multiplayer || demoplayback)) - mapvisited[gamemap-1] |= MV_VISITED; - else if (netgame || multiplayer) - mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently + if (!demoplayback) + { + clientGamedata->mapvisited[gamemap-1] |= MV_VISITED; + serverGamedata->mapvisited[gamemap-1] |= MV_VISITED; + } levelloading = false; diff --git a/src/p_spec.c b/src/p_spec.c index 8489a227f..877b9c7bc 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1795,9 +1795,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller { // Unlockable triggers required INT32 trigid = triggerline->args[1]; - if (netgame || multiplayer) - return false; - else if (trigid < 0 || trigid > 31) // limited by 32 bit variable + if (trigid < 0 || trigid > 31) // limited by 32 bit variable { CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", triggerline->sidenum[0], trigid); return false; @@ -1810,14 +1808,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller { // An unlockable itself must be unlocked! INT32 unlockid = triggerline->args[1]; - if (netgame || multiplayer) - return false; - else if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count + if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count { CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); return false; } - else if (!(unlockables[unlockid-1].unlocked)) + else if (!(serverGamedata->unlocked[unlockid-1])) return false; } break; @@ -2942,7 +2938,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 441: // Trigger unlockable - if (!(netgame || multiplayer)) { INT32 trigid = line->args[0]; @@ -2953,10 +2948,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) unlocktriggers |= 1 << trigid; // Unlocked something? - if (M_UpdateUnlockablesAndExtraEmblems()) + M_SilentUpdateUnlockablesAndEmblems(serverGamedata); + + if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata)) { S_StartSound(NULL, sfx_s3k68); - G_SaveGameData(); // only save if unlocked something + G_SaveGameData(clientGamedata); // only save if unlocked something } } } diff --git a/src/p_tick.c b/src/p_tick.c index 0357258e8..b1fd367ed 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -675,7 +675,10 @@ void P_Ticker(boolean run) // Keep track of how long they've been playing! if (!demoplayback) // Don't increment if a demo is playing. - totalplaytime++; + { + clientGamedata->totalplaytime++; + serverGamedata->totalplaytime++; + } if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap)) P_DoSpecialStageStuff(); diff --git a/src/r_defs.h b/src/r_defs.h index 6d2b7d3d8..963d655b1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -559,6 +559,10 @@ typedef struct // add this to the calculated texture top fixed_t rowoffset; + // per-texture offsets for UDMF + fixed_t offsetx_top, offsetx_mid, offsetx_bot; + fixed_t offsety_top, offsety_mid, offsety_bot; + // Texture indices. // We do not maintain names here. INT32 toptexture, bottomtexture, midtexture; diff --git a/src/r_main.c b/src/r_main.c index ebf7a28bf..55bb9c4ff 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1092,34 +1092,12 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y) void R_SetupFrame(player_t *player) { camera_t *thiscam; - boolean chasecam = false; - - if (splitscreen && player == &players[secondarydisplayplayer] - && player != &players[consoleplayer]) - { + boolean chasecam = R_ViewpointHasChasecam(player); + + if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer]) thiscam = &camera2; - chasecam = (cv_chasecam2.value != 0); - R_SetViewContext(VIEWCONTEXT_PLAYER2); - } else - { thiscam = &camera; - chasecam = (cv_chasecam.value != 0); - R_SetViewContext(VIEWCONTEXT_PLAYER1); - } - - if (player->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 - - if (chasecam && !thiscam->chase) - { - P_ResetCamera(player, thiscam); - thiscam->chase = true; - } - else if (!chasecam) - thiscam->chase = false; newview->sky = false; @@ -1348,11 +1326,37 @@ boolean R_ViewpointHasChasecam(player_t *player) { camera_t *thiscam; boolean chasecam = false; + boolean isplayer2 = (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer]); - if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer]) + if (isplayer2) { thiscam = &camera2; chasecam = (cv_chasecam2.value != 0); + } + else + { + thiscam = &camera; + chasecam = (cv_chasecam.value != 0); + } + + if (player->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 + + if (chasecam && !thiscam->chase) + { + P_ResetCamera(player, thiscam); + thiscam->chase = true; + } + else if (!chasecam && thiscam->chase) + { + P_ResetCamera(player, thiscam); + thiscam->chase = false; + } + + if (isplayer2) + { R_SetViewContext(VIEWCONTEXT_PLAYER2); if (thiscam->reset) { @@ -1362,8 +1366,6 @@ boolean R_ViewpointHasChasecam(player_t *player) } else { - thiscam = &camera; - chasecam = (cv_chasecam.value != 0); R_SetViewContext(VIEWCONTEXT_PLAYER1); if (thiscam->reset) { @@ -1372,11 +1374,6 @@ boolean R_ViewpointHasChasecam(player_t *player) } } - if (player->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; } diff --git a/src/r_segs.c b/src/r_segs.c index 71fc9f9b2..5acca9b17 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -49,6 +49,7 @@ fixed_t rw_distance; static INT32 rw_x, rw_stopx; static angle_t rw_centerangle; static fixed_t rw_offset; +static fixed_t rw_offset_top, rw_offset_mid, rw_offset_bot; static fixed_t rw_offset2; // for splats static fixed_t rw_scale, rw_scalestep; static fixed_t rw_midtexturemid, rw_toptexturemid, rw_bottomtexturemid; @@ -778,7 +779,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (newline) { - offsetvalue = sides[newline->sidenum[0]].rowoffset; + offsetvalue = sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid; if (newline->flags & ML_DONTPEGBOTTOM) { skewslope = *pfloor->b_slope; // skew using bottom slope @@ -790,7 +791,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) } else { - offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset; + offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset + sides[pfloor->master->sidenum[0]].offsety_mid; if (curline->linedef->flags & ML_DONTPEGBOTTOM) { skewslope = *pfloor->b_slope; // skew using bottom slope @@ -1335,7 +1336,7 @@ static void R_RenderSegLoop (void) dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; - dc_source = R_GetColumn(midtexture,texturecolumn); + dc_source = R_GetColumn(midtexture,texturecolumn + (rw_offset_mid>>FRACBITS)); dc_texheight = textureheight[midtexture]>>FRACBITS; //profile stuff --------------------------------------------------------- @@ -1396,7 +1397,7 @@ static void R_RenderSegLoop (void) dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; - dc_source = R_GetColumn(toptexture,texturecolumn); + dc_source = R_GetColumn(toptexture,texturecolumn + (rw_offset_top>>FRACBITS)); dc_texheight = textureheight[toptexture]>>FRACBITS; colfunc(); ceilingclip[rw_x] = (INT16)mid; @@ -1433,7 +1434,7 @@ static void R_RenderSegLoop (void) dc_yh = yh; dc_texturemid = rw_bottomtexturemid; dc_source = R_GetColumn(bottomtexture, - texturecolumn); + texturecolumn + (rw_offset_bot>>FRACBITS)); dc_texheight = textureheight[bottomtexture]>>FRACBITS; colfunc(); floorclip[rw_x] = (INT16)mid; @@ -1452,7 +1453,7 @@ static void R_RenderSegLoop (void) { // save texturecol // for backdrawing of masked mid texture - maskedtexturecol[rw_x] = (INT16)texturecolumn; + maskedtexturecol[rw_x] = (INT16)(texturecolumn + (rw_offset_mid>>FRACBITS)); if (maskedtextureheight != NULL) { maskedtextureheight[rw_x] = (curline->linedef->flags & ML_MIDPEG) ? @@ -1783,7 +1784,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_midtexturemid = worldtop; rw_midtextureslide = ceilingfrontslide; } - rw_midtexturemid += sidedef->rowoffset; + rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; @@ -2022,8 +2023,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) } } - rw_toptexturemid += sidedef->rowoffset; - rw_bottomtexturemid += sidedef->rowoffset; + rw_toptexturemid += sidedef->rowoffset + sidedef->offsety_top; + rw_bottomtexturemid += sidedef->rowoffset + sidedef->offsety_bot; // allocate space for masked texture tables if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) @@ -2266,8 +2267,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_midtexturebackslide = ceilingbackslide; } } - rw_midtexturemid += sidedef->rowoffset; - rw_midtextureback += sidedef->rowoffset; + rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid; + rw_midtextureback += sidedef->rowoffset + sidedef->offsety_mid; maskedtexture = true; } @@ -2305,6 +2306,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) /// don't use texture offset for splats rw_offset2 = rw_offset + curline->offset; rw_offset += sidedef->textureoffset + curline->offset; + rw_offset_top = sidedef->offsetx_top; + rw_offset_mid = sidedef->offsetx_mid; + rw_offset_bot = sidedef->offsetx_bot; rw_centerangle = ANGLE_90 + viewangle - rw_normalangle; // calculate light table diff --git a/src/r_skins.c b/src/r_skins.c index e59e085b8..2c031ee85 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -194,7 +194,7 @@ UINT32 R_GetSkinAvailabilities(void) return 0; } - if (unlockables[i].unlocked) + if (clientGamedata->unlocked[i]) { response |= (1 << unlockShift); } @@ -242,11 +242,12 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum) // Force 3. return true; } + if (playernum != -1 && players[playernum].bot) - { - //Force 4. - return true; - } + { + // Force 4. + return true; + } // We will now check if this skin is supposed to be locked or not. @@ -284,7 +285,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum) else { // We want to check our global unlockables. - return (unlockables[unlockID].unlocked); + return (clientGamedata->unlocked[unlockID]); } } diff --git a/src/r_things.c b/src/r_things.c index 916a7ee4b..89b9fe07e 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1324,6 +1324,8 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, if (trans >= 9) return; scalemul = FixedMul(FRACUNIT - floordiff/640, scale); + if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs + scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale)); patch = W_CachePatchName("DSHADOW", PU_SPRITE); xscale = FixedDiv(projection, tz); diff --git a/src/s_sound.c b/src/s_sound.c index 111b6ce25..ada1a0fd2 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1692,6 +1692,7 @@ UINT8 soundtestpage = 1; // boolean S_PrepareSoundTest(void) { + gamedata_t *data = clientGamedata; musicdef_t *def; INT32 pos = numsoundtestdefs = 0; @@ -1717,9 +1718,9 @@ boolean S_PrepareSoundTest(void) if (!(def->soundtestpage & soundtestpage)) continue; soundtestdefs[pos++] = def; - if (def->soundtestcond > 0 && !(mapvisited[def->soundtestcond-1] & MV_BEATEN)) + if (def->soundtestcond > 0 && !(data->mapvisited[def->soundtestcond-1] & MV_BEATEN)) continue; - if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond)) + if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond, data)) continue; def->allowed = true; } diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 67ee8d668..66eeffa30 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2352,7 +2352,7 @@ void I_Quit(void) #ifndef NONET D_SaveBan(); // save the ban list #endif - G_SaveGameData(); // Tails 12-08-2002 + G_SaveGameData(clientGamedata); // Tails 12-08-2002 //added:16-02-98: when recording a demo, should exit using 'q' key, // but sometimes we forget and use 'F10'.. so save here too. @@ -2436,7 +2436,7 @@ void I_Error(const char *error, ...) if (errorcount == 8) { M_SaveConfig(NULL); - G_SaveGameData(); + G_SaveGameData(clientGamedata); } if (errorcount > 20) { @@ -2469,7 +2469,7 @@ void I_Error(const char *error, ...) #ifndef NONET D_SaveBan(); // save the ban list #endif - G_SaveGameData(); // Tails 12-08-2002 + G_SaveGameData(clientGamedata); // Tails 12-08-2002 // Shutdown. Here might be other errors. if (demorecording) diff --git a/src/st_stuff.c b/src/st_stuff.c index 206c93273..dcab2bb9c 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -108,6 +108,9 @@ static patch_t *sneakers; static patch_t *gravboots; static patch_t *nonicon; static patch_t *nonicon2; +static patch_t *nightopianhelper; +static patch_t *linkfreeze; +static patch_t *superparaloop; static patch_t *bluestat; static patch_t *byelstat; static patch_t *orngstat; @@ -313,6 +316,10 @@ void ST_LoadGraphics(void) nonicon2 = W_CachePatchName("NONICON2", PU_HUDGFX); // NiGHTS HUD things + nightopianhelper = W_CachePatchName("NHLPICON", PU_HUDGFX); + linkfreeze = W_CachePatchName("NLFZICON", PU_HUDGFX); + superparaloop = W_CachePatchName("NSPRICON", PU_HUDGFX); + bluestat = W_CachePatchName("BLUESTAT", PU_HUDGFX); byelstat = W_CachePatchName("BYELSTAT", PU_HUDGFX); orngstat = W_CachePatchName("ORNGSTAT", PU_HUDGFX); @@ -1448,6 +1455,21 @@ void ST_drawWipeTitleCard(void) } } +#define ICONSEP (16+4) // matches weapon rings HUD + +static INT32 ST_powerupHUDoffset(UINT16 timer) +{ + if (timer > 7) + return ICONSEP; + else + { + UINT8 a = ICONSEP, b = 7-timer; + while (b--) + a = 2*a/3; + return a; + } +} + static void ST_drawPowerupHUD(void) { patch_t *p = NULL; @@ -1455,7 +1477,6 @@ static void ST_drawPowerupHUD(void) INT32 offs = hudinfo[HUD_POWERUPS].x; const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0); static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0}, finishoffs[2] = {0, 0}; -#define ICONSEP (16+4) // matches weapon rings HUD if (F_GetPromptHideHud(hudinfo[HUD_POWERUPS].y)) return; @@ -1567,15 +1588,7 @@ static void ST_drawPowerupHUD(void) DRAWTIMERICON(invincibility, invulntime) } - if (invulntime > 7) - offs -= ICONSEP; - else - { - UINT8 a = ICONSEP, b = 7-invulntime; - while (b--) - a = 2*a/3; - offs -= a; - } + offs -= ST_powerupHUDoffset(invulntime); // Super Sneakers if (stplyr->powers[pw_sneakers] > 3*TICRATE || (stplyr->powers[pw_sneakers] && leveltime & 1)) @@ -1583,15 +1596,7 @@ static void ST_drawPowerupHUD(void) DRAWTIMERICON(sneakers, stplyr->powers[pw_sneakers]) } - if (stplyr->powers[pw_sneakers] > 7) - offs -= ICONSEP; - else - { - UINT8 a = ICONSEP, b = 7-stplyr->powers[pw_sneakers]; - while (b--) - a = 2*a/3; - offs -= a; - } + offs -= ST_powerupHUDoffset(stplyr->powers[pw_sneakers]); // Gravity Boots if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1)) @@ -1599,6 +1604,36 @@ static void ST_drawPowerupHUD(void) DRAWTIMERICON(gravboots, stplyr->powers[pw_gravityboots]) } + offs -= ST_powerupHUDoffset(stplyr->powers[pw_gravityboots]); + +// -------------------- +// NiGHTS timer-based powerups +// -------------------- + + // Nightopian Helper + if (stplyr->powers[pw_nights_helper] > 3*TICRATE || (stplyr->powers[pw_nights_helper] && leveltime & 1)) + { + DRAWTIMERICON(nightopianhelper, stplyr->powers[pw_nights_helper]) + } + + offs -= ST_powerupHUDoffset(stplyr->powers[pw_nights_helper]); + + // Link Freeze + if (stplyr->powers[pw_nights_linkfreeze] > 3*TICRATE || (stplyr->powers[pw_nights_linkfreeze] && leveltime & 1)) + { + DRAWTIMERICON(linkfreeze, stplyr->powers[pw_nights_linkfreeze]) + } + + offs -= ST_powerupHUDoffset(stplyr->powers[pw_nights_linkfreeze]); + + // Super Paraloop + if (stplyr->powers[pw_nights_superloop] > 3*TICRATE || (stplyr->powers[pw_nights_superloop] && leveltime & 1)) + { + DRAWTIMERICON(superparaloop, stplyr->powers[pw_nights_superloop]) + } + + //offs -= ST_powerupHUDoffset(stplyr->powers[pw_nights_superloop]); + #undef DRAWTIMERICON #undef ICONSEP } @@ -1697,7 +1732,7 @@ static void ST_drawNightsRecords(void) ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<lastmarescore, nightsnum, SKINCOLOR_AZURE); // If new record, say so! - if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore) + if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1, clientGamedata) <= stplyr->lastmarescore) { if (stplyr->texttimer & 16) V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *"); @@ -2545,7 +2580,7 @@ static void ST_doHuntIconsAndSound(void) S_StartSound(NULL, sfx_emfind); } -static void ST_doItemFinderIconsAndSound(void) +static boolean ST_doItemFinderIconsAndSound(void) { INT32 emblems[16]; thinker_t *th; @@ -2556,6 +2591,12 @@ static void ST_doItemFinderIconsAndSound(void) INT32 interval = 0, newinterval = 0; INT32 soffset; + if (!(cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata))) + { + // Not unlocked, or not enabled. Use emerald hunt radar. + return false; + } + for (i = 0; i < numemblems; ++i) { if (emblemlocations[i].type > ET_SKIN || emblemlocations[i].level != gamemap) @@ -2563,15 +2604,21 @@ static void ST_doItemFinderIconsAndSound(void) emblems[stemblems++] = i; - if (!emblemlocations[i].collected) + if (!P_EmblemWasCollected(i) && P_CanPickupEmblem(stplyr, i)) + { ++stunfound; + } if (stemblems >= 16) break; } + // Found all/none exist? Don't waste our time if (!stunfound) - return; + { + // Allow emerald hunt radar to function after they're all collected. + return false; + } // Scan thinkers to find emblem mobj with these ids for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -2591,6 +2638,9 @@ static void ST_doItemFinderIconsAndSound(void) { if (mo2->health == emblems[i] + 1) { + if (P_EmblemWasCollected(emblems[i]) || !P_CanPickupEmblem(stplyr, emblems[i])) + break; + soffset = (i * 20) - ((stemblems - 1) * 10); newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset); @@ -2605,6 +2655,8 @@ static void ST_doItemFinderIconsAndSound(void) if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0 && renderisnewtic) S_StartSound(NULL, sfx_emfind); + + return true; } // @@ -2723,9 +2775,7 @@ static void ST_overlayDrawer(void) ST_drawRaceHUD(); // Emerald Hunt Indicators - if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER)) - ST_doItemFinderIconsAndSound(); - else + if (!ST_doItemFinderIconsAndSound()) ST_doHuntIconsAndSound(); if(!P_IsLocalPlayer(stplyr)) @@ -2740,18 +2790,16 @@ static void ST_overlayDrawer(void) } // This is where we draw all the fun cheese if you have the chasecam off! - if (!(maptol & TOL_NIGHTS)) + if ((stplyr == &players[displayplayer] && !camera.chase) + || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) { - if ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) - { - ST_drawFirstPersonHUD(); - if (cv_powerupdisplay.value) - ST_drawPowerupHUD(); // same as it ever was... - } - else if (cv_powerupdisplay.value == 2) + ST_drawFirstPersonHUD(); + if (cv_powerupdisplay.value) ST_drawPowerupHUD(); // same as it ever was... } + else if (cv_powerupdisplay.value == 2) + ST_drawPowerupHUD(); // same as it ever was... + } else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2) ST_drawPowerupHUD(); // same as it ever was... diff --git a/src/y_inter.c b/src/y_inter.c index 02d01233e..6e7d362a7 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1092,12 +1092,14 @@ void Y_Ticker(void) S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching! // Update when done with tally - if (!(netgame || multiplayer) && !demoplayback) + if (!demoplayback) { - if (M_UpdateUnlockablesAndExtraEmblems()) + M_SilentUpdateUnlockablesAndEmblems(serverGamedata); + + if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata)) S_StartSound(NULL, sfx_s3k68); - G_SaveGameData(); + G_SaveGameData(clientGamedata); } } else if (!(intertic & 1)) @@ -1228,12 +1230,14 @@ void Y_Ticker(void) S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching! // Update when done with tally - if (!(netgame || multiplayer) && !demoplayback) + if (!demoplayback) { - if (M_UpdateUnlockablesAndExtraEmblems()) + M_SilentUpdateUnlockablesAndEmblems(serverGamedata); + + if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata)) S_StartSound(NULL, sfx_s3k68); - G_SaveGameData(); + G_SaveGameData(clientGamedata); } } else if (!(intertic & 1))