krz/micro-roguelike

A micro roguelike web game in 1kb and 1mb versions.

clone: git clone https://gitbay.org/krz/micro-roguelike.git

main: 1mb/data.js · raw

   1// Game data — edit this file to mod the run (floors, relics, hazards, balance).
   2// Loaded before the engine in index.html.
   3const W=12,H=12,FUEL=16
   4const BEAST_CALM_RADIUS=4,BEAST_ENRAGED_SPEED=2,TORCH_DRAIN_BASE=1,TORCH_DRAIN_HAZARD=2,RELIC_SLOTS_LOW=2,RELIC_SLOTS_MID=3,RELIC_SLOTS_HIGH=4,RELIC_SLOTS_RICH_BONUS=1
   5const P={g:[5,2],b:[2,2],e:[2,9],h:[2,9],p:[2,2],i:[2,2],c:[2,2],v:[2,2],d:[2,2]}
   6const PITS=[[
   7"############",
   8"#OOOOOOOOOO#",
   9"#O....F...O#",
  10"#O...OO...O#",
  11"#O........O#",
  12"#O....>...O#",
  13"#O........O#",
  14"#O...OO...O#",
  15"#O........O#",
  16"#O........O#",
  17"#OOOOOOOOOO#",
  18"############"],[
  19"############",
  20"#OOOOOOOOOO#",
  21"#O.......OO#",
  22"#O.OOOOO..O#",
  23"#O.......OO#",
  24"#O..>.....O#",
  25"#O....F...O#",
  26"#O..OOOOO.O#",
  27"#O........O#",
  28"#O........O#",
  29"#OOOOOOOOOO#",
  30"############"],[
  31"############",
  32"#OOOOOOOOOO#",
  33"#O........O#",
  34"#O..OO....O#",
  35"#O........O#",
  36"#OF....>..O#",
  37"#O....OO..O#",
  38"#O........O#",
  39"#O..OO....O#",
  40"#O........O#",
  41"#OOOOOOOOOO#",
  42"############"]]
  43const IDOLS=[[
  44"############",
  45"#..........#",
  46"#...ggg....#",
  47"#...gIg....#",
  48"#...ggg....#",
  49"#..........#",
  50"#..........#",
  51"#..........#",
  52"#..........#",
  53"#..........#",
  54"#....>.....#",
  55"############"],[
  56"############",
  57"#..........#",
  58"#....gg....#",
  59"#...gIg....#",
  60"#....ggg...#",
  61"#..........#",
  62"#..........#",
  63"#..........#",
  64"#..........#",
  65"#..........#",
  66"#....>.....#",
  67"############"],[
  68"############",
  69"#..........#",
  70"#...gg.....#",
  71"#...gIgg...#",
  72"#.....gg...#",
  73"#..........#",
  74"#..........#",
  75"#..........#",
  76"#..........#",
  77"#..........#",
  78"#....>.....#",
  79"############"]]
  80const IDOLS2=[[
  81"############",
  82"#..........#",
  83"#..ggg.....#",
  84"#..gIgg....#",
  85"#....gg....#",
  86"#..........#",
  87"#.....#....#",
  88"#..........#",
  89"#..........#",
  90"#..........#",
  91"#...>......#",
  92"############"],[
  93"############",
  94"#..........#",
  95"#....ggg...#",
  96"#...ggIg...#",
  97"#....gg....#",
  98"#..........#",
  99"#..........#",
 100"#....#.....#",
 101"#..........#",
 102"#..........#",
 103"#.....>....#",
 104"############"],[
 105"############",
 106"#..........#",
 107"#...gg.....#",
 108"#..ggIg....#",
 109"#...gg.....#",
 110"#..........#",
 111"#..........#",
 112"#.....#....#",
 113"#..........#",
 114"#..........#",
 115"#....>.....#",
 116"############"]]
 117const CRACKS=[[
 118"############",
 119"#..........#",
 120"#.####.....#",
 121"#....#.....#",
 122"#..x.>.....#",
 123"#....#.....#",
 124"#....#.....#",
 125"#..........#",
 126"#..........#",
 127"#..........#",
 128"#..........#",
 129"############"],[
 130"############",
 131"#..........#",
 132"#.....####.#",
 133"#.....#....#",
 134"#.....#....#",
 135"#...x.>....#",
 136"#.....#....#",
 137"#.....####.#",
 138"#..........#",
 139"#..........#",
 140"#..........#",
 141"############"],[
 142"############",
 143"#..........#",
 144"#..######..#",
 145"#.......#..#",
 146"#...x...#..#",
 147"#....>..#..#",
 148"#.......#..#",
 149"#..######..#",
 150"#..........#",
 151"#..........#",
 152"#..........#",
 153"############"]]
 154const HALLS=[[
 155"############",
 156"#..........#",
 157"#..a.......#",
 158"#......b...#",
 159"#..........#",
 160"#....c.....#",
 161"#......d...#",
 162"#..........#",
 163"#....F.....#",
 164"#....>.....#",
 165"#..........#",
 166"############"],[
 167"############",
 168"#..........#",
 169"#......b...#",
 170"#..........#",
 171"#..a.......#",
 172"#..........#",
 173"#....c..d..#",
 174"#..........#",
 175"#..F.>.....#",
 176"#..........#",
 177"#..........#",
 178"############"],[
 179"############",
 180"#..........#",
 181"#..a....b..#",
 182"#..........#",
 183"#..........#",
 184"#....c..F..#",
 185"#..........#",
 186"#......d...#",
 187"#..........#",
 188"#....>.....#",
 189"#..........#",
 190"############"]]
 191const ESCAPES=[[
 192"############",
 193"#..........#",
 194"#..........#",
 195"#..........#",
 196"#..........#",
 197"#....>.....#",
 198"#..........#",
 199"#..........#",
 200"#..........#",
 201"#..........#",
 202"#..........#",
 203"############"],[
 204"############",
 205"#..........#",
 206"#..........#",
 207"#...##.....#",
 208"#......>...#",
 209"#..........#",
 210"#.....##...#",
 211"#..........#",
 212"#..........#",
 213"#..........#",
 214"#..........#",
 215"############"],[
 216"############",
 217"#..........#",
 218"#....##....#",
 219"#..........#",
 220"#..........#",
 221"#..>.......#",
 222"#.......##.#",
 223"#..........#",
 224"#..........#",
 225"#..........#",
 226"#..........#",
 227"############"]]
 228const BEASTS=[[10,8],[9,7]]
 229const PITS2=[[
 230"############",
 231"#OOOOOOOOOO#",
 232"#O..FOOO..O#",
 233"#O...OO...O#",
 234"#O........O#",
 235"#O...O>O..O#",
 236"#O........O#",
 237"#O...OO...O#",
 238"#O..OOOO..O#",
 239"#O........O#",
 240"#OOOOOOOOOO#",
 241"############"],[
 242"############",
 243"#OOOOOOOOOO#",
 244"#O......OOO#",
 245"#O.OOOOO..O#",
 246"#O....O...O#",
 247"#O..O>O...O#",
 248"#O....F...O#",
 249"#O..OOOOO.O#",
 250"#O....O...O#",
 251"#O........O#",
 252"#OOOOOOOOOO#",
 253"############"],[
 254"############",
 255"#OOOOOOOOOO#",
 256"#O....O...O#",
 257"#O..OOO...O#",
 258"#O........O#",
 259"#OF..O.>..O#",
 260"#O....OOO.O#",
 261"#O........O#",
 262"#O..OOO...O#",
 263"#O....O...O#",
 264"#OOOOOOOOOO#",
 265"############"],[
 266"############",
 267"#OOOOOOOOOO#",
 268"#O..F.....O#",
 269"#O.OOOO...O#",
 270"#O.....O..O#",
 271"#O..>.OO..O#",
 272"#O.....O..O#",
 273"#O...OOOO.O#",
 274"#O........O#",
 275"#O........O#",
 276"#OOOOOOOOOO#",
 277"############"]]
 278const CRACKS2=[[
 279"############",
 280"#.....x....#",
 281"#.#####....#",
 282"#....##....#",
 283"#..x.>#....#",
 284"#....##....#",
 285"#....##....#",
 286"#.....x....#",
 287"#..........#",
 288"#..........#",
 289"#..........#",
 290"############"],[
 291"############",
 292"#....x.....#",
 293"#.....####.#",
 294"#....##....#",
 295"#....##....#",
 296"#...x.>....#",
 297"#....##....#",
 298"#.....####.#",
 299"#....x.....#",
 300"#..........#",
 301"#..........#",
 302"############"],[
 303"############",
 304"#....x.....#",
 305"#..######..#",
 306"#.... ..#..#",
 307"#...x...#..#",
 308"#..x.>..#..#",
 309"#.......#..#",
 310"#..######..#",
 311"#....x.....#",
 312"#..........#",
 313"#..........#",
 314"############"]].map(m=>m.map(r=>r.replace(/ /g,".")))
 315const HALLS2=[[
 316"############",
 317"#..........#",
 318"#..a...b...#",
 319"#..........#",
 320"#....F.....#",
 321"#....c.....#",
 322"#......d...#",
 323"#..........#",
 324"#....>.....#",
 325"#..........#",
 326"#..........#",
 327"############"],[
 328"############",
 329"#..........#",
 330"#....b.....#",
 331"#..a.......#",
 332"#....F.....#",
 333"#....c..d..#",
 334"#..........#",
 335"#....>.....#",
 336"#..........#",
 337"#..........#",
 338"#..........#",
 339"############"],[
 340"############",
 341"#..........#",
 342"#..a....b..#",
 343"#....F.....#",
 344"#..........#",
 345"#....c.....#",
 346"#......d...#",
 347"#..........#",
 348"#....>.....#",
 349"#..........#",
 350"#..........#",
 351"############"]]
 352const ESCAPES2=[[
 353"############",
 354"#....##....#",
 355"#..........#",
 356"#..........#",
 357"#...>......#",
 358"#..........#",
 359"#..##......#",
 360"#..........#",
 361"#......##..#",
 362"#..........#",
 363"#..........#",
 364"############"],[
 365"############",
 366"#..........#",
 367"#...##.....#",
 368"#..........#",
 369"#..>.......#",
 370"#..........#",
 371"#.....##...#",
 372"#..........#",
 373"#..........#",
 374"#..........#",
 375"#..........#",
 376"############"],[
 377"############",
 378"#..........#",
 379"#..##......#",
 380"#..........#",
 381"#..>....##.#",
 382"#..........#",
 383"#......##..#",
 384"#..........#",
 385"#..........#",
 386"#..........#",
 387"#..........#",
 388"############"]]
 389const BEASTS2=[[9,8],[9,7],[10,7]]
 390const PITS3=[[
 391"############",
 392"#OOOOOOOOOO#",
 393"#O..SFOO..O#",
 394"#O...OO...O#",
 395"#O........O#",
 396"#O...O>O..O#",
 397"#O........O#",
 398"#O...OO...O#",
 399"#O..OOOO..O#",
 400"#O........O#",
 401"#OOOOOOOOOO#",
 402"############"],[
 403"############",
 404"#OOOOOOOOOO#",
 405"#O.....SOOO#",
 406"#O.OOOOO..O#",
 407"#O....O...O#",
 408"#O..O>O...O#",
 409"#O....F...O#",
 410"#O..OOOOO.O#",
 411"#O....O...O#",
 412"#O........O#",
 413"#OOOOOOOOOO#",
 414"############"],[
 415"############",
 416"#OOOOOOOOOO#",
 417"#O....O...O#",
 418"#O..OOO...O#",
 419"#O....S...O#",
 420"#OF..O.>..O#",
 421"#O....OOO.O#",
 422"#O........O#",
 423"#O..OOO...O#",
 424"#O....O...O#",
 425"#OOOOOOOOOO#",
 426"############"],[
 427"############",
 428"#OOOOOOOOOO#",
 429"#O..S.O...O#",
 430"#O..OOO...O#",
 431"#O........O#",
 432"#O...O.>..O#",
 433"#O....OOO.O#",
 434"#O....F...O#",
 435"#O..OOO...O#",
 436"#O....O...O#",
 437"#OOOOOOOOOO#",
 438"############"]]
 439const IDOLS3=[[
 440"############",
 441"#..........#",
 442"#..ggg.....#",
 443"#..gISg....#",
 444"#....gg....#",
 445"#..........#",
 446"#.....#....#",
 447"#..........#",
 448"#..........#",
 449"#..........#",
 450"#...>......#",
 451"############"],[
 452"############",
 453"#..........#",
 454"#....ggg...#",
 455"#...gSIg...#",
 456"#....gg....#",
 457"#..........#",
 458"#..........#",
 459"#....#.....#",
 460"#..........#",
 461"#..........#",
 462"#.....>....#",
 463"############"],[
 464"############",
 465"#..........#",
 466"#...gg.....#",
 467"#..gSIg....#",
 468"#...gg.....#",
 469"#..........#",
 470"#..........#",
 471"#.....#....#",
 472"#..........#",
 473"#..........#",
 474"#....>.....#",
 475"############"]]
 476const CRACKS3=[[
 477"############",
 478"#....Sx....#",
 479"#.#####....#",
 480"#....##....#",
 481"#..x.>#....#",
 482"#....##....#",
 483"#....##....#",
 484"#.....x....#",
 485"#..........#",
 486"#..........#",
 487"#..........#",
 488"############"],[
 489"############",
 490"#....x.....#",
 491"#...S.####.#",
 492"#....##....#",
 493"#....##....#",
 494"#...x.>....#",
 495"#....##....#",
 496"#.....####.#",
 497"#....x.....#",
 498"#..........#",
 499"#..........#",
 500"############"],[
 501"############",
 502"#....x.....#",
 503"#..######..#",
 504"#....S..#..#",
 505"#...x...#..#",
 506"#..x.>..#..#",
 507"#.......#..#",
 508"#..######..#",
 509"#....x.....#",
 510"#..........#",
 511"#..........#",
 512"############"]]
 513const HALLS3=[[
 514"############",
 515"#..........#",
 516"#..a..S.b..#",
 517"#..........#",
 518"#....F.....#",
 519"#....c.....#",
 520"#......d...#",
 521"#..........#",
 522"#....>.....#",
 523"#..........#",
 524"#..........#",
 525"############"],[
 526"############",
 527"#..........#",
 528"#....b..S..#",
 529"#..a.......#",
 530"#....F.....#",
 531"#....c..d..#",
 532"#..........#",
 533"#....>.....#",
 534"#..........#",
 535"#..........#",
 536"#..........#",
 537"############"],[
 538"############",
 539"#..........#",
 540"#..a....b..#",
 541"#....F..S..#",
 542"#..........#",
 543"#....c.....#",
 544"#......d...#",
 545"#..........#",
 546"#....>.....#",
 547"#..........#",
 548"#..........#",
 549"############"],[
 550"############",
 551"#..........#",
 552"#..a..S.b..#",
 553"#....F.....#",
 554"#..........#",
 555"#....c.....#",
 556"#......d...#",
 557"#..........#",
 558"#....>..F..#",
 559"#..........#",
 560"#..........#",
 561"############"]]
 562const ESCAPES3=[[
 563"############",
 564"#....##....#",
 565"#..........#",
 566"#....S.....#",
 567"#...>......#",
 568"#..........#",
 569"#..##......#",
 570"#..........#",
 571"#......##..#",
 572"#..........#",
 573"#..........#",
 574"############"],[
 575"############",
 576"#..........#",
 577"#...##.....#",
 578"#....S.....#",
 579"#....>.....#",
 580"#..........#",
 581"#.....##...#",
 582"#..........#",
 583"#..##......#",
 584"#..........#",
 585"#..........#",
 586"############"],[
 587"############",
 588"#..........#",
 589"#..##......#",
 590"#....S.....#",
 591"#..>....##.#",
 592"#..........#",
 593"#......##..#",
 594"#..........#",
 595"#..........#",
 596"#..........#",
 597"#..........#",
 598"############"],[
 599"############",
 600"#....##....#",
 601"#..........#",
 602"#..S.......#",
 603"#....>.....#",
 604"#..........#",
 605"#..##..S...#",
 606"#..........#",
 607"#......##..#",
 608"#..........#",
 609"#..........#",
 610"############"]]
 611const BEASTS3=[[9,8],[9,7],[9,6],[10,7]]
 612const ESCAPES4=[[
 613"############",
 614"#....##....#",
 615"#....S.....#",
 616"#..........#",
 617"#...>......#",
 618"#..........#",
 619"#..##......#",
 620"#......S...#",
 621"#......##..#",
 622"#..........#",
 623"#..........#",
 624"############"],[
 625"############",
 626"#..........#",
 627"#...##.....#",
 628"#....S.....#",
 629"#..>.......#",
 630"#..........#",
 631"#.....##...#",
 632"#.....S....#",
 633"#..........#",
 634"#..........#",
 635"#..........#",
 636"############"],[
 637"############",
 638"#..........#",
 639"#..##......#",
 640"#....S.....#",
 641"#..>....##.#",
 642"#..........#",
 643"#......##..#",
 644"#.....S....#",
 645"#..........#",
 646"#..........#",
 647"#..........#",
 648"############"],[
 649"############",
 650"#....##....#",
 651"#..........#",
 652"#..S.......#",
 653"#....>.....#",
 654"#..........#",
 655"#..##..S...#",
 656"#..........#",
 657"#......##..#",
 658"#..........#",
 659"#..........#",
 660"############"]]
 661const BEASTS4=[[9,8],[10,8],[9,7],[10,7]]
 662const PITS4=[[
 663"############",
 664"#OOOOOOOOOO#",
 665"#O..SFOO..O#",
 666"#O.O.OO...O#",
 667"#O........O#",
 668"#O..OO>O..O#",
 669"#O........O#",
 670"#O...OO...O#",
 671"#O..OOOO..O#",
 672"#O........O#",
 673"#OOOOOOOOOO#",
 674"############"],[
 675"############",
 676"#OOOOOOOOOO#",
 677"#O....SO..O#",
 678"#O.OOOOO..O#",
 679"#O....O...O#",
 680"#O..O>O...O#",
 681"#O....F...O#",
 682"#O..OOOOO.O#",
 683"#O....O...O#",
 684"#O........O#",
 685"#OOOOOOOOOO#",
 686"############"],[
 687"############",
 688"#OOOOOOOOOO#",
 689"#O....O...O#",
 690"#O..OOO...O#",
 691"#O....S...O#",
 692"#OF..O.>..O#",
 693"#O....OOO.O#",
 694"#O........O#",
 695"#O..OOO...O#",
 696"#O....O...O#",
 697"#OOOOOOOOOO#",
 698"############"],[
 699"############",
 700"#OOOOOOOOOO#",
 701"#O..F.O...O#",
 702"#O..OOO...O#",
 703"#O....S...O#",
 704"#O...O.>..O#",
 705"#O....OOO.O#",
 706"#O........O#",
 707"#O..OOO...O#",
 708"#O....O...O#",
 709"#OOOOOOOOOO#",
 710"############"]]
 711const IDOLS4=[[
 712"############",
 713"#..........#",
 714"#..ggg.....#",
 715"#..gISg....#",
 716"#...Sgg....#",
 717"#..........#",
 718"#.....#....#",
 719"#..........#",
 720"#..........#",
 721"#..........#",
 722"#...>......#",
 723"############"],[
 724"############",
 725"#..........#",
 726"#....ggg...#",
 727"#...gSIg...#",
 728"#....gg....#",
 729"#....S.....#",
 730"#..........#",
 731"#....#.....#",
 732"#..........#",
 733"#..........#",
 734"#.....>....#",
 735"############"],[
 736"############",
 737"#..........#",
 738"#...gg.....#",
 739"#..gSIg....#",
 740"#...gg..S..#",
 741"#..........#",
 742"#..........#",
 743"#.....#....#",
 744"#..........#",
 745"#..........#",
 746"#....>.....#",
 747"############"]]
 748const CRACKS4=[[
 749"############",
 750"#....Sx....#",
 751"#.#####....#",
 752"#....##....#",
 753"#..x.>#....#",
 754"#....##....#",
 755"#....##....#",
 756"#..x.......#",
 757"#..........#",
 758"#..........#",
 759"#..........#",
 760"############"],[
 761"############",
 762"#....x.....#",
 763"#...S.####.#",
 764"#....##....#",
 765"#....##....#",
 766"#..xx.>....#",
 767"#....##....#",
 768"#.....####.#",
 769"#....x.....#",
 770"#..........#",
 771"#..........#",
 772"############"],[
 773"############",
 774"#....x.....#",
 775"#..######..#",
 776"#....S..#..#",
 777"#...x...#..#",
 778"#..x.>..#..#",
 779"#...x...#..#",
 780"#..######..#",
 781"#....x.....#",
 782"#..........#",
 783"#..........#",
 784"############"],[
 785"############",
 786"#..S.x.....#",
 787"#..######..#",
 788"#.......#..#",
 789"#..xx...#..#",
 790"#....>..#..#",
 791"#.......#..#",
 792"#..######..#",
 793"#....x.....#",
 794"#..........#",
 795"#..........#",
 796"############"]]
 797const HALLS4=[[
 798"############",
 799"#..........#",
 800"#..a..S.b..#",
 801"#..........#",
 802"#....F.....#",
 803"#....c.....#",
 804"#......d...#",
 805"#.....S....#",
 806"#....>.....#",
 807"#..........#",
 808"#..........#",
 809"############"],[
 810"############",
 811"#..........#",
 812"#....b..S..#",
 813"#..a.......#",
 814"#....F.....#",
 815"#....c..d..#",
 816"#.....S....#",
 817"#....>.....#",
 818"#..........#",
 819"#..........#",
 820"#..........#",
 821"############"],[
 822"############",
 823"#..........#",
 824"#..a....b..#",
 825"#....F..S..#",
 826"#..........#",
 827"#....c.....#",
 828"#......d...#",
 829"#.....S....#",
 830"#....>.....#",
 831"#..........#",
 832"#..........#",
 833"############"],[
 834"############",
 835"#..........#",
 836"#..a..S.b..#",
 837"#....F.....#",
 838"#..........#",
 839"#....c.....#",
 840"#...S..d...#",
 841"#..........#",
 842"#....>..F..#",
 843"#..........#",
 844"#..........#",
 845"############"]]
 846const ESCAPES5=[[
 847"############",
 848"#....##....#",
 849"#....S.....#",
 850"#..........#",
 851"#...>......#",
 852"#..........#",
 853"#..##......#",
 854"#..........#",
 855"#......##..#",
 856"#....S.....#",
 857"#..........#",
 858"############"],[
 859"############",
 860"#..........#",
 861"#...##.....#",
 862"#....S.....#",
 863"#..>.......#",
 864"#..........#",
 865"#.....##...#",
 866"#....S.....#",
 867"#..........#",
 868"#..........#",
 869"#..........#",
 870"############"],[
 871"############",
 872"#..........#",
 873"#..##......#",
 874"#....S.....#",
 875"#..>....##.#",
 876"#..........#",
 877"#......##..#",
 878"#....S.....#",
 879"#..........#",
 880"#..........#",
 881"#..........#",
 882"############"],[
 883"############",
 884"#....##....#",
 885"#..........#",
 886"#..S.......#",
 887"#....>.....#",
 888"#..........#",
 889"#..##..S...#",
 890"#..........#",
 891"#......##..#",
 892"#....S.....#",
 893"#..........#",
 894"############"]]
 895const BEASTS5=[[10,8],[10,7],[9,7],[9,6]]
 896const ESCAPES6=[[
 897"############",
 898"#....##....#",
 899"#....S.....#",
 900"#..........#",
 901"#...>......#",
 902"#....S.....#",
 903"#..##......#",
 904"#......S...#",
 905"#......##..#",
 906"#..........#",
 907"#..........#",
 908"############"],[
 909"############",
 910"#..........#",
 911"#...##.....#",
 912"#....S.....#",
 913"#..>.......#",
 914"#.....S....#",
 915"#.....##...#",
 916"#.....S....#",
 917"#..........#",
 918"#..........#",
 919"#..........#",
 920"############"],[
 921"############",
 922"#..........#",
 923"#..##......#",
 924"#....S.....#",
 925"#..>....##.#",
 926"#.....S....#",
 927"#......##..#",
 928"#.....S....#",
 929"#..........#",
 930"#..........#",
 931"#..........#",
 932"############"],[
 933"############",
 934"#....##....#",
 935"#....S.....#",
 936"#..S.......#",
 937"#....>.....#",
 938"#..........#",
 939"#..##..S...#",
 940"#..........#",
 941"#......##..#",
 942"#..........#",
 943"#..........#",
 944"############"]]
 945const BEASTS6=[[10,8],[10,7],[9,7],[10,6]]
 946const LEVEL_ORDER=[1,2,3,4,5,6]
 947const LEVEL_ARCS={1:"foundation",2:"pressure",3:"ward",4:"hunt",5:"hollow",6:"finale",7:"afterglow",9:"proving ground"}
 948const MODES={
 949 standard:{label:"standard",desc:"full campaign"},
 950 iron:{label:"iron",desc:"early beast"},
 951 greed:{label:"greed",desc:"hot relics, costly gold"},
 952 dark:{label:"dark",desc:"weak flame, fast dread"},
 953 daily:{label:"daily",desc:"fixed daily seed"},
 954 heavy:{label:"heavy torch",desc:"starts lit, more fuel"},
 955 swift:{label:"swift",desc:"pits never catch you"},
 956 warded:{label:"warded",desc:"starts warded, wards hold longer"}
 957}
 958const MODE_IDS=Object.keys(MODES)
 959const MODS={
 960 thin:{label:"thin flame",desc:"torches burn faster"},
 961 wake:{label:"wakeful beast",desc:"the beast starts hotter"},
 962 rich:{label:"rich relics",desc:"more relics surface"},
 963 gloom:{label:"heavy dread",desc:"darkness grips sooner"},
 964 grace:{label:"strong shrines",desc:"wards hold longer"}
 965}
 966const MOD_IDS=Object.keys(MODS)
 967const FLOOR_TEXT={
 968 1:["A first descent through stale rites.","The old ruin still pretends to be fair."],
 969 2:["Pressure arrives before understanding catches up.","Every branch feels closer to pursuit."],
 970 3:["Wards answer, but never for free.","Blessing and burden share the same stone."],
 971 4:["The hunt floor wants you heard.","Noise becomes destiny down here."],
 972 5:["The hollow floor strips runs to their bones.","Only the sharpest choices still matter."],
 973 6:["The last gate weighs what you became.","Every surviving system cashes in here."],
 974 7:["Dawn should have ended this. The ruin has other plans.","Nothing left down here owes you mercy."]
 975}
 976const FLOOR_THEMES={
 977 1:{name:"foundation",tag:"stale rite",accent:"verdigris",fog:"soft lantern fog"},
 978 2:{name:"pressure",tag:"ember choke",accent:"rust flare",fog:"hot dust"},
 979 3:{name:"ward",tag:"cold liturgy",accent:"aqua ward",fog:"glass mist"},
 980 4:{name:"hunt",tag:"rose alarm",accent:"pink hunt",fog:"thin red haze"},
 981 5:{name:"hollow",tag:"ash hush",accent:"bone gray",fog:"dry blackout"},
 982 6:{name:"finale",tag:"crown weather",accent:"gold ruin",fog:"judging dark"},
 983 7:{name:"afterglow",tag:"borrowed dawn",accent:"ash gold",fog:"embered haze"},
 984 9:{name:"proving ground",tag:"debug",accent:"bare stone",fog:"none"}
 985}
 986const ENEMY_TEXT={
 987  beast:["A one-eyed pursuer that reads space better than fear.","It wants a lane, not a duel."],
 988  shade:["A cold pass-through that feeds dread and tells on you.","It does not block the path; it poisons it."],
 989  watcher:["A fixed witness that turns position into pursuit.","Quiet fails where it stands."],
 990  leech:["A grave thing that eats ward and heat.","It survives by thinning what protects you."],
 991  effigy:["A second relic, and a third. Only one is true.","The others were never meant to be found."]
 992}
 993const SHRINE_TEXT=[
 994  "The shrine lends shape to your nerve.",
 995  "A ward forms, thin and listening.",
 996  "The shrine answers, and the answer is costly."
 997]
 998const BRAZIER_TEXT=[
 999  "The brazier spits up old warmth.",
1000  "A hungry flame leans toward your torch.",
1001  "The coals remember better fires than yours."
1002]
1003const CURSE_TEXT=[
1004  "The stone bites back.",
1005  "A mean seam in the floor wakes underfoot.",
1006  "The room answers touch with dread."
1007]
1008const SFX_MAP={
1009 hit:{freq:180,dur:.08,type:"square"},
1010 beast:{freq:90,dur:.12,type:"sawtooth"},
1011 win:{freq:660,dur:.4,type:"sine"},
1012 relic:{freq:520,dur:.15,type:"triangle"},
1013 ward:{freq:340,dur:.2,type:"sine"},
1014 shift:{freq:220,dur:.1,type:"sine"},
1015 dead:{freq:70,dur:.5,type:"sawtooth"}
1016}
1017const FINALE_NAMES=["Ash Gate","Gold Gate","Hush Gate","Ward Gate"]
1018const INTRO_TEXT=["Move with arrows or WASD.","Carry flame. Bow for gold.","Wards hold. Cracks strip. The beast reads haste."].join("\n")
1019const HINT_TEXT={
1020 torch:"Take the torch early. Darkness taxes every step without it.",
1021 ward:"Shrines raise ward. Ward softens dark pressure, then burns down.",
1022 crack:"Cracks are fast but costly. Mask or ward makes the crossing safer.",
1023 beast:"Fire slows pursuit. A dropped torch can buy one clean lane."
1024}
1025const RELICS={
1026 ember:{name:"ember heart",label:"ember",up:"slower torch drain",down:"beast ignores dropped flame"},
1027 tooth:{name:"gold tooth",label:"tooth",up:"gold slips the crack",down:"beast enrages sooner"},
1028 hush:{name:"hush bell",label:"hush",up:"dread stays low",down:"fire never slows beast"},
1029 eye:{name:"idol eye",label:"eye",up:"idol bows easier, shrines strengthen",down:"crown scorches torch"},
1030 brand:{name:"night brand",label:"brand",up:"shades break on touch",down:"cursed ground bites harder"},
1031 wick:{name:"long wick",label:"wick",up:"sight and dropped flame last longer",down:"carried torch burns hotter"},
1032 chain:{name:"ward chain",label:"chain",up:"wards and shrines linger",down:"gold no longer softens torch loss"},
1033 veil:{name:"veil thread",label:"veil",up:"mask protects torch through the crack",down:"shrines grant less"},
1034 greave:{name:"pit greaves",label:"greave",up:"pit footing stays sure",down:"crack crossings cost extra"},
1035 lure:{name:"lure spool",label:"lure",up:"dropped flame always pulls the beast",down:"carried fire never slows it"},
1036 salt:{name:"salt sigil",label:"salt",up:"watchers and curses bite softer",down:"shades drain more torch"},
1037 ash:{name:"ash lung",label:"ash",up:"braziers flare stronger",down:"shrines sip your torch"}
1038}
1039const RELIC_IDS=Object.keys(RELICS)
1040const RELIC_SPOTS={
10411:[["b",7,2],["v",8,8],["h",6,6]],
10422:[["h",6,6],["v",5,8],["p",8,8]],
10433:[["i",2,8],["c",2,1],["v",8,8],["h",6,6]],
10444:[["h",5,6],["i",5,8],["p",8,8],["v",8,8]],
10455:[["h",5,6],["i",5,8],["c",2,1],["v",5,8],["p",8,8]],
10466:[["e",7,3],["e",9,5],["e",5,8]],
10477:[["h",5,6],["i",5,8],["c",2,1],["v",5,8],["p",8,8]]
1048}
1049const EFFIGY_SPOTS={
10501:[],
10512:[["v",9,8]],
10523:[["v",9,8]],
10534:[["v",9,8]],
10545:[["v",9,8]],
10556:[],
10567:[["v",9,8]]
1057}
1058const BRAZIER_SPOTS={
10591:[["h",8,8],["p",2,8]],
10602:[["h",8,8],["v",2,8],["c",8,8]],
10613:[["h",8,8],["i",8,8],["p",2,8],["v",2,8]],
10624:[["h",8,8],["i",8,8],["p",2,8],["v",2,8]],
10635:[["h",8,8],["i",8,8],["p",2,8],["v",2,8],["c",8,8]],
10646:[["e",8,2],["e",2,8],["e",8,8]],
10657:[["h",8,8],["i",8,8],["p",2,8],["v",2,8],["c",8,8]]
1066}
1067const SHRINE_SPOTS={
10681:[["i",2,8]],
10692:[["h",8,4],["v",8,8]],
10703:[["h",8,4],["i",8,8],["c",8,8]],
10714:[["h",8,4],["i",8,8],["c",8,8],["p",8,4]],
10725:[["h",8,4],["i",8,8],["c",8,8],["v",8,8],["p",8,4]],
10736:[["e",8,4],["e",3,3],["e",8,8]],
10747:[["h",8,4],["i",8,8],["c",8,8],["v",8,8],["p",8,4]]
1075}
1076const CURSE_SPOTS={
10771:[["h",8,8],["p",8,2],["c",8,8]],
10782:[["h",7,4],["c",2,1],["p",8,8],["v",8,4]],
10793:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4]],
10804:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4]],
10815:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4],["b",8,8]],
10826:[["e",8,8],["e",2,2],["e",8,2],["e",3,8]],
10837:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4],["b",8,8]]
1084}
1085const SHADE_SPOTS={
10861:[["h",9,4],["p",8,8]],
10872:[["h",9,4],["c",8,8],["v",8,8]],
10883:[["h",9,4],["i",8,8],["c",8,8],["p",8,4]],
10894:[["h",9,4],["i",8,8],["c",8,8],["p",8,4],["v",8,8]],
10905:[["h",9,4],["i",8,8],["c",8,8],["p",8,4],["v",8,8],["b",8,8]],
10916:[["e",8,8],["e",2,8],["e",8,2],["e",3,8]],
10927:[["h",9,4],["i",8,8],["c",8,8],["p",8,4],["v",8,8],["b",8,8]]
1093}
1094const BLOCK_SPOTS={
10951:[],
10962:[["h",7,8],["p",2,8],["v",2,4]],
10973:[["h",7,8],["p",2,8],["c",8,2],["v",2,4]],
10984:[["h",7,8],["p",2,8],["c",8,2],["v",2,4],["b",8,8]],
10995:[["h",7,8],["p",2,8],["c",8,2],["v",2,4],["b",8,8],["i",8,4]],
11006:[["e",2,4],["e",7,7],["e",2,7]],
11017:[["h",7,8],["p",2,8],["c",8,2],["v",2,4],["b",8,8],["i",8,4]]
1102}
1103const WATCHER_SPOTS={
11041:[],
11052:[["h",8,8],["v",8,8]],
11063:[["h",8,8],["c",2,8],["v",8,8]],
11074:[["h",8,8],["c",2,8],["p",8,8],["v",8,8]],
11085:[["h",8,8],["c",2,8],["p",8,8],["v",8,8],["i",8,8]],
11096:[["e",8,2],["e",2,8]],
11107:[["h",8,8],["c",2,8],["p",8,8],["v",8,8],["i",8,8]]
1111}
1112const LEECH_SPOTS={
11131:[],
11142:[],
11153:[["p",8,8],["c",8,8]],
11164:[["p",8,8],["c",8,8],["v",8,8]],
11175:[["p",8,8],["c",8,8],["v",8,8],["h",8,4]],
11186:[["e",8,8],["e",3,3]],
11197:[["p",8,8],["c",8,8],["v",8,8],["h",8,4]]
1120}
1121const LEVELS={
11221:{pits:PITS,idols:IDOLS,cracks:CRACKS,halls:HALLS,escapes:ESCAPES,beasts:BEASTS,dark:"pecv",tone:"The air is stale with old rites."},
11232:{pits:PITS2,idols:IDOLS2,cracks:CRACKS2,halls:HALLS2,escapes:ESCAPES2,beasts:BEASTS2,dark:"behipcv",tone:"The ruin tightens. It knows your name now."},
11243:{pits:PITS3,idols:IDOLS3,cracks:CRACKS3,halls:HALLS3,escapes:ESCAPES3,beasts:BEASTS3,dark:"behipcv",tone:"The shrines still answer, but every blessing exacts a price."},
11254:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES4,beasts:BEASTS4,dark:"behipcv",tone:"The hunt floor listens for every sound you make."},
11265:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES5,beasts:BEASTS5,dark:"behipcv",tone:"The hollow floor strips away whatever was merely enough."},
11276:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES6,beasts:BEASTS6,dark:"behipcv",tone:"The final gate wakes. Everything left in you will be tested."},
11287:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES6,beasts:BEASTS6,dark:"behipcv",tone:"You already won. The ruin didn't agree to let you leave."},
11299:{pits:PITS,idols:IDOLS,cracks:CRACKS,halls:HALLS,escapes:ESCAPES,beasts:BEASTS,dark:"",tone:"A proving ground outside the campaign."}
1130}
1131const BASE={
1132g:[
1133"############",
1134"#..........#",
1135"#..L.....R.#",
1136"#..........#",
1137"#..........#",
1138"#....>.....#",
1139"#..........#",
1140"#..........#",
1141"#..........#",
1142"#..........#",
1143"#..........#",
1144"############"],
1145b:[
1146"############",
1147"#..........#",
1148"#...MT.....#",
1149"#..........#",
1150"#..........#",
1151"#.....>....#",
1152"#..........#",
1153"#..........#",
1154"#..........#",
1155"#..........#",
1156"#..........#",
1157"############"],
1158v:[
1159"############",
1160"#..........#",
1161"#....C.K...#",
1162"#..........#",
1163"#..........#",
1164"#..........#",
1165"#..........#",
1166"#..........#",
1167"#..........#",
1168"#....>.....#",
1169"#..........#",
1170"############"],
1171d:["############","#..........#","#..........#","#..........#","#....X.....#","#..........#","#..........#","#..........#","#..........#","#..........#","#..........#","############"]
1172}
1173const BASE2={
1174g:[
1175"############",
1176"#..........#",
1177"#..L..#..R.#",
1178"#..........#",
1179"#....#.....#",
1180"#....>.....#",
1181"#..........#",
1182"#.....#....#",
1183"#..........#",
1184"#..........#",
1185"#..........#",
1186"############"],
1187b:[
1188"############",
1189"#..........#",
1190"#...MT.....#",
1191"#....#.....#",
1192"#..........#",
1193"#..#..>....#",
1194"#..........#",
1195"#.....#....#",
1196"#..........#",
1197"#..........#",
1198"#..........#",
1199"############"],
1200v:[
1201"############",
1202"#..........#",
1203"#...#C.K...#",
1204"#..........#",
1205"#....#.....#",
1206"#..........#",
1207"#.....#....#",
1208"#..........#",
1209"#..........#",
1210"#...>......#",
1211"#..........#",
1212"############"],
1213d:BASE.d
1214}
1215const BASE3={
1216g:[
1217"############",
1218"#..........#",
1219"#..L..S..R.#",
1220"#..........#",
1221"#....#.....#",
1222"#....>.....#",
1223"#..........#",
1224"#.....#....#",
1225"#..........#",
1226"#..........#",
1227"#..........#",
1228"############"],
1229b:[
1230"############",
1231"#..........#",
1232"#..SMT.....#",
1233"#....#.....#",
1234"#..........#",
1235"#..#..>....#",
1236"#..........#",
1237"#.....#....#",
1238"#..........#",
1239"#..........#",
1240"#..........#",
1241"############"],
1242v:[
1243"############",
1244"#..........#",
1245"#...#C.K.S.#",
1246"#..........#",
1247"#....#.....#",
1248"#..........#",
1249"#.....#....#",
1250"#..........#",
1251"#..........#",
1252"#...>......#",
1253"#..........#",
1254"############"],
1255d:BASE.d
1256}
1257const BASES={1:BASE,2:BASE2,3:BASE3,4:BASE3,5:BASE3,6:BASE3,7:BASE3,9:BASE}
1258// Procedural room slots: floors 2+ draw each variant pick from the authored
1259// arrays above plus PROC_SLOTS generated layouts per room type (escapes only
1260// through floor 5 — the finale arenas stay authored, as do BASES rooms).
1261// Specs feed genRoom() in the engine: exits lists required exit letters
1262// ("any" = random open tile), ring is the pit-room O border, walls and pits
1263// are tile budgets for wall clusters and pit veins, traps/items sprinkle
1264// chars onto open floor, stamp drops a small pattern whole onto the map.
1265const PROC_SLOTS=2
1266const PROC_SPECS={
1267 pits:{ring:1,pits:9,walls:2,exits:{">":"any"},items:{F:1}},
1268 idols:{walls:3,exits:{">":"any"},stamp:["ggg","gIg","ggg"]},
1269 cracks:{walls:14,traps:{x:3},exits:{">":"any"}},
1270 halls:{walls:5,exits:{a:"any",b:"any",c:"any",d:"any",">":"any"},items:{F:1}},
1271 escapes:{walls:5,exits:{">":"any"}}
1272}
1273// Floor topology: room set + exit wiring, consumed generically by build().
1274// base: fixed map from BASES[floor]. arr + v: variant array in LEVELS[floor]
1275// and the V slot that picks the variant. An exit destination prefixed "!" is
1276// one-way: it seals behind you after one crossing. Room codes beyond one char
1277// (h2) are extra instances; they inherit family behavior from the first letter.
1278const TOPO={
1279 g:{base:"g",ex:{">":"h",L:"b",R:"e"}},
1280 b:{base:"b",ex:{">":"h"}},
1281 v:{base:"v",ex:{">":"e"}},
1282 d:{base:"d",ex:{}},
1283 h:{arr:"halls",v:"hall",ex:{a:"p",b:"i",c:"c",d:"d",">":"g"}},
1284 p:{arr:"pits",v:"pit",ex:{">":"v"}},
1285 i:{arr:"idols",v:"idol",ex:{">":"h"}},
1286 c:{arr:"cracks",v:"crack",ex:{">":"v"}},
1287 e:{arr:"escapes",v:"escape",ex:{">":"g"}}
1288}
1289const GRAPH={1:TOPO,2:TOPO,3:TOPO,4:TOPO,5:TOPO,6:TOPO,7:TOPO,
1290// floor 9: debug proving ground (T in play) — a second hall instance reached
1291// by a one-way drop; exit b in h2 climbs back to the first hall.
12929:{
1293 g:{base:"g",ex:{">":"h"}},
1294 h:{arr:"halls",v:"hall",ex:{a:"!h2",">":"g"}},
1295 h2:{arr:"halls",v:"hall",ex:{b:"h",">":"g"}}
1296}}