您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Fetches PNG/JSON map data, draws floor tiles using different images for boosts and portals, computes walls from PNG hex codes, overlays gate tiles using JSON fields, and updates the preview image. Your texture pack choice is remembered until you reset it.
当前为
// ==UserScript== // @name Fortunate Maps Texture Preview // @namespace http://tampermonkey.net/ // @version 0.6 // @description Fetches PNG/JSON map data, draws floor tiles using different images for boosts and portals, computes walls from PNG hex codes, overlays gate tiles using JSON fields, and updates the preview image. Your texture pack choice is remembered until you reset it. // @match https://fortunatemaps.herokuapp.com/map/* // @run-at document-end // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; console.log("[FM] Script started"); // Base URL for texture images. const baseUrl = "https://static.koalabeast.com"; // ---------------------------- // Configuration & Global Data // ---------------------------- const config = { tileSize: 40, // Final tile is 40x40px. quadSize: 20 // Each wall quadrant is 20x20px. }; // Mapping for floor/feature tiles (except boosts/portals). const floorTiles = { "d4d4d4": { y: 4, x: 13 }, "808000": { y: 1, x: 13 }, "ff0000": { y: 1, x: 14 }, "0000ff": { y: 1, x: 15 }, "373737": { y: 0, x: 12 }, "202020": { y: 0, x: 13 }, "b90000": { y: 5, x: 14 }, "190094": { y: 5, x: 15 }, "dcbaba": { y: 4, x: 14 }, "bbb8dd": { y: 4, x: 15 }, "dcdcba": { y: 5, x: 13 }, "00ff00": { y: 4, x: 12 }, "b97a57": { y: 6, x: 13 }, "ff8000": { y: 1, x: 12 }, "007500_empty": { y: 3, x: 12 }, "007500_green": { y: 3, x: 13 }, "007500_red": { y: 3, x: 14 }, "007500_blue": { y: 3, x: 15 }, "8080ff": { y: 8, x: 14 }, "8080ff": { y: 7, x: 14 }, "656500": { y: 6, x: 14 }, }; // Texture packs definition using relative paths. const textures ={"texturePacks":[{"name":"Classic","author":"LuckySpammer","url":"classic","tiles":"/textures/classic/tiles.png","speedpad":"/textures/classic/speedpad.png","speedpadRed":"/textures/classic/speedpadred.png","speedpadBlue":"/textures/classic/speedpadblue.png","portal":"/textures/classic/portal.png","portalRed":"/textures/classic/portalred.png","portalBlue":"/textures/classic/portalblue.png","splats":"/textures/classic/splats.png","popularity":3259028385,"popularityScore":"3259"},{"name":"Sniper Pack","author":"DOKE","url":"sniperpack","tiles":"/textures/sniperpack/tiles.png","speedpad":"/textures/sniperpack/speedpad.png","speedpadRed":"/textures/sniperpack/speedpadred.png","speedpadBlue":"/textures/sniperpack/speedpadblue.png","portal":"/textures/sniperpack/portal.png","portalRed":"/textures/sniperpack/portalred.png","portalBlue":"/textures/sniperpack/portalblue.png","splats":"/textures/sniperpack/splats.png","popularity":1437466820,"popularityScore":"1437"},{"name":"Muscle's Cup Gradients","author":"MuscleCups","url":"musclescupgradients","tiles":"/textures/musclescupgradients/tiles.png","speedpad":"/textures/musclescupgradients/speedpad.png","speedpadRed":"/textures/musclescupgradients/speedpadred.png","speedpadBlue":"/textures/musclescupgradients/speedpadblue.png","portal":"/textures/musclescupgradients/portal.png","portalRed":"/textures/musclescupgradients/portalred.png","portalBlue":"/textures/musclescupgradients/portalblue.png","splats":"/textures/musclescupgradients/splats.png","popularity":1436532153,"popularityScore":"1437"},{"name":"Coral Light","author":"MagicPigeon","url":"corallight","tiles":"/textures/corallight/tiles.png","speedpad":"/textures/corallight/speedpad.png","speedpadRed":"/textures/corallight/speedpadred.png","speedpadBlue":"/textures/corallight/speedpadblue.png","portal":"/textures/corallight/portal.png","portalRed":"/textures/corallight/portalred.png","portalBlue":"/textures/corallight/portalblue.png","splats":"/textures/corallight/splats.png","popularity":1161028272,"popularityScore":"1161"},{"name":"Muscle's Cup OG","author":"MuscleCups","url":"musclescupog","tiles":"/textures/musclescupog/tiles.png","speedpad":"/textures/musclescupog/speedpad.png","speedpadRed":"/textures/musclescupog/speedpadred.png","speedpadBlue":"/textures/musclescupog/speedpadblue.png","portal":"/textures/musclescupog/portal.png","portalRed":"/textures/musclescupog/portalred.png","portalBlue":"/textures/musclescupog/portalblue.png","splats":"/textures/musclescupog/splats.png","popularity":687443389,"popularityScore":"687"},{"name":"Coral","author":"MagicPigeon","url":"coral","tiles":"/textures/coral/tiles.png","speedpad":"/textures/coral/speedpad.png","speedpadRed":"/textures/coral/speedpadred.png","speedpadBlue":"/textures/coral/speedpadblue.png","portal":"/textures/coral/portal.png","portalRed":"/textures/coral/portalred.png","portalBlue":"/textures/coral/portalblue.png","splats":"/textures/coral/splats.png","popularity":457526831,"popularityScore":"458"},{"name":"MTBad","author":"mtbkr24","url":"mtbad","tiles":"/textures/mtbad/tiles.png","speedpad":"/textures/mtbad/speedpad.png","speedpadRed":"/textures/mtbad/speedpadred.png","speedpadBlue":"/textures/mtbad/speedpadblue.png","portal":"/textures/mtbad/portal.png","portalRed":"/textures/mtbad/portalred.png","portalBlue":"/textures/mtbad/portalblue.png","splats":"/textures/mtbad/splats.png","popularity":412084222,"popularityScore":"412"},{"name":"Flat","author":"why","url":"flat","tiles":"/textures/flat/tiles.png","speedpad":"/textures/flat/speedpad.png","speedpadRed":"/textures/flat/speedpadred.png","speedpadBlue":"/textures/flat/speedpadblue.png","portal":"/textures/flat/portal.png","portalRed":"/textures/flat/portalred.png","portalBlue":"/textures/flat/portalblue.png","splats":"/textures/flat/splats.png","popularity":401656196,"popularityScore":"402"},{"name":"MLTP Live","author":"Ron Spawnson","url":"mltplive","tiles":"/textures/mltplive/tiles.png","speedpad":"/textures/mltplive/speedpad.png","speedpadRed":"/textures/mltplive/speedpadred.png","speedpadBlue":"/textures/mltplive/speedpadblue.png","portal":"/textures/mltplive/portal.png","portalRed":"/textures/mltplive/portalred.png","portalBlue":"/textures/mltplive/portalblue.png","splats":"/textures/mltplive/splats.png","popularity":263983209,"popularityScore":"264"},{"name":"24K","author":"MagicPigeon","url":"24k","tiles":"/textures/24k/tiles.png","speedpad":"/textures/24k/speedpad.png","speedpadRed":"/textures/24k/speedpadred.png","speedpadBlue":"/textures/24k/speedpadblue.png","portal":"/textures/24k/portal.png","portalRed":"/textures/24k/portalred.png","portalBlue":"/textures/24k/portalblue.png","splats":"/textures/24k/splats.png","popularity":233605766,"popularityScore":"234"},{"name":"Precision Dark","author":"Peach Fuzz","url":"precisiondark","tiles":"/textures/precisiondark/tiles.png","speedpad":"/textures/precisiondark/speedpad.png","speedpadRed":"/textures/precisiondark/speedpadred.png","speedpadBlue":"/textures/precisiondark/speedpadblue.png","portal":"/textures/precisiondark/portal.png","portalRed":"/textures/precisiondark/portalred.png","portalBlue":"/textures/precisiondark/portalblue.png","splats":"/textures/precisiondark/splats.png","popularity":213202866,"popularityScore":"213"},{"name":"Plumb","author":"SuperTed","url":"plumb","tiles":"/textures/plumb/tiles.png","speedpad":"/textures/plumb/speedpad.png","speedpadRed":"/textures/plumb/speedpadred.png","speedpadBlue":"/textures/plumb/speedpadblue.png","portal":"/textures/plumb/portal.png","portalRed":"/textures/plumb/portalred.png","portalBlue":"/textures/plumb/portalblue.png","splats":"/textures/plumb/splats.png","popularity":192741223,"popularityScore":"193"},{"name":"Plique","author":"Despair","url":"plique","tiles":"/textures/plique/tiles.png","speedpad":"/textures/plique/speedpad.png","speedpadRed":"/textures/plique/speedpadred.png","speedpadBlue":"/textures/plique/speedpadblue.png","portal":"/textures/plique/portal.png","portalRed":"/textures/plique/portalred.png","portalBlue":"/textures/plique/portalblue.png","splats":"/textures/plique/splats.png","popularity":183995905,"popularityScore":"184"},{"name":"Isometric","author":"mtbkr24","url":"isometric","tiles":"/textures/isometric/tiles.png","speedpad":"/textures/isometric/speedpad.png","speedpadRed":"/textures/isometric/speedpadred.png","speedpadBlue":"/textures/isometric/speedpadblue.png","portal":"/textures/isometric/portal.png","portalRed":"/textures/isometric/portalred.png","portalBlue":"/textures/isometric/portalblue.png","splats":"/textures/isometric/splats.png","popularity":167044212,"popularityScore":"167"},{"name":"Sparkle","author":"MagicPigeon","url":"sparkle","tiles":"/textures/sparkle/tiles.png","speedpad":"/textures/sparkle/speedpad.png","speedpadRed":"/textures/sparkle/speedpadred.png","speedpadBlue":"/textures/sparkle/speedpadblue.png","portal":"/textures/sparkle/portal.png","portalRed":"/textures/sparkle/portalred.png","portalBlue":"/textures/sparkle/portalblue.png","splats":"/textures/sparkle/splats.png","popularity":166286098,"popularityScore":"166"},{"name":"CamsPP Dark","author":"Cam","url":"camsppdark","tiles":"/textures/camsppdark/tiles.png","speedpad":"/textures/camsppdark/speedpad.png","speedpadRed":"/textures/camsppdark/speedpadred.png","speedpadBlue":"/textures/camsppdark/speedpadblue.png","portal":"/textures/camsppdark/portal.png","portalRed":"/textures/camsppdark/portalred.png","portalBlue":"/textures/camsppdark/portalblue.png","splats":"/textures/camsppdark/splats.png","popularity":159743715,"popularityScore":"160"},{"name":"CamsPP Old","author":"Cam","url":"camsppold","tiles":"/textures/camsppold/tiles.png","speedpad":"/textures/camsppold/speedpad.png","speedpadRed":"/textures/camsppold/speedpadred.png","speedpadBlue":"/textures/camsppold/speedpadblue.png","portal":"/textures/camsppold/portal.png","portalRed":"/textures/camsppold/portalred.png","portalBlue":"/textures/camsppold/portalblue.png","splats":"/textures/camsppold/splats.png","popularity":157841341,"popularityScore":"158"},{"name":"CMYK","author":"MagicPigeon","url":"cmyk","tiles":"/textures/cmyk/tiles.png","speedpad":"/textures/cmyk/speedpad.png","speedpadRed":"/textures/cmyk/speedpadred.png","speedpadBlue":"/textures/cmyk/speedpadblue.png","portal":"/textures/cmyk/portal.png","portalRed":"/textures/cmyk/portalred.png","portalBlue":"/textures/cmyk/portalblue.png","splats":"/textures/cmyk/splats.png","popularity":144688179,"popularityScore":"145"},{"name":"CamsPP Light","author":"Cam","url":"camspplight","tiles":"/textures/camspplight/tiles.png","speedpad":"/textures/camspplight/speedpad.png","speedpadRed":"/textures/camspplight/speedpadred.png","speedpadBlue":"/textures/camspplight/speedpadblue.png","portal":"/textures/camspplight/portal.png","portalRed":"/textures/camspplight/portalred.png","portalBlue":"/textures/camspplight/portalblue.png","splats":"/textures/camspplight/splats.png","popularity":135009946,"popularityScore":"135"},{"name":"Electric","author":"Bug","url":"electric","tiles":"/textures/electric/tiles.png","speedpad":"/textures/electric/speedpad.png","speedpadRed":"/textures/electric/speedpadred.png","speedpadBlue":"/textures/electric/speedpadblue.png","portal":"/textures/electric/portal.png","portalRed":"/textures/electric/portalred.png","portalBlue":"/textures/electric/portalblue.png","splats":"/textures/electric/splats.png","popularity":127175831,"popularityScore":"127"},{"name":"Sketch+","author":"MagicPigeon","url":"sketch","tiles":"/textures/sketch/tiles.png","speedpad":"/textures/sketch/speedpad.png","speedpadRed":"/textures/sketch/speedpadred.png","speedpadBlue":"/textures/sketch/speedpadblue.png","portal":"/textures/sketch/portal.png","portalRed":"/textures/sketch/portalred.png","portalBlue":"/textures/sketch/portalblue.png","splats":"/textures/sketch/splats.png","popularity":126489052,"popularityScore":"126"},{"name":"Sharp","author":"MagicPigeon","url":"sharp","tiles":"/textures/sharp/tiles.png","speedpad":"/textures/sharp/speedpad.png","speedpadRed":"/textures/sharp/speedpadred.png","speedpadBlue":"/textures/sharp/speedpadblue.png","portal":"/textures/sharp/portal.png","portalRed":"/textures/sharp/portalred.png","portalBlue":"/textures/sharp/portalblue.png","splats":"/textures/sharp/splats.png","popularity":103226439,"popularityScore":"103"},{"name":"PastelPro","author":"SuperTed","url":"pastelpro","tiles":"/textures/pastelpro/tiles.png","speedpad":"/textures/pastelpro/speedpad.png","speedpadRed":"/textures/pastelpro/speedpadred.png","speedpadBlue":"/textures/pastelpro/speedpadblue.png","portal":"/textures/pastelpro/portal.png","portalRed":"/textures/pastelpro/portalred.png","portalBlue":"/textures/pastelpro/portalblue.png","splats":"/textures/pastelpro/splats.png","popularity":99507002,"popularityScore":"100"},{"name":"Element+","author":"MagicPigeon","url":"element","tiles":"/textures/element/tiles.png","speedpad":"/textures/element/speedpad.png","speedpadRed":"/textures/element/speedpadred.png","speedpadBlue":"/textures/element/speedpadblue.png","portal":"/textures/element/portal.png","portalRed":"/textures/element/portalred.png","portalBlue":"/textures/element/portalblue.png","splats":"/textures/element/splats.png","popularity":98019109,"popularityScore":"98"},{"name":"Mural","author":"DaEvil1","url":"mural","tiles":"/textures/mural/tiles.png","speedpad":"/textures/mural/speedpad.png","speedpadRed":"/textures/mural/speedpadred.png","speedpadBlue":"/textures/mural/speedpadblue.png","portal":"/textures/mural/portal.png","portalRed":"/textures/mural/portalred.png","portalBlue":"/textures/mural/portalblue.png","splats":"/textures/mural/splats.png","popularity":80387834,"popularityScore":"80"},{"name":"Supreme","author":"bicycle","url":"supreme","tiles":"/textures/supreme/tiles.png","speedpad":"/textures/supreme/speedpad.png","speedpadRed":"/textures/supreme/speedpadred.png","speedpadBlue":"/textures/supreme/speedpadblue.png","portal":"/textures/supreme/portal.png","portalRed":"/textures/supreme/portalred.png","portalBlue":"/textures/supreme/portalblue.png","splats":"/textures/supreme/splats.png","popularity":69068153,"popularityScore":"69"},{"name":"Circlejerk","author":"Bizkut and Ion","url":"circlejerk","tiles":"/textures/circlejerk/tiles.png","speedpad":"/textures/circlejerk/speedpad.png","speedpadRed":"/textures/circlejerk/speedpadred.png","speedpadBlue":"/textures/circlejerk/speedpadblue.png","portal":"/textures/circlejerk/portal.png","portalRed":"/textures/circlejerk/portalred.png","portalBlue":"/textures/circlejerk/portalblue.png","splats":"/textures/circlejerk/splats.png","popularity":68828720,"popularityScore":"69"},{"name":"nom","author":"anom","url":"nom","tiles":"/textures/nom/tiles.png","speedpad":"/textures/nom/speedpad.png","speedpadRed":"/textures/nom/speedpadred.png","speedpadBlue":"/textures/nom/speedpadblue.png","portal":"/textures/nom/portal.png","portalRed":"/textures/nom/portalred.png","portalBlue":"/textures/nom/portalblue.png","splats":"/textures/nom/splats.png","popularity":58222444,"popularityScore":"58"},{"name":"Starlight","author":"MagicPigeon","url":"starlight","tiles":"/textures/starlight/tiles.png","speedpad":"/textures/starlight/speedpad.png","speedpadRed":"/textures/starlight/speedpadred.png","speedpadBlue":"/textures/starlight/speedpadblue.png","portal":"/textures/starlight/portal.png","portalRed":"/textures/starlight/portalred.png","portalBlue":"/textures/starlight/portalblue.png","splats":"/textures/starlight/splats.png","popularity":54456391,"popularityScore":"54"},{"name":"TerminalPX","author":"pooppants","url":"terminalpx","tiles":"/textures/terminalpx/tiles.png","speedpad":"/textures/terminalpx/speedpad.png","speedpadRed":"/textures/terminalpx/speedpadred.png","speedpadBlue":"/textures/terminalpx/speedpadblue.png","portal":"/textures/terminalpx/portal.png","portalRed":"/textures/terminalpx/portalred.png","portalBlue":"/textures/terminalpx/portalblue.png","splats":"/textures/terminalpx/splats.png","popularity":49589262,"popularityScore":"50"},{"name":"Brioche Light","author":"Brioche","url":"briochelight","tiles":"/textures/briochelight/tiles.png","speedpad":"/textures/briochelight/speedpad.png","speedpadRed":"/textures/briochelight/speedpadred.png","speedpadBlue":"/textures/briochelight/speedpadblue.png","portal":"/textures/briochelight/portal.png","portalRed":"/textures/briochelight/portalred.png","portalBlue":"/textures/briochelight/portalblue.png","splats":"/textures/briochelight/splats.png","popularity":46374492,"popularityScore":"46"},{"name":"Crystal","author":"MagicPigeon","url":"crystal","tiles":"/textures/crystal/tiles.png","speedpad":"/textures/crystal/speedpad.png","speedpadRed":"/textures/crystal/speedpadred.png","speedpadBlue":"/textures/crystal/speedpadblue.png","portal":"/textures/crystal/portal.png","portalRed":"/textures/crystal/portalred.png","portalBlue":"/textures/crystal/portalblue.png","splats":"/textures/crystal/splats.png","popularity":41009434,"popularityScore":"41"},{"name":"Bold","author":"MagicPigeon","url":"bold","tiles":"/textures/bold/tiles.png","speedpad":"/textures/bold/speedpad.png","speedpadRed":"/textures/bold/speedpadred.png","speedpadBlue":"/textures/bold/speedpadblue.png","portal":"/textures/bold/portal.png","portalRed":"/textures/bold/portalred.png","portalBlue":"/textures/bold/portalblue.png","splats":"/textures/bold/splats.png","popularity":35898990,"popularityScore":"36"},{"name":"Turbo","author":"Ooops","url":"turbo","tiles":"/textures/turbo/tiles.png","speedpad":"/textures/turbo/speedpad.png","speedpadRed":"/textures/turbo/speedpadred.png","speedpadBlue":"/textures/turbo/speedpadblue.png","portal":"/textures/turbo/portal.png","portalRed":"/textures/turbo/portalred.png","portalBlue":"/textures/turbo/portalblue.png","splats":"/textures/turbo/splats.png","popularity":35092795,"popularityScore":"35"},{"name":"Granata","author":"_Coffee_","url":"granata","tiles":"/textures/granata/tiles.png","speedpad":"/textures/granata/speedpad.png","speedpadRed":"/textures/granata/speedpadred.png","speedpadBlue":"/textures/granata/speedpadblue.png","portal":"/textures/granata/portal.png","portalRed":"/textures/granata/portalred.png","portalBlue":"/textures/granata/portalblue.png","splats":"/textures/granata/splats.png","popularity":32450816,"popularityScore":"32"},{"name":"Celeste","author":"MagicPigeon","url":"celeste","tiles":"/textures/celeste/tiles.png","speedpad":"/textures/celeste/speedpad.png","speedpadRed":"/textures/celeste/speedpadred.png","speedpadBlue":"/textures/celeste/speedpadblue.png","portal":"/textures/celeste/portal.png","portalRed":"/textures/celeste/portalred.png","portalBlue":"/textures/celeste/portalblue.png","splats":"/textures/celeste/splats.png","popularity":30547603,"popularityScore":"31"},{"name":"Brioche Deluxe","author":"Bumballbee and Brioche","url":"briochedeluxe","tiles":"/textures/briochedeluxe/tiles.png","speedpad":"/textures/briochedeluxe/speedpad.png","speedpadRed":"/textures/briochedeluxe/speedpadred.png","speedpadBlue":"/textures/briochedeluxe/speedpadblue.png","portal":"/textures/briochedeluxe/portal.png","portalRed":"/textures/briochedeluxe/portalred.png","portalBlue":"/textures/briochedeluxe/portalblue.png","splats":"/textures/briochedeluxe/splats.png","popularity":29724638,"popularityScore":"30"},{"name":"Brioche Extra Light","author":"Brioche","url":"briocheextralight","tiles":"/textures/briocheextralight/tiles.png","speedpad":"/textures/briocheextralight/speedpad.png","speedpadRed":"/textures/briocheextralight/speedpadred.png","speedpadBlue":"/textures/briocheextralight/speedpadblue.png","portal":"/textures/briocheextralight/portal.png","portalRed":"/textures/briocheextralight/portalred.png","portalBlue":"/textures/briocheextralight/portalblue.png","splats":"/textures/briocheextralight/splats.png","popularity":28923330,"popularityScore":"29"},{"name":"TagPro Next Classic","author":"KoalaBeast, MagicPigeon, Ronding","url":"tagpronextclassic","tiles":"/textures/tagpronextclassic/tiles.png","speedpad":"/textures/tagpronextclassic/speedpad.png","speedpadRed":"/textures/tagpronextclassic/speedpadred.png","speedpadBlue":"/textures/tagpronextclassic/speedpadblue.png","portal":"/textures/tagpronextclassic/portal.png","portalRed":"/textures/tagpronextclassic/portalred.png","portalBlue":"/textures/tagpronextclassic/portalblue.png","splats":"/textures/tagpronextclassic/splats.png","popularity":27984534,"popularityScore":"28"},{"name":"Flat (Bug)","author":"Bug","url":"flatbug","tiles":"/textures/flatbug/tiles.png","speedpad":"/textures/flatbug/speedpad.png","speedpadRed":"/textures/flatbug/speedpadred.png","speedpadBlue":"/textures/flatbug/speedpadblue.png","portal":"/textures/flatbug/portal.png","portalRed":"/textures/flatbug/portalred.png","portalBlue":"/textures/flatbug/portalblue.png","splats":"/textures/flatbug/splats.png","popularity":24945237,"popularityScore":"25"},{"name":"Maxima","author":"MagicPigeon","url":"maxima","tiles":"/textures/maxima/tiles.png","speedpad":"/textures/maxima/speedpad.png","speedpadRed":"/textures/maxima/speedpadred.png","speedpadBlue":"/textures/maxima/speedpadblue.png","portal":"/textures/maxima/portal.png","portalRed":"/textures/maxima/portalred.png","portalBlue":"/textures/maxima/portalblue.png","splats":"/textures/maxima/splats.png","popularity":24314189,"popularityScore":"24"},{"name":"Jello","author":"MC Ride","url":"jello","tiles":"/textures/jello/tiles.png","speedpad":"/textures/jello/speedpad.png","speedpadRed":"/textures/jello/speedpadred.png","speedpadBlue":"/textures/jello/speedpadblue.png","portal":"/textures/jello/portal.png","portalRed":"/textures/jello/portalred.png","portalBlue":"/textures/jello/portalblue.png","splats":"/textures/jello/splats.png","popularity":19824774,"popularityScore":"20"},{"name":"Chip","author":"anom","url":"chip","tiles":"/textures/chip/tiles.png","speedpad":"/textures/chip/speedpad.png","speedpadRed":"/textures/chip/speedpadred.png","speedpadBlue":"/textures/chip/speedpadblue.png","portal":"/textures/chip/portal.png","portalRed":"/textures/chip/portalred.png","portalBlue":"/textures/chip/portalblue.png","splats":"/textures/chip/splats.png","popularity":17452655,"popularityScore":"17"},{"name":"Wave","author":"Waterwheel","url":"wave","tiles":"/textures/wave/tiles.png","speedpad":"/textures/wave/speedpad.png","speedpadRed":"/textures/wave/speedpadred.png","speedpadBlue":"/textures/wave/speedpadblue.png","portal":"/textures/wave/portal.png","portalRed":"/textures/wave/portalred.png","portalBlue":"/textures/wave/portalblue.png","splats":"/textures/wave/splats.png","popularity":16795172,"popularityScore":"17"},{"name":"Mumbo","author":"MagicPigeon","url":"mumbo","tiles":"/textures/mumbo/tiles.png","speedpad":"/textures/mumbo/speedpad.png","speedpadRed":"/textures/mumbo/speedpadred.png","speedpadBlue":"/textures/mumbo/speedpadblue.png","portal":"/textures/mumbo/portal.png","portalRed":"/textures/mumbo/portalred.png","portalBlue":"/textures/mumbo/portalblue.png","splats":"/textures/mumbo/splats.png","popularity":14947784,"popularityScore":"15"},{"name":"Funko","author":"MC Ride","url":"funko","tiles":"/textures/funko/tiles.png","speedpad":"/textures/funko/speedpad.png","speedpadRed":"/textures/funko/speedpadred.png","speedpadBlue":"/textures/funko/speedpadblue.png","portal":"/textures/funko/portal.png","portalRed":"/textures/funko/portalred.png","portalBlue":"/textures/funko/portalblue.png","splats":"/textures/funko/splats.png","popularity":7612965,"popularityScore":"8"},{"name":"Ancient Gems","author":"Flaccid Trip ft. jazzz","url":"ancientgems","tiles":"/textures/ancientgems/tiles.png","speedpad":"/textures/ancientgems/speedpad.png","speedpadRed":"/textures/ancientgems/speedpadred.png","speedpadBlue":"/textures/ancientgems/speedpadblue.png","portal":"/textures/ancientgems/portal.png","portalRed":"/textures/ancientgems/portalred.png","portalBlue":"/textures/ancientgems/portalblue.png","splats":"/textures/ancientgems/splats.png","popularity":5546128,"popularityScore":"6"},{"name":"Yin & Yang","author":"_Coffee_","url":"yinyang","tiles":"/textures/yinyang/tiles.png","speedpad":"/textures/yinyang/speedpad.png","speedpadRed":"/textures/yinyang/speedpadred.png","speedpadBlue":"/textures/yinyang/speedpadblue.png","portal":"/textures/yinyang/portal.png","portalRed":"/textures/yinyang/portalred.png","portalBlue":"/textures/yinyang/portalblue.png","splats":"/textures/yinyang/splats.png","popularity":5255750,"popularityScore":"5"},{"name":"Spongepack","author":"_Coffee_","url":"spongepack","tiles":"/textures/spongepack/tiles.png","speedpad":"/textures/spongepack/speedpad.png","speedpadRed":"/textures/spongepack/speedpadred.png","speedpadBlue":"/textures/spongepack/speedpadblue.png","portal":"/textures/spongepack/portal.png","portalRed":"/textures/spongepack/portalred.png","portalBlue":"/textures/spongepack/portalblue.png","splats":"/textures/spongepack/splats.png","popularity":5125995,"popularityScore":"5"},{"name":"Xmas","author":"jazzz","url":"xmas","tiles":"/textures/xmas/tiles.png","speedpad":"/textures/xmas/speedpad.png","speedpadRed":"/textures/xmas/speedpadred.png","speedpadBlue":"/textures/xmas/speedpadblue.png","portal":"/textures/xmas/portal.png","portalRed":"/textures/xmas/portalred.png","portalBlue":"/textures/xmas/portalblue.png","splats":"/textures/xmas/splats.png","popularity":3897718,"popularityScore":"4"},{"name":"Afloat","author":"Pingu","url":"afloat","tiles":"/textures/afloat/tiles.png","speedpad":"/textures/afloat/speedpad.png","speedpadRed":"/textures/afloat/speedpadred.png","speedpadBlue":"/textures/afloat/speedpadblue.png","portal":"/textures/afloat/portal.png","portalRed":"/textures/afloat/portalred.png","portalBlue":"/textures/afloat/portalblue.png","splats":"/textures/afloat/splats.png","popularity":2873024,"popularityScore":"3"},{"name":"Twine","author":"Flaccid Trip","url":"twine","tiles":"/textures/twine/tiles.png","speedpad":"/textures/twine/speedpad.png","speedpadRed":"/textures/twine/speedpadred.png","speedpadBlue":"/textures/twine/speedpadblue.png","portal":"/textures/twine/portal.png","portalRed":"/textures/twine/portalred.png","portalBlue":"/textures/twine/portalblue.png","splats":"/textures/twine/splats.png","popularity":2340488,"popularityScore":"2"},{"name":"Bowling","author":"_Coffee_","url":"bowling","tiles":"/textures/bowling/tiles.png","speedpad":"/textures/bowling/speedpad.png","speedpadRed":"/textures/bowling/speedpadred.png","speedpadBlue":"/textures/bowling/speedpadblue.png","portal":"/textures/bowling/portal.png","portalRed":"/textures/bowling/portalred.png","portalBlue":"/textures/bowling/portalblue.png","splats":"/textures/bowling/splats.png","popularity":913939,"popularityScore":"1"},{"name":"Supreme Shine","author":"Flaccid Trip","url":"supremeshine","tiles":"/textures/supremeshine/tiles.png","speedpad":"/textures/supremeshine/speedpad.png","speedpadRed":"/textures/supremeshine/speedpadred.png","speedpadBlue":"/textures/supremeshine/speedpadblue.png","portal":"/textures/supremeshine/portal.png","portalRed":"/textures/supremeshine/portalred.png","portalBlue":"/textures/supremeshine/portalblue.png","splats":"/textures/supremeshine/splats.png","popularity":696670,"popularityScore":"1"},{"name":"Softpaint","author":"Xcissors ft. anom","url":"softpaint","tiles":"/textures/softpaint/tiles.png","speedpad":"/textures/softpaint/speedpad.png","speedpadRed":"/textures/softpaint/speedpadred.png","speedpadBlue":"/textures/softpaint/speedpadblue.png","portal":"/textures/softpaint/portal.png","portalRed":"/textures/softpaint/portalred.png","portalBlue":"/textures/softpaint/portalblue.png","splats":"/textures/softpaint/splats.png","popularity":618115,"popularityScore":"1"},{"name":"Return","author":"Flaccid Trip","url":"return","tiles":"/textures/return/tiles.png","speedpad":"/textures/return/speedpad.png","speedpadRed":"/textures/return/speedpadred.png","speedpadBlue":"/textures/return/speedpadblue.png","portal":"/textures/return/portal.png","portalRed":"/textures/return/portalred.png","portalBlue":"/textures/return/portalblue.png","splats":"/textures/return/splats.png","popularity":149148,"popularityScore":"0"}]} const wallTypes = { "787878": { wallSolids: 0xff }, "804070": { wallSolids: 0x2d }, "408050": { wallSolids: 0xd2 }, "405080": { wallSolids: 0x4b }, "807040": { wallSolids: 0xb4 } }; const quadrantCoords = { "132": [10.5, 7.5], "232": [11, 7.5], "332": [11, 8], "032": [10.5, 8], "132d": [0.5, 3.5], "232d": [1, 3.5], "032d": [0.5, 4], "143": [4.5, 9.5], "243": [5, 9.5], "343": [5, 10], "043": [4.5, 10], "143d": [1.5, 2.5], "243d": [2, 2.5], "043d": [1.5, 3], "154": [6.5, 9.5], "254": [7, 9.5], "354": [7, 10], "054": [6.5, 10], "154d": [9.5, 2.5], "254d": [10, 2.5], "354d": [10, 3], "165": [0.5, 7.5], "265": [1, 7.5], "365": [1, 8], "065": [0.5, 8], "165d": [10.5, 3.5], "265d": [11, 3.5], "365d": [11, 4], "176": [1.5, 6.5], "276": [2, 6.5], "376": [2, 7], "076": [1.5, 7], "276d": [9, 1.5], "376d": [9, 2], "076d": [8.5, 2], "107": [6.5, 8.5], "207": [7, 8.5], "307": [7, 9], "007": [6.5, 9], "207d": [11, 1.5], "307d": [11, 2], "007d": [10.5, 2], "110": [4.5, 8.5], "210": [5, 8.5], "310": [5, 9], "010": [4.5, 9], "110d": [0.5, 1.5], "310d": [1, 2], "010d": [0.5, 2], "121": [9.5, 6.5], "221": [10, 6.5], "321": [10, 7], "021": [9.5, 7], "121d": [2.5, 1.5], "321d": [3, 2], "021d": [2.5, 2], "142": [1.5, 7.5], "242": [2, 7.5], "042": [1.5, 8], "142d": [10.5, 0.5], "242d": [11, 0.5], "042d": [10.5, 1], "153": [5.5, 6.5], "253": [6, 6.5], "353": [6, 7], "053": [5.5, 7], "153d": [5.5, 0.5], "253d": [6, 0.5], "164": [9.5, 7.5], "264": [10, 7.5], "364": [10, 8], "164d": [0.5, 0.5], "264d": [1, 0.5], "364d": [1, 1], "175": [4.5, 5.5], "275": [5, 5.5], "375": [5, 6], "075": [4.5, 6], "275d": [7, 1.5], "375d": [7, 2], "206": [4.5, 9.5], "306": [4.5, 10], "006": [3.5, 10], "206d": [2, 3.5], "306d": [2, 4], "006d": [1.5, 4], "117": [5.5, 2.5], "217": [6, 2.5], "317": [6, 4], "017": [5.5, 4], "317d": [6, 3], "017d": [5.5, 3], "120": [7.5, 9.5], "320": [8, 10], "020": [7.5, 10], "120d": [9.5, 3.5], "320d": [10, 4], "020d": [9.5, 4], "131": [6.5, 5.5], "231": [7, 5.5], "331": [7, 6], "031": [6.5, 6], "131d": [4.5, 1.5], "031d": [4.5, 2], "141": [7.5, 8.5], "241": [8, 8.5], "323": [4, 5], "041": [7.5, 9], "141d": [8.5, 3.5], "041d": [8.5, 4], "152": [8.5, 7.5], "252": [9, 7.5], "334": [2, 0], "052": [8.5, 8], "152d": [3.5, 0.5], "252d": [4, 0.5], "163": [2, 7.5], "263": [3, 7.5], "363": [3, 8], "045": [9.5, 0], "163d": [7.5, 0.5], "263d": [8, 0.5], "174": [3.5, 8.5], "274": [4, 8.5], "374": [4, 9], "056": [7.5, 5], "274d": [3, 3.5], "374d": [3, 4], "167": [7.5, 6.5], "205": [10, 8.5], "305": [10, 9], "005": [9.5, 9], "205d": [2, 0.5], "305d": [2, 1], "170": [6.5, 7.5], "216": [9, 9.5], "316": [9, 10], "016": [8.5, 10], "316d": [10, 5], "016d": [9.5, 5], "127": [2.5, 9.5], "201": [5, 7.5], "327": [3, 10], "027": [2.5, 10], "327d": [2, 5], "027d": [1.5, 5], "130": [1.5, 8.5], "212": [4, 6.5], "330": [2, 9], "030": [1.5, 9], "130d": [9.5, 0.5], "030d": [9.5, 1], "151": [10.5, 9.5], "251": [11, 9.5], "324": [0, 7], "051": [10.5, 10], "151d": [10.5, 4.5], "324d": [0, 0], "162": [8.5, 10.5], "262": [9, 10.5], "335": [6, 8], "035": [5.5, 8], "162d": [3.5, 2.5], "262d": [8, 2.5], "173": [0.5, 9.5], "273": [1, 9.5], "373": [1, 10], "046": [11.5, 7], "046d": [11.5, 0], "273d": [1, 4.5], "157": [11.5, 8.5], "204": [0, 5.5], "304": [0, 5], "057": [11.5, 9], "204d": [0, 4.5], "304d": [0, 6], "160": [11.5, 7.5], "215": [8, 6.5], "315": [8, 7], "015": [7.5, 7], "160d": [2.5, 4.5], "315d": [9, 3], "171": [5.5, 10.5], "271": [6, 10.5], "326": [6, 5], "026": [5.5, 5], "326d": [7, 5], "026d": [4.5, 5], "137": [3.5, 6.5], "202": [0, 7.5], "337": [4, 7], "037": [3.5, 7], "202d": [9, 4.5], "037d": [2.5, 3], "140": [11.5, 5.5], "213": [0, 8.5], "313": [0, 9], "040": [11.5, 5], "140d": [11.5, 4.5], "040d": [11.5, 6], "161": [9.5, 10.5], "261": [10, 10.5], "325": [9, 6], "025": [8.5, 6], "161d": [3.5, 1.5], "325d": [4, 1], "172": [1.5, 10.5], "272": [2, 10.5], "336": [3, 6], "036": [2.5, 6], "036d": [7.5, 1], "272d": [8, 1.5], "147": [4.5, 7.5], "203": [4, 3.5], "303": [4, 4], "047": [4.5, 8], "047d": [8.5, 5], "203d": [8, 4.5], "150": [7.5, 3.5], "214": [7, 7.5], "314": [7, 8], "050": [7.5, 4], "150d": [3.5, 4.5], "314d": [3, 5], "100": [5.5, 5.5], "200": [6, 5.5], "300": [6, 6], "000": [5.5, 6], "100d": [5.5, 8.5], "200d": [6, 8.5], "300d": [6, 10], "000d": [5.5, 10] }; // ---------------------------- // Global Image Variables // ---------------------------- let images = { tile: null, speedpad: null, speedpadRed: null, speedpadBlue: null, portal: null, portalRed: null, portalBlue: null }; // ---------------------------- // JSON Gate Data Explanation // ---------------------------- // (See description above) // ---------------------------- let originalPNGImage = null; let mapJSONData = null; let wallMap = []; // Set currentTexturePack from localStorage if available. let currentTexturePack = textures.texturePacks[0]; const savedTexture = localStorage.getItem('fm_selected_texturePack'); if (savedTexture) { const found = textures.texturePacks.find(tp => tp.url === savedTexture); if (found) { currentTexturePack = found; console.log("[FM] Loaded saved texture pack:", currentTexturePack.name); } } // ---------------------------- // Utility: waitForElement // ---------------------------- function waitForElement(selector, callback, timeout = 10000) { const start = Date.now(); (function check() { const el = document.querySelector(selector); if (el) { console.log(`[FM] Found element for selector "${selector}"`); callback(el); } else if (Date.now() - start > timeout) { console.warn(`[FM] Timeout waiting for element: ${selector}`); } else { setTimeout(check, 200); } })(); } // ---------------------------- // Utility Functions // ---------------------------- function rgbToHex(r, g, b) { return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); } // loadImage prepends baseUrl if needed. function loadImage(url) { if (url.startsWith("/")) { url = baseUrl + url; } return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = "anonymous"; img.onload = () => { console.log(`[FM] Loaded image: ${url}`); resolve(img); }; img.onerror = (e) => { console.error(`[FM] Error loading image: ${url}`, e); reject(e); }; img.src = url; }); } function getFloorTile(key) { if (key === "ffff00") { return { image: images.speedpad, y: 0, x: 0 }; } else if (key === "ff7373") { return { image: images.speedpadRed, y: 0, x: 0 }; } else if (key === "7373ff") { return { image: images.speedpadBlue, y: 0, x: 0 }; } else if (key === "cac000") { return { image: images.portal, x: 0, y: 0 }; } else if (key === "cc3300") { return { image: images.portalRed, x: 0, y: 0 }; } else if (key === "0066cc") { return { image: images.portalBlue, x: 0, y: 0 }; } else if (floorTiles.hasOwnProperty(key)) { return { image: images.tile, x: floorTiles[key].x, y: floorTiles[key].y }; } else { return null; } } function wallSolidsAt(col, row) { if (col < 0 || row < 0 || row >= wallMap.length || col >= wallMap[0].length) return 0; return wallMap[row][col]; } function drawWallTile(ctx, col, row) { const solids = wallMap[row][col]; if (!solids) return; for (let q = 0; q < 4; q++) { const mask = (solids >> (q << 1)) & 3; if (mask === 0) continue; const cornerX = col + ((q & 2) === 0 ? 1 : 0); const cornerY = row + (((q + 1) & 2) === 0 ? 0 : 1); let aroundCorner = (wallSolidsAt(cornerX, cornerY) & 0xc0) | (wallSolidsAt(cornerX - 1, cornerY) & 0x03) | (wallSolidsAt(cornerX - 1, cornerY - 1) & 0x0c) | (wallSolidsAt(cornerX, cornerY - 1) & 0x30); aroundCorner |= (aroundCorner << 8); const startDirection = q * 2 + 1; let cwSteps = 0; while (cwSteps < 8 && (aroundCorner & (1 << (startDirection + cwSteps)))) { cwSteps++; } let ccwSteps = 0; while (ccwSteps < 8 && (aroundCorner & (1 << (startDirection + 7 - ccwSteps)))) { ccwSteps++; } const hasChip = (mask === 3 && (((solids | (solids << 8)) >> ((q + 2) << 1)) & 3) === 0); let solidStart, solidEnd; if (cwSteps === 8) { solidStart = solidEnd = 0; } else { solidEnd = (startDirection + cwSteps + 4) % 8; solidStart = (startDirection - ccwSteps + 12) % 8; } const key = `${q}${solidStart}${solidEnd}${hasChip ? "d" : ""}`; const coords = quadrantCoords[key] || [5.5, 5.5]; let destX = col * config.tileSize; let destY = row * config.tileSize; if (q === 0) destX += config.quadSize; else if (q === 1) { destX += config.quadSize; destY += config.quadSize; } else if (q === 2) destY += config.quadSize; const srcX = coords[0] * 40; const srcY = coords[1] * 40; ctx.drawImage(images.tile, srcX, srcY, config.quadSize, config.quadSize, destX, destY, config.quadSize, config.quadSize); } } function fetchMapData(mapCode) { const pngURL = `https://fortunatemaps.herokuapp.com/png/${mapCode}.png`; const jsonURL = `https://fortunatemaps.herokuapp.com/json/${mapCode}.json`; console.log(`[FM] Fetching map data for code: ${mapCode}`); return Promise.all([ fetch(pngURL) .then(res => res.blob()) .then(blob => { console.log("[FM] PNG fetched successfully"); return URL.createObjectURL(blob); }), fetch(jsonURL) .then(res => res.json()) .then(json => { console.log("[FM] JSON fetched successfully:", json); return json; }) ]); } async function processMap() { if (!originalPNGImage) return; console.log("[FM] Starting map processing..."); try { images.tile = await loadImage(currentTexturePack.tiles); images.speedpad = await loadImage(currentTexturePack.speedpad); images.speedpadRed = await loadImage(currentTexturePack.speedpadRed); images.speedpadBlue = await loadImage(currentTexturePack.speedpadBlue); images.portal = await loadImage(currentTexturePack.portal); images.portalRed = await loadImage(currentTexturePack.portalRed); images.portalBlue = await loadImage(currentTexturePack.portalBlue); } catch(e) { console.error("[FM] Error loading texture images", e); return; } console.log("[FM] All texture images loaded"); const offCanvas = document.createElement('canvas'); offCanvas.width = originalPNGImage.width; offCanvas.height = originalPNGImage.height; const offCtx = offCanvas.getContext('2d'); offCtx.drawImage(originalPNGImage, 0, 0); console.log("[FM] Offscreen canvas drawn"); const imageData = offCtx.getImageData(0, 0, offCanvas.width, offCanvas.height); const data = imageData.data; wallMap = []; for (let y = 0; y < offCanvas.height; y++) { wallMap[y] = []; for (let x = 0; x < offCanvas.width; x++) { const idx = (y * offCanvas.width + x) * 4; const r = data[idx], g = data[idx + 1], b = data[idx + 2], a = data[idx + 3]; const hex = rgbToHex(r, g, b).toLowerCase(); wallMap[y][x] = (a === 0) ? 0 : (wallTypes.hasOwnProperty(hex) ? wallTypes[hex].wallSolids : 0); } } console.log("[FM] wallMap built:", wallMap); const finalCanvas = document.createElement('canvas'); finalCanvas.width = offCanvas.width * config.tileSize; finalCanvas.height = offCanvas.height * config.tileSize; const finalCtx = finalCanvas.getContext('2d'); finalCtx.imageSmoothingEnabled = false; console.log("[FM] Final canvas created"); const defaultFloorTile = getFloorTile("d4d4d4"); if (defaultFloorTile) { const sx = defaultFloorTile.x * config.tileSize; const sy = defaultFloorTile.y * config.tileSize; for (let y = 0; y < offCanvas.height; y++) { for (let x = 0; x < offCanvas.width; x++) { finalCtx.drawImage(defaultFloorTile.image, sx, sy, config.tileSize, config.tileSize, x * config.tileSize, y * config.tileSize, config.tileSize, config.tileSize); } } } for (let y = 0; y < offCanvas.height; y++) { for (let x = 0; x < offCanvas.width; x++) { const idx = (y * offCanvas.width + x) * 4; const r = data[idx], g = data[idx + 1], b = data[idx + 2], a = data[idx + 3]; if (a === 0) continue; const hex = rgbToHex(r, g, b).toLowerCase(); if (wallTypes.hasOwnProperty(hex)) continue; let tileSource = null; if (hex === "007500") { const fieldKey = `${x},${y}`; let state = "empty"; // Default state remains "empty" if (mapJSONData && mapJSONData.fields && mapJSONData.fields[fieldKey]) { let ds = mapJSONData.fields[fieldKey].defaultState; if (ds === "on") { state = "green"; } else if (ds === "off") { state = "empty"; // Change "off" to "empty" } else { state = ds; } } const tileKey = "007500_" + state; tileSource = getFloorTile(tileKey); } else { tileSource = getFloorTile(hex); } if (tileSource) { const sx = tileSource.x * config.tileSize; const sy = tileSource.y * config.tileSize; finalCtx.drawImage(tileSource.image, sx, sy, config.tileSize, config.tileSize, x * config.tileSize, y * config.tileSize, config.tileSize, config.tileSize); } else { finalCtx.fillStyle = "#000000"; finalCtx.fillRect(x * config.tileSize, y * config.tileSize, config.tileSize, config.tileSize); } } } console.log("[FM] Floor and gate tiles drawn"); for (let y = 0; y < wallMap.length; y++) { for (let x = 0; x < wallMap[0].length; x++) { if (wallMap[y][x] !== 0) { drawWallTile(finalCtx, x, y); } } } console.log("[FM] Wall tiles overlaid"); // Marsball rendering: // For each marsball in the JSON, draw an 80x80 image from the tiles texture (source: 12*40, 9*40) // Now centered over the tile instead of having its top-left corner at the tile's top-left. if (mapJSONData && mapJSONData.marsballs) { mapJSONData.marsballs.forEach(mars => { // Calculate destination so the marsball is centered over the tile. const destX = mars.x * config.tileSize - config.tileSize/2; const destY = mars.y * config.tileSize - config.tileSize/2; finalCtx.drawImage( images.tile, 12 * config.tileSize, 9 * config.tileSize, 2 * config.tileSize, 2 * config.tileSize, destX, destY, 2 * config.tileSize, 2 * config.tileSize ); }); console.log("[FM] Marsballs drawn"); } waitForElement('img.card-img-top', function(previewImg) { previewImg.src = finalCanvas.toDataURL(); console.log("[FM] Preview image updated"); }); } // ---------------------------- // UI: Texture Pack Dropdown with Search & Scrollbar // ---------------------------- function addTextureDropdown() { const referenceDiv = document.querySelector('main.container div.row.mb-2 div.col-md-4 div.card.stats-card div.card-body div.dropdown.w-100.mt-2'); if (!referenceDiv) { console.error("[FM] Reference dropdown not found"); return; } const textureContainerHTML = ` <div id="fm-texture-container"> <div class="dropdown w-100 mt-2" id="fm-texture-dropdown"> <button class="btn btn-primary w-100 dropdown-toggle" type="button" id="fm-dropdown-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> ${currentTexturePack.name} </button> <div class="dropdown-menu" aria-labelledby="fm-dropdown-button" style="max-height: 200px; overflow-y: auto; padding: 0.5rem;"> <div class="px-2"> <input type="text" id="fm-dropdown-search" class="form-control form-control-sm" placeholder="Search Texture Packs..."> </div> <div id="fm-dropdown-items"> ${textures.texturePacks.map(tp => `<a class="dropdown-item" href="#" data-value="${tp.url}">${tp.name}</a>`).join('')} </div> </div> </div> </div> `; referenceDiv.insertAdjacentHTML('afterend', textureContainerHTML); console.log("[FM] Texture pack dropdown container inserted directly below the reference dropdown"); function filterItems() { const query = document.getElementById('fm-dropdown-search').value.toLowerCase(); const items = document.querySelectorAll('#fm-dropdown-items .dropdown-item'); items.forEach(item => { const text = item.textContent.toLowerCase(); item.style.display = text.indexOf(query) > -1 ? "" : "none"; }); } const searchInput = document.getElementById('fm-dropdown-search'); searchInput.addEventListener('input', filterItems); const items = document.querySelectorAll('#fm-dropdown-items .dropdown-item'); items.forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); const selectedUrl = this.getAttribute('data-value'); const selectedTexture = textures.texturePacks.find(tp => tp.url === selectedUrl); if (selectedTexture && selectedTexture.url !== currentTexturePack.url) { currentTexturePack = selectedTexture; localStorage.setItem('fm_selected_texturePack', selectedTexture.url); console.log("[FM] Texture pack changed to:", selectedTexture.name); processMap(); document.getElementById('fm-dropdown-button').textContent = selectedTexture.name; } }); }); } // ---------------------------- // Main Execution // ---------------------------- function main() { console.log("[FM] Main execution started"); const mapCodeMatch = window.location.href.match(/\/map\/(\d+)/); if (!mapCodeMatch) { console.error("[FM] No map code found in URL"); return; } const mapCode = mapCodeMatch[1]; console.log("[FM] Map code:", mapCode); fetchMapData(mapCode) .then(([pngObjectUrl, jsonData]) => { mapJSONData = jsonData; console.log("[FM] Map JSON data stored"); return loadImage(pngObjectUrl); }) .then(img => { originalPNGImage = img; console.log("[FM] Original PNG loaded"); processMap(); }) .catch(err => console.error("[FM] Error fetching or processing map data:", err)); addTextureDropdown(); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", main); } else { main(); } })();