v1.204.0
This commit is contained in:
parent
d075252329
commit
5e0cc455b9
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -104,7 +104,7 @@ jobs:
|
||||
|
||||
# Pull the old images
|
||||
docker pull $IMAGE_ID:latest
|
||||
docker pull IMAGE_ID_IMG:latest
|
||||
docker pull $IMAGE_ID_IMG:latest
|
||||
|
||||
# Save the current CMD from the image
|
||||
SAVE_CMD=$(docker inspect --format='{{json .Config.Cmd}}' $IMAGE_ID:latest)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -740,16 +740,16 @@
|
||||
"type": "list",
|
||||
"columns": 2,
|
||||
"items": [
|
||||
"{@5etools Azorius Vedlaken Wizard|pdf/adventure/AZfyT/Azorius Vedlaken Wizard 2.pdf}",
|
||||
"{@5etools Boros Minotaur Fighter|pdf/adventure/AZfyT/Boros Minotaur Fighter 2.pdf}",
|
||||
"{@5etools Dimir Human Rogue|pdf/adventure/AZfyT/Dimir Human Rogue 2.pdf}",
|
||||
"{@5etools Golgari Elf Druid|pdf/adventure/AZfyT/Golgari Elf Druid 2.pdf}",
|
||||
"{@5etools Gruul Human Barbarian|pdf/adventure/AZfyT/Gruul Human Barbarian 2.pdf}",
|
||||
"{@5etools Izzet Goblin Sorcerer|pdf/adventure/AZfyT/Izzet Goblin Sorcerer 2.pdf}",
|
||||
"{@5etools Orzhov Human Cleric|pdf/adventure/AZfyT/Orzhov Human Cleric 2.pdf}",
|
||||
"{@5etools Rakdos Goblin Bard|pdf/adventure/AZfyT/Rakdos Goblin Bard 2.pdf}",
|
||||
"{@5etools Selesnya Loxodon Paladin|pdf/adventure/AZfyT/Selesnya Loxodon Paladin 2.pdf}",
|
||||
"{@5etools Simic Hybrid Monk|pdf/adventure/AZfyT/Simic Hybrid Monk 2.pdf}"
|
||||
"{@5etools Azorius Vedlaken Wizard|img/pdf/AZfyT/Azorius Vedlaken Wizard 2.pdf}",
|
||||
"{@5etools Boros Minotaur Fighter|img/pdf/AZfyT/Boros Minotaur Fighter 2.pdf}",
|
||||
"{@5etools Dimir Human Rogue|img/pdf/AZfyT/Dimir Human Rogue 2.pdf}",
|
||||
"{@5etools Golgari Elf Druid|img/pdf/AZfyT/Golgari Elf Druid 2.pdf}",
|
||||
"{@5etools Gruul Human Barbarian|img/pdf/AZfyT/Gruul Human Barbarian 2.pdf}",
|
||||
"{@5etools Izzet Goblin Sorcerer|img/pdf/AZfyT/Izzet Goblin Sorcerer 2.pdf}",
|
||||
"{@5etools Orzhov Human Cleric|img/pdf/AZfyT/Orzhov Human Cleric 2.pdf}",
|
||||
"{@5etools Rakdos Goblin Bard|img/pdf/AZfyT/Rakdos Goblin Bard 2.pdf}",
|
||||
"{@5etools Selesnya Loxodon Paladin|img/pdf/AZfyT/Selesnya Loxodon Paladin 2.pdf}",
|
||||
"{@5etools Simic Hybrid Monk|img/pdf/AZfyT/Simic Hybrid Monk 2.pdf}"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -255,7 +255,15 @@
|
||||
"credit": "Mike Schley",
|
||||
"width": 4096,
|
||||
"height": 5301,
|
||||
"id": "05e"
|
||||
"id": "05e",
|
||||
"grid": {
|
||||
"type": "square",
|
||||
"size": 225,
|
||||
"offsetX": 52,
|
||||
"offsetY": -23,
|
||||
"scale": 2,
|
||||
"distance": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
@ -270,6 +278,14 @@
|
||||
"credit": "Mike Schley",
|
||||
"mapParent": {
|
||||
"id": "05e"
|
||||
},
|
||||
"grid": {
|
||||
"type": "square",
|
||||
"size": 225,
|
||||
"offsetX": 52,
|
||||
"offsetY": -23,
|
||||
"scale": 2,
|
||||
"distance": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@ -59,11 +59,11 @@
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"{@5etools Hill Dwarf Cleric|pdf/adventure/DoSI/Hill-Dwarf-Cleric.pdf}",
|
||||
"{@5etools Human Paladin|pdf/adventure/DoSI/Human-Paladin.pdf}",
|
||||
"{@5etools Wood Elf Fighter|pdf/adventure/DoSI/Wood-Elf-Fighter.pdf}",
|
||||
"{@5etools Lightfoot Halfling Rogue|pdf/adventure/DoSI/Lightfoot-Halfling-Rogue.pdf}",
|
||||
"{@5etools High Elf Wizard|pdf/adventure/DoSI/High-Elf-Wizard.pdf}"
|
||||
"{@5etools Hill Dwarf Cleric|img/pdf/DoSI/Hill-Dwarf-Cleric.pdf}",
|
||||
"{@5etools Human Paladin|img/pdf/DoSI/Human-Paladin.pdf}",
|
||||
"{@5etools Wood Elf Fighter|img/pdf/DoSI/Wood-Elf-Fighter.pdf}",
|
||||
"{@5etools Lightfoot Halfling Rogue|img/pdf/DoSI/Lightfoot-Halfling-Rogue.pdf}",
|
||||
"{@5etools High Elf Wizard|img/pdf/DoSI/High-Elf-Wizard.pdf}"
|
||||
]
|
||||
},
|
||||
"Tell the players to read over the character sheets; give their characters names; and invent the details of their characters' personality and appearance. Encourage the players to write on the character sheets to make these characters their own."
|
||||
|
||||
@ -7832,7 +7832,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/IMR/042-al-cert.webp"
|
||||
},
|
||||
"title": "{@5etools Download PDF|pdf/adventure/IMR/000-advl_cert-revised-dndxl2019.pdf}",
|
||||
"title": "{@5etools Download PDF|img/pdf/IMR/000-advl_cert-revised-dndxl2019.pdf}",
|
||||
"width": 600,
|
||||
"height": 462
|
||||
}
|
||||
|
||||
1782
data/adventure/adventure-lrdt.json
Normal file
1782
data/adventure/adventure-lrdt.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -67,10 +67,10 @@
|
||||
"type": "list",
|
||||
"columns": 2,
|
||||
"items": [
|
||||
"{@5etools Evandon Haart|pdf/adventure/PiP/Evandon_Haart.pdf}",
|
||||
"{@5etools Gallantine Birchenbough|pdf/adventure/PiP/Gallantine_Birchenbough.pdf}",
|
||||
"{@5etools Noorah Eldenfield|pdf/adventure/PiP/Noorah_Eldenfield.pdf}",
|
||||
"{@5etools Shalefire Stoutheart|pdf/adventure/PiP/Shalefire_Stoutheart.pdf}"
|
||||
"{@5etools Evandon Haart|img/pdf/PiP/Evandon_Haart.pdf}",
|
||||
"{@5etools Gallantine Birchenbough|img/pdf/PiP/Gallantine_Birchenbough.pdf}",
|
||||
"{@5etools Noorah Eldenfield|img/pdf/PiP/Noorah_Eldenfield.pdf}",
|
||||
"{@5etools Shalefire Stoutheart|img/pdf/PiP/Shalefire_Stoutheart.pdf}"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "section",
|
||||
"name": "Introduction",
|
||||
"entries": [
|
||||
"Coming soon! In the meantime, check out the {@adventure preview adventure|DitLCoT}."
|
||||
]
|
||||
"type": "section",
|
||||
"name": "Introduction",
|
||||
"entries": [
|
||||
"Coming soon! In the meantime, check out the {@adventure preview adventure|DitLCoT}."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1510,7 +1510,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/RMBRE/005-ddvram-pregen-01.webp"
|
||||
},
|
||||
"title": "{@comic {@5etools Meatface|pdf/adventure/RMBRE/Meatface.pdf}: Human Fighter}",
|
||||
"title": "{@comic {@5etools Meatface|img/pdf/RMBRE/Meatface.pdf}: Human Fighter}",
|
||||
"width": 240,
|
||||
"height": 300,
|
||||
"credit": "Troy Little"
|
||||
@ -1521,7 +1521,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/RMBRE/006-ddvram-pregen-02.webp"
|
||||
},
|
||||
"title": "{@comic {@5etools Lyan Amaranthia|pdf/adventure/RMBRE/Lyan Amaranthia.pdf}: Wood Elf Cleric}",
|
||||
"title": "{@comic {@5etools Lyan Amaranthia|img/pdf/RMBRE/Lyan Amaranthia.pdf}: Wood Elf Cleric}",
|
||||
"width": 240,
|
||||
"height": 300,
|
||||
"credit": "Troy Little"
|
||||
@ -1532,7 +1532,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/RMBRE/007-ddvram-pregen-03.webp"
|
||||
},
|
||||
"title": "{@comic {@5etools Keth Silverson|pdf/adventure/RMBRE/Keth Silverson.pdf}: Half-orc Rogue}",
|
||||
"title": "{@comic {@5etools Keth Silverson|img/pdf/RMBRE/Keth Silverson.pdf}: Half-orc Rogue}",
|
||||
"width": 240,
|
||||
"height": 300,
|
||||
"credit": "Troy Little"
|
||||
@ -1543,7 +1543,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/RMBRE/008-ddvram-pregen-04.webp"
|
||||
},
|
||||
"title": "{@comic {@5etools Kiir Bravan|pdf/adventure/RMBRE/Kiir Bravan.pdf}: Half-elf Wizard}",
|
||||
"title": "{@comic {@5etools Kiir Bravan|img/pdf/RMBRE/Kiir Bravan.pdf}: Half-elf Wizard}",
|
||||
"width": 240,
|
||||
"height": 300,
|
||||
"credit": "Troy Little"
|
||||
@ -1554,7 +1554,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/RMBRE/009-ddvram-pregen-05.webp"
|
||||
},
|
||||
"title": "{@comic {@5etools Ari Strongbow|pdf/adventure/RMBRE/Ari Strongbow.pdf}: Half-elf Fighter}",
|
||||
"title": "{@comic {@5etools Ari Strongbow|img/pdf/RMBRE/Ari Strongbow.pdf}: Half-elf Fighter}",
|
||||
"width": 240,
|
||||
"height": 300,
|
||||
"credit": "Troy Little"
|
||||
|
||||
@ -833,7 +833,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/XMtS/alante.webp"
|
||||
},
|
||||
"title": "{@5etools Alante, Cleric of the Five Sacraments|pdf/adventure/XMtS/alante.pdf}",
|
||||
"title": "{@5etools Alante, Cleric of the Five Sacraments|img/pdf/XMtS/alante.pdf}",
|
||||
"width": 507,
|
||||
"height": 582
|
||||
},
|
||||
@ -843,7 +843,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/XMtS/artinoq.webp"
|
||||
},
|
||||
"title": "{@5etools Artinoq, Atzocan Archer|pdf/adventure/XMtS/artinoq.pdf}",
|
||||
"title": "{@5etools Artinoq, Atzocan Archer|img/pdf/XMtS/artinoq.pdf}",
|
||||
"width": 507,
|
||||
"height": 582
|
||||
}
|
||||
@ -875,7 +875,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/XMtS/rouxil.webp"
|
||||
},
|
||||
"title": "{@5etools Rouxil, Emperor's Vanguard|pdf/adventure/XMtS/rouxil.pdf}",
|
||||
"title": "{@5etools Rouxil, Emperor's Vanguard|img/pdf/XMtS/rouxil.pdf}",
|
||||
"width": 507,
|
||||
"height": 582
|
||||
}
|
||||
@ -897,7 +897,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/XMtS/velisha.webp"
|
||||
},
|
||||
"title": "{@5etools Velisha, Shaper of Highbranch|pdf/adventure/XMtS/velisha.pdf}",
|
||||
"title": "{@5etools Velisha, Shaper of Highbranch|img/pdf/XMtS/velisha.pdf}",
|
||||
"width": 507,
|
||||
"height": 582
|
||||
},
|
||||
@ -907,7 +907,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/XMtS/ellie.webp"
|
||||
},
|
||||
"title": "{@5etools Ellie Redcap, Fathom Fleet Firebrand|pdf/adventure/XMtS/ellie.pdf}",
|
||||
"title": "{@5etools Ellie Redcap, Fathom Fleet Firebrand|img/pdf/XMtS/ellie.pdf}",
|
||||
"width": 507,
|
||||
"height": 582
|
||||
}
|
||||
@ -931,7 +931,7 @@
|
||||
"type": "internal",
|
||||
"path": "adventure/XMtS/turk.webp"
|
||||
},
|
||||
"title": "{@5etools Turk Two Coins, Ruthless Knave|pdf/adventure/XMtS/turk.pdf}",
|
||||
"title": "{@5etools Turk Two Coins, Ruthless Knave|img/pdf/XMtS/turk.pdf}",
|
||||
"width": 507,
|
||||
"height": 582
|
||||
},
|
||||
@ -959,9 +959,9 @@
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"name": "Plane Shift",
|
||||
"name": "Plane Shift: Ixalan Design",
|
||||
"entries": [
|
||||
"Ixalan Design:James Wyatt"
|
||||
"James Wyatt"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
"path": "covers/LMoP.webp"
|
||||
},
|
||||
"published": "2014-07-15",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Starter Set",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -113,6 +114,7 @@
|
||||
"path": "covers/HotDQ.webp"
|
||||
},
|
||||
"published": "2014-08-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tyranny of Dragons",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -882,6 +884,7 @@
|
||||
"path": "covers/RoT.webp"
|
||||
},
|
||||
"published": "2014-11-04",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tyranny of Dragons",
|
||||
"level": {
|
||||
"start": 8,
|
||||
@ -1445,6 +1448,7 @@
|
||||
"path": "covers/PotA.webp"
|
||||
},
|
||||
"published": "2015-04-07",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Elemental Evil",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -2895,6 +2899,7 @@
|
||||
"path": "covers/OotA.webp"
|
||||
},
|
||||
"published": "2015-09-15",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Rage of Demons",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -3647,6 +3652,7 @@
|
||||
"path": "covers/CoS.webp"
|
||||
},
|
||||
"published": "2016-03-15",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Ravenloft",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -5269,6 +5275,7 @@
|
||||
"path": "covers/SKT.webp"
|
||||
},
|
||||
"published": "2016-09-06",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Storm King's Thunder",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -7140,6 +7147,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 0,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -7436,6 +7444,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 1,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 3,
|
||||
@ -7716,6 +7725,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 2,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 5,
|
||||
@ -8000,6 +8010,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 3,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 8,
|
||||
@ -8160,6 +8171,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 4,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 9,
|
||||
@ -8651,6 +8663,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 5,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 11,
|
||||
@ -9455,6 +9468,7 @@
|
||||
},
|
||||
"published": "2017-03-24",
|
||||
"publishedOrder": 6,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tales from the Yawning Portal",
|
||||
"level": {
|
||||
"start": 10,
|
||||
@ -9649,6 +9663,7 @@
|
||||
"path": "covers/ToA.webp"
|
||||
},
|
||||
"published": "2017-09-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tomb of Annihilation",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -11222,6 +11237,7 @@
|
||||
"path": "covers/TTP.webp"
|
||||
},
|
||||
"published": "2017-11-03",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Tomb of Annihilation",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -11306,6 +11322,7 @@
|
||||
"path": "covers/TLK.webp"
|
||||
},
|
||||
"published": "2017-11-28",
|
||||
"author": "Shawn Wood",
|
||||
"storyline": "Extra Life",
|
||||
"level": {
|
||||
"start": 4,
|
||||
@ -11330,6 +11347,7 @@
|
||||
"path": "covers/XMtS.webp"
|
||||
},
|
||||
"published": "2017-12-11",
|
||||
"author": "Wizards MTG Team",
|
||||
"storyline": "Ixalan",
|
||||
"level": {
|
||||
"start": 4,
|
||||
@ -11413,6 +11431,7 @@
|
||||
"path": "covers/WDH.webp"
|
||||
},
|
||||
"published": "2018-09-18",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Waterdeep",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -11669,6 +11688,7 @@
|
||||
"path": "covers/LLK.webp"
|
||||
},
|
||||
"published": "2018-11-10",
|
||||
"author": "Extra Life",
|
||||
"storyline": "Extra Life",
|
||||
"level": {
|
||||
"start": 5,
|
||||
@ -11796,6 +11816,7 @@
|
||||
"path": "covers/WDMM.webp"
|
||||
},
|
||||
"published": "2018-11-13",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Waterdeep",
|
||||
"level": {
|
||||
"start": 5,
|
||||
@ -15056,6 +15077,7 @@
|
||||
"path": "covers/GGR.webp"
|
||||
},
|
||||
"published": "2018-11-20",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Ravnica",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -15091,6 +15113,7 @@
|
||||
"path": "covers/AZfyT.webp"
|
||||
},
|
||||
"published": "2019-03-05",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Ravnica",
|
||||
"level": {
|
||||
"start": 2,
|
||||
@ -15130,6 +15153,7 @@
|
||||
"path": "covers/GoS.webp"
|
||||
},
|
||||
"published": "2019-05-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Ghosts of Saltmarsh",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -16303,6 +16327,7 @@
|
||||
"path": "covers/HftT.webp"
|
||||
},
|
||||
"published": "2019-05-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Stranger Things",
|
||||
"level": {
|
||||
"start": 3,
|
||||
@ -16338,6 +16363,7 @@
|
||||
"path": "covers/HWAitW.webp"
|
||||
},
|
||||
"published": "2019-06-17",
|
||||
"author": "The Deck of Many",
|
||||
"storyline": "Humblewood",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -16450,6 +16476,7 @@
|
||||
"path": "covers/AI.webp"
|
||||
},
|
||||
"published": "2019-06-18",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Acquisitions Incorporated",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -16780,6 +16807,7 @@
|
||||
},
|
||||
"published": "2019-06-24",
|
||||
"publishedOrder": 0,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Essentials Kit",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -16941,6 +16969,7 @@
|
||||
},
|
||||
"published": "2019-09-03",
|
||||
"publishedOrder": 1,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Essentials Kit",
|
||||
"level": {
|
||||
"start": 7,
|
||||
@ -17747,6 +17776,7 @@
|
||||
},
|
||||
"published": "2019-09-03",
|
||||
"publishedOrder": 2,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Essentials Kit",
|
||||
"level": {
|
||||
"start": 9,
|
||||
@ -18482,6 +18512,7 @@
|
||||
},
|
||||
"published": "2019-09-03",
|
||||
"publishedOrder": 3,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Essentials Kit",
|
||||
"level": {
|
||||
"start": 11,
|
||||
@ -19499,6 +19530,7 @@
|
||||
"path": "covers/BGDIA.webp"
|
||||
},
|
||||
"published": "2019-09-18",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Baldur's Gate",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -20393,6 +20425,7 @@
|
||||
"path": "covers/LR.webp"
|
||||
},
|
||||
"published": "2019-09-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Extra Life",
|
||||
"level": {
|
||||
"start": 9,
|
||||
@ -20495,6 +20528,7 @@
|
||||
"path": "covers/IMR.webp"
|
||||
},
|
||||
"published": "2019-11-12",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Extra Life",
|
||||
"level": {
|
||||
"start": 5,
|
||||
@ -20875,6 +20909,7 @@
|
||||
"path": "covers/ERLW.webp"
|
||||
},
|
||||
"published": "2019-11-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Eberron",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -20969,6 +21004,7 @@
|
||||
"path": "covers/RMR.webp"
|
||||
},
|
||||
"published": "2019-11-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Rick and Morty",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -21191,6 +21227,7 @@
|
||||
},
|
||||
"published": "2020-03-17",
|
||||
"publishedOrder": 0,
|
||||
"author": "Darrington Press",
|
||||
"storyline": "Wildemount",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -21268,6 +21305,7 @@
|
||||
},
|
||||
"published": "2020-03-17",
|
||||
"publishedOrder": 1,
|
||||
"author": "Darrington Press",
|
||||
"storyline": "Wildemount",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -21412,6 +21450,7 @@
|
||||
},
|
||||
"published": "2020-03-17",
|
||||
"publishedOrder": 2,
|
||||
"author": "Darrington Press",
|
||||
"storyline": "Wildemount",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -21547,6 +21586,7 @@
|
||||
},
|
||||
"published": "2020-03-17",
|
||||
"publishedOrder": 3,
|
||||
"author": "Darrington Press",
|
||||
"storyline": "Wildemount",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -21662,6 +21702,7 @@
|
||||
"path": "covers/MOT.webp"
|
||||
},
|
||||
"published": "2020-06-02",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Mythic Odysseys of Theros",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -21728,6 +21769,7 @@
|
||||
"path": "covers/IDRotF.webp"
|
||||
},
|
||||
"published": "2020-09-15",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Icewind Dale",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -23474,6 +23516,7 @@
|
||||
"path": "covers/CM.webp"
|
||||
},
|
||||
"published": "2021-03-16",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Candlekeep Mysteries",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -24517,6 +24560,7 @@
|
||||
"path": "covers/VRGR.webp"
|
||||
},
|
||||
"published": "2021-05-18",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Ravenloft",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -24683,6 +24727,7 @@
|
||||
"path": "covers/RtG.webp"
|
||||
},
|
||||
"published": "2021-05-21",
|
||||
"author": "Extra Life",
|
||||
"storyline": "Extra Life",
|
||||
"level": {
|
||||
"start": 6,
|
||||
@ -24737,6 +24782,7 @@
|
||||
"path": "covers/AitFR-ISF.webp"
|
||||
},
|
||||
"published": "2021-06-30",
|
||||
"author": "Wizards MTG Team",
|
||||
"storyline": "Adventures in the Forgotten Realms",
|
||||
"level": {
|
||||
"start": 8,
|
||||
@ -24844,6 +24890,7 @@
|
||||
"path": "covers/AitFR-THP.webp"
|
||||
},
|
||||
"published": "2021-07-07",
|
||||
"author": "Wizards MTG Team",
|
||||
"storyline": "Adventures in the Forgotten Realms",
|
||||
"level": {
|
||||
"start": 8,
|
||||
@ -24944,6 +24991,7 @@
|
||||
"path": "covers/AitFR-AVT.webp"
|
||||
},
|
||||
"published": "2021-07-14",
|
||||
"author": "Wizards MTG Team",
|
||||
"storyline": "Adventures in the Forgotten Realms",
|
||||
"level": {
|
||||
"start": 9,
|
||||
@ -25040,6 +25088,7 @@
|
||||
"path": "covers/AitFR-DN.webp"
|
||||
},
|
||||
"published": "2021-07-21",
|
||||
"author": "Wizards MTG Team",
|
||||
"storyline": "Adventures in the Forgotten Realms",
|
||||
"level": {
|
||||
"start": 9,
|
||||
@ -25149,6 +25198,7 @@
|
||||
"path": "covers/AitFR-FCD.webp"
|
||||
},
|
||||
"published": "2021-07-28",
|
||||
"author": "Wizards MTG Team",
|
||||
"storyline": "Adventures in the Forgotten Realms",
|
||||
"level": {
|
||||
"start": 10,
|
||||
@ -25253,6 +25303,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 0,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25332,6 +25383,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 1,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25376,6 +25428,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 2,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25416,6 +25469,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 3,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25479,6 +25533,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 4,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25527,6 +25582,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 5,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25571,6 +25627,7 @@
|
||||
},
|
||||
"published": "2021-09-01",
|
||||
"publishedOrder": 6,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "NERDS Restoring Harmony",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -25625,6 +25682,7 @@
|
||||
"path": "covers/WBtW.webp"
|
||||
},
|
||||
"published": "2021-09-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "The Wild Beyond the Witchlight",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -26308,6 +26366,7 @@
|
||||
},
|
||||
"published": "2021-12-07",
|
||||
"publishedOrder": 0,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Strixhaven",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -26616,6 +26675,7 @@
|
||||
},
|
||||
"published": "2021-12-07",
|
||||
"publishedOrder": 1,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Strixhaven",
|
||||
"level": {
|
||||
"start": 4,
|
||||
@ -26749,6 +26809,7 @@
|
||||
},
|
||||
"published": "2021-12-07",
|
||||
"publishedOrder": 2,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Strixhaven",
|
||||
"level": {
|
||||
"start": 6,
|
||||
@ -26867,6 +26928,7 @@
|
||||
},
|
||||
"published": "2021-12-07",
|
||||
"publishedOrder": 3,
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Strixhaven",
|
||||
"level": {
|
||||
"start": 8,
|
||||
@ -27029,6 +27091,7 @@
|
||||
"path": "covers/CRCotN.webp"
|
||||
},
|
||||
"published": "2022-03-15",
|
||||
"author": "Darrington Press",
|
||||
"storyline": "Critical Role",
|
||||
"level": {
|
||||
"start": 3,
|
||||
@ -27600,6 +27663,7 @@
|
||||
"path": "covers/JttRC.webp"
|
||||
},
|
||||
"published": "2022-07-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Journeys through the Radiant Citadel",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -28081,6 +28145,7 @@
|
||||
"path": "covers/DoSI.webp"
|
||||
},
|
||||
"published": "2022-07-31",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Starter Set",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -28304,6 +28369,7 @@
|
||||
"path": "covers/SjA.webp"
|
||||
},
|
||||
"published": "2022-08-01",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Spelljammer",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -28390,6 +28456,7 @@
|
||||
"path": "covers/SAiS.webp"
|
||||
},
|
||||
"published": "2022-08-16",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Spelljammer",
|
||||
"level": {
|
||||
"start": 5,
|
||||
@ -28538,6 +28605,7 @@
|
||||
"path": "covers/DSotDQ.webp"
|
||||
},
|
||||
"published": "2022-11-22",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Dragonlance",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -29150,6 +29218,7 @@
|
||||
"path": "covers/KftGV.webp"
|
||||
},
|
||||
"published": "2023-02-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Keys from the Golden Vault",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -30384,6 +30453,7 @@
|
||||
"path": "covers/GotSF.webp"
|
||||
},
|
||||
"published": "2023-08-01",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Giants of the Star Forge",
|
||||
"level": {
|
||||
"start": 16,
|
||||
@ -30441,6 +30511,7 @@
|
||||
"path": "covers/PaBTSO.webp"
|
||||
},
|
||||
"published": "2023-09-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Starter Set",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -31531,6 +31602,7 @@
|
||||
"path": "covers/LK.webp"
|
||||
},
|
||||
"published": "2023-09-26",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Minecraft",
|
||||
"level": {
|
||||
"start": 3,
|
||||
@ -31646,6 +31718,7 @@
|
||||
"path": "covers/PAitM.webp"
|
||||
},
|
||||
"published": "2023-10-17",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Planescape",
|
||||
"level": {
|
||||
"start": 3,
|
||||
@ -31890,6 +31963,7 @@
|
||||
"path": "covers/CoA.webp"
|
||||
},
|
||||
"published": "2023-10-30",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Extra Life",
|
||||
"level": {
|
||||
"start": 11,
|
||||
@ -32510,6 +32584,7 @@
|
||||
"path": "covers/PiP.webp"
|
||||
},
|
||||
"published": "2023-11-20",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Family Friendly",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -32545,6 +32620,7 @@
|
||||
"path": "covers/HFStCM.webp"
|
||||
},
|
||||
"published": "2023-11-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Heroes' Feast",
|
||||
"level": {
|
||||
"start": 10,
|
||||
@ -32611,6 +32687,7 @@
|
||||
"path": "covers/GHLoE.webp"
|
||||
},
|
||||
"published": "2023-11-30",
|
||||
"author": "Ghostfire Gaming",
|
||||
"storyline": "Grim Hollow",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -33411,6 +33488,7 @@
|
||||
"path": "covers/DoDk.webp"
|
||||
},
|
||||
"published": "2023-12-21",
|
||||
"author": "Ghostfire Gaming",
|
||||
"storyline": "Drakkenheim",
|
||||
"level": {
|
||||
"start": 1,
|
||||
@ -34026,8 +34104,12 @@
|
||||
"id": "DitLCoT",
|
||||
"source": "DitLCoT",
|
||||
"group": "supplement",
|
||||
"coverUrl": "img/covers/QftIS.webp",
|
||||
"cover": {
|
||||
"type": "internal",
|
||||
"path": "covers/QftIS.webp"
|
||||
},
|
||||
"published": "2024-03-26",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Quests from the Infinite Staircase",
|
||||
"level": {
|
||||
"start": 9,
|
||||
@ -34131,13 +34213,76 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Red Dragon's Tale: A LEGO Adventure",
|
||||
"id": "LRDT",
|
||||
"source": "LRDT",
|
||||
"group": "supplement-alt",
|
||||
"cover": {
|
||||
"type": "internal",
|
||||
"path": "covers/LRDT.webp"
|
||||
},
|
||||
"published": "2024-04-01",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "LEGO",
|
||||
"level": {
|
||||
"start": 5,
|
||||
"end": 5
|
||||
},
|
||||
"contents": [
|
||||
{
|
||||
"name": "Introduction",
|
||||
"headers": [
|
||||
"About the Heroes",
|
||||
"Running the Adventure"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Scene 1: Inn Plain Sight"
|
||||
},
|
||||
{
|
||||
"name": "Scene 2: The Meadow"
|
||||
},
|
||||
{
|
||||
"name": "Scene 3: The Dungeon"
|
||||
},
|
||||
{
|
||||
"name": "Scene 4: The Basement"
|
||||
},
|
||||
{
|
||||
"name": "Scene 5: The Tower"
|
||||
},
|
||||
{
|
||||
"name": "Scene 6: The Dragon"
|
||||
},
|
||||
{
|
||||
"name": "Conclusion"
|
||||
},
|
||||
{
|
||||
"name": "Nonplayer Characters"
|
||||
},
|
||||
{
|
||||
"name": "Without D&D Rules"
|
||||
},
|
||||
{
|
||||
"name": "Character Sheets"
|
||||
},
|
||||
{
|
||||
"name": "Credits"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Quests from the Infinite Staircase",
|
||||
"id": "QftIS",
|
||||
"source": "QftIS",
|
||||
"group": "supplement",
|
||||
"coverUrl": "img/covers/QftIS.webp",
|
||||
"cover": {
|
||||
"type": "internal",
|
||||
"path": "covers/QftIS.webp"
|
||||
},
|
||||
"published": "2024-07-16",
|
||||
"author": "Wizards RPG Team",
|
||||
"storyline": "Quests from the Infinite Staircase",
|
||||
"level": {
|
||||
"start": 1,
|
||||
|
||||
@ -5381,6 +5381,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"traitTags": [
|
||||
"Beast of Burden"
|
||||
],
|
||||
"languageTags": [
|
||||
"CS",
|
||||
"GI",
|
||||
@ -9384,6 +9387,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"traitTags": [
|
||||
"Beast of Burden"
|
||||
],
|
||||
"damageTags": [
|
||||
"B"
|
||||
],
|
||||
|
||||
@ -62,10 +62,36 @@
|
||||
"name": "Communal Spellcasting (2/Day)",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"The pech works with three or more pechs to cast spells, requiring no spell components and using Wisdom as the spellcasting ability (save {@dc 12}). If at least three other pechs are within 30 feet of it, the pech can cast Wall of Stone. If at least seven other pechs are within 30 feet of it, it can cast Greater Restoration. Each other pech involved in casting the spell can't have the incapacitated condition and must have at least one use of Communal Spellcasting remaining, which it must immediately expend to participate (no action required)."
|
||||
"The pech works with three or more pechs to cast spells, requiring no spell components and using Wisdom as the spellcasting ability (save {@dc 12}). If at least three other pechs are within 30 feet of it, the pech can cast {@spell Wall of Stone}. If at least seven other pechs are within 30 feet of it, it can cast {@spell Greater Restoration}. Each other pech involved in casting the spell can't have the incapacitated condition and must have at least one use of Communal Spellcasting remaining, which it must immediately expend to participate (no action required)."
|
||||
],
|
||||
"daily": {
|
||||
"2": [
|
||||
"{@spell wall of stone}",
|
||||
"{@spell greater restoration}"
|
||||
]
|
||||
},
|
||||
"ability": "wis",
|
||||
"displayAs": "action"
|
||||
"displayAs": "action",
|
||||
"hidden": [
|
||||
"daily"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Stone Shape (3/Day)",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"The pech casts {@spell Stone Shape}, requiring no spell components and using Wisdom as the spellcasting ability."
|
||||
],
|
||||
"daily": {
|
||||
"3e": [
|
||||
"{@spell stone shape}"
|
||||
]
|
||||
},
|
||||
"ability": "wis",
|
||||
"displayAs": "action",
|
||||
"hidden": [
|
||||
"daily"
|
||||
]
|
||||
}
|
||||
],
|
||||
"trait": [
|
||||
@ -94,12 +120,6 @@
|
||||
"entries": [
|
||||
"{@atk mw} {@hit 6} to hit, reach 5 ft., one target. {@h}11 ({@damage 2d6 + 4}) force damage. If the target is a Construct or an object, the attack is automatically a critical hit."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Stone Shape (3/Day)",
|
||||
"entries": [
|
||||
"The pech casts {@spell Stone Shape}, requiring no spell components and using Wisdom as the spellcasting ability."
|
||||
]
|
||||
}
|
||||
],
|
||||
"traitTags": [
|
||||
|
||||
251
data/bestiary/bestiary-lrdt.json
Normal file
251
data/bestiary/bestiary-lrdt.json
Normal file
@ -0,0 +1,251 @@
|
||||
{
|
||||
"monster": [
|
||||
{
|
||||
"name": "Alax Jadescales",
|
||||
"isNpc": true,
|
||||
"isNamedCreature": true,
|
||||
"source": "LRDT",
|
||||
"page": 11,
|
||||
"size": [
|
||||
"M"
|
||||
],
|
||||
"type": {
|
||||
"type": "humanoid",
|
||||
"tags": [
|
||||
"dragonborn"
|
||||
]
|
||||
},
|
||||
"alignment": [
|
||||
"N",
|
||||
"G"
|
||||
],
|
||||
"ac": [
|
||||
10
|
||||
],
|
||||
"hp": {
|
||||
"average": 58,
|
||||
"formula": "9d8 + 18"
|
||||
},
|
||||
"speed": {
|
||||
"walk": 30
|
||||
},
|
||||
"str": 11,
|
||||
"dex": 10,
|
||||
"con": 14,
|
||||
"int": 11,
|
||||
"wis": 16,
|
||||
"cha": 15,
|
||||
"skill": {
|
||||
"animal handling": "+5",
|
||||
"survival": "+5"
|
||||
},
|
||||
"senses": [
|
||||
"darkvision 60 ft."
|
||||
],
|
||||
"passive": 13,
|
||||
"resist": [
|
||||
"poison"
|
||||
],
|
||||
"languages": [
|
||||
"Common",
|
||||
"Draconic"
|
||||
],
|
||||
"cr": "2",
|
||||
"spellcasting": [
|
||||
{
|
||||
"name": "Spellcasting",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"Alax casts one of the following spells, using Wisdom as the spellcasting ability (spell save {@dc 13}):"
|
||||
],
|
||||
"will": [
|
||||
"{@spell Druidcraft}",
|
||||
"{@spell Resistance}"
|
||||
],
|
||||
"daily": {
|
||||
"1e": [
|
||||
"{@spell Cure Wounds}",
|
||||
"{@spell Faerie Fire}",
|
||||
"{@spell Purify Food and Drink}"
|
||||
]
|
||||
},
|
||||
"ability": "wis",
|
||||
"displayAs": "action"
|
||||
}
|
||||
],
|
||||
"action": [
|
||||
{
|
||||
"name": "Multiattack",
|
||||
"entries": [
|
||||
"Alax makes two Fire Strike attacks."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Fire Strike",
|
||||
"entries": [
|
||||
"{@atk ms,rs} {@hit 5} to hit, reach 5 ft. or range 60 ft., one target. {@h}10 ({@damage 2d6 + 3}) fire damage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Breath Weapon (Recharges after a Short or Long Rest)",
|
||||
"entries": [
|
||||
"Alax exhales a 15-foot cone of fire. Each creature in that area must make a {@dc 12} Dexterity saving throw, taking 14 ({@damage 4d6}) fire damage on a failed save, or half as much damage on a successful one."
|
||||
]
|
||||
}
|
||||
],
|
||||
"senseTags": [
|
||||
"D"
|
||||
],
|
||||
"actionTags": [
|
||||
"Breath Weapon",
|
||||
"Multiattack"
|
||||
],
|
||||
"languageTags": [
|
||||
"C",
|
||||
"DR"
|
||||
],
|
||||
"damageTags": [
|
||||
"F"
|
||||
],
|
||||
"spellcastingTags": [
|
||||
"O"
|
||||
],
|
||||
"miscTags": [
|
||||
"AOE"
|
||||
],
|
||||
"savingThrowForced": [
|
||||
"dexterity"
|
||||
],
|
||||
"savingThrowForcedSpell": [
|
||||
"dexterity"
|
||||
],
|
||||
"hasToken": true,
|
||||
"hasFluffImages": true
|
||||
},
|
||||
{
|
||||
"name": "Ervan Soulfallen",
|
||||
"isNpc": true,
|
||||
"isNamedCreature": true,
|
||||
"source": "LRDT",
|
||||
"page": 11,
|
||||
"size": [
|
||||
"M"
|
||||
],
|
||||
"type": {
|
||||
"type": "humanoid",
|
||||
"tags": [
|
||||
"human"
|
||||
]
|
||||
},
|
||||
"alignment": [
|
||||
"C",
|
||||
"E"
|
||||
],
|
||||
"ac": [
|
||||
12,
|
||||
{
|
||||
"ac": 15,
|
||||
"condition": "with {@spell mage armor}",
|
||||
"braces": true
|
||||
}
|
||||
],
|
||||
"hp": {
|
||||
"average": 84,
|
||||
"formula": "13d8 + 26"
|
||||
},
|
||||
"speed": {
|
||||
"walk": 30
|
||||
},
|
||||
"str": 10,
|
||||
"dex": 15,
|
||||
"con": 14,
|
||||
"int": 11,
|
||||
"wis": 8,
|
||||
"cha": 17,
|
||||
"skill": {
|
||||
"arcana": "3",
|
||||
"deception": "+6"
|
||||
},
|
||||
"passive": 9,
|
||||
"languages": [
|
||||
"Common",
|
||||
"Draconic"
|
||||
],
|
||||
"cr": "5",
|
||||
"spellcasting": [
|
||||
{
|
||||
"name": "Spellcasting",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"Ervan casts one of the following spells, using Charisma as the spellcasting ability (spell save {@dc 14}):"
|
||||
],
|
||||
"will": [
|
||||
"{@spell Light}",
|
||||
"{@spell Mage Hand}"
|
||||
],
|
||||
"daily": {
|
||||
"2": [
|
||||
"{@spell Dimension Door}"
|
||||
],
|
||||
"1e": [
|
||||
"{@spell Disguise Self}",
|
||||
"{@spell Levitate}",
|
||||
"{@spell Mage Armor}"
|
||||
]
|
||||
},
|
||||
"ability": "cha",
|
||||
"displayAs": "action"
|
||||
}
|
||||
],
|
||||
"action": [
|
||||
{
|
||||
"name": "Multiattack",
|
||||
"entries": [
|
||||
"Ervan uses his staff to make three Arcane Blast attacks."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Arcane Blast",
|
||||
"entries": [
|
||||
"{@atk ms,rs} {@hit 6} to hit, reach 5 ft. or range 120 ft., one target. {@h}13 ({@damage 3d6 + 3}) force damage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Acid Rain (Recharges after a Short or Long Rest)",
|
||||
"entries": [
|
||||
"Acid falls in a 10-foot-radius, 20-foot-high cylinder centered on a point Ervan can see within 120 feet of himself. Each creature in that area must make a {@dc 14} Dexterity saving throw, taking 22 ({@damage 4d10}) acid damage on a failed save, or half as much damage on a successful one."
|
||||
]
|
||||
}
|
||||
],
|
||||
"actionTags": [
|
||||
"Multiattack"
|
||||
],
|
||||
"languageTags": [
|
||||
"C",
|
||||
"DR"
|
||||
],
|
||||
"damageTags": [
|
||||
"A",
|
||||
"O"
|
||||
],
|
||||
"damageTagsSpell": [
|
||||
"O"
|
||||
],
|
||||
"spellcastingTags": [
|
||||
"O"
|
||||
],
|
||||
"miscTags": [
|
||||
"AOE"
|
||||
],
|
||||
"savingThrowForced": [
|
||||
"dexterity"
|
||||
],
|
||||
"savingThrowForcedSpell": [
|
||||
"constitution",
|
||||
"dexterity"
|
||||
],
|
||||
"hasToken": true,
|
||||
"hasFluffImages": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -47276,6 +47276,9 @@
|
||||
"type": "internal",
|
||||
"path": "bestiary/mule.mp3"
|
||||
},
|
||||
"traitTags": [
|
||||
"Beast of Burden"
|
||||
],
|
||||
"damageTags": [
|
||||
"B"
|
||||
],
|
||||
|
||||
@ -8702,6 +8702,9 @@
|
||||
"type": "internal",
|
||||
"path": "bestiary/rothe.mp3"
|
||||
},
|
||||
"traitTags": [
|
||||
"Beast of Burden"
|
||||
],
|
||||
"senseTags": [
|
||||
"D"
|
||||
],
|
||||
@ -28636,6 +28639,9 @@
|
||||
"type": "internal",
|
||||
"path": "bestiary/ox.mp3"
|
||||
},
|
||||
"traitTags": [
|
||||
"Beast of Burden"
|
||||
],
|
||||
"damageTags": [
|
||||
"P"
|
||||
],
|
||||
|
||||
@ -7838,6 +7838,41 @@
|
||||
"Common",
|
||||
"Giant"
|
||||
],
|
||||
"spellcasting": [
|
||||
{
|
||||
"name": "Innate Spellcasting",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"The giant's innate spellcasting ability is Charisma. It can innately cast the following spells, requiring no material components:"
|
||||
],
|
||||
"will": [
|
||||
"{@spell detect magic}",
|
||||
"{@spell fog cloud}",
|
||||
"{@spell light}"
|
||||
],
|
||||
"daily": {
|
||||
"3e": [
|
||||
"{@spell feather fall}",
|
||||
"{@spell fly}",
|
||||
"{@spell misty step}",
|
||||
"{@spell telekinesis}"
|
||||
],
|
||||
"1e": [
|
||||
"{@spell control weather}",
|
||||
"{@spell gaseous form}"
|
||||
]
|
||||
},
|
||||
"ability": "cha"
|
||||
}
|
||||
],
|
||||
"trait": [
|
||||
{
|
||||
"name": "Keen Smell",
|
||||
"entries": [
|
||||
"The giant has advantage on Wisdom ({@skill Perception}) checks that rely on smell."
|
||||
]
|
||||
}
|
||||
],
|
||||
"traitTags": [
|
||||
"Keen Senses"
|
||||
],
|
||||
|
||||
@ -8210,10 +8210,18 @@
|
||||
"name": "Spellcasting (3/Day; Humanoid Form Only)",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"The bone collective casts the animate dead spell as an action, requiring no material components and using Charisma as the spellcasting ability (spell save {@dc 14})."
|
||||
"The bone collective casts the {@spell animate dead} spell as an action, requiring no material components and using Charisma as the spellcasting ability (spell save {@dc 14})."
|
||||
],
|
||||
"daily": {
|
||||
"3e": [
|
||||
"{@spell animate dead}"
|
||||
]
|
||||
},
|
||||
"ability": "cha",
|
||||
"displayAs": "action"
|
||||
"displayAs": "action",
|
||||
"hidden": [
|
||||
"daily"
|
||||
]
|
||||
}
|
||||
],
|
||||
"trait": [
|
||||
@ -50583,10 +50591,18 @@
|
||||
"name": "Spellcasting (3/Day)",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"The stryx casts the comprehend languages spell, requiring no material components and using Wisdom as the spellcasting ability."
|
||||
"The stryx casts the {@spell comprehend languages} spell, requiring no material components and using Wisdom as the spellcasting ability."
|
||||
],
|
||||
"daily": {
|
||||
"3e": [
|
||||
"{@spell comprehend languages}"
|
||||
]
|
||||
},
|
||||
"ability": "wis",
|
||||
"displayAs": "action"
|
||||
"displayAs": "action",
|
||||
"hidden": [
|
||||
"daily"
|
||||
]
|
||||
}
|
||||
],
|
||||
"trait": [
|
||||
@ -56667,16 +56683,13 @@
|
||||
"Common"
|
||||
],
|
||||
"cr": "6",
|
||||
"spellcasting": [
|
||||
"trait": [
|
||||
{
|
||||
"name": "Spellcasting Animosity",
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [
|
||||
"entries": [
|
||||
"If the white ape sees a creature cast a spell, the ape has advantage on attack rolls against that creature on the ape's next turn."
|
||||
]
|
||||
}
|
||||
],
|
||||
"trait": [
|
||||
},
|
||||
{
|
||||
"name": "Arcane Wasting",
|
||||
"entries": [
|
||||
@ -56737,9 +56750,6 @@
|
||||
"B",
|
||||
"P"
|
||||
],
|
||||
"spellcastingTags": [
|
||||
"O"
|
||||
],
|
||||
"miscTags": [
|
||||
"AOE",
|
||||
"MW"
|
||||
|
||||
@ -15243,6 +15243,7 @@
|
||||
"path": "bestiary/ox.mp3"
|
||||
},
|
||||
"traitTags": [
|
||||
"Beast of Burden",
|
||||
"Charge"
|
||||
],
|
||||
"damageTags": [
|
||||
|
||||
30
data/bestiary/fluff-bestiary-lrdt.json
Normal file
30
data/bestiary/fluff-bestiary-lrdt.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"monsterFluff": [
|
||||
{
|
||||
"name": "Alax Jadescales",
|
||||
"source": "LRDT",
|
||||
"images": [
|
||||
{
|
||||
"type": "image",
|
||||
"href": {
|
||||
"type": "internal",
|
||||
"path": "bestiary/LRDT/Alax Jadescales.webp"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Ervan Soulfallen",
|
||||
"source": "LRDT",
|
||||
"images": [
|
||||
{
|
||||
"type": "image",
|
||||
"href": {
|
||||
"type": "internal",
|
||||
"path": "bestiary/LRDT/Ervan Soulfallen.webp"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -124,7 +124,7 @@
|
||||
"type": "entries",
|
||||
"name": "A Hard Life",
|
||||
"entries": [
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014 and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -793,7 +793,7 @@
|
||||
"type": "entries",
|
||||
"name": "A Hard Life",
|
||||
"entries": [
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014 and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1657,7 +1657,7 @@
|
||||
"type": "entries",
|
||||
"name": "Iron Eaters",
|
||||
"entries": [
|
||||
"The asanbosam diet includes iron in red meat, poultry, fish, and leaf vegetables, and\u2014in times of desperation\u2014 grinding iron filings off their own hooks to slake their cravings. The asanbosams' taste for fresh blood and humanoid flesh led to the folklore that they are vampiric (not true)."
|
||||
"The asanbosam diet includes iron in red meat, poultry, fish, and leaf vegetables, and\u2014in times of desperation\u2014grinding iron filings off their own hooks to slake their cravings. The asanbosams' taste for fresh blood and humanoid flesh led to the folklore that they are vampiric (not true)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -3339,7 +3339,7 @@
|
||||
"type": "entries",
|
||||
"name": "A Hard Life",
|
||||
"entries": [
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014 and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -7716,7 +7716,7 @@
|
||||
"type": "entries",
|
||||
"name": "Elvish Water Steeds",
|
||||
"entries": [
|
||||
"Known by their Elvish name, these large fey water striders were enchanted and bred by the elves in ages past, when their explorers roamed the world. Elven mages started with normal water striders and\u2014through elaborate magical procedures and complex cross-breeding programs\u2014 transformed the mundane water striders into large, docile mounts. They can cross large bodies of water quickly while carrying a humanoid rider, even in windy conditions."
|
||||
"Known by their Elvish name, these large fey water striders were enchanted and bred by the elves in ages past, when their explorers roamed the world. Elven mages started with normal water striders and\u2014through elaborate magical procedures and complex cross-breeding programs\u2014transformed the mundane water striders into large, docile mounts. They can cross large bodies of water quickly while carrying a humanoid rider, even in windy conditions."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -8878,7 +8878,7 @@
|
||||
"type": "entries",
|
||||
"name": "Relics of Dark Gods",
|
||||
"entries": [
|
||||
"Idolic deities are found in ancient temples and deserted tombs. They are relics of an elder age and all that remain of the favored children of a deceiving dark god\u2014 mighty lordlings like Akoman the Evil Thought, Nanghant the Discontented, and Sarvar the Oppressor. Sent to consume the souls of those worshiping gods of light, these beings of shadow and sand labor slowly through corruption of the soul rather than outright war."
|
||||
"Idolic deities are found in ancient temples and deserted tombs. They are relics of an elder age and all that remain of the favored children of a deceiving dark god\u2014mighty lordlings like Akoman the Evil Thought, Nanghant the Discontented, and Sarvar the Oppressor. Sent to consume the souls of those worshiping gods of light, these beings of shadow and sand labor slowly through corruption of the soul rather than outright war."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -11552,7 +11552,7 @@
|
||||
"type": "entries",
|
||||
"name": "Urchin Rhymes and Songs",
|
||||
"entries": [
|
||||
"Some mylings maintain traces of the personalities they had while alive\u2014 charming, sullen, or sadistic\u2014and can speak touchingly and piteously. Dressed in ragged clothing, their skin blue with cold, they sometimes reach victims who believe they are helping an injured child or young adult. They hide their faces and sing innocent rhymes when they aren't screeching in fury, for they know that their dead eyes and cold blue skin cause fright and alarm."
|
||||
"Some mylings maintain traces of the personalities they had while alive\u2014charming, sullen, or sadistic\u2014and can speak touchingly and piteously. Dressed in ragged clothing, their skin blue with cold, they sometimes reach victims who believe they are helping an injured child or young adult. They hide their faces and sing innocent rhymes when they aren't screeching in fury, for they know that their dead eyes and cold blue skin cause fright and alarm."
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -11904,7 +11904,7 @@
|
||||
"type": "entries",
|
||||
"name": "Changed by Planar Wandering",
|
||||
"entries": [
|
||||
"The plane-wanderers hadn't died. Instead, their eons-long exposure to alien realms and the space between changed them, restructuring their life force, making them into something even more nightmarish\u2014 but better able to withstand both strange hells and golden realms of eldritch delight. They returned even more corrupt and powerful than when left, and these wandering nihileths returned to the mortal world intent on spreading the influence of the Void and the utter evil they found in the vast darkness between worlds."
|
||||
"The plane-wanderers hadn't died. Instead, their eons-long exposure to alien realms and the space between changed them, restructuring their life force, making them into something even more nightmarish\u2014but better able to withstand both strange hells and golden realms of eldritch delight. They returned even more corrupt and powerful than when left, and these wandering nihileths returned to the mortal world intent on spreading the influence of the Void and the utter evil they found in the vast darkness between worlds."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -11963,7 +11963,7 @@
|
||||
"type": "entries",
|
||||
"name": "Changed by Planar Wandering",
|
||||
"entries": [
|
||||
"The plane-wanderers hadn't died. Instead, their eons-long exposure to alien realms and the space between changed them, restructuring their life force, making them into something even more nightmarish\u2014 but better able to withstand both strange hells and golden realms of eldritch delight. They returned even more corrupt and powerful than when left, and these wandering nihileths returned to the mortal world intent on spreading the influence of the Void and the utter evil they found in the vast darkness between worlds."
|
||||
"The plane-wanderers hadn't died. Instead, their eons-long exposure to alien realms and the space between changed them, restructuring their life force, making them into something even more nightmarish\u2014but better able to withstand both strange hells and golden realms of eldritch delight. They returned even more corrupt and powerful than when left, and these wandering nihileths returned to the mortal world intent on spreading the influence of the Void and the utter evil they found in the vast darkness between worlds."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -12001,7 +12001,7 @@
|
||||
"type": "entries",
|
||||
"name": "Changed by Planar Wandering",
|
||||
"entries": [
|
||||
"The plane-wanderers hadn't died. Instead, their eons-long exposure to alien realms and the space between changed them, restructuring their life force, making them into something even more nightmarish\u2014 but better able to withstand both strange hells and golden realms of eldritch delight. They returned even more corrupt and powerful than when left, and these wandering nihileths returned to the mortal world intent on spreading the influence of the Void and the utter evil they found in the vast darkness between worlds."
|
||||
"The plane-wanderers hadn't died. Instead, their eons-long exposure to alien realms and the space between changed them, restructuring their life force, making them into something even more nightmarish\u2014but better able to withstand both strange hells and golden realms of eldritch delight. They returned even more corrupt and powerful than when left, and these wandering nihileths returned to the mortal world intent on spreading the influence of the Void and the utter evil they found in the vast darkness between worlds."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -15081,7 +15081,7 @@
|
||||
{
|
||||
"type": "entries",
|
||||
"entries": [
|
||||
"The ground, lush and overgrown, squelches under every footstep. Curtains of menacing vines block the way, and muffled groans echo distantly under the darkening canopy. By the time you realize the ground is moving, it's too late\u2014 the shambling mound has taken you.",
|
||||
"The ground, lush and overgrown, squelches under every footstep. Curtains of menacing vines block the way, and muffled groans echo distantly under the darkening canopy. By the time you realize the ground is moving, it's too late\u2014the shambling mound has taken you.",
|
||||
"Found in overgrown swamps, stinking marshes, dense wodes, and dark, damp rainforests, the shambling mound is a wandering mass of vegetation that feeds on everything in their path.",
|
||||
{
|
||||
"type": "entries",
|
||||
@ -18055,7 +18055,7 @@
|
||||
"type": "entries",
|
||||
"name": "Sustained by Darkness",
|
||||
"entries": [
|
||||
"Voidlings are said to devour life and knowledge, and they subsist on darkness. The places they inhabit are known for their dank chill and obscurity. Voidlings are summoned by those hungry for power at any cost, and\u2014despite their dark reputation\u2014 they serve well for years or even decades, until one day they turn on their summoners. If they slay their summoner, they grow in strength and return to the Void. Exactly what voidlings seek when they have not been summoned\u2014and what triggers their betrayals\u2014is a mystery."
|
||||
"Voidlings are said to devour life and knowledge, and they subsist on darkness. The places they inhabit are known for their dank chill and obscurity. Voidlings are summoned by those hungry for power at any cost, and\u2014despite their dark reputation\u2014they serve well for years or even decades, until one day they turn on their summoners. If they slay their summoner, they grow in strength and return to the Void. Exactly what voidlings seek when they have not been summoned\u2014and what triggers their betrayals\u2014is a mystery."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -18678,7 +18678,7 @@
|
||||
"type": "entries",
|
||||
"name": "Dimensional Travelers",
|
||||
"entries": [
|
||||
"The clandestine xhkarsh are beings from another cosmic cycle. Their devices and armor are incomprehensible\u2014possibly even incompatible with\u2014 creatures of this reality."
|
||||
"The clandestine xhkarsh are beings from another cosmic cycle. Their devices and armor are incomprehensible\u2014possibly even incompatible with\u2014creatures of this reality."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -18788,7 +18788,7 @@
|
||||
"type": "entries",
|
||||
"name": "A Hard Life",
|
||||
"entries": [
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014 and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
"Limited food underground makes truly ancient cave dragons almost unheard of. The eldest tend to die of starvation after stripping their territory bare of prey. Their nigh-endless hunger leaves the ancients the most likely of cave dragons to form alliances, especially with allies that promise\u2014and deliver\u2014food. On occasion, cave dragons climb to the surface to feed, but their earthbound, plodding pace leaves them outcompeted by other predators or unable to keep up with swift or flying prey. They prefer tight tunnels where they can ambush and outmaneuver prey."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
"LLK": "fluff-bestiary-llk.json",
|
||||
"LMoP": "fluff-bestiary-lmop.json",
|
||||
"LR": "fluff-bestiary-lr.json",
|
||||
"LRDT": "fluff-bestiary-lrdt.json",
|
||||
"LoX": "fluff-bestiary-lox.json",
|
||||
"MaBJoV": "fluff-bestiary-mabjov.json",
|
||||
"MCV1SC": "fluff-bestiary-mcv1sc.json",
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
"LMoP": "bestiary-lmop.json",
|
||||
"LoX": "bestiary-lox.json",
|
||||
"LR": "bestiary-lr.json",
|
||||
"LRDT": "bestiary-lrdt.json",
|
||||
"MaBJoV": "bestiary-mabjov.json",
|
||||
"MCV1SC": "bestiary-mcv1sc.json",
|
||||
"MCV2DC": "bestiary-mcv2dc.json",
|
||||
|
||||
@ -476,6 +476,7 @@
|
||||
"path": "covers/Screen.webp"
|
||||
},
|
||||
"published": "2015-01-20",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Tables"
|
||||
@ -695,6 +696,7 @@
|
||||
"path": "covers/AL.webp"
|
||||
},
|
||||
"published": "2016-08-26",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Faction Guide",
|
||||
@ -1168,6 +1170,7 @@
|
||||
"path": "covers/GGR.webp"
|
||||
},
|
||||
"published": "2018-11-20",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Welcome to Ravnica",
|
||||
@ -1303,6 +1306,7 @@
|
||||
"path": "covers/SAC.webp"
|
||||
},
|
||||
"published": "2019-01-31",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Sage Advice Compendium",
|
||||
@ -1418,6 +1422,7 @@
|
||||
"path": "covers/AI.webp"
|
||||
},
|
||||
"published": "2019-06-18",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Acquisitions Incorporated",
|
||||
@ -1560,6 +1565,7 @@
|
||||
"path": "covers/RMR.webp"
|
||||
},
|
||||
"published": "2019-11-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "How to Play",
|
||||
@ -1669,6 +1675,7 @@
|
||||
"path": "covers/ERLW.webp"
|
||||
},
|
||||
"published": "2019-11-19",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Welcome to Eberron",
|
||||
@ -1933,6 +1940,7 @@
|
||||
"path": "covers/EGW.webp"
|
||||
},
|
||||
"published": "2020-03-17",
|
||||
"author": "Darrington Press",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Preface"
|
||||
@ -2238,6 +2246,7 @@
|
||||
"path": "covers/MOT.webp"
|
||||
},
|
||||
"published": "2020-06-02",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Welcome to Theros",
|
||||
@ -2366,6 +2375,7 @@
|
||||
"path": "covers/ScreenDungeonKit.webp"
|
||||
},
|
||||
"published": "2020-09-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Screen",
|
||||
@ -2566,6 +2576,7 @@
|
||||
"path": "covers/ScreenWildernessKit.webp"
|
||||
},
|
||||
"published": "2020-11-17",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Wilderness Journeys"
|
||||
@ -2744,6 +2755,7 @@
|
||||
"path": "covers/VRGR.webp"
|
||||
},
|
||||
"published": "2021-05-18",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Welcome to Ravenloft",
|
||||
@ -3388,6 +3400,7 @@
|
||||
"path": "covers/DoD.webp"
|
||||
},
|
||||
"published": "2021-09-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Feywild Overview",
|
||||
@ -4324,6 +4337,7 @@
|
||||
"path": "covers/SAiS.webp"
|
||||
},
|
||||
"published": "2022-08-16",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Introduction: Vast Oceans of Adventure",
|
||||
@ -4402,6 +4416,7 @@
|
||||
"path": "covers/SAiS.webp"
|
||||
},
|
||||
"published": "2022-08-16",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Introduction",
|
||||
@ -4427,6 +4442,7 @@
|
||||
"path": "covers/ScreenSpelljammer.webp"
|
||||
},
|
||||
"published": "2022-08-16",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Screen"
|
||||
@ -4458,8 +4474,12 @@
|
||||
"id": "ToB1-2023",
|
||||
"source": "ToB1-2023",
|
||||
"group": "supplement-alt",
|
||||
"coverUrl": "img/covers/ToB1-2023.webp",
|
||||
"cover": {
|
||||
"type": "internal",
|
||||
"path": "covers/ToB1-2023.webp"
|
||||
},
|
||||
"published": "2023-05-31",
|
||||
"author": "Kobold Press",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Introduction",
|
||||
@ -4620,6 +4640,7 @@
|
||||
"path": "covers/MCV4EC.webp"
|
||||
},
|
||||
"published": "2023-09-21",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Monstrous Compendium Vol. Four: Eldraine Creatures",
|
||||
@ -4645,6 +4666,7 @@
|
||||
"path": "covers/PAitM.webp"
|
||||
},
|
||||
"published": "2023-10-07",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Introduction: Multiversal Menagerie",
|
||||
@ -4700,6 +4722,7 @@
|
||||
"path": "covers/PAitM.webp"
|
||||
},
|
||||
"published": "2023-10-07",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Introduction: Infinite Doors to Adventure",
|
||||
@ -4768,6 +4791,7 @@
|
||||
"path": "covers/AATM.webp"
|
||||
},
|
||||
"published": "2023-10-17",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Adventure Atlas: The Mortuary",
|
||||
@ -4932,6 +4956,7 @@
|
||||
"path": "covers/BMT.webp"
|
||||
},
|
||||
"published": "2023-11-14",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "Fool",
|
||||
@ -5625,6 +5650,7 @@
|
||||
"path": "covers/DMTCRG.webp"
|
||||
},
|
||||
"published": "2023-11-14",
|
||||
"author": "Wizards RPG Team",
|
||||
"contents": [
|
||||
{
|
||||
"name": "The Deck of Many Things",
|
||||
|
||||
@ -2679,5 +2679,11 @@
|
||||
"date": "2024-03-26",
|
||||
"title": "Mind the Step",
|
||||
"txt": "- Added Descent into the Lost Caverns of Tsojcanth content\n- (Brew) Improved Item Text Converter handling of generic variant armor types\n- (Brew) Improved Creature Text Converter handling of bulleted lists\n- (Fixed typos/added tags)"
|
||||
},
|
||||
{
|
||||
"ver": "1.204.0",
|
||||
"date": "2024-04-02",
|
||||
"title": "Brickolage",
|
||||
"txt": "- Added Red Dragon's Tale: A LEGO Adventure content\n- Added optional \"feeling lucky\" parameter to Search page for use in browser custom search engine configuration. Note that this changes the syntax for any custom search engines; `?<search>` -> `?q=<search>[&lucky]` (i.e. `?q=goblin` or `?q=goblin&lucky`)\n- Added \"Page\" column to List page Table Views\n- Fixed dice rollers in Decks page card viewer\n- (Brew) Improved Creature Text Converter handling of spells in spellcasting headers\n- (Fixed typos/added tags)"
|
||||
}
|
||||
]
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -21,7 +21,7 @@
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"Style tags; {@bold some text to be bolded} (alternative {@b shorthand}), {@italic some text to be italicised} (alternative {@i shorthand}), {@underline some text to be underlined} (alternative {@u shorthand}), {@strike some text to strike-through}, (alternative {@s shorthand}), {@color color|e40707}/{@color color variable|--rgb-name} tags, {@highlight highlight} tags, {@sup superscript} tags, {@sub subscript} tags, {@kbd keyboard} tags, {@code print("hello world")} tags, misc {@style Style|small-caps;small;capitalize;dnd-font} tags, {@font alternate font|Comic Sans MS} tags",
|
||||
"Style tags; {@bold some text to be bolded} (alternative {@b shorthand}), {@italic some text to be italicised} (alternative {@i shorthand}), {@underline some text to be underlined} (alternative {@u shorthand}), {@underlineDouble some text to be underlined} (alternative {@u2 shorthand}), {@strike some text to strike-through}, (alternative {@s shorthand}), , {@strikeDouble some text to strike-through}, (alternative {@s2 shorthand}), {@color color|e40707}/{@color color variable|--rgb-name} tags, {@highlight highlight} tags, {@sup superscript} tags, {@sub subscript} tags, {@kbd keyboard} tags, {@code print("hello world")} tags, misc {@style Style|small-caps;small;capitalize;dnd-font} tags, {@font alternate font|Comic Sans MS} tags",
|
||||
"Additionally, {@note note tags}, used for adding errata or Twitter \"designer footnotes,\" and {@tip tooltip tags|a note}.",
|
||||
"Dice roller tags; {@dice 1d2-2+2d3+5} for regular dice rolls ({@dice 1d6;2d6} for multiple options; {@dice 1d6 + #$prompt_number:min=1,title=Enter a Number!,default=123$#} for input prompts), with extended {@dice 1d20+2|display text} and {@dice 1d20+2|display text|rolled by name}, and a special 'hit' version which assumes a d20 is to be rolled {@hit +7} (and rolls advantage on {@kbd SHIFT}+click, disadvantage on {@kbd ALT}+click). There's also {@damage 1d12+3} which will roll critical hits on {@kbd SHIFT}+click and half damage (rounding down) on {@kbd ALT}+click, and {@d20 -4} which will also roll advantage/disadvantage, although @hit tags are preferred where appropriate. Spells can have scaling-dice tags, (damage of 2d6 or 3d6 at level 1, add an extra {@scaledamage 2d6;3d6|2-9|1d6} for each level beyond 2nd; or, roll 2d6 when using 1 psi point, add an {@scaledice 2d6|1,3,5,7,9|1d6|psi|extra amount} for each additional psi point spent), for when a spell effect scales at higher levels. {@ability str 20}, {@savingThrow str 5}, and {@skillCheck animal_handling 5} are used as internal shorthand, but may be useful elsewhere.",
|
||||
"Auto dice tags; as above, but a result is automatically rolled upon rendering: {@autodice 2d10+2}.",
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
<button class="btn btn-default reset" id="reset" type="button">Reset</button>
|
||||
</div>
|
||||
|
||||
<div class="flex-col overflow-y-scroll min-h-0 pr-2" data-name="tablepage-wrp-list">
|
||||
<div class="flex-col ve-overflow-y-scroll min-h-0 pr-2" data-name="tablepage-wrp-list">
|
||||
<!-- populate with JS -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -224,7 +224,7 @@ Unearthed Arcana content can be accessed by cycling the "All Sources"
|
||||
<p><b>Anything else I should know?</b> Hold <kbd>SHIFT</kbd> when hovering to lock a window in place. Everything has tooltips. You will forever be a DM.</p>
|
||||
|
||||
<h3>Self-Hosting</h3>
|
||||
<p>You can host a copy of 5etools on anything that can run a basic webserver—examples include <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server" rel="noopener noreferrer">your computer</a>, <a href="https://play.google.com/store/apps/details?id=com.sylkat.apache" rel="noopener noreferrer">your phone</a>, a <a href="https://www.raspberrypi.org/products/" rel="noopener noreferrer">Raspberry Pi</a>, or a free <a href="https://aws.amazon.com/free" rel="noopener noreferrer">EC2</a>/<a href="https://cloud.google.com/free" rel="noopener noreferrer">Compute Engine</a> instance. <a href="https://github.com/5etools-mirror-2/5etools-mirror-2.github.io/releases/latest" rel="noopener noreferrer">Download the files</a>, copy them into your server's root directory, and enjoy!</p>
|
||||
<p>You can host a copy of 5etools on anything that can run a basic webserver—examples include <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server" rel="noopener noreferrer">your computer</a>, <a href="https://play.google.com/store/apps/details?id=com.sylkat.apache" rel="noopener noreferrer">your phone</a>, a <a href="https://www.raspberrypi.org/products/" rel="noopener noreferrer">Raspberry Pi</a>, or a free <a href="https://aws.amazon.com/free" rel="noopener noreferrer">EC2</a>/<a href="https://cloud.google.com/free" rel="noopener noreferrer">Compute Engine</a> instance. <a href="https://github.com/5etools-mirror-2/5etools-mirror-2.github.io/releases/latest" rel="noopener noreferrer">Download the files</a> and <a href="https://github.com/5etools-mirror-2/5etools-img/releases/latest" rel="noopener noreferrer">images</a>, <a href="https://wiki.tercept.net/en/5eTools/InstallGuide" rel="noopener noreferrer">copy them into your server's root directory</a>, and enjoy!</p>
|
||||
|
||||
<h3 title=":^)">Disclaimer</h3>
|
||||
<p title=":^)">5etools is intended as an easily-accessible digital reference for products you already own. Please ensure you only access content in accordance with your local laws.</p>
|
||||
|
||||
@ -302,6 +302,7 @@ class BestiaryPage extends ListPageMultiSource {
|
||||
colTransforms: {
|
||||
name: UtilsTableview.COL_TRANSFORM_NAME,
|
||||
source: UtilsTableview.COL_TRANSFORM_SOURCE,
|
||||
page: UtilsTableview.COL_TRANSFORM_PAGE,
|
||||
size: {name: "Size", transform: size => Renderer.utils.getRenderedSize(size)},
|
||||
type: {name: "Type", transform: type => Parser.monTypeToFullObj(type).asText},
|
||||
alignment: {name: "Alignment", transform: align => Parser.alignmentListToFull(align)},
|
||||
|
||||
@ -226,7 +226,7 @@ class BlocklistUi {
|
||||
<button class="ve-col-1 sort btn btn-default btn-xs" disabled> </button>
|
||||
</div>`;
|
||||
|
||||
const $wrpList = $(`<div class="list-display-only smooth-scroll overflow-y-auto h-100 min-h-0"></div>`);
|
||||
const $wrpList = $(`<div class="list-display-only smooth-scroll ve-overflow-y-auto h-100 min-h-0"></div>`);
|
||||
|
||||
$$(this._$wrpContent.empty())`
|
||||
${this._$wrpControls}
|
||||
|
||||
@ -2375,7 +2375,7 @@ ClassesPage.ClassBookView = class extends BookModeViewBase {
|
||||
|
||||
// Main panel
|
||||
const $tblBook = $(`<table class="w-100 stats stats--book stats--book-large stats--bkmv"></div>`);
|
||||
$$`<div class="ve-flex-col overflow-y-auto container">${$tblBook}</div>`.appendTo($wrpContent);
|
||||
$$`<div class="ve-flex-col ve-overflow-y-auto container">${$tblBook}</div>`.appendTo($wrpContent);
|
||||
|
||||
const renderStack = [];
|
||||
Renderer.get().setFirstSection(true);
|
||||
|
||||
@ -1432,7 +1432,17 @@ class CreatureParser extends BaseParser {
|
||||
const spellcasting = [];
|
||||
stats[prop] = stats[prop].map(ent => {
|
||||
if (!ent.name || !ent.name.toLowerCase().includes("spellcasting")) return ent;
|
||||
const parsed = SpellcastingTraitConvert.tryParseSpellcasting(ent, {isMarkdown, cbErr: options.cbErr, displayAs: prop, actions: stats.action, reactions: stats.reaction});
|
||||
const parsed = SpellcastingTraitConvert.tryParseSpellcasting(
|
||||
ent,
|
||||
{
|
||||
isMarkdown,
|
||||
cbMan: (wrn) => options.cbWarning(`${stats.name ? `(${stats.name}) ` : ""}${wrn}`),
|
||||
cbErr: (err) => options.cbWarning(`${stats.name ? `(${stats.name}) ` : ""}${err}`),
|
||||
displayAs: prop,
|
||||
actions: stats.action,
|
||||
reactions: stats.reaction,
|
||||
},
|
||||
);
|
||||
if (!parsed) return ent;
|
||||
spellcasting.push(parsed);
|
||||
return null;
|
||||
|
||||
@ -645,7 +645,130 @@ class AlignmentConvert {
|
||||
globalThis.AlignmentConvert = AlignmentConvert;
|
||||
|
||||
class TraitActionTag {
|
||||
static _doTag ({m, cbMan, prop, outProp}) {
|
||||
static _TAGS = { // true = map directly; string = map to this string
|
||||
trait: {
|
||||
"turn immunity": "Turn Immunity",
|
||||
"brute": "Brute",
|
||||
"antimagic susceptibility": "Antimagic Susceptibility",
|
||||
"sneak attack": "Sneak Attack",
|
||||
"reckless": "Reckless",
|
||||
"web sense": "Web Sense",
|
||||
"flyby": "Flyby",
|
||||
"pounce": "Pounce",
|
||||
"water breathing": "Water Breathing",
|
||||
|
||||
"turn resistance": "Turn Resistance",
|
||||
"turn defiance": "Turn Resistance",
|
||||
"turning defiance": "Turn Resistance",
|
||||
"turn resistance aura": "Turn Resistance",
|
||||
"undead fortitude": "Undead Fortitude",
|
||||
|
||||
"aggressive": "Aggressive",
|
||||
"illumination": "Illumination",
|
||||
"rampage": "Rampage",
|
||||
"rejuvenation": "Rejuvenation",
|
||||
"web walker": "Web Walker",
|
||||
"incorporeal movement": "Incorporeal Movement",
|
||||
"incorporeal passage": "Incorporeal Movement",
|
||||
|
||||
"keen hearing and smell": "Keen Senses",
|
||||
"keen sight and smell": "Keen Senses",
|
||||
"keen hearing and sight": "Keen Senses",
|
||||
"keen hearing": "Keen Senses",
|
||||
"keen smell": "Keen Senses",
|
||||
"keen senses": "Keen Senses",
|
||||
|
||||
"hold breath": "Hold Breath",
|
||||
|
||||
"charge": "Charge",
|
||||
|
||||
"fey ancestry": "Fey Ancestry",
|
||||
|
||||
"siege monster": "Siege Monster",
|
||||
|
||||
"pack tactics": "Pack Tactics",
|
||||
|
||||
"regeneration": "Regeneration",
|
||||
|
||||
"shapechanger": "Shapechanger",
|
||||
|
||||
"false appearance": "False Appearance",
|
||||
|
||||
"spider climb": "Spider Climb",
|
||||
|
||||
"sunlight sensitivity": "Sunlight Sensitivity",
|
||||
"sunlight hypersensitivity": "Sunlight Sensitivity",
|
||||
"light sensitivity": "Light Sensitivity",
|
||||
"vampire weaknesses": "Sunlight Sensitivity",
|
||||
|
||||
"amphibious": "Amphibious",
|
||||
|
||||
"legendary resistance": "Legendary Resistances",
|
||||
|
||||
"magic weapon": "Magic Weapons",
|
||||
"magic weapons": "Magic Weapons",
|
||||
|
||||
"magic resistance": "Magic Resistance",
|
||||
|
||||
"spell immunity": "Spell Immunity",
|
||||
|
||||
"ambush": "Ambusher",
|
||||
"ambusher": "Ambusher",
|
||||
|
||||
"amorphous": "Amorphous",
|
||||
"amorphous form": "Amorphous",
|
||||
|
||||
"death burst": "Death Burst",
|
||||
"death throes": "Death Burst",
|
||||
|
||||
"devil's sight": "Devil's Sight",
|
||||
"devil sight": "Devil's Sight",
|
||||
|
||||
"immutable form": "Immutable Form",
|
||||
|
||||
"tree stride": "Tree Stride",
|
||||
|
||||
"unusual nature": "Unusual Nature",
|
||||
|
||||
"tunneler": "Tunneler",
|
||||
|
||||
"beast of burden": "Beast of Burden",
|
||||
},
|
||||
action: {
|
||||
"multiattack": "Multiattack",
|
||||
"frightful presence": "Frightful Presence",
|
||||
"teleport": "Teleport",
|
||||
"swallow": "Swallow",
|
||||
"tentacle": "Tentacles",
|
||||
"tentacles": "Tentacles",
|
||||
"change shape": "Shapechanger",
|
||||
},
|
||||
reaction: {
|
||||
"parry": "Parry",
|
||||
},
|
||||
bonus: {
|
||||
"change shape": "Shapechanger",
|
||||
},
|
||||
legendary: {
|
||||
// unused
|
||||
},
|
||||
mythic: {
|
||||
// unused
|
||||
},
|
||||
};
|
||||
|
||||
static _TAGS_DEEP = {
|
||||
action: {
|
||||
"Swallow": strEntries => /\bswallowed\b/i.test(strEntries),
|
||||
},
|
||||
};
|
||||
|
||||
static _doAdd ({tags, tag, allowlist}) {
|
||||
if (allowlist && !allowlist.has(tag)) return;
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
static _doTag ({m, cbMan, prop, tags, allowlist}) {
|
||||
if (!m[prop]) return;
|
||||
|
||||
m[prop]
|
||||
@ -658,36 +781,36 @@ class TraitActionTag {
|
||||
.replace(/\([^)]+\)/g, "") // Remove parentheses
|
||||
.trim();
|
||||
|
||||
const mapped = TraitActionTag.tags[prop][cleanName];
|
||||
const mapped = TraitActionTag._TAGS[prop][cleanName];
|
||||
if (mapped) {
|
||||
if (mapped === true) return m[outProp].add(t.name);
|
||||
return m[outProp].add(mapped);
|
||||
if (mapped === true) return this._doAdd({tags, tag: t.name, allowlist});
|
||||
return this._doAdd({tags, tag: mapped, allowlist});
|
||||
}
|
||||
|
||||
if (this._isTraits(prop)) {
|
||||
if (cleanName.startsWith("keen ")) return m[outProp].add("Keen Senses");
|
||||
if (cleanName.endsWith(" absorption")) return m[outProp].add("Damage Absorption");
|
||||
if (cleanName.startsWith("keen ")) return this._doAdd({tags, tag: "Keen Senses", allowlist});
|
||||
if (cleanName.endsWith(" absorption")) return this._doAdd({tags, tag: "Damage Absorption", allowlist});
|
||||
}
|
||||
|
||||
if (this._isActions(prop)) {
|
||||
if (/\bbreath\b/.test(cleanName)) return m[outProp].add("Breath Weapon");
|
||||
if (/\bbreath\b/.test(cleanName)) return this._doAdd({tags, tag: "Breath Weapon", allowlist});
|
||||
}
|
||||
|
||||
if (cbMan) cbMan(prop, outProp, cleanName);
|
||||
if (cbMan) cbMan(prop, tags, cleanName);
|
||||
});
|
||||
}
|
||||
|
||||
static _doTagDeep ({m, prop, outProp}) {
|
||||
if (!TraitActionTag.tagsDeep[prop]) return;
|
||||
static _doTagDeep ({m, prop, tags, allowlist}) {
|
||||
if (!TraitActionTag._TAGS_DEEP[prop]) return;
|
||||
if (!m[prop]) return;
|
||||
|
||||
m[prop].forEach(t => {
|
||||
if (!t.entries) return;
|
||||
const strEntries = JSON.stringify(t.entries);
|
||||
|
||||
Object.entries(TraitActionTag.tagsDeep[prop])
|
||||
Object.entries(TraitActionTag._TAGS_DEEP[prop])
|
||||
.forEach(([tagName, fnShouldTag]) => {
|
||||
if (fnShouldTag(strEntries)) m[outProp].add(tagName);
|
||||
if (fnShouldTag(strEntries)) this._doAdd({tags, tag: tagName, allowlist});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -695,138 +818,21 @@ class TraitActionTag {
|
||||
static _isTraits (prop) { return prop === "trait"; }
|
||||
static _isActions (prop) { return prop === "action"; }
|
||||
|
||||
static tryRun (m, cbMan) {
|
||||
m.traitTags = new Set(m.traitTags || []);
|
||||
m.actionTags = new Set(m.actionTags || []);
|
||||
static tryRun (m, {cbMan, allowlistTraitTags, allowlistActionTags} = {}) {
|
||||
const traitTags = new Set(m.traitTags || []);
|
||||
const actionTags = new Set(m.actionTags || []);
|
||||
|
||||
this._doTag({m, cbMan, prop: "trait", outProp: "traitTags"});
|
||||
this._doTag({m, cbMan, prop: "action", outProp: "actionTags"});
|
||||
this._doTag({m, cbMan, prop: "reaction", outProp: "actionTags"});
|
||||
this._doTag({m, cbMan, prop: "bonus", outProp: "actionTags"});
|
||||
this._doTag({m, cbMan, prop: "trait", tags: traitTags, allowlist: allowlistTraitTags});
|
||||
this._doTag({m, cbMan, prop: "action", tags: actionTags, allowlist: allowlistActionTags});
|
||||
this._doTag({m, cbMan, prop: "reaction", tags: actionTags, allowlist: allowlistActionTags});
|
||||
this._doTag({m, cbMan, prop: "bonus", tags: actionTags, allowlist: allowlistActionTags});
|
||||
|
||||
this._doTagDeep({m, prop: "action", outProp: "actionTags"});
|
||||
this._doTagDeep({m, prop: "action", tags: actionTags, allowlist: allowlistActionTags});
|
||||
|
||||
if (!m.traitTags.size) delete m.traitTags;
|
||||
else m.traitTags = [...m.traitTags].sort(SortUtil.ascSortLower);
|
||||
|
||||
if (!m.actionTags.size) delete m.actionTags;
|
||||
else m.actionTags = [...m.actionTags].sort(SortUtil.ascSortLower);
|
||||
if (traitTags.size) m.traitTags = [...traitTags].sort(SortUtil.ascSortLower);
|
||||
if (actionTags.size) m.actionTags = [...actionTags].sort(SortUtil.ascSortLower);
|
||||
}
|
||||
}
|
||||
TraitActionTag.tags = { // true = map directly; string = map to this string
|
||||
trait: {
|
||||
"turn immunity": "Turn Immunity",
|
||||
"brute": "Brute",
|
||||
"antimagic susceptibility": "Antimagic Susceptibility",
|
||||
"sneak attack": "Sneak Attack",
|
||||
"reckless": "Reckless",
|
||||
"web sense": "Web Sense",
|
||||
"flyby": "Flyby",
|
||||
"pounce": "Pounce",
|
||||
"water breathing": "Water Breathing",
|
||||
|
||||
"turn resistance": "Turn Resistance",
|
||||
"turn defiance": "Turn Resistance",
|
||||
"turning defiance": "Turn Resistance",
|
||||
"turn resistance aura": "Turn Resistance",
|
||||
"undead fortitude": "Undead Fortitude",
|
||||
|
||||
"aggressive": "Aggressive",
|
||||
"illumination": "Illumination",
|
||||
"rampage": "Rampage",
|
||||
"rejuvenation": "Rejuvenation",
|
||||
"web walker": "Web Walker",
|
||||
"incorporeal movement": "Incorporeal Movement",
|
||||
"incorporeal passage": "Incorporeal Movement",
|
||||
|
||||
"keen hearing and smell": "Keen Senses",
|
||||
"keen sight and smell": "Keen Senses",
|
||||
"keen hearing and sight": "Keen Senses",
|
||||
"keen hearing": "Keen Senses",
|
||||
"keen smell": "Keen Senses",
|
||||
"keen senses": "Keen Senses",
|
||||
|
||||
"hold breath": "Hold Breath",
|
||||
|
||||
"charge": "Charge",
|
||||
|
||||
"fey ancestry": "Fey Ancestry",
|
||||
|
||||
"siege monster": "Siege Monster",
|
||||
|
||||
"pack tactics": "Pack Tactics",
|
||||
|
||||
"regeneration": "Regeneration",
|
||||
|
||||
"shapechanger": "Shapechanger",
|
||||
|
||||
"false appearance": "False Appearance",
|
||||
|
||||
"spider climb": "Spider Climb",
|
||||
|
||||
"sunlight sensitivity": "Sunlight Sensitivity",
|
||||
"sunlight hypersensitivity": "Sunlight Sensitivity",
|
||||
"light sensitivity": "Light Sensitivity",
|
||||
"vampire weaknesses": "Sunlight Sensitivity",
|
||||
|
||||
"amphibious": "Amphibious",
|
||||
|
||||
"legendary resistance": "Legendary Resistances",
|
||||
|
||||
"magic weapon": "Magic Weapons",
|
||||
"magic weapons": "Magic Weapons",
|
||||
|
||||
"magic resistance": "Magic Resistance",
|
||||
|
||||
"spell immunity": "Spell Immunity",
|
||||
|
||||
"ambush": "Ambusher",
|
||||
"ambusher": "Ambusher",
|
||||
|
||||
"amorphous": "Amorphous",
|
||||
"amorphous form": "Amorphous",
|
||||
|
||||
"death burst": "Death Burst",
|
||||
"death throes": "Death Burst",
|
||||
|
||||
"devil's sight": "Devil's Sight",
|
||||
"devil sight": "Devil's Sight",
|
||||
|
||||
"immutable form": "Immutable Form",
|
||||
|
||||
"tree stride": "Tree Stride",
|
||||
|
||||
"unusual nature": "Unusual Nature",
|
||||
|
||||
"tunneler": "Tunneler",
|
||||
},
|
||||
action: {
|
||||
"multiattack": "Multiattack",
|
||||
"frightful presence": "Frightful Presence",
|
||||
"teleport": "Teleport",
|
||||
"swallow": "Swallow",
|
||||
"tentacle": "Tentacles",
|
||||
"tentacles": "Tentacles",
|
||||
"change shape": "Shapechanger",
|
||||
},
|
||||
reaction: {
|
||||
"parry": "Parry",
|
||||
},
|
||||
bonus: {
|
||||
"change shape": "Shapechanger",
|
||||
},
|
||||
legendary: {
|
||||
// unused
|
||||
},
|
||||
mythic: {
|
||||
// unused
|
||||
},
|
||||
};
|
||||
TraitActionTag.tagsDeep = {
|
||||
action: {
|
||||
"Swallow": strEntries => /\bswallowed\b/i.test(strEntries),
|
||||
},
|
||||
};
|
||||
|
||||
globalThis.TraitActionTag = TraitActionTag;
|
||||
|
||||
@ -1373,85 +1379,93 @@ class SpellcastingTraitConvert {
|
||||
});
|
||||
}
|
||||
|
||||
static tryParseSpellcasting (ent, {isMarkdown, cbErr, displayAs, actions, reactions}) {
|
||||
static tryParseSpellcasting (ent, {isMarkdown, cbMan, cbErr, displayAs, actions, reactions}) {
|
||||
try {
|
||||
return this._parseSpellcasting({ent, isMarkdown, displayAs, actions, reactions});
|
||||
return this._parseSpellcasting({ent, isMarkdown, cbMan, displayAs, actions, reactions});
|
||||
} catch (e) {
|
||||
cbErr && cbErr(`Failed to parse spellcasting: ${e.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static _parseSpellcasting ({ent, isMarkdown, displayAs, actions, reactions}) {
|
||||
let hasAnyHeader = false;
|
||||
static _parseSpellcasting ({ent, isMarkdown, cbMan, displayAs, actions, reactions}) {
|
||||
const spellcastingEntry = {
|
||||
"name": ent.name,
|
||||
"type": "spellcasting",
|
||||
"headerEntries": [this._parseToHit(ent.entries[0])],
|
||||
"headerEntries": [],
|
||||
};
|
||||
ent.entries.forEach((thisLine, i) => {
|
||||
thisLine = thisLine.replace(/,\s*\*/g, ",*"); // put asterisks on the correct side of commas
|
||||
if (i === 0) return;
|
||||
|
||||
const perDurations = [
|
||||
{re: /\/rest/i, prop: "rest"},
|
||||
{re: /\/day/i, prop: "daily"},
|
||||
{re: /\/week/i, prop: "weekly"},
|
||||
{re: /\/month/i, prop: "monthly"},
|
||||
{re: /\/yeark/i, prop: "yearly"},
|
||||
];
|
||||
const headerEntry = this._getMutHeaderEntries({ent, cbMan, spellcastingEntry});
|
||||
spellcastingEntry.headerEntries.push(headerEntry);
|
||||
|
||||
const perDuration = perDurations.find(({re}) => re.test(thisLine));
|
||||
let hasAnyHeader = false;
|
||||
ent.entries
|
||||
.slice(1)
|
||||
.forEach(line => {
|
||||
line = line.replace(/,\s*\*/g, ",*"); // put asterisks on the correct side of commas
|
||||
|
||||
if (perDuration) {
|
||||
hasAnyHeader = true;
|
||||
let property = thisLine.substring(0, 1) + (/ each(?::| - )/.test(thisLine) ? "e" : "");
|
||||
const value = this._getParsedSpells({thisLine, isMarkdown});
|
||||
if (!spellcastingEntry[perDuration.prop]) spellcastingEntry[perDuration.prop] = {};
|
||||
spellcastingEntry[perDuration.prop][property] = value;
|
||||
} else if (/^Constant(?::| -) /.test(thisLine)) {
|
||||
hasAnyHeader = true;
|
||||
spellcastingEntry.constant = this._getParsedSpells({thisLine, isMarkdown});
|
||||
} else if (/^At[- ][Ww]ill(?::| -) /.test(thisLine)) {
|
||||
hasAnyHeader = true;
|
||||
spellcastingEntry.will = this._getParsedSpells({thisLine, isMarkdown});
|
||||
} else if (thisLine.includes("Cantrip")) {
|
||||
hasAnyHeader = true;
|
||||
const value = this._getParsedSpells({thisLine, isMarkdown});
|
||||
if (!spellcastingEntry.spells) spellcastingEntry.spells = {"0": {"spells": []}};
|
||||
spellcastingEntry.spells["0"].spells = value;
|
||||
} else if (/[- ][Ll]evel/.test(thisLine) && /(?::| -) /.test(thisLine)) {
|
||||
hasAnyHeader = true;
|
||||
let property = thisLine.substring(0, 1);
|
||||
const allSpells = this._getParsedSpells({thisLine, isMarkdown});
|
||||
spellcastingEntry.spells = spellcastingEntry.spells || {};
|
||||
const usesMeta = this._getUsesMeta({line, isMarkdown});
|
||||
if (usesMeta) {
|
||||
hasAnyHeader = true;
|
||||
|
||||
const out = {};
|
||||
if (thisLine.includes(" slot")) {
|
||||
const mWarlock = /^(\d)..(?:[- ][Ll]evel)?-(\d)..[- ][Ll]evel \((\d) (\d)..[- ][Ll]evel slots?\)/.exec(thisLine);
|
||||
if (mWarlock) {
|
||||
out.lower = parseInt(mWarlock[1]);
|
||||
out.slots = parseInt(mWarlock[3]);
|
||||
property = mWarlock[4];
|
||||
} else {
|
||||
const mSlots = /\((\d) slots?\)/.exec(thisLine);
|
||||
if (!mSlots) throw new Error(`Could not find slot count!`);
|
||||
out.slots = parseInt(mSlots[1]);
|
||||
const value = this._getParsedSpells({line: usesMeta.lineRemaining});
|
||||
MiscUtil.getOrSet(spellcastingEntry, usesMeta.prop, usesMeta.propPer, value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (/^Constant(?::| -) /.test(line)) {
|
||||
hasAnyHeader = true;
|
||||
spellcastingEntry.constant = this._getParsedSpells({line, isMarkdown});
|
||||
return;
|
||||
}
|
||||
|
||||
if (/^At[- ][Ww]ill(?::| -) /.test(line)) {
|
||||
hasAnyHeader = true;
|
||||
spellcastingEntry.will = this._getParsedSpells({line, isMarkdown});
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.includes("Cantrip")) {
|
||||
hasAnyHeader = true;
|
||||
const value = this._getParsedSpells({line, isMarkdown});
|
||||
if (!spellcastingEntry.spells) spellcastingEntry.spells = {"0": {"spells": []}};
|
||||
spellcastingEntry.spells["0"].spells = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (/[- ][Ll]evel/.test(line) && /(?::| -) /.test(line)) {
|
||||
hasAnyHeader = true;
|
||||
let property = line.substring(0, 1);
|
||||
const allSpells = this._getParsedSpells({line, isMarkdown});
|
||||
spellcastingEntry.spells = spellcastingEntry.spells || {};
|
||||
|
||||
const out = {};
|
||||
if (line.includes(" slot")) {
|
||||
const mWarlock = /^(\d)..(?:[- ][Ll]evel)?-(\d)..[- ][Ll]evel \((\d) (\d)..[- ][Ll]evel slots?\)/.exec(line);
|
||||
if (mWarlock) {
|
||||
out.lower = parseInt(mWarlock[1]);
|
||||
out.slots = parseInt(mWarlock[3]);
|
||||
property = mWarlock[4];
|
||||
} else {
|
||||
const mSlots = /\((\d) slots?\)/.exec(line);
|
||||
if (!mSlots) throw new Error(`Could not find slot count!`);
|
||||
out.slots = parseInt(mSlots[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// add these last, to have nicer ordering
|
||||
out.spells = allSpells;
|
||||
// add these last, to have nicer ordering
|
||||
out.spells = allSpells;
|
||||
|
||||
spellcastingEntry.spells[property] = out;
|
||||
} else {
|
||||
if (hasAnyHeader) {
|
||||
if (!spellcastingEntry.footerEntries) spellcastingEntry.footerEntries = [];
|
||||
spellcastingEntry.footerEntries.push(this._parseToHit(thisLine));
|
||||
} else {
|
||||
spellcastingEntry.headerEntries.push(this._parseToHit(thisLine));
|
||||
spellcastingEntry.spells[property] = out;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasAnyHeader) {
|
||||
(spellcastingEntry.footerEntries ||= []).push(this._parseToHit(line));
|
||||
} else {
|
||||
spellcastingEntry.headerEntries.push(this._parseToHit(line));
|
||||
}
|
||||
});
|
||||
|
||||
SpellcastingTraitConvert.mutSpellcastingAbility(spellcastingEntry);
|
||||
SpellcastingTraitConvert._mutDisplayAs(spellcastingEntry, displayAs);
|
||||
@ -1462,9 +1476,84 @@ class SpellcastingTraitConvert {
|
||||
return spellcastingEntry;
|
||||
}
|
||||
|
||||
static _getParsedSpells ({thisLine, isMarkdown}) {
|
||||
const mLabelSep = /(?::| -) /.exec(thisLine);
|
||||
let spellPart = thisLine.substring((mLabelSep?.index || 0) + (mLabelSep?.[0]?.length || 0)).trim();
|
||||
static _getMutHeaderEntries ({ent, cbMan, spellcastingEntry}) {
|
||||
let line = this._parseToHit(ent.entries[0]);
|
||||
|
||||
const usesMeta = this._getUsesMeta({line: ent.name});
|
||||
|
||||
line = line
|
||||
.replace(/(?<pre>casts? (?:the )?)(?<spell>[^.,?!:]+)(?<post>\.| spell |at[ -]will)/g, (...m) => {
|
||||
const isWill = m.last().post.toLowerCase().replace(/-/g, " ") === "at will";
|
||||
|
||||
if (!usesMeta && !isWill) {
|
||||
cbMan(`Found spell in header with no usage info: ${m.last().spell}`);
|
||||
return m[0];
|
||||
}
|
||||
|
||||
const ptSpells = m.last().spell
|
||||
.split(" and ")
|
||||
.map(sp => {
|
||||
const value = this._getParsedSpells({line: sp});
|
||||
const hidden = MiscUtil.getOrSet(spellcastingEntry, "hidden", []);
|
||||
|
||||
if (isWill) {
|
||||
const tgt = MiscUtil.getOrSet(spellcastingEntry, "will", []);
|
||||
tgt.push(...value);
|
||||
|
||||
if (!hidden.includes("will")) hidden.push("will");
|
||||
} else {
|
||||
const tgt = MiscUtil.getOrSet(spellcastingEntry, usesMeta.prop, usesMeta.propPer, []);
|
||||
tgt.push(...value);
|
||||
|
||||
if (!hidden.includes(usesMeta.prop)) hidden.push(usesMeta.prop);
|
||||
}
|
||||
|
||||
return value.join(", ");
|
||||
})
|
||||
.join(" and ");
|
||||
|
||||
return [
|
||||
m.last().pre,
|
||||
ptSpells,
|
||||
m.last().post,
|
||||
]
|
||||
.join(" ")
|
||||
.replace(/ +/g, " ");
|
||||
});
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
static _getUsesMeta ({line}) {
|
||||
const perDurations = [
|
||||
{re: /(?<cnt>\d+)\/rest(?<ptEach> each)?/i, prop: "rest"},
|
||||
{re: /(?<cnt>\d+)\/day(?<ptEach> each)?/i, prop: "daily"},
|
||||
{re: /(?<cnt>\d+)\/week(?<ptEach> each)?/i, prop: "weekly"},
|
||||
{re: /(?<cnt>\d+)\/month(?<ptEach> each)?/i, prop: "monthly"},
|
||||
{re: /(?<cnt>\d+)\/yeark(?<ptEach> each)?/i, prop: "yearly"},
|
||||
];
|
||||
|
||||
const metasPerDuration = perDurations
|
||||
.map(({re, prop}) => ({m: re.exec(line), prop}))
|
||||
.filter(({m}) => !!m);
|
||||
if (!metasPerDuration.length) return null;
|
||||
|
||||
// Arbitrarily pick the first
|
||||
const [metaPerDuration] = metasPerDuration;
|
||||
|
||||
const propPer = `${metaPerDuration.m.groups.cnt}${metaPerDuration.m.groups.ptEach ? "e" : ""}`;
|
||||
|
||||
return {
|
||||
prop: metaPerDuration.prop,
|
||||
propPer,
|
||||
lineRemaining: line.slice(metaPerDuration.m.length),
|
||||
};
|
||||
}
|
||||
|
||||
static _getParsedSpells ({line, isMarkdown}) {
|
||||
const mLabelSep = /(?::| -) /.exec(line);
|
||||
let spellPart = line.substring((mLabelSep?.index || 0) + (mLabelSep?.[0]?.length || 0)).trim();
|
||||
|
||||
if (isMarkdown) {
|
||||
const cleanPart = (part) => {
|
||||
part = part.trim();
|
||||
|
||||
@ -1605,7 +1605,7 @@ class Panel {
|
||||
this.set$ContentTab(
|
||||
PANEL_TYP_TEXTBOX,
|
||||
null,
|
||||
$(`<div class="panel-content-wrapper-inner overflow-y-hidden"/>`).append(NoteBox.make$Notebox(this.board, content)),
|
||||
$(`<div class="panel-content-wrapper-inner ve-overflow-y-hidden"/>`).append(NoteBox.make$Notebox(this.board, content)),
|
||||
title,
|
||||
true,
|
||||
);
|
||||
@ -2284,7 +2284,7 @@ class Panel {
|
||||
if (!this.board.getConfirmTabClose() || (this.board.getConfirmTabClose() && confirm(`Are you sure you want to close tab "${this.tabDatas[ix].title}"?`))) this.doCloseTab(ix);
|
||||
};
|
||||
|
||||
const $btnSelTab = $(`<span class="btn btn-default content-tab ve-flex ${tabCanRename ? "content-tab-can-rename" : ""}"><span class="content-tab-title overflow-ellipsis" title="${title}">${title}</span></span>`)
|
||||
const $btnSelTab = $(`<span class="btn btn-default content-tab ve-flex ${tabCanRename ? "content-tab-can-rename" : ""}"><span class="content-tab-title ve-overflow-ellipsis" title="${title}">${title}</span></span>`)
|
||||
.on("mousedown", (evt) => {
|
||||
if (evt.which === 1) {
|
||||
this.setActiveTab(ix);
|
||||
@ -3259,7 +3259,7 @@ class AddMenuSpecialTab extends AddMenuTab {
|
||||
|
||||
render () {
|
||||
if (!this.$tab) {
|
||||
const $tab = $(`<div class="ui-search__wrp-output underline-tabs overflow-y-auto pr-1" id="${this.tabId}"/>`);
|
||||
const $tab = $(`<div class="ui-search__wrp-output underline-tabs ve-overflow-y-auto pr-1" id="${this.tabId}"/>`);
|
||||
|
||||
const $wrpRoller = $(`<div class="ui-modal__row"><span>Dice Roller <i class="text-muted">(pins the existing dice roller to a panel)</i></span></div>`).appendTo($tab);
|
||||
const $btnRoller = $(`<button class="btn btn-primary btn-sm">Pin</button>`).appendTo($wrpRoller);
|
||||
@ -3972,8 +3972,8 @@ class AdventureOrBookView {
|
||||
}
|
||||
|
||||
$getEle () {
|
||||
this._$titlePrev = $(`<div class="dm-book__controls-title overflow-ellipsis text-right"/>`);
|
||||
this._$titleNext = $(`<div class="dm-book__controls-title overflow-ellipsis"/>`);
|
||||
this._$titlePrev = $(`<div class="dm-book__controls-title ve-overflow-ellipsis text-right"/>`);
|
||||
this._$titleNext = $(`<div class="dm-book__controls-title ve-overflow-ellipsis"/>`);
|
||||
|
||||
const $btnPrev = $(`<button class="btn btn-xs btn-default mr-2" title="Previous Chapter"><span class="glyphicon glyphicon-chevron-left"/></button>`)
|
||||
.click(() => this._handleButtonClick(-1));
|
||||
|
||||
@ -31,7 +31,7 @@ class CounterRoot extends CounterComponent {
|
||||
|
||||
const pod = this.getPod();
|
||||
|
||||
this._$wrpRows = $$`<div class="ve-flex-col w-100 h-100 overflow-y-auto relative"/>`;
|
||||
this._$wrpRows = $$`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto relative"/>`;
|
||||
this._childComps.forEach(it => it.render(this._$wrpRows, pod));
|
||||
|
||||
const $btnAdd = $(`<button class="btn btn-primary btn-xs"><span class="glyphicon glyphicon-plus"/> Add Counter</button>`)
|
||||
|
||||
@ -158,7 +158,7 @@ export class InitiativeTrackerCreatureViewer extends BaseComponent {
|
||||
}
|
||||
})().then(null);
|
||||
|
||||
const $stg = $$`<div class="ve-flex-col w-100 h-100 min-h-0 overflow-y-auto">
|
||||
const $stg = $$`<div class="ve-flex-col w-100 h-100 min-h-0 ve-overflow-y-auto">
|
||||
${dispCreature}
|
||||
</div>`;
|
||||
|
||||
|
||||
@ -666,9 +666,9 @@ class TimeTrackerRoot extends TimeTrackerBase {
|
||||
render ($parent) {
|
||||
$parent.empty();
|
||||
|
||||
const $wrpClock = $(`<div class="ve-flex-col w-100 h-100 overflow-y-auto">`);
|
||||
const $wrpCalendar = $(`<div class="ve-flex-col w-100 h-100 overflow-y-auto ve-flex-h-center">`);
|
||||
const $wrpSettings = $(`<div class="ve-flex-col w-100 h-100 overflow-y-auto">`);
|
||||
const $wrpClock = $(`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto">`);
|
||||
const $wrpCalendar = $(`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto ve-flex-h-center">`);
|
||||
const $wrpSettings = $(`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto">`);
|
||||
|
||||
const pod = this.getPod();
|
||||
|
||||
@ -1771,7 +1771,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
|
||||
},
|
||||
);
|
||||
|
||||
const $wrpCalendar = $(`<div class="overflow-y-auto smooth-scroll"/>`);
|
||||
const $wrpCalendar = $(`<div class="ve-overflow-y-auto smooth-scroll"/>`);
|
||||
|
||||
const hookCalendar = (prop) => {
|
||||
const timeInfo = getTimeInfo();
|
||||
@ -2239,7 +2239,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
|
||||
this._parent.addHook("moons", hookMoons);
|
||||
hookMoons();
|
||||
|
||||
const $wrpEvents = $(`<div class="ve-flex-col w-100 overflow-y-auto dm-time__day-entry-wrapper"/>`);
|
||||
const $wrpEvents = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto dm-time__day-entry-wrapper"/>`);
|
||||
const hookEvents = () => {
|
||||
const todayEvents = getEvents(year, eventDay);
|
||||
$wrpEvents.empty();
|
||||
@ -2260,7 +2260,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
|
||||
this._parent.addHook("events", hookEvents);
|
||||
hookEvents();
|
||||
|
||||
const $wrpEncounters = $(`<div class="ve-flex-col w-100 overflow-y-auto dm-time__day-entry-wrapper"/>`);
|
||||
const $wrpEncounters = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto dm-time__day-entry-wrapper"/>`);
|
||||
const hookEncounters = async () => {
|
||||
await this._pLock("encounters");
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ export class InitiativeTrackerConditionCustomEdit extends BaseComponent {
|
||||
this._state.conditionsCustom = [...this._state.conditionsCustom, InitiativeTrackerConditionUtil.getNewRowState()];
|
||||
});
|
||||
|
||||
const $wrpRows = $(`<div class="ve-flex-col h-100 min-h-0 overflow-y-auto"></div>`);
|
||||
const $wrpRows = $(`<div class="ve-flex-col h-100 min-h-0 ve-overflow-y-auto"></div>`);
|
||||
|
||||
const compRows = new _RenderableCollectionConditionsCustomEdit({comp: this, $wrpRows});
|
||||
this._addHookBase("conditionsCustom", () => compRows.render())();
|
||||
|
||||
@ -50,7 +50,7 @@ class _InitiativeTrackerMonsterAddCustomizer extends BaseComponent {
|
||||
const $iptCustomName = ComponentUiUtil.$getIptStr(this, "customName");
|
||||
|
||||
$$($modalInner)`
|
||||
<div class="ve-flex-col py-2 w-100 h-100 overflow-y-auto">
|
||||
<div class="ve-flex-col py-2 w-100 h-100 ve-overflow-y-auto">
|
||||
<label class="split-v-center mb-2">
|
||||
<span class="w-200p text-right no-shrink mr-2 bold">Custom Name:</span>
|
||||
${$iptCustomName}
|
||||
|
||||
@ -62,7 +62,7 @@ export class RenderableCollectionRowDataBase extends RenderableCollectionAsyncGe
|
||||
/* -------------------------------------------- */
|
||||
|
||||
_$getWrpRow () {
|
||||
return $(`<div class="dm-init__row overflow-hidden pr-1"></div>`);
|
||||
return $(`<div class="dm-init__row ve-overflow-hidden pr-1"></div>`);
|
||||
}
|
||||
|
||||
async _pPopulateRow ({comp, $wrpRow, entity}) {
|
||||
|
||||
@ -191,7 +191,7 @@ export class InitiativeTrackerSettings extends BaseComponent {
|
||||
}
|
||||
|
||||
_pGetShowModalResults_renderSection_additionalCols_body ({$modalInner}) {
|
||||
const $wrpRows = $(`<div class="pr-1 h-120p ve-flex-col overflow-y-auto relative"></div>`).appendTo($modalInner);
|
||||
const $wrpRows = $(`<div class="pr-1 h-120p ve-flex-col ve-overflow-y-auto relative"></div>`).appendTo($modalInner);
|
||||
this._addHookBase("isStatsAddColumns", () => $wrpRows.toggleVe(this._state.isStatsAddColumns))();
|
||||
|
||||
const renderableCollectionStatsCols = new _RenderableCollectionStatsCols(
|
||||
|
||||
@ -334,7 +334,7 @@ export class EncounterBuilderUi extends BaseComponent {
|
||||
|
||||
const $wrpRows = $(`<div class="ve-flex-col"></div>`);
|
||||
|
||||
const $stg = $$`<div class="w-70 overflow-x-auto ve-flex-col">
|
||||
const $stg = $$`<div class="w-70 ve-overflow-x-auto ve-flex-col">
|
||||
<div class="ve-flex-h-center mb-2 bb-1p small-caps ve-self-flex-start">
|
||||
<div class="w-100p mr-1 h-ipt-xs no-shrink">Name</div>
|
||||
<div class="w-40p ve-text-center mr-1 h-ipt-xs no-shrink">Level</div>
|
||||
|
||||
@ -214,6 +214,7 @@ class PageFilterSpells extends PageFilter {
|
||||
case Parser.SP_TM_ROUND: multiplier = 6; break;
|
||||
case Parser.SP_TM_MINS: multiplier = 60; break;
|
||||
case Parser.SP_TM_HRS: multiplier = 3600; break;
|
||||
case Parser.SP_TM_SPECIAL: multiplier = 1_000_000; break; // Arbitrary large number
|
||||
}
|
||||
if (time.length > 1) offset += 0.5;
|
||||
return (multiplier * firstTime.number) + offset;
|
||||
@ -415,6 +416,7 @@ class PageFilterSpells extends PageFilter {
|
||||
Parser.SP_TM_ROUND,
|
||||
Parser.SP_TM_MINS,
|
||||
Parser.SP_TM_HRS,
|
||||
Parser.SP_TM_SPECIAL,
|
||||
],
|
||||
displayFn: Parser.spTimeUnitToFull,
|
||||
itemSortFn: null,
|
||||
|
||||
@ -133,7 +133,7 @@ class ModalFilter {
|
||||
|
||||
get allData () { return this._allData; }
|
||||
|
||||
_$getWrpList () { return $(`<div class="list ui-list__wrp overflow-x-hidden overflow-y-auto h-100 min-h-0"></div>`); }
|
||||
_$getWrpList () { return $(`<div class="list ui-list__wrp ve-overflow-x-hidden ve-overflow-y-auto h-100 min-h-0"></div>`); }
|
||||
|
||||
_$getColumnHeaderPreviewAll (opts) {
|
||||
return $(`<button class="btn btn-default btn-xs ${opts.isBuildUi ? "ve-col-1" : "ve-col-0-5"}">${ListUiUtil.HTML_GLYPHICON_EXPAND}</button>`);
|
||||
@ -2613,7 +2613,7 @@ class SearchableFilter extends Filter {
|
||||
|
||||
const wrpValues = e_({
|
||||
tag: "div",
|
||||
clazz: "overflow-y-auto bt-0 absolute fltr-search__wrp-values",
|
||||
clazz: "ve-overflow-y-auto bt-0 absolute fltr-search__wrp-values",
|
||||
});
|
||||
|
||||
const fnsCleanup = [];
|
||||
@ -3440,7 +3440,7 @@ class AbilityScoreFilter extends FilterBase {
|
||||
|
||||
const wrpControls = this._getHeaderControls(opts);
|
||||
|
||||
this.__wrpPills = e_({tag: "div", clazz: `fltr__wrp-pills overflow-x-auto ve-flex-col w-100`});
|
||||
this.__wrpPills = e_({tag: "div", clazz: `fltr__wrp-pills ve-overflow-x-auto ve-flex-col w-100`});
|
||||
const hook = () => this.__wrpPills.toggleVe(!this._meta.isHidden);
|
||||
this._addHook("meta", "isHidden", hook);
|
||||
hook();
|
||||
|
||||
@ -203,6 +203,7 @@ class ItemsPage extends ListPage {
|
||||
colTransforms: {
|
||||
name: UtilsTableview.COL_TRANSFORM_NAME,
|
||||
source: UtilsTableview.COL_TRANSFORM_SOURCE,
|
||||
page: UtilsTableview.COL_TRANSFORM_PAGE,
|
||||
rarity: {name: "Rarity"},
|
||||
_type: {name: "Type", transform: it => [it._typeHtml || "", it._subTypeHtml || ""].filter(Boolean).join(", ")},
|
||||
_attunement: {name: "Attunement", transform: it => it._attunement ? it._attunement.slice(1, it._attunement.length - 1) : ""},
|
||||
|
||||
@ -1187,7 +1187,7 @@ class LootGenUi extends BaseComponent {
|
||||
}
|
||||
|
||||
_render_output ({$wrp}) {
|
||||
this._$wrpOutputRows = $(`<div class="w-100 h-100 ve-flex-col overflow-y-auto smooth-scroll"></div>`);
|
||||
this._$wrpOutputRows = $(`<div class="w-100 h-100 ve-flex-col ve-overflow-y-auto smooth-scroll"></div>`);
|
||||
|
||||
$$`<div class="ve-flex-col w-100 h-100">
|
||||
<h4 class="my-0"><i>Output</i></h4>
|
||||
|
||||
@ -194,7 +194,7 @@ class MakeCards extends BaseComponent {
|
||||
</div>`.appendTo($wrpContainer);
|
||||
|
||||
const $wrpList = $(`<div class="w-100 h-100"/>`);
|
||||
$$`<div class="ve-flex-col h-100 w-100 overflow-y-auto mt-2 overflow-x-hidden">${$wrpList}</div>`.appendTo($wrpContainer);
|
||||
$$`<div class="ve-flex-col h-100 w-100 ve-overflow-y-auto mt-2 ve-overflow-x-hidden">${$wrpList}</div>`.appendTo($wrpContainer);
|
||||
|
||||
this._list = new List({$iptSearch, $wrpList, isUseJquery: true});
|
||||
this._list.init();
|
||||
|
||||
@ -317,7 +317,7 @@ class MapsPage extends BaseComponent {
|
||||
hkAnyVisible();
|
||||
|
||||
$$($root.empty())`
|
||||
<div class="ve-flex-col h-100 no-shrink maps-menu pr-4 py-3 shadow-big overflow-y-auto smooth-scroll scrollbar-stable mobile__w-100 mobile__my-4">
|
||||
<div class="ve-flex-col h-100 no-shrink maps-menu pr-4 py-3 shadow-big ve-overflow-y-auto smooth-scroll scrollbar-stable mobile__w-100 mobile__my-4">
|
||||
<label class="split-v-center pl-2 py-1">
|
||||
<div class="mr-3 no-shrink">Image Scale</div>
|
||||
${$sldImageScale}
|
||||
@ -333,7 +333,7 @@ class MapsPage extends BaseComponent {
|
||||
${rendersSource.map(({$wrpMenu}) => $wrpMenu)}
|
||||
</div>
|
||||
|
||||
<div class="w-100 h-100 mobile__h-initial overflow-y-auto smooth-scroll ve-flex-col">
|
||||
<div class="w-100 h-100 mobile__h-initial ve-overflow-y-auto smooth-scroll ve-flex-col">
|
||||
${$dispNoneVisible}
|
||||
${rendersSource.map(({$wrpContent}) => $wrpContent)}
|
||||
</div>
|
||||
|
||||
@ -332,12 +332,22 @@ class Omnisearch {
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
static _isFauxPage (r) {
|
||||
return !!r.hx;
|
||||
}
|
||||
|
||||
static getResultHref (r) {
|
||||
const isFauxPage = this._isFauxPage(r);
|
||||
if (isFauxPage) return null;
|
||||
return r.c === Parser.CAT_ID_PAGE ? r.u : `${Renderer.get().baseUrl}${UrlUtil.categoryToPage(r.c)}#${r.uh || r.u}`;
|
||||
}
|
||||
|
||||
static $getResultLink (r) {
|
||||
const isFauxPage = !!r.hx;
|
||||
const isFauxPage = this._isFauxPage(r);
|
||||
|
||||
if (isFauxPage) return $(`<span tabindex="0" ${r.h ? this._renderLink_getHoverString(r.c, r.u, r.s, {isFauxPage}) : ""} class="omni__lnk-name help">${r.cf}: ${r.n}</span>`);
|
||||
|
||||
const href = r.c === Parser.CAT_ID_PAGE ? r.u : `${Renderer.get().baseUrl}${UrlUtil.categoryToPage(r.c)}#${r.uh || r.u}`;
|
||||
const href = this.getResultHref(r);
|
||||
return $(`<a href="${href}" ${r.h ? this._renderLink_getHoverString(r.c, r.u, r.s, {isFauxPage}) : ""} class="omni__lnk-name">${r.cf}: ${r.n}</a>`);
|
||||
}
|
||||
|
||||
|
||||
12
js/parser.js
12
js/parser.js
@ -2297,6 +2297,7 @@ Parser.SP_TM_REACTION = "reaction";
|
||||
Parser.SP_TM_ROUND = "round";
|
||||
Parser.SP_TM_MINS = "minute";
|
||||
Parser.SP_TM_HRS = "hour";
|
||||
Parser.SP_TM_SPECIAL = "special";
|
||||
Parser.SP_TIME_SINGLETONS = [Parser.SP_TM_ACTION, Parser.SP_TM_B_ACTION, Parser.SP_TM_REACTION, Parser.SP_TM_ROUND];
|
||||
Parser.SP_TIME_TO_FULL = {
|
||||
[Parser.SP_TM_ACTION]: "Action",
|
||||
@ -2305,6 +2306,7 @@ Parser.SP_TIME_TO_FULL = {
|
||||
[Parser.SP_TM_ROUND]: "Rounds",
|
||||
[Parser.SP_TM_MINS]: "Minutes",
|
||||
[Parser.SP_TM_HRS]: "Hours",
|
||||
[Parser.SP_TM_SPECIAL]: "Special",
|
||||
};
|
||||
Parser.spTimeUnitToFull = function (timeUnit) {
|
||||
return Parser._parse_aToB(Parser.SP_TIME_TO_FULL, timeUnit);
|
||||
@ -2326,6 +2328,7 @@ Parser.SP_TIME_TO_ABV = {
|
||||
[Parser.SP_TM_ROUND]: "rnd",
|
||||
[Parser.SP_TM_MINS]: "min",
|
||||
[Parser.SP_TM_HRS]: "hr",
|
||||
[Parser.SP_TM_SPECIAL]: "SPC",
|
||||
};
|
||||
Parser.spTimeUnitToAbv = function (timeUnit) {
|
||||
return Parser._parse_aToB(Parser.SP_TIME_TO_ABV, timeUnit);
|
||||
@ -2674,6 +2677,7 @@ Parser.SRC_LK = "LK";
|
||||
Parser.SRC_CoA = "CoA";
|
||||
Parser.SRC_PiP = "PiP";
|
||||
Parser.SRC_DitLCoT = "DitLCoT";
|
||||
Parser.SRC_LRDT = "LRDT";
|
||||
|
||||
Parser.SRC_AL_PREFIX = "AL";
|
||||
|
||||
@ -2853,6 +2857,7 @@ Parser.SOURCE_JSON_TO_FULL[Parser.SRC_LK] = "Lightning Keep";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_CoA] = "Chains of Asmodeus";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_PiP] = "Peril in Pinebrook";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_DitLCoT] = "Descent into the Lost Caverns of Tsojcanth";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_LRDT] = "Red Dragon's Tale: A LEGO Adventure";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ALCoS] = `${Parser.AL_PREFIX}Curse of Strahd`;
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ALEE] = `${Parser.AL_PREFIX}Elemental Evil`;
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ALRoD] = `${Parser.AL_PREFIX}Rage of Demons`;
|
||||
@ -3007,6 +3012,7 @@ Parser.SOURCE_JSON_TO_ABV[Parser.SRC_LK] = "LK";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_CoA] = "CoA";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_PiP] = "PiP";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_DitLCoT] = "DitLCoT";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_LRDT] = "LRDT";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ALCoS] = "ALCoS";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ALEE] = "ALEE";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ALRoD] = "ALRoD";
|
||||
@ -3160,6 +3166,7 @@ Parser.SOURCE_JSON_TO_DATE[Parser.SRC_LK] = "2023-09-26";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_CoA] = "2023-10-30";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_PiP] = "2023-11-20";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_DitLCoT] = "2024-03-26";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_LRDT] = "2024-04-01";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ALCoS] = "2016-03-15";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ALEE] = "2015-04-07";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ALRoD] = "2015-09-15";
|
||||
@ -3257,6 +3264,7 @@ Parser.SOURCES_ADVENTURES = new Set([
|
||||
Parser.SRC_CoA,
|
||||
Parser.SRC_PiP,
|
||||
Parser.SRC_DitLCoT,
|
||||
Parser.SRC_LRDT,
|
||||
Parser.SRC_HFStCM,
|
||||
Parser.SRC_GHLoE,
|
||||
Parser.SRC_DoDk,
|
||||
@ -3326,6 +3334,7 @@ Parser.SOURCES_PARTNERED_WOTC = new Set([
|
||||
Parser.SRC_HWAitW,
|
||||
Parser.SRC_ToB1_2023,
|
||||
Parser.SRC_TD,
|
||||
Parser.SRC_LRDT,
|
||||
]);
|
||||
// region Source categories
|
||||
|
||||
@ -3372,6 +3381,7 @@ Parser.SOURCES_COMEDY = new Set([
|
||||
Parser.SRC_MisMV1,
|
||||
Parser.SRC_LK,
|
||||
Parser.SRC_PiP,
|
||||
Parser.SRC_LRDT,
|
||||
]);
|
||||
|
||||
// Any opinionated set of sources that are "other settings"
|
||||
@ -3412,6 +3422,7 @@ Parser.SOURCES_NON_FR = new Set([
|
||||
Parser.SRC_HWCS,
|
||||
Parser.SRC_HWAitW,
|
||||
Parser.SRC_ToB1_2023,
|
||||
Parser.SRC_LRDT,
|
||||
]);
|
||||
|
||||
// endregion
|
||||
@ -3552,6 +3563,7 @@ Parser.SOURCES_AVAILABLE_DOCS_ADVENTURE = {};
|
||||
Parser.SRC_DoDk,
|
||||
Parser.SRC_HWAitW,
|
||||
Parser.SRC_QftIS,
|
||||
Parser.SRC_LRDT,
|
||||
].forEach(src => {
|
||||
Parser.SOURCES_AVAILABLE_DOCS_ADVENTURE[src] = src;
|
||||
Parser.SOURCES_AVAILABLE_DOCS_ADVENTURE[src.toLowerCase()] = src;
|
||||
|
||||
@ -74,6 +74,7 @@ class PsionicsPage extends ListPage {
|
||||
colTransforms: {
|
||||
name: UtilsTableview.COL_TRANSFORM_NAME,
|
||||
source: UtilsTableview.COL_TRANSFORM_SOURCE,
|
||||
page: UtilsTableview.COL_TRANSFORM_PAGE,
|
||||
_text: {name: "Text", transform: (it) => Renderer.psionic.getBodyText(it), flex: 3},
|
||||
},
|
||||
},
|
||||
|
||||
@ -223,6 +223,8 @@ class RenderDecks {
|
||||
const $wrpInfo = $$`<div class="stats stats--book decks-draw__wrp-desc mobile__hidden px-2 ve-text-center mb-4">${ptText}</div>`
|
||||
.click(evt => evt.stopPropagation());
|
||||
|
||||
Renderer.dice.bindOnclickListener($wrpInfo[0]);
|
||||
|
||||
const $btnFlip = imgBack
|
||||
? $(`<button class="btn btn-default btn-xs px-3" title="Flip Card"><i class="fas fa-rotate"></i> Flip</button>`)
|
||||
.click(evt => {
|
||||
|
||||
@ -19,6 +19,8 @@ Renderer.dice = {
|
||||
|
||||
_isManualMode: false,
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
// region Utilities
|
||||
DICE: [4, 6, 8, 10, 12, 20, 100],
|
||||
getNextDice (faces) {
|
||||
@ -34,6 +36,8 @@ Renderer.dice = {
|
||||
},
|
||||
// endregion
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
// region DM Screen integration
|
||||
_panel: null,
|
||||
bindDmScreenPanel (panel, title) {
|
||||
@ -60,6 +64,27 @@ Renderer.dice = {
|
||||
},
|
||||
// endregion
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
bindOnclickListener (ele) {
|
||||
ele.addEventListener("click", (evt) => {
|
||||
const eleDice = evt.target.hasAttribute("data-packed-dice")
|
||||
? evt.target
|
||||
// Tolerate e.g. Bestiary wrapped proficiency dice rollers
|
||||
: evt.target.parentElement?.hasAttribute("data-packed-dice")
|
||||
? evt.target.parentElement
|
||||
: null;
|
||||
|
||||
if (!eleDice) return;
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopImmediatePropagation();
|
||||
Renderer.dice.pRollerClickUseData(evt, eleDice).then(null);
|
||||
});
|
||||
},
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Silently roll an expression and get the result.
|
||||
* Note that this does not support dynamic variables (e.g. user proficiency bonus).
|
||||
|
||||
@ -373,7 +373,7 @@ class RenderMap {
|
||||
`);
|
||||
});
|
||||
|
||||
const $wrpCvs = $$`<div class="w-100 h-100 overflow-x-scroll overflow-y-scroll rd__scroller-viewer">
|
||||
const $wrpCvs = $$`<div class="w-100 h-100 ve-overflow-x-scroll ve-overflow-y-scroll rd__scroller-viewer">
|
||||
${$cvs}
|
||||
</div>`
|
||||
.on("mousewheel DOMMouseScroll", evt => {
|
||||
|
||||
@ -692,6 +692,12 @@ class RendererMarkdown {
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
textStack[0] += `~~`;
|
||||
break;
|
||||
case "@s2":
|
||||
case "@strikeDouble":
|
||||
textStack[0] += `~~`;
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
textStack[0] += `~~`;
|
||||
break;
|
||||
case "@note":
|
||||
textStack[0] += "*";
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
|
||||
54
js/render.js
54
js/render.js
@ -1625,12 +1625,24 @@ globalThis.Renderer = function () {
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
textStack[0] += `</s>`;
|
||||
break;
|
||||
case "@s2":
|
||||
case "@strikeDouble":
|
||||
textStack[0] += `<s class="ve-strike-double">`;
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
textStack[0] += `</s>`;
|
||||
break;
|
||||
case "@u":
|
||||
case "@underline":
|
||||
textStack[0] += `<u>`;
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
textStack[0] += `</u>`;
|
||||
break;
|
||||
case "@u2":
|
||||
case "@underlineDouble":
|
||||
textStack[0] += `<u class="ve-underline-double">`;
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
textStack[0] += `</u>`;
|
||||
break;
|
||||
case "@sup":
|
||||
textStack[0] += `<sup>`;
|
||||
this._recursiveRender(text, textStack, meta);
|
||||
@ -2044,20 +2056,23 @@ globalThis.Renderer = function () {
|
||||
};
|
||||
|
||||
this._renderLink_getHref = function (entry) {
|
||||
let href;
|
||||
if (entry.href.type === "internal") {
|
||||
// baseURL is blank by default
|
||||
href = `${this.baseUrl}${entry.href.path}#`;
|
||||
const ptBase = `${this.baseUrl}${entry.href.path}`;
|
||||
let ptHash = "";
|
||||
if (entry.href.hash != null) {
|
||||
href += entry.href.hashPreEncoded ? entry.href.hash : UrlUtil.encodeForHash(entry.href.hash);
|
||||
ptHash += entry.href.hashPreEncoded ? entry.href.hash : UrlUtil.encodeForHash(entry.href.hash);
|
||||
}
|
||||
if (entry.href.subhashes != null) {
|
||||
href += Renderer.utils.getLinkSubhashString(entry.href.subhashes);
|
||||
ptHash += Renderer.utils.getLinkSubhashString(entry.href.subhashes);
|
||||
}
|
||||
} else if (entry.href.type === "external") {
|
||||
href = entry.href.url;
|
||||
if (!ptHash) return ptBase;
|
||||
return `${ptBase}#${ptHash}`;
|
||||
}
|
||||
return href;
|
||||
if (entry.href.type === "external") {
|
||||
return entry.href.url;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
this._renderLink_getHoverString = function (entry) {
|
||||
@ -2141,6 +2156,7 @@ Renderer._INLINE_HEADER_TERMINATORS = new Set([".", ",", "!", "?", ";", ":", `"`
|
||||
Renderer._STYLE_TAG_ID_TO_STYLE = {
|
||||
"small-caps": "small-caps",
|
||||
"small": "ve-small",
|
||||
"large": "ve-large",
|
||||
"capitalize": "capitalize",
|
||||
"dnd-font": "dnd-font",
|
||||
};
|
||||
@ -4334,6 +4350,14 @@ Renderer.tag = class {
|
||||
tagName = "strike";
|
||||
};
|
||||
|
||||
static TagStrikethroughDoubleShort = class extends this._TagTextStyle {
|
||||
tagName = "s2";
|
||||
};
|
||||
|
||||
static TagStrikethroughDoubleLong = class extends this._TagTextStyle {
|
||||
tagName = "strikeDouble";
|
||||
};
|
||||
|
||||
static TagUnderlineShort = class extends this._TagTextStyle {
|
||||
tagName = "u";
|
||||
};
|
||||
@ -4342,6 +4366,14 @@ Renderer.tag = class {
|
||||
tagName = "underline";
|
||||
};
|
||||
|
||||
static TagUnderlineDoubleShort = class extends this._TagTextStyle {
|
||||
tagName = "u2";
|
||||
};
|
||||
|
||||
static TagUnderlineDoubleLong = class extends this._TagTextStyle {
|
||||
tagName = "underlineDouble";
|
||||
};
|
||||
|
||||
static TagSup = class extends this._TagTextStyle {
|
||||
tagName = "sup";
|
||||
};
|
||||
@ -4913,8 +4945,12 @@ Renderer.tag = class {
|
||||
new this.TagItalicLong(),
|
||||
new this.TagStrikethroughShort(),
|
||||
new this.TagStrikethroughLong(),
|
||||
new this.TagStrikethroughDoubleShort(),
|
||||
new this.TagStrikethroughDoubleLong(),
|
||||
new this.TagUnderlineShort(),
|
||||
new this.TagUnderlineLong(),
|
||||
new this.TagUnderlineDoubleShort(),
|
||||
new this.TagUnderlineDoubleLong(),
|
||||
new this.TagSup(),
|
||||
new this.TagSub(),
|
||||
new this.TagKbd(),
|
||||
@ -10412,7 +10448,7 @@ Renderer.recipe = class {
|
||||
${entriesMeta.entryCooksNotes ? `<div class="w-100 ve-flex-col mt-4"><div class="ve-flex-vh-center bold mb-1 small-caps">Cook's Notes</div><div class="italic">${Renderer.get().render(entriesMeta.entryCooksNotes)}</div></div>` : ""}
|
||||
</div>
|
||||
|
||||
<div class="pl-2 ve-flex-2 rd-recipes__wrp-instructions overflow-x-auto">
|
||||
<div class="pl-2 ve-flex-2 rd-recipes__wrp-instructions ve-overflow-x-auto">
|
||||
${Renderer.get().setFirstSection(true).render(entriesMeta.entryInstructions, 2)}
|
||||
</div>
|
||||
</div>`;
|
||||
@ -11621,7 +11657,7 @@ Renderer.hover = class {
|
||||
});
|
||||
const $wrpContent = $(`<div class="hwin__wrp-table"></div>`);
|
||||
if (opts.height != null) $wrpContent.css("height", opts.height);
|
||||
const $hovTitle = $(`<span class="window-title min-w-0 overflow-ellipsis" title="${`${opts.title || ""}`.qq()}">${opts.title || ""}</span>`);
|
||||
const $hovTitle = $(`<span class="window-title min-w-0 ve-overflow-ellipsis" title="${`${opts.title || ""}`.qq()}">${opts.title || ""}</span>`);
|
||||
|
||||
const hoverWindow = {};
|
||||
const hoverId = Renderer.hover._getNextId();
|
||||
|
||||
35
js/search.js
35
js/search.js
@ -13,6 +13,23 @@ class SearchPage {
|
||||
this._render();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static _PARAM_QUERY = "q";
|
||||
static _PARAM_LUCKY = "lucky";
|
||||
|
||||
static _getSearchParams () {
|
||||
const params = new URLSearchParams(location.search);
|
||||
return Object.fromEntries(params);
|
||||
}
|
||||
|
||||
static _setSearchParams (obj) {
|
||||
const params = new URLSearchParams(obj);
|
||||
location.search = params.toString();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static _render_$getBtnToggleFilter (
|
||||
{
|
||||
propOmnisearch,
|
||||
@ -43,11 +60,13 @@ class SearchPage {
|
||||
if (evt.key !== "Enter") return;
|
||||
$btnSearch.click();
|
||||
})
|
||||
.val(decodeURIComponent(location.search.slice(1).replace(/\+/g, " ")));
|
||||
.val(this._getSearchParams()[this._PARAM_QUERY]);
|
||||
|
||||
const $btnSearch = $(`<button class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>`)
|
||||
.click(() => {
|
||||
location.search = encodeURIComponent($iptSearch.val().trim().toLowerCase());
|
||||
this._setSearchParams({
|
||||
[this._PARAM_QUERY]: $iptSearch.val().trim().toLowerCase(),
|
||||
});
|
||||
});
|
||||
|
||||
const $btnHelp = $(`<button class="btn btn-default mr-2 mobile__hidden" title="Help"><span class="glyphicon glyphicon-info-sign"></span></button>`)
|
||||
@ -146,12 +165,14 @@ class SearchPage {
|
||||
}
|
||||
SearchPage._rowMetas = [];
|
||||
|
||||
if (!location.search.slice(1)) {
|
||||
const params = this._getSearchParams();
|
||||
|
||||
if (!params[this._PARAM_QUERY]) {
|
||||
SearchPage._$wrpResults.empty().append(this._getWrpResult_message("Enter a search to view results"));
|
||||
return;
|
||||
}
|
||||
|
||||
Omnisearch.pGetResults(decodeURIComponent(location.search.slice(1).replace(/\+/g, " ")))
|
||||
Omnisearch.pGetResults(params[this._PARAM_QUERY])
|
||||
.then(results => {
|
||||
SearchPage._$wrpResults.empty();
|
||||
|
||||
@ -160,6 +181,12 @@ class SearchPage {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._PARAM_LUCKY in params) {
|
||||
const [result] = results;
|
||||
window.location = `${Renderer.get().baseUrl}${Omnisearch.getResultHref(result.doc)}`;
|
||||
return;
|
||||
}
|
||||
|
||||
SearchPage._rowMetas = results.map(result => {
|
||||
const r = result.doc;
|
||||
|
||||
|
||||
@ -231,6 +231,7 @@ class SpellsPage extends ListPageMultiSource {
|
||||
colTransforms: {
|
||||
name: UtilsTableview.COL_TRANSFORM_NAME,
|
||||
source: UtilsTableview.COL_TRANSFORM_SOURCE,
|
||||
page: UtilsTableview.COL_TRANSFORM_PAGE,
|
||||
level: {name: "Level", transform: (it) => Parser.spLevelToFull(it)},
|
||||
time: {name: "Casting Time", transform: (it) => PageFilterSpells.getTblTimeStr(it[0])},
|
||||
duration: {name: "Duration", transform: (it) => Parser.spDurationToFull(it)},
|
||||
|
||||
@ -2325,10 +2325,10 @@ StatGenUi.CompAsi = class extends BaseComponent {
|
||||
}
|
||||
|
||||
render ($wrpAsi) {
|
||||
const $wrpRowsAsi = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
|
||||
const $wrpRowsRace = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
|
||||
const $wrpRowsBackground = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
|
||||
const $wrpRowsCustom = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
|
||||
const $wrpRowsAsi = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
|
||||
const $wrpRowsRace = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
|
||||
const $wrpRowsBackground = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
|
||||
const $wrpRowsCustom = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
|
||||
|
||||
this._render_renderAsiFeatSection("common_cntAsi", "ability", $wrpRowsAsi);
|
||||
this._render_renderAsiFeatSection("common_cntFeatsCustom", "custom", $wrpRowsCustom);
|
||||
|
||||
@ -1896,7 +1896,7 @@ class ManageBrewUi {
|
||||
.click(evt => this._pHandleClick_btnListMass({evt, rdState}));
|
||||
const $iptSearch = $(`<input type="search" class="search manbrew__search form-control" placeholder="Search ${this._brewUtil.DISPLAY_NAME}...">`);
|
||||
const $cbAll = $(`<input type="checkbox">`);
|
||||
const $wrpList = $(`<div class="list-display-only max-h-unset smooth-scroll overflow-y-auto h-100 min-h-0 brew-list brew-list--target manbrew__list relative ve-flex-col w-100 mb-3"></div>`);
|
||||
const $wrpList = $(`<div class="list-display-only max-h-unset smooth-scroll ve-overflow-y-auto h-100 min-h-0 brew-list brew-list--target manbrew__list relative ve-flex-col w-100 mb-3"></div>`);
|
||||
|
||||
rdState.list = new List({
|
||||
$iptSearch,
|
||||
|
||||
@ -17,6 +17,15 @@ class _DataLoaderConst {
|
||||
static SOURCE_BREW_ALL_CURRENT = Symbol("SOURCE_BREW_ALL_CURRENT");
|
||||
|
||||
static ENTITY_NULL = Symbol("ENTITY_NULL");
|
||||
|
||||
static _SOURCES_ALL_NON_SITE = new Set([
|
||||
this.SOURCE_PRERELEASE_ALL_CURRENT,
|
||||
this.SOURCE_BREW_ALL_CURRENT,
|
||||
]);
|
||||
|
||||
static isSourceAllNonSite (source) {
|
||||
return this._SOURCES_ALL_NON_SITE.has(source);
|
||||
}
|
||||
}
|
||||
|
||||
class _DataLoaderInternalUtil {
|
||||
@ -638,6 +647,7 @@ class _DataTypeLoader {
|
||||
async _pPrePopulate ({data, isPrerelease, isBrew}) { /* Implement as required */ }
|
||||
|
||||
async pGetSiteData ({pageClean, sourceClean}) {
|
||||
if (_DataLoaderConst.isSourceAllNonSite(sourceClean)) return {};
|
||||
const propCache = this._getSiteIdent({pageClean, sourceClean});
|
||||
this._cache_pSiteData[propCache] = this._cache_pSiteData[propCache] || this._pGetSiteData({pageClean, sourceClean});
|
||||
return this._cache_pSiteData[propCache];
|
||||
|
||||
@ -993,6 +993,8 @@ PropOrder._CONDITION = [
|
||||
"basicRules",
|
||||
"otherSources",
|
||||
|
||||
"color",
|
||||
|
||||
"entries",
|
||||
|
||||
"hasFluff",
|
||||
@ -1028,6 +1030,8 @@ PropOrder._STATUS = [
|
||||
"srd",
|
||||
"basicRules",
|
||||
|
||||
"color",
|
||||
|
||||
"entries",
|
||||
];
|
||||
PropOrder._CULT = [
|
||||
|
||||
@ -68,7 +68,7 @@ class UtilsTableview {
|
||||
}
|
||||
|
||||
static _getTableHtml ({state, entities, colTransforms, sorter}) {
|
||||
let stack = `<div class="overflow-y-auto w-100 h-100 ve-flex-col overflow-x-auto">
|
||||
let stack = `<div class="ve-overflow-y-auto w-100 h-100 ve-flex-col ve-overflow-x-auto">
|
||||
<table class="w-100 table-striped stats stats--book stats--book-large min-w-100 w-initial">
|
||||
<thead>
|
||||
<tr>${Object.values(colTransforms).map((c, i) => `<th data-col="${i}" class="px-2" colspan="${c.flex || 1}">${c.name}</th>`).join("")}</tr>
|
||||
@ -100,5 +100,6 @@ class UtilsTableview {
|
||||
// region Default/generic transforms
|
||||
static COL_TRANSFORM_NAME = {name: "Name"};
|
||||
static COL_TRANSFORM_SOURCE = {name: "Source", transform: (it) => `<span class="${Parser.sourceJsonToColor(it)}" title="${Parser.sourceJsonToFull(it)}" ${Parser.sourceJsonToStyle(it)}>${Parser.sourceJsonToAbv(it)}</span>`};
|
||||
static COL_TRANSFORM_PAGE = {name: "Page"};
|
||||
// endregion
|
||||
}
|
||||
|
||||
@ -1411,7 +1411,7 @@ class TabUiUtilSide extends TabUiUtilBase {
|
||||
};
|
||||
|
||||
obj.__$getWrpTab = function ({tabMeta}) {
|
||||
return $(`<div class="ve-flex-col w-100 h-100 ui-tab-side__wrp-tab ${tabMeta.isNoPadding ? "" : "px-3 py-2"} overflow-y-auto"></div>`);
|
||||
return $(`<div class="ve-flex-col w-100 h-100 ui-tab-side__wrp-tab ${tabMeta.isNoPadding ? "" : "px-3 py-2"} ve-overflow-y-auto"></div>`);
|
||||
};
|
||||
|
||||
obj.__renderTabs_addToParent = function ({$dispTabTitle, $parent, tabMetasOut}) {
|
||||
@ -5075,7 +5075,7 @@ class ComponentUiUtil {
|
||||
.prop("disabled", !!opts.isDisabled)
|
||||
.disableSpellcheck();
|
||||
|
||||
const $wrpChoices = $(`<div class="absolute ui-sel2__wrp-options overflow-y-scroll"></div>`);
|
||||
const $wrpChoices = $(`<div class="absolute ui-sel2__wrp-options ve-overflow-y-scroll"></div>`);
|
||||
|
||||
const $wrp = $$`<div class="ve-flex relative ui-sel2__wrp w-100">
|
||||
${$iptDisplay}
|
||||
@ -5586,7 +5586,7 @@ class ComponentUiUtil {
|
||||
// Always return this as a "meta" object
|
||||
const unhook = () => rowMetas.forEach(it => it.unhook());
|
||||
return {
|
||||
$ele: $$`<div class="ve-flex-col w-100 overflow-y-auto">${$eles}</div>`,
|
||||
$ele: $$`<div class="ve-flex-col w-100 ve-overflow-y-auto">${$eles}</div>`,
|
||||
$iptSearch,
|
||||
rowMetas, // Return this to allow for creating custom UI
|
||||
propIsAcceptable,
|
||||
@ -5911,7 +5911,7 @@ ComponentUiUtil.RangeSlider = class {
|
||||
_getDispValue ({isVisible, side}) {
|
||||
return e_({
|
||||
tag: "div",
|
||||
clazz: `overflow-hidden ui-slidr__disp-value no-shrink no-grow ve-flex-vh-center bold no-select ${isVisible ? `ui-slidr__disp-value--visible` : ""} ui-slidr__disp-value--${side}`,
|
||||
clazz: `ve-overflow-hidden ui-slidr__disp-value no-shrink no-grow ve-flex-vh-center bold no-select ${isVisible ? `ui-slidr__disp-value--visible` : ""} ui-slidr__disp-value--${side}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
21
js/utils.js
21
js/utils.js
@ -2,7 +2,7 @@
|
||||
|
||||
// in deployment, `IS_DEPLOYED = "<version number>";` should be set below.
|
||||
globalThis.IS_DEPLOYED = undefined;
|
||||
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.203.0"/* 5ETOOLS_VERSION__CLOSE */;
|
||||
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.204.0"/* 5ETOOLS_VERSION__CLOSE */;
|
||||
globalThis.DEPLOYED_IMG_ROOT = undefined;
|
||||
// for the roll20 script to set
|
||||
globalThis.IS_VTT = false;
|
||||
@ -915,7 +915,7 @@ globalThis.JqueryUtil = {
|
||||
if (JqueryUtil._WRP_TOAST == null) {
|
||||
JqueryUtil._WRP_TOAST = e_({
|
||||
tag: "div",
|
||||
clazz: "toast__container no-events w-100 overflow-y-hidden ve-flex-col",
|
||||
clazz: "toast__container no-events w-100 ve-overflow-y-hidden ve-flex-col",
|
||||
});
|
||||
document.body.appendChild(JqueryUtil._WRP_TOAST);
|
||||
}
|
||||
@ -7249,7 +7249,7 @@ class BookModeViewBase {
|
||||
}
|
||||
|
||||
async _pGetContentElementMetas () {
|
||||
const $wrpContent = $(`<div class="bkmv__scroller smooth-scroll overflow-y-auto print__overflow-visible ${this._isColumns ? "bkmv__wrp" : "ve-flex-col"} w-100 min-h-0"></div>`);
|
||||
const $wrpContent = $(`<div class="bkmv__scroller smooth-scroll ve-overflow-y-auto print__overflow-visible ${this._isColumns ? "bkmv__wrp" : "ve-flex-col"} w-100 min-h-0"></div>`);
|
||||
|
||||
const $wrpContentOuter = $$`<div class="h-100 print__h-initial w-100 min-h-0 ve-flex-col print__ve-block">${$wrpContent}</div>`;
|
||||
|
||||
@ -7700,20 +7700,7 @@ if (!IS_VTT && typeof window !== "undefined") {
|
||||
});
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
document.body.addEventListener("click", (evt) => {
|
||||
const eleDice = evt.target.hasAttribute("data-packed-dice")
|
||||
? evt.target
|
||||
// Tolerate e.g. Bestiary wrapped proficiency dice rollers
|
||||
: evt.target.parentElement?.hasAttribute("data-packed-dice")
|
||||
? evt.target.parentElement
|
||||
: null;
|
||||
|
||||
if (!eleDice) return;
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopImmediatePropagation();
|
||||
Renderer.dice.pRollerClickUseData(evt, eleDice).then(null);
|
||||
});
|
||||
Renderer.dice.bindOnclickListener(document.body);
|
||||
Renderer.events.bindGeneric();
|
||||
});
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
<nav class="container page__nav" id="navigation"><ul class="nav nav-pills page__nav-inner" id="navbar"></ul></nav>
|
||||
|
||||
<div class="container view-col-wrapper mt-2">
|
||||
<div class="view-col overflow-y-auto" style="flex: 3;">
|
||||
<div class="view-col ve-overflow-y-auto" style="flex: 3;">
|
||||
<p>This tool can be used to create data compatible with the <a href="https://rpg-cards.vercel.app" rel="noopener noreferrer">RPG Cards</a> app.</p>
|
||||
<p>Icons are taken from the open-source <i>RPG Cards</i> code, which is in turn sources icons from <a href="https://game-icons.net/" rel="noopener noreferrer">Game-icons.net</a>. Most of the icons available there should be available here.</p>
|
||||
<hr class="hr-0">
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
<button class="btn btn-default reset" id="reset" type="button">Reset</button>
|
||||
</div>
|
||||
|
||||
<div class="flex-col overflow-y-scroll min-h-0 pr-2" data-name="tablepage-wrp-list">
|
||||
<div class="flex-col ve-overflow-y-scroll min-h-0 pr-2" data-name="tablepage-wrp-list">
|
||||
<!-- populate with JS -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "5etools",
|
||||
"version": "1.203.0",
|
||||
"version": "1.204.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "5etools",
|
||||
"version": "1.203.0",
|
||||
"version": "1.204.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"5etools-utils": "^0.10.19",
|
||||
"5etools-utils": "^0.10.21",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"commander": "^12.0.0",
|
||||
@ -3926,9 +3926,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/5etools-utils": {
|
||||
"version": "0.10.19",
|
||||
"resolved": "https://registry.npmjs.org/5etools-utils/-/5etools-utils-0.10.19.tgz",
|
||||
"integrity": "sha512-0Zmbyu8S9NdwdTxAtZeVMi81jGRZBUyF5nBptSHtcCmuVfOaHPY6v4Z3kH3DuCokvqxWqzELw793a+JFNpYeCw==",
|
||||
"version": "0.10.21",
|
||||
"resolved": "https://registry.npmjs.org/5etools-utils/-/5etools-utils-0.10.21.tgz",
|
||||
"integrity": "sha512-m5Oroj31XkXa2S7eMATDxZ7nuo77uy12eAI+4HMzmxNNZiDNp1v/I4TAWmrDUb0jGX+iIv8O6qMDQHTc6k8cYw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^8.12.0",
|
||||
@ -14589,9 +14589,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"5etools-utils": {
|
||||
"version": "0.10.19",
|
||||
"resolved": "https://registry.npmjs.org/5etools-utils/-/5etools-utils-0.10.19.tgz",
|
||||
"integrity": "sha512-0Zmbyu8S9NdwdTxAtZeVMi81jGRZBUyF5nBptSHtcCmuVfOaHPY6v4Z3kH3DuCokvqxWqzELw793a+JFNpYeCw==",
|
||||
"version": "0.10.21",
|
||||
"resolved": "https://registry.npmjs.org/5etools-utils/-/5etools-utils-0.10.21.tgz",
|
||||
"integrity": "sha512-m5Oroj31XkXa2S7eMATDxZ7nuo77uy12eAI+4HMzmxNNZiDNp1v/I4TAWmrDUb0jGX+iIv8O6qMDQHTc6k8cYw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^8.12.0",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "5etools",
|
||||
"author": "TheGiddyLimit",
|
||||
"version": "1.203.0",
|
||||
"version": "1.204.0",
|
||||
"license": "MIT",
|
||||
"description": "A site dedicated to making playing games with your friends as easy as possible.",
|
||||
"type": "module",
|
||||
@ -46,7 +46,7 @@
|
||||
"url": "git+https://github.com/5etools-mirror-2/5etools-mirror-2.github.io.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"5etools-utils": "^0.10.19",
|
||||
"5etools-utils": "^0.10.21",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"commander": "^12.0.0",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user